cobalt-i2c.c (8929B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * cobalt I2C functions 4 * 5 * Derived from cx18-i2c.c 6 * 7 * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. 8 * All rights reserved. 9 */ 10 11#include "cobalt-driver.h" 12#include "cobalt-i2c.h" 13 14struct cobalt_i2c_regs { 15 /* Clock prescaler register lo-byte */ 16 u8 prerlo; 17 u8 dummy0[3]; 18 /* Clock prescaler register high-byte */ 19 u8 prerhi; 20 u8 dummy1[3]; 21 /* Control register */ 22 u8 ctr; 23 u8 dummy2[3]; 24 /* Transmit/Receive register */ 25 u8 txr_rxr; 26 u8 dummy3[3]; 27 /* Command and Status register */ 28 u8 cr_sr; 29 u8 dummy4[3]; 30}; 31 32/* CTR[7:0] - Control register */ 33 34/* I2C Core enable bit */ 35#define M00018_CTR_BITMAP_EN_MSK (1 << 7) 36 37/* I2C Core interrupt enable bit */ 38#define M00018_CTR_BITMAP_IEN_MSK (1 << 6) 39 40/* CR[7:0] - Command register */ 41 42/* I2C start condition */ 43#define M00018_CR_BITMAP_STA_MSK (1 << 7) 44 45/* I2C stop condition */ 46#define M00018_CR_BITMAP_STO_MSK (1 << 6) 47 48/* I2C read from slave */ 49#define M00018_CR_BITMAP_RD_MSK (1 << 5) 50 51/* I2C write to slave */ 52#define M00018_CR_BITMAP_WR_MSK (1 << 4) 53 54/* I2C ack */ 55#define M00018_CR_BITMAP_ACK_MSK (1 << 3) 56 57/* I2C Interrupt ack */ 58#define M00018_CR_BITMAP_IACK_MSK (1 << 0) 59 60/* SR[7:0] - Status register */ 61 62/* Receive acknowledge from slave */ 63#define M00018_SR_BITMAP_RXACK_MSK (1 << 7) 64 65/* Busy, I2C bus busy (as defined by start / stop bits) */ 66#define M00018_SR_BITMAP_BUSY_MSK (1 << 6) 67 68/* Arbitration lost - core lost arbitration */ 69#define M00018_SR_BITMAP_AL_MSK (1 << 5) 70 71/* Transfer in progress */ 72#define M00018_SR_BITMAP_TIP_MSK (1 << 1) 73 74/* Interrupt flag */ 75#define M00018_SR_BITMAP_IF_MSK (1 << 0) 76 77/* Frequency, in Hz */ 78#define I2C_FREQUENCY 400000 79#define ALT_CPU_FREQ 83333333 80 81static struct cobalt_i2c_regs __iomem * 82cobalt_i2c_regs(struct cobalt *cobalt, unsigned idx) 83{ 84 switch (idx) { 85 case 0: 86 default: 87 return (struct cobalt_i2c_regs __iomem *) 88 (cobalt->bar1 + COBALT_I2C_0_BASE); 89 case 1: 90 return (struct cobalt_i2c_regs __iomem *) 91 (cobalt->bar1 + COBALT_I2C_1_BASE); 92 case 2: 93 return (struct cobalt_i2c_regs __iomem *) 94 (cobalt->bar1 + COBALT_I2C_2_BASE); 95 case 3: 96 return (struct cobalt_i2c_regs __iomem *) 97 (cobalt->bar1 + COBALT_I2C_3_BASE); 98 case 4: 99 return (struct cobalt_i2c_regs __iomem *) 100 (cobalt->bar1 + COBALT_I2C_HSMA_BASE); 101 } 102} 103 104/* Do low-level i2c byte transfer. 105 * Returns -1 in case of an error or 0 otherwise. 106 */ 107static int cobalt_tx_bytes(struct cobalt_i2c_regs __iomem *regs, 108 struct i2c_adapter *adap, bool start, bool stop, 109 u8 *data, u16 len) 110{ 111 unsigned long start_time; 112 int status; 113 int cmd; 114 int i; 115 116 for (i = 0; i < len; i++) { 117 /* Setup data */ 118 iowrite8(data[i], ®s->txr_rxr); 119 120 /* Setup command */ 121 if (i == 0 && start) { 122 /* Write + Start */ 123 cmd = M00018_CR_BITMAP_WR_MSK | 124 M00018_CR_BITMAP_STA_MSK; 125 } else if (i == len - 1 && stop) { 126 /* Write + Stop */ 127 cmd = M00018_CR_BITMAP_WR_MSK | 128 M00018_CR_BITMAP_STO_MSK; 129 } else { 130 /* Write only */ 131 cmd = M00018_CR_BITMAP_WR_MSK; 132 } 133 134 /* Execute command */ 135 iowrite8(cmd, ®s->cr_sr); 136 137 /* Wait for transfer to complete (TIP = 0) */ 138 start_time = jiffies; 139 status = ioread8(®s->cr_sr); 140 while (status & M00018_SR_BITMAP_TIP_MSK) { 141 if (time_after(jiffies, start_time + adap->timeout)) 142 return -ETIMEDOUT; 143 cond_resched(); 144 status = ioread8(®s->cr_sr); 145 } 146 147 /* Verify ACK */ 148 if (status & M00018_SR_BITMAP_RXACK_MSK) { 149 /* NO ACK! */ 150 return -EIO; 151 } 152 153 /* Verify arbitration */ 154 if (status & M00018_SR_BITMAP_AL_MSK) { 155 /* Arbitration lost! */ 156 return -EIO; 157 } 158 } 159 return 0; 160} 161 162/* Do low-level i2c byte read. 163 * Returns -1 in case of an error or 0 otherwise. 164 */ 165static int cobalt_rx_bytes(struct cobalt_i2c_regs __iomem *regs, 166 struct i2c_adapter *adap, bool start, bool stop, 167 u8 *data, u16 len) 168{ 169 unsigned long start_time; 170 int status; 171 int cmd; 172 int i; 173 174 for (i = 0; i < len; i++) { 175 /* Setup command */ 176 if (i == 0 && start) { 177 /* Read + Start */ 178 cmd = M00018_CR_BITMAP_RD_MSK | 179 M00018_CR_BITMAP_STA_MSK; 180 } else if (i == len - 1 && stop) { 181 /* Read + Stop */ 182 cmd = M00018_CR_BITMAP_RD_MSK | 183 M00018_CR_BITMAP_STO_MSK; 184 } else { 185 /* Read only */ 186 cmd = M00018_CR_BITMAP_RD_MSK; 187 } 188 189 /* Last byte to read, no ACK */ 190 if (i == len - 1) 191 cmd |= M00018_CR_BITMAP_ACK_MSK; 192 193 /* Execute command */ 194 iowrite8(cmd, ®s->cr_sr); 195 196 /* Wait for transfer to complete (TIP = 0) */ 197 start_time = jiffies; 198 status = ioread8(®s->cr_sr); 199 while (status & M00018_SR_BITMAP_TIP_MSK) { 200 if (time_after(jiffies, start_time + adap->timeout)) 201 return -ETIMEDOUT; 202 cond_resched(); 203 status = ioread8(®s->cr_sr); 204 } 205 206 /* Verify arbitration */ 207 if (status & M00018_SR_BITMAP_AL_MSK) { 208 /* Arbitration lost! */ 209 return -EIO; 210 } 211 212 /* Store data */ 213 data[i] = ioread8(®s->txr_rxr); 214 } 215 return 0; 216} 217 218/* Generate stop condition on i2c bus. 219 * The m00018 stop isn't doing the right thing (wrong timing). 220 * So instead send a start condition, 8 zeroes and a stop condition. 221 */ 222static int cobalt_stop(struct cobalt_i2c_regs __iomem *regs, 223 struct i2c_adapter *adap) 224{ 225 u8 data = 0; 226 227 return cobalt_tx_bytes(regs, adap, true, true, &data, 1); 228} 229 230static int cobalt_xfer(struct i2c_adapter *adap, 231 struct i2c_msg msgs[], int num) 232{ 233 struct cobalt_i2c_data *data = adap->algo_data; 234 struct cobalt_i2c_regs __iomem *regs = data->regs; 235 struct i2c_msg *pmsg; 236 unsigned short flags; 237 int ret = 0; 238 int i, j; 239 240 for (i = 0; i < num; i++) { 241 int stop = (i == num - 1); 242 243 pmsg = &msgs[i]; 244 flags = pmsg->flags; 245 246 if (!(pmsg->flags & I2C_M_NOSTART)) { 247 u8 addr = pmsg->addr << 1; 248 249 if (flags & I2C_M_RD) 250 addr |= 1; 251 if (flags & I2C_M_REV_DIR_ADDR) 252 addr ^= 1; 253 for (j = 0; j < adap->retries; j++) { 254 ret = cobalt_tx_bytes(regs, adap, true, false, 255 &addr, 1); 256 if (!ret) 257 break; 258 cobalt_stop(regs, adap); 259 } 260 if (ret < 0) 261 return ret; 262 ret = 0; 263 } 264 if (pmsg->flags & I2C_M_RD) { 265 /* read bytes into buffer */ 266 ret = cobalt_rx_bytes(regs, adap, false, stop, 267 pmsg->buf, pmsg->len); 268 if (ret < 0) 269 goto bailout; 270 } else { 271 /* write bytes from buffer */ 272 ret = cobalt_tx_bytes(regs, adap, false, stop, 273 pmsg->buf, pmsg->len); 274 if (ret < 0) 275 goto bailout; 276 } 277 } 278 ret = i; 279 280bailout: 281 if (ret < 0) 282 cobalt_stop(regs, adap); 283 return ret; 284} 285 286static u32 cobalt_func(struct i2c_adapter *adap) 287{ 288 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 289} 290 291/* template for i2c-bit-algo */ 292static const struct i2c_adapter cobalt_i2c_adap_template = { 293 .name = "cobalt i2c driver", 294 .algo = NULL, /* set by i2c-algo-bit */ 295 .algo_data = NULL, /* filled from template */ 296 .owner = THIS_MODULE, 297}; 298 299static const struct i2c_algorithm cobalt_algo = { 300 .master_xfer = cobalt_xfer, 301 .functionality = cobalt_func, 302}; 303 304/* init + register i2c algo-bit adapter */ 305int cobalt_i2c_init(struct cobalt *cobalt) 306{ 307 int i, err; 308 int status; 309 int prescale; 310 unsigned long start_time; 311 312 cobalt_dbg(1, "i2c init\n"); 313 314 /* Define I2C clock prescaler */ 315 prescale = ((ALT_CPU_FREQ) / (5 * I2C_FREQUENCY)) - 1; 316 317 for (i = 0; i < COBALT_NUM_ADAPTERS; i++) { 318 struct cobalt_i2c_regs __iomem *regs = 319 cobalt_i2c_regs(cobalt, i); 320 struct i2c_adapter *adap = &cobalt->i2c_adap[i]; 321 322 /* Disable I2C */ 323 iowrite8(M00018_CTR_BITMAP_EN_MSK, ®s->cr_sr); 324 iowrite8(0, ®s->ctr); 325 iowrite8(0, ®s->cr_sr); 326 327 start_time = jiffies; 328 do { 329 if (time_after(jiffies, start_time + HZ)) { 330 if (cobalt_ignore_err) { 331 adap->dev.parent = NULL; 332 return 0; 333 } 334 return -ETIMEDOUT; 335 } 336 status = ioread8(®s->cr_sr); 337 } while (status & M00018_SR_BITMAP_TIP_MSK); 338 339 /* Disable I2C */ 340 iowrite8(0, ®s->ctr); 341 iowrite8(0, ®s->cr_sr); 342 343 /* Calculate i2c prescaler */ 344 iowrite8(prescale & 0xff, ®s->prerlo); 345 iowrite8((prescale >> 8) & 0xff, ®s->prerhi); 346 /* Enable I2C, interrupts disabled */ 347 iowrite8(M00018_CTR_BITMAP_EN_MSK, ®s->ctr); 348 /* Setup algorithm for adapter */ 349 cobalt->i2c_data[i].cobalt = cobalt; 350 cobalt->i2c_data[i].regs = regs; 351 *adap = cobalt_i2c_adap_template; 352 adap->algo = &cobalt_algo; 353 adap->algo_data = &cobalt->i2c_data[i]; 354 adap->retries = 3; 355 sprintf(adap->name + strlen(adap->name), 356 " #%d-%d", cobalt->instance, i); 357 i2c_set_adapdata(adap, &cobalt->v4l2_dev); 358 adap->dev.parent = &cobalt->pci_dev->dev; 359 err = i2c_add_adapter(adap); 360 if (err) { 361 if (cobalt_ignore_err) { 362 adap->dev.parent = NULL; 363 return 0; 364 } 365 while (i--) 366 i2c_del_adapter(&cobalt->i2c_adap[i]); 367 return err; 368 } 369 cobalt_info("registered bus %s\n", adap->name); 370 } 371 return 0; 372} 373 374void cobalt_i2c_exit(struct cobalt *cobalt) 375{ 376 int i; 377 378 cobalt_dbg(1, "i2c exit\n"); 379 380 for (i = 0; i < COBALT_NUM_ADAPTERS; i++) { 381 cobalt_err("unregistered bus %s\n", cobalt->i2c_adap[i].name); 382 i2c_del_adapter(&cobalt->i2c_adap[i]); 383 } 384}