root/drivers/media/pci/cobalt/cobalt-i2c.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cobalt_i2c_regs
  2. cobalt_tx_bytes
  3. cobalt_rx_bytes
  4. cobalt_stop
  5. cobalt_xfer
  6. cobalt_func
  7. cobalt_i2c_init
  8. cobalt_i2c_exit

   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 
  14 struct 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 
  81 static struct cobalt_i2c_regs __iomem *
  82 cobalt_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  */
 107 static 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], &regs->txr_rxr);
 119 
 120                 /* Setup command */
 121                 if (i == 0 && start != 0) {
 122                         /* Write + Start */
 123                         cmd = M00018_CR_BITMAP_WR_MSK |
 124                               M00018_CR_BITMAP_STA_MSK;
 125                 } else if (i == len - 1 && stop != 0) {
 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, &regs->cr_sr);
 136 
 137                 /* Wait for transfer to complete (TIP = 0) */
 138                 start_time = jiffies;
 139                 status = ioread8(&regs->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(&regs->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  */
 165 static 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 != 0) {
 177                         /* Read + Start */
 178                         cmd = M00018_CR_BITMAP_RD_MSK |
 179                               M00018_CR_BITMAP_STA_MSK;
 180                 } else if (i == len - 1 && stop != 0) {
 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, &regs->cr_sr);
 195 
 196                 /* Wait for transfer to complete (TIP = 0) */
 197                 start_time = jiffies;
 198                 status = ioread8(&regs->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(&regs->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(&regs->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  */
 222 static 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 
 230 static 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 
 280 bailout:
 281         if (ret < 0)
 282                 cobalt_stop(regs, adap);
 283         return ret;
 284 }
 285 
 286 static 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 */
 292 static 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 
 299 static const struct i2c_algorithm cobalt_algo = {
 300         .master_xfer    = cobalt_xfer,
 301         .functionality  = cobalt_func,
 302 };
 303 
 304 /* init + register i2c algo-bit adapter */
 305 int 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, &regs->cr_sr);
 324                 iowrite8(0, &regs->ctr);
 325                 iowrite8(0, &regs->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(&regs->cr_sr);
 337                 } while (status & M00018_SR_BITMAP_TIP_MSK);
 338 
 339                 /* Disable I2C */
 340                 iowrite8(0, &regs->ctr);
 341                 iowrite8(0, &regs->cr_sr);
 342 
 343                 /* Calculate i2c prescaler */
 344                 iowrite8(prescale & 0xff, &regs->prerlo);
 345                 iowrite8((prescale >> 8) & 0xff, &regs->prerhi);
 346                 /* Enable I2C, interrupts disabled */
 347                 iowrite8(M00018_CTR_BITMAP_EN_MSK, &regs->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 
 374 void 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 }

/* [<][>][^][v][top][bottom][index][help] */