xref: /openbmc/u-boot/drivers/w1/mxc_w1.c (revision 7e40d0a3)
1*a2e99a71SMartin Fuzzey // SPDX-License-Identifier: GPL-2.0+
2*a2e99a71SMartin Fuzzey /*
3*a2e99a71SMartin Fuzzey  * Driver for one wire controller in some i.MX Socs
4*a2e99a71SMartin Fuzzey  *
5*a2e99a71SMartin Fuzzey  * There are currently two silicon variants:
6*a2e99a71SMartin Fuzzey  * V1: i.MX21, i.MX27, i.MX31, i.MX51
7*a2e99a71SMartin Fuzzey  * V2: i.MX25, i.MX35, i.MX50, i.MX53
8*a2e99a71SMartin Fuzzey  * Newer i.MX SoCs such as the i.MX6 do not have one wire controllers.
9*a2e99a71SMartin Fuzzey  *
10*a2e99a71SMartin Fuzzey  * The V1 controller only supports single bit operations.
11*a2e99a71SMartin Fuzzey  * The V2 controller is backwards compatible on the register level but adds
12*a2e99a71SMartin Fuzzey  * byte size operations and a "search ROM accelerator mode"
13*a2e99a71SMartin Fuzzey  *
14*a2e99a71SMartin Fuzzey  * This driver does not currently support the search ROM accelerator
15*a2e99a71SMartin Fuzzey  *
16*a2e99a71SMartin Fuzzey  * Copyright (c) 2018 Flowbird
17*a2e99a71SMartin Fuzzey  * Martin Fuzzey <martin.fuzzey@flowbird.group>
18*a2e99a71SMartin Fuzzey  */
19*a2e99a71SMartin Fuzzey 
20*a2e99a71SMartin Fuzzey #include <asm/arch/clock.h>
21*a2e99a71SMartin Fuzzey #include <common.h>
22*a2e99a71SMartin Fuzzey #include <dm.h>
23*a2e99a71SMartin Fuzzey #include <linux/io.h>
24*a2e99a71SMartin Fuzzey #include <w1.h>
25*a2e99a71SMartin Fuzzey 
26*a2e99a71SMartin Fuzzey struct mxc_w1_regs {
27*a2e99a71SMartin Fuzzey 	u16 control;
28*a2e99a71SMartin Fuzzey #define MXC_W1_CONTROL_RPP	BIT(7)
29*a2e99a71SMartin Fuzzey #define MXC_W1_CONTROL_PST	BIT(6)
30*a2e99a71SMartin Fuzzey #define MXC_W1_CONTROL_WR(x)	BIT(5 - (x))
31*a2e99a71SMartin Fuzzey #define MXC_W1_CONTROL_RDST	BIT(3)
32*a2e99a71SMartin Fuzzey 
33*a2e99a71SMartin Fuzzey 	u16 time_divider;
34*a2e99a71SMartin Fuzzey 	u16 reset;
35*a2e99a71SMartin Fuzzey 
36*a2e99a71SMartin Fuzzey 	/* Registers below on V2 silicon only */
37*a2e99a71SMartin Fuzzey 	u16 command;
38*a2e99a71SMartin Fuzzey 	u16 tx_rx;
39*a2e99a71SMartin Fuzzey 	u16 interrupt;
40*a2e99a71SMartin Fuzzey #define MXC_W1_INTERRUPT_TBE	BIT(2)
41*a2e99a71SMartin Fuzzey #define MXC_W1_INTERRUPT_TSRE	BIT(3)
42*a2e99a71SMartin Fuzzey #define MXC_W1_INTERRUPT_RBF	BIT(4)
43*a2e99a71SMartin Fuzzey #define MXC_W1_INTERRUPT_RSRF	BIT(5)
44*a2e99a71SMartin Fuzzey 
45*a2e99a71SMartin Fuzzey 	u16 interrupt_en;
46*a2e99a71SMartin Fuzzey };
47*a2e99a71SMartin Fuzzey 
48*a2e99a71SMartin Fuzzey struct mxc_w1_pdata {
49*a2e99a71SMartin Fuzzey 	struct mxc_w1_regs *regs;
50*a2e99a71SMartin Fuzzey };
51*a2e99a71SMartin Fuzzey 
52*a2e99a71SMartin Fuzzey /*
53*a2e99a71SMartin Fuzzey  * this is the low level routine to read/write a bit on the One Wire
54*a2e99a71SMartin Fuzzey  * interface on the hardware. It does write 0 if parameter bit is set
55*a2e99a71SMartin Fuzzey  * to 0, otherwise a write 1/read.
56*a2e99a71SMartin Fuzzey  */
mxc_w1_touch_bit(struct mxc_w1_pdata * pdata,u8 bit)57*a2e99a71SMartin Fuzzey static u8 mxc_w1_touch_bit(struct mxc_w1_pdata *pdata, u8 bit)
58*a2e99a71SMartin Fuzzey {
59*a2e99a71SMartin Fuzzey 	u16 *ctrl_addr = &pdata->regs->control;
60*a2e99a71SMartin Fuzzey 	u16 mask = MXC_W1_CONTROL_WR(bit);
61*a2e99a71SMartin Fuzzey 	unsigned int timeout_cnt = 400; /* Takes max. 120us according to
62*a2e99a71SMartin Fuzzey 					 * datasheet.
63*a2e99a71SMartin Fuzzey 					 */
64*a2e99a71SMartin Fuzzey 
65*a2e99a71SMartin Fuzzey 	writew(mask, ctrl_addr);
66*a2e99a71SMartin Fuzzey 
67*a2e99a71SMartin Fuzzey 	while (timeout_cnt--) {
68*a2e99a71SMartin Fuzzey 		if (!(readw(ctrl_addr) & mask))
69*a2e99a71SMartin Fuzzey 			break;
70*a2e99a71SMartin Fuzzey 
71*a2e99a71SMartin Fuzzey 		udelay(1);
72*a2e99a71SMartin Fuzzey 	}
73*a2e99a71SMartin Fuzzey 
74*a2e99a71SMartin Fuzzey 	return (readw(ctrl_addr) & MXC_W1_CONTROL_RDST) ? 1 : 0;
75*a2e99a71SMartin Fuzzey }
76*a2e99a71SMartin Fuzzey 
mxc_w1_read_byte(struct udevice * dev)77*a2e99a71SMartin Fuzzey static u8 mxc_w1_read_byte(struct udevice *dev)
78*a2e99a71SMartin Fuzzey {
79*a2e99a71SMartin Fuzzey 	struct mxc_w1_pdata *pdata = dev_get_platdata(dev);
80*a2e99a71SMartin Fuzzey 	struct mxc_w1_regs *regs = pdata->regs;
81*a2e99a71SMartin Fuzzey 	u16 status;
82*a2e99a71SMartin Fuzzey 
83*a2e99a71SMartin Fuzzey 	if (dev_get_driver_data(dev) < 2) {
84*a2e99a71SMartin Fuzzey 		int i;
85*a2e99a71SMartin Fuzzey 		u8 ret = 0;
86*a2e99a71SMartin Fuzzey 
87*a2e99a71SMartin Fuzzey 		for (i = 0; i < 8; i++)
88*a2e99a71SMartin Fuzzey 			ret |= (mxc_w1_touch_bit(pdata, 1) << i);
89*a2e99a71SMartin Fuzzey 
90*a2e99a71SMartin Fuzzey 		return ret;
91*a2e99a71SMartin Fuzzey 	}
92*a2e99a71SMartin Fuzzey 
93*a2e99a71SMartin Fuzzey 	readw(&regs->tx_rx);
94*a2e99a71SMartin Fuzzey 	writew(0xFF, &regs->tx_rx);
95*a2e99a71SMartin Fuzzey 
96*a2e99a71SMartin Fuzzey 	do {
97*a2e99a71SMartin Fuzzey 		udelay(1); /* Without this bytes are sometimes duplicated... */
98*a2e99a71SMartin Fuzzey 		status = readw(&regs->interrupt);
99*a2e99a71SMartin Fuzzey 	} while (!(status & MXC_W1_INTERRUPT_RBF));
100*a2e99a71SMartin Fuzzey 
101*a2e99a71SMartin Fuzzey 	return (u8)readw(&regs->tx_rx);
102*a2e99a71SMartin Fuzzey }
103*a2e99a71SMartin Fuzzey 
mxc_w1_write_byte(struct udevice * dev,u8 byte)104*a2e99a71SMartin Fuzzey static void mxc_w1_write_byte(struct udevice *dev, u8 byte)
105*a2e99a71SMartin Fuzzey {
106*a2e99a71SMartin Fuzzey 	struct mxc_w1_pdata *pdata = dev_get_platdata(dev);
107*a2e99a71SMartin Fuzzey 	struct mxc_w1_regs *regs = pdata->regs;
108*a2e99a71SMartin Fuzzey 	u16 status;
109*a2e99a71SMartin Fuzzey 
110*a2e99a71SMartin Fuzzey 	if (dev_get_driver_data(dev) < 2) {
111*a2e99a71SMartin Fuzzey 		int i;
112*a2e99a71SMartin Fuzzey 
113*a2e99a71SMartin Fuzzey 		for (i = 0; i < 8; i++)
114*a2e99a71SMartin Fuzzey 			mxc_w1_touch_bit(pdata, (byte >> i) & 0x1);
115*a2e99a71SMartin Fuzzey 
116*a2e99a71SMartin Fuzzey 		return;
117*a2e99a71SMartin Fuzzey 	}
118*a2e99a71SMartin Fuzzey 
119*a2e99a71SMartin Fuzzey 	readw(&regs->tx_rx);
120*a2e99a71SMartin Fuzzey 	writew(byte, &regs->tx_rx);
121*a2e99a71SMartin Fuzzey 
122*a2e99a71SMartin Fuzzey 	do {
123*a2e99a71SMartin Fuzzey 		udelay(1);
124*a2e99a71SMartin Fuzzey 		status = readw(&regs->interrupt);
125*a2e99a71SMartin Fuzzey 	} while (!(status & MXC_W1_INTERRUPT_TSRE));
126*a2e99a71SMartin Fuzzey }
127*a2e99a71SMartin Fuzzey 
mxc_w1_reset(struct udevice * dev)128*a2e99a71SMartin Fuzzey static bool mxc_w1_reset(struct udevice *dev)
129*a2e99a71SMartin Fuzzey {
130*a2e99a71SMartin Fuzzey 	struct mxc_w1_pdata *pdata = dev_get_platdata(dev);
131*a2e99a71SMartin Fuzzey 	u16 reg_val;
132*a2e99a71SMartin Fuzzey 
133*a2e99a71SMartin Fuzzey 	writew(MXC_W1_CONTROL_RPP, &pdata->regs->control);
134*a2e99a71SMartin Fuzzey 
135*a2e99a71SMartin Fuzzey 	do {
136*a2e99a71SMartin Fuzzey 		reg_val = readw(&pdata->regs->control);
137*a2e99a71SMartin Fuzzey 	}  while (reg_val & MXC_W1_CONTROL_RPP);
138*a2e99a71SMartin Fuzzey 
139*a2e99a71SMartin Fuzzey 	return !(reg_val & MXC_W1_CONTROL_PST);
140*a2e99a71SMartin Fuzzey }
141*a2e99a71SMartin Fuzzey 
mxc_w1_triplet(struct udevice * dev,bool bdir)142*a2e99a71SMartin Fuzzey static u8 mxc_w1_triplet(struct udevice *dev, bool bdir)
143*a2e99a71SMartin Fuzzey {
144*a2e99a71SMartin Fuzzey 	struct mxc_w1_pdata *pdata = dev_get_platdata(dev);
145*a2e99a71SMartin Fuzzey 	u8 id_bit   = mxc_w1_touch_bit(pdata, 1);
146*a2e99a71SMartin Fuzzey 	u8 comp_bit = mxc_w1_touch_bit(pdata, 1);
147*a2e99a71SMartin Fuzzey 	u8 retval;
148*a2e99a71SMartin Fuzzey 
149*a2e99a71SMartin Fuzzey 	if (id_bit && comp_bit)
150*a2e99a71SMartin Fuzzey 		return 0x03;  /* error */
151*a2e99a71SMartin Fuzzey 
152*a2e99a71SMartin Fuzzey 	if (!id_bit && !comp_bit) {
153*a2e99a71SMartin Fuzzey 		/* Both bits are valid, take the direction given */
154*a2e99a71SMartin Fuzzey 		retval = bdir ? 0x04 : 0;
155*a2e99a71SMartin Fuzzey 	} else {
156*a2e99a71SMartin Fuzzey 		/* Only one bit is valid, take that direction */
157*a2e99a71SMartin Fuzzey 		bdir = id_bit;
158*a2e99a71SMartin Fuzzey 		retval = id_bit ? 0x05 : 0x02;
159*a2e99a71SMartin Fuzzey 	}
160*a2e99a71SMartin Fuzzey 
161*a2e99a71SMartin Fuzzey 	mxc_w1_touch_bit(pdata, bdir);
162*a2e99a71SMartin Fuzzey 
163*a2e99a71SMartin Fuzzey 	return retval;
164*a2e99a71SMartin Fuzzey }
165*a2e99a71SMartin Fuzzey 
mxc_w1_ofdata_to_platdata(struct udevice * dev)166*a2e99a71SMartin Fuzzey static int mxc_w1_ofdata_to_platdata(struct udevice *dev)
167*a2e99a71SMartin Fuzzey {
168*a2e99a71SMartin Fuzzey 	struct mxc_w1_pdata *pdata = dev_get_platdata(dev);
169*a2e99a71SMartin Fuzzey 	fdt_addr_t addr;
170*a2e99a71SMartin Fuzzey 
171*a2e99a71SMartin Fuzzey 	addr = devfdt_get_addr(dev);
172*a2e99a71SMartin Fuzzey 	if (addr == FDT_ADDR_T_NONE)
173*a2e99a71SMartin Fuzzey 		return -EINVAL;
174*a2e99a71SMartin Fuzzey 
175*a2e99a71SMartin Fuzzey 	pdata->regs = (struct mxc_w1_regs *)addr;
176*a2e99a71SMartin Fuzzey 
177*a2e99a71SMartin Fuzzey 	return 0;
178*a2e99a71SMartin Fuzzey };
179*a2e99a71SMartin Fuzzey 
mxc_w1_probe(struct udevice * dev)180*a2e99a71SMartin Fuzzey static int mxc_w1_probe(struct udevice *dev)
181*a2e99a71SMartin Fuzzey {
182*a2e99a71SMartin Fuzzey 	struct mxc_w1_pdata *pdata = dev_get_platdata(dev);
183*a2e99a71SMartin Fuzzey 	unsigned int clkrate = mxc_get_clock(MXC_IPG_PERCLK);
184*a2e99a71SMartin Fuzzey 	unsigned int clkdiv;
185*a2e99a71SMartin Fuzzey 
186*a2e99a71SMartin Fuzzey 	if (clkrate < 10000000) {
187*a2e99a71SMartin Fuzzey 		dev_err(dev, "input clock frequency (%u Hz) too low\n",
188*a2e99a71SMartin Fuzzey 			clkrate);
189*a2e99a71SMartin Fuzzey 		return -EINVAL;
190*a2e99a71SMartin Fuzzey 	}
191*a2e99a71SMartin Fuzzey 
192*a2e99a71SMartin Fuzzey 	clkdiv = clkrate / 1000000;
193*a2e99a71SMartin Fuzzey 	clkrate /= clkdiv;
194*a2e99a71SMartin Fuzzey 	if (clkrate < 980000 || clkrate > 1020000) {
195*a2e99a71SMartin Fuzzey 		dev_err(dev, "Incorrect time base frequency %u Hz\n", clkrate);
196*a2e99a71SMartin Fuzzey 		return -EINVAL;
197*a2e99a71SMartin Fuzzey 	}
198*a2e99a71SMartin Fuzzey 
199*a2e99a71SMartin Fuzzey 	writew(clkdiv - 1, &pdata->regs->time_divider);
200*a2e99a71SMartin Fuzzey 
201*a2e99a71SMartin Fuzzey 	return 0;
202*a2e99a71SMartin Fuzzey }
203*a2e99a71SMartin Fuzzey 
204*a2e99a71SMartin Fuzzey static const struct w1_ops mxc_w1_ops = {
205*a2e99a71SMartin Fuzzey 	.read_byte	= mxc_w1_read_byte,
206*a2e99a71SMartin Fuzzey 	.reset		= mxc_w1_reset,
207*a2e99a71SMartin Fuzzey 	.triplet	= mxc_w1_triplet,
208*a2e99a71SMartin Fuzzey 	.write_byte	= mxc_w1_write_byte,
209*a2e99a71SMartin Fuzzey };
210*a2e99a71SMartin Fuzzey 
211*a2e99a71SMartin Fuzzey static const struct udevice_id mxc_w1_id[] = {
212*a2e99a71SMartin Fuzzey 	{ .compatible = "fsl,imx21-owire", .data = 1 },
213*a2e99a71SMartin Fuzzey 	{ .compatible = "fsl,imx27-owire", .data = 1 },
214*a2e99a71SMartin Fuzzey 	{ .compatible = "fsl,imx31-owire", .data = 1 },
215*a2e99a71SMartin Fuzzey 	{ .compatible = "fsl,imx51-owire", .data = 1 },
216*a2e99a71SMartin Fuzzey 
217*a2e99a71SMartin Fuzzey 	{ .compatible = "fsl,imx25-owire", .data = 2 },
218*a2e99a71SMartin Fuzzey 	{ .compatible = "fsl,imx35-owire", .data = 2 },
219*a2e99a71SMartin Fuzzey 	{ .compatible = "fsl,imx50-owire", .data = 2 },
220*a2e99a71SMartin Fuzzey 	{ .compatible = "fsl,imx53-owire", .data = 2 },
221*a2e99a71SMartin Fuzzey 	{ },
222*a2e99a71SMartin Fuzzey };
223*a2e99a71SMartin Fuzzey 
224*a2e99a71SMartin Fuzzey U_BOOT_DRIVER(mxc_w1_drv) = {
225*a2e99a71SMartin Fuzzey 	.id				= UCLASS_W1,
226*a2e99a71SMartin Fuzzey 	.name				= "mxc_w1_drv",
227*a2e99a71SMartin Fuzzey 	.of_match			= mxc_w1_id,
228*a2e99a71SMartin Fuzzey 	.ofdata_to_platdata		= mxc_w1_ofdata_to_platdata,
229*a2e99a71SMartin Fuzzey 	.ops				= &mxc_w1_ops,
230*a2e99a71SMartin Fuzzey 	.platdata_auto_alloc_size	= sizeof(struct mxc_w1_pdata),
231*a2e99a71SMartin Fuzzey 	.probe				= mxc_w1_probe,
232*a2e99a71SMartin Fuzzey };
233