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 */ 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 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 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 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 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 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 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