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(®s->tx_rx);
94*a2e99a71SMartin Fuzzey writew(0xFF, ®s->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(®s->interrupt);
99*a2e99a71SMartin Fuzzey } while (!(status & MXC_W1_INTERRUPT_RBF));
100*a2e99a71SMartin Fuzzey
101*a2e99a71SMartin Fuzzey return (u8)readw(®s->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(®s->tx_rx);
120*a2e99a71SMartin Fuzzey writew(byte, ®s->tx_rx);
121*a2e99a71SMartin Fuzzey
122*a2e99a71SMartin Fuzzey do {
123*a2e99a71SMartin Fuzzey udelay(1);
124*a2e99a71SMartin Fuzzey status = readw(®s->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