Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | // SPDX-License-Identifier: GPL-2.0-or-later /* * (C) Copyright 2022 - Analog Devices, Inc. * * Written and/or maintained by Timesys Corporation * * Converted to driver model by Nathan Barrett-Morrison * * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com> * Contact: Greg Malysa <greg.malysa@timesys.com> */ #include <clk.h> #include <dm.h> #include <i2c.h> #include <mapmem.h> #include <linux/io.h> #define CLKLOW(x) ((x) & 0xFF) // Periods Clock Is Held Low #define CLKHI(y) (((y) & 0xFF) << 0x8) // Periods Clock Is High #define PRESCALE 0x007F // SCLKs Per Internal Time Reference (10MHz) #define TWI_ENA 0x0080 // TWI Enable #define SCCB 0x0200 // SCCB Compatibility Enable #define SEN 0x0001 // Slave Enable #define SADD_LEN 0x0002 // Slave Address Length #define STDVAL 0x0004 // Slave Transmit Data Valid #define TSC_NAK 0x0008 // NAK Generated At Conclusion Of Transfer #define GEN 0x0010 // General Call Adrress Matching Enabled #define SDIR 0x0001 // Slave Transfer Direction #define GCALL 0x0002 // General Call Indicator #define MEN 0x0001 // Master Mode Enable #define MADD_LEN 0x0002 // Master Address Length #define MDIR 0x0004 // Master Transmit Direction (RX/TX*) #define FAST 0x0008 // Use Fast Mode Timing Specs #define STOP 0x0010 // Issue Stop Condition #define RSTART 0x0020 // Repeat Start or Stop* At End Of Transfer #define DCNT 0x3FC0 // Data Bytes To Transfer #define SDAOVR 0x4000 // Serial Data Override #define SCLOVR 0x8000 // Serial Clock Override #define MPROG 0x0001 // Master Transfer In Progress #define LOSTARB 0x0002 // Lost Arbitration Indicator (Xfer Aborted) #define ANAK 0x0004 // Address Not Acknowledged #define DNAK 0x0008 // Data Not Acknowledged #define BUFRDERR 0x0010 // Buffer Read Error #define BUFWRERR 0x0020 // Buffer Write Error #define SDASEN 0x0040 // Serial Data Sense #define SCLSEN 0x0080 // Serial Clock Sense #define BUSBUSY 0x0100 // Bus Busy Indicator #define SINIT 0x0001 // Slave Transfer Initiated #define SCOMP 0x0002 // Slave Transfer Complete #define SERR 0x0004 // Slave Transfer Error #define SOVF 0x0008 // Slave Overflow #define MCOMP 0x0010 // Master Transfer Complete #define MERR 0x0020 // Master Transfer Error #define XMTSERV 0x0040 // Transmit FIFO Service #define RCVSERV 0x0080 // Receive FIFO Service #define XMTFLUSH 0x0001 // Transmit Buffer Flush #define RCVFLUSH 0x0002 // Receive Buffer Flush #define XMTINTLEN 0x0004 // Transmit Buffer Interrupt Length #define RCVINTLEN 0x0008 // Receive Buffer Interrupt Length #define XMTSTAT 0x0003 // Transmit FIFO Status #define XMT_EMPTY 0x0000 // Transmit FIFO Empty #define XMT_HALF 0x0001 // Transmit FIFO Has 1 Byte To Write #define XMT_FULL 0x0003 // Transmit FIFO Full (2 Bytes To Write) #define RCVSTAT 0x000C // Receive FIFO Status #define RCV_EMPTY 0x0000 // Receive FIFO Empty #define RCV_HALF 0x0004 // Receive FIFO Has 1 Byte To Read #define RCV_FULL 0x000C // Receive FIFO Full (2 Bytes To Read) /* Every register is 32bit aligned, but only 16bits in size */ #define ureg(name) u16 name; u16 __pad_##name struct twi_regs { ureg(clkdiv); ureg(control); ureg(slave_ctl); ureg(slave_stat); ureg(slave_addr); ureg(master_ctl); ureg(master_stat); ureg(master_addr); ureg(int_stat); ureg(int_mask); ureg(fifo_ctl); ureg(fifo_stat); u8 __pad[0x50]; ureg(xmt_data8); ureg(xmt_data16); ureg(rcv_data8); ureg(rcv_data16); }; #undef ureg /* * The way speed is changed into duty often results in integer truncation * with 50% duty, so we'll force rounding up to the next duty by adding 1 * to the max. In practice this will get us a speed of something like * 385 KHz. The other limit is easy to handle as it is only 8 bits. */ #define I2C_SPEED_MAX 400000 #define I2C_SPEED_TO_DUTY(speed) (5000000 / (speed)) #define I2C_DUTY_MAX (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1) #define I2C_DUTY_MIN 0xff /* 8 bit limited */ #define I2C_M_COMBO 0x4 #define I2C_M_STOP 0x2 #define I2C_M_READ 0x1 /* * All transfers are described by this data structure */ struct adi_i2c_msg { u8 flags; u32 len; /* msg length */ u8 *buf; /* pointer to msg data */ u32 olen; /* addr length */ u8 *obuf; /* addr buffer */ }; struct adi_i2c_dev { struct twi_regs __iomem *base; u32 i2c_clk; uint speed; }; /* Allow msec timeout per ~byte transfer */ #define I2C_TIMEOUT 10 /** * wait_for_completion - manage the actual i2c transfer * @msg: the i2c msg */ static int wait_for_completion(struct twi_regs *twi, struct adi_i2c_msg *msg) { u16 int_stat; ulong timebase = get_timer(0); do { int_stat = ioread16(&twi->int_stat); if (int_stat & XMTSERV) { iowrite16(XMTSERV, &twi->int_stat); if (msg->olen) { iowrite16(*(msg->obuf++), &twi->xmt_data8); --msg->olen; } else if (!(msg->flags & I2C_M_COMBO) && msg->len) { iowrite16(*(msg->buf++), &twi->xmt_data8); --msg->len; } else { if (msg->flags & I2C_M_COMBO) setbits_16(&twi->master_ctl, RSTART | MDIR); else setbits_16(&twi->master_ctl, STOP); } } if (int_stat & RCVSERV) { iowrite16(RCVSERV, &twi->int_stat); if (msg->len) { *(msg->buf++) = ioread16(&twi->rcv_data8); --msg->len; } else if (msg->flags & I2C_M_STOP) { setbits_16(&twi->master_ctl, STOP); } } if (int_stat & MERR) { pr_err("%s: master transmit terror: %d\n", __func__, ioread16(&twi->master_stat)); iowrite16(MERR, &twi->int_stat); return -EIO; } if (int_stat & MCOMP) { iowrite16(MCOMP, &twi->int_stat); if (msg->flags & I2C_M_COMBO && msg->len) { u16 mlen = min(msg->len, 0xffu) << 6; clrsetbits_16(&twi->master_ctl, RSTART, mlen | MEN | MDIR); } else { break; } } /* If we were able to do something, reset timeout */ if (int_stat) timebase = get_timer(0); } while (get_timer(timebase) < I2C_TIMEOUT); return 0; } static int i2c_transfer(struct twi_regs *twi, u8 chip, u8 *offset, int olen, u8 *buffer, int len, u8 flags) { int ret; u16 ctl; struct adi_i2c_msg msg = { .flags = flags | (len >= 0xff ? I2C_M_STOP : 0), .buf = buffer, .len = len, .obuf = offset, .olen = olen, }; /* wait for things to settle */ while (ioread16(&twi->master_stat) & BUSBUSY) if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc()) return -EINTR; /* Set Transmit device address */ iowrite16(chip, &twi->master_addr); /* Clear the FIFO before starting things */ iowrite16(XMTFLUSH | RCVFLUSH, &twi->fifo_ctl); iowrite16(0, &twi->fifo_ctl); /* Prime the pump */ if (msg.olen) { len = (msg.flags & I2C_M_COMBO) ? msg.olen : msg.olen + len; iowrite16(*(msg.obuf++), &twi->xmt_data8); --msg.olen; } else if (!(msg.flags & I2C_M_READ) && msg.len) { iowrite16(*(msg.buf++), &twi->xmt_data8); --msg.len; } /* clear int stat */ iowrite16(-1, &twi->master_stat); iowrite16(-1, &twi->int_stat); iowrite16(0, &twi->int_mask); /* Master enable */ ctl = ioread16(&twi->master_ctl); ctl = (ctl & FAST) | (min(len, 0xff) << 6) | MEN | ((msg.flags & I2C_M_READ) ? MDIR : 0); iowrite16(ctl, &twi->master_ctl); /* Process the rest */ ret = wait_for_completion(twi, &msg); clrbits_16(&twi->master_ctl, MEN); clrbits_16(&twi->control, TWI_ENA); setbits_16(&twi->control, TWI_ENA); return ret; } static int adi_i2c_read(struct twi_regs *twi, u8 chip, u8 *offset, int olen, u8 *buffer, int len) { return i2c_transfer(twi, chip, offset, olen, buffer, len, olen ? I2C_M_COMBO : I2C_M_READ); } static int adi_i2c_write(struct twi_regs *twi, u8 chip, u8 *offset, int olen, u8 *buffer, int len) { return i2c_transfer(twi, chip, offset, olen, buffer, len, 0); } static int adi_i2c_set_bus_speed(struct udevice *bus, uint speed) { struct adi_i2c_dev *dev = dev_get_priv(bus); struct twi_regs *twi = dev->base; u16 clkdiv = I2C_SPEED_TO_DUTY(speed); /* Set TWI interface clock */ if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN) return -1; clkdiv = (clkdiv << 8) | (clkdiv & 0xff); iowrite16(clkdiv, &twi->clkdiv); /* Don't turn it on */ iowrite16(speed > 100000 ? FAST : 0, &twi->master_ctl); return 0; } static int adi_i2c_of_to_plat(struct udevice *bus) { struct adi_i2c_dev *dev = dev_get_priv(bus); struct clk clock; u32 ret; dev->base = map_sysmem(dev_read_addr(bus), sizeof(struct twi_regs)); if (!dev->base) return -ENOMEM; dev->speed = dev_read_u32_default(bus, "clock-frequency", I2C_SPEED_FAST_RATE); ret = clk_get_by_name(bus, "i2c", &clock); if (ret < 0) printf("%s: Can't get I2C clk: %d\n", __func__, ret); else dev->i2c_clk = clk_get_rate(&clock); return 0; } static int adi_i2c_probe_chip(struct udevice *bus, u32 chip_addr, u32 chip_flags) { struct adi_i2c_dev *dev = dev_get_priv(bus); u8 byte; return adi_i2c_read(dev->base, chip_addr, NULL, 0, &byte, 1); } static int adi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) { struct adi_i2c_dev *dev = dev_get_priv(bus); struct i2c_msg *dmsg, *omsg, dummy; memset(&dummy, 0, sizeof(struct i2c_msg)); /* * We expect either two messages (one with an offset and one with the * actual data) or one message (just data) */ if (nmsgs > 2 || nmsgs == 0) { debug("%s: Only one or two messages are supported.", __func__); return -EINVAL; } omsg = nmsgs == 1 ? &dummy : msg; dmsg = nmsgs == 1 ? msg : msg + 1; if (dmsg->flags & I2C_M_RD) return adi_i2c_read(dev->base, dmsg->addr, omsg->buf, omsg->len, dmsg->buf, dmsg->len); else return adi_i2c_write(dev->base, dmsg->addr, omsg->buf, omsg->len, dmsg->buf, dmsg->len); } int adi_i2c_probe(struct udevice *bus) { struct adi_i2c_dev *dev = dev_get_priv(bus); struct twi_regs *twi = dev->base; u16 prescale = ((dev->i2c_clk / 1000 / 1000 + 5) / 10) & 0x7F; /* Set TWI internal clock as 10MHz */ iowrite16(prescale, &twi->control); /* Set TWI interface clock as specified */ adi_i2c_set_bus_speed(bus, dev->speed); /* Enable it */ iowrite16(TWI_ENA | prescale, &twi->control); return 0; } static const struct dm_i2c_ops adi_i2c_ops = { .xfer = adi_i2c_xfer, .probe_chip = adi_i2c_probe_chip, .set_bus_speed = adi_i2c_set_bus_speed, }; static const struct udevice_id adi_i2c_ids[] = { { .compatible = "adi-i2c", }, { /* sentinel */ } }; U_BOOT_DRIVER(i2c_adi) = { .name = "i2c_adi", .id = UCLASS_I2C, .of_match = adi_i2c_ids, .probe = adi_i2c_probe, .of_to_plat = adi_i2c_of_to_plat, .priv_auto = sizeof(struct adi_i2c_dev), .ops = &adi_i2c_ops, .flags = DM_FLAG_PRE_RELOC, }; |