Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  cobalt I2C functions
0004  *
0005  *  Derived from cx18-i2c.c
0006  *
0007  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
0008  *  All rights reserved.
0009  */
0010 
0011 #include "cobalt-driver.h"
0012 #include "cobalt-i2c.h"
0013 
0014 struct cobalt_i2c_regs {
0015     /* Clock prescaler register lo-byte */
0016     u8 prerlo;
0017     u8 dummy0[3];
0018     /* Clock prescaler register high-byte */
0019     u8 prerhi;
0020     u8 dummy1[3];
0021     /* Control register */
0022     u8 ctr;
0023     u8 dummy2[3];
0024     /* Transmit/Receive register */
0025     u8 txr_rxr;
0026     u8 dummy3[3];
0027     /* Command and Status register */
0028     u8 cr_sr;
0029     u8 dummy4[3];
0030 };
0031 
0032 /* CTR[7:0] - Control register */
0033 
0034 /* I2C Core enable bit */
0035 #define M00018_CTR_BITMAP_EN_MSK    (1 << 7)
0036 
0037 /* I2C Core interrupt enable bit */
0038 #define M00018_CTR_BITMAP_IEN_MSK   (1 << 6)
0039 
0040 /* CR[7:0] - Command register */
0041 
0042 /* I2C start condition */
0043 #define M00018_CR_BITMAP_STA_MSK    (1 << 7)
0044 
0045 /* I2C stop condition */
0046 #define M00018_CR_BITMAP_STO_MSK    (1 << 6)
0047 
0048 /* I2C read from slave */
0049 #define M00018_CR_BITMAP_RD_MSK     (1 << 5)
0050 
0051 /* I2C write to slave */
0052 #define M00018_CR_BITMAP_WR_MSK     (1 << 4)
0053 
0054 /* I2C ack */
0055 #define M00018_CR_BITMAP_ACK_MSK    (1 << 3)
0056 
0057 /* I2C Interrupt ack */
0058 #define M00018_CR_BITMAP_IACK_MSK   (1 << 0)
0059 
0060 /* SR[7:0] - Status register */
0061 
0062 /* Receive acknowledge from slave */
0063 #define M00018_SR_BITMAP_RXACK_MSK  (1 << 7)
0064 
0065 /* Busy, I2C bus busy (as defined by start / stop bits) */
0066 #define M00018_SR_BITMAP_BUSY_MSK   (1 << 6)
0067 
0068 /* Arbitration lost - core lost arbitration */
0069 #define M00018_SR_BITMAP_AL_MSK     (1 << 5)
0070 
0071 /* Transfer in progress */
0072 #define M00018_SR_BITMAP_TIP_MSK    (1 << 1)
0073 
0074 /* Interrupt flag */
0075 #define M00018_SR_BITMAP_IF_MSK     (1 << 0)
0076 
0077 /* Frequency, in Hz */
0078 #define I2C_FREQUENCY           400000
0079 #define ALT_CPU_FREQ            83333333
0080 
0081 static struct cobalt_i2c_regs __iomem *
0082 cobalt_i2c_regs(struct cobalt *cobalt, unsigned idx)
0083 {
0084     switch (idx) {
0085     case 0:
0086     default:
0087         return (struct cobalt_i2c_regs __iomem *)
0088             (cobalt->bar1 + COBALT_I2C_0_BASE);
0089     case 1:
0090         return (struct cobalt_i2c_regs __iomem *)
0091             (cobalt->bar1 + COBALT_I2C_1_BASE);
0092     case 2:
0093         return (struct cobalt_i2c_regs __iomem *)
0094             (cobalt->bar1 + COBALT_I2C_2_BASE);
0095     case 3:
0096         return (struct cobalt_i2c_regs __iomem *)
0097             (cobalt->bar1 + COBALT_I2C_3_BASE);
0098     case 4:
0099         return (struct cobalt_i2c_regs __iomem *)
0100             (cobalt->bar1 + COBALT_I2C_HSMA_BASE);
0101     }
0102 }
0103 
0104 /* Do low-level i2c byte transfer.
0105  * Returns -1 in case of an error or 0 otherwise.
0106  */
0107 static int cobalt_tx_bytes(struct cobalt_i2c_regs __iomem *regs,
0108         struct i2c_adapter *adap, bool start, bool stop,
0109         u8 *data, u16 len)
0110 {
0111     unsigned long start_time;
0112     int status;
0113     int cmd;
0114     int i;
0115 
0116     for (i = 0; i < len; i++) {
0117         /* Setup data */
0118         iowrite8(data[i], &regs->txr_rxr);
0119 
0120         /* Setup command */
0121         if (i == 0 && start) {
0122             /* Write + Start */
0123             cmd = M00018_CR_BITMAP_WR_MSK |
0124                   M00018_CR_BITMAP_STA_MSK;
0125         } else if (i == len - 1 && stop) {
0126             /* Write + Stop */
0127             cmd = M00018_CR_BITMAP_WR_MSK |
0128                   M00018_CR_BITMAP_STO_MSK;
0129         } else {
0130             /* Write only */
0131             cmd = M00018_CR_BITMAP_WR_MSK;
0132         }
0133 
0134         /* Execute command */
0135         iowrite8(cmd, &regs->cr_sr);
0136 
0137         /* Wait for transfer to complete (TIP = 0) */
0138         start_time = jiffies;
0139         status = ioread8(&regs->cr_sr);
0140         while (status & M00018_SR_BITMAP_TIP_MSK) {
0141             if (time_after(jiffies, start_time + adap->timeout))
0142                 return -ETIMEDOUT;
0143             cond_resched();
0144             status = ioread8(&regs->cr_sr);
0145         }
0146 
0147         /* Verify ACK */
0148         if (status & M00018_SR_BITMAP_RXACK_MSK) {
0149             /* NO ACK! */
0150             return -EIO;
0151         }
0152 
0153         /* Verify arbitration */
0154         if (status & M00018_SR_BITMAP_AL_MSK) {
0155             /* Arbitration lost! */
0156             return -EIO;
0157         }
0158     }
0159     return 0;
0160 }
0161 
0162 /* Do low-level i2c byte read.
0163  * Returns -1 in case of an error or 0 otherwise.
0164  */
0165 static int cobalt_rx_bytes(struct cobalt_i2c_regs __iomem *regs,
0166         struct i2c_adapter *adap, bool start, bool stop,
0167         u8 *data, u16 len)
0168 {
0169     unsigned long start_time;
0170     int status;
0171     int cmd;
0172     int i;
0173 
0174     for (i = 0; i < len; i++) {
0175         /* Setup command */
0176         if (i == 0 && start) {
0177             /* Read + Start */
0178             cmd = M00018_CR_BITMAP_RD_MSK |
0179                   M00018_CR_BITMAP_STA_MSK;
0180         } else if (i == len - 1 && stop) {
0181             /* Read + Stop */
0182             cmd = M00018_CR_BITMAP_RD_MSK |
0183                   M00018_CR_BITMAP_STO_MSK;
0184         } else {
0185             /* Read only */
0186             cmd = M00018_CR_BITMAP_RD_MSK;
0187         }
0188 
0189         /* Last byte to read, no ACK */
0190         if (i == len - 1)
0191             cmd |= M00018_CR_BITMAP_ACK_MSK;
0192 
0193         /* Execute command */
0194         iowrite8(cmd, &regs->cr_sr);
0195 
0196         /* Wait for transfer to complete (TIP = 0) */
0197         start_time = jiffies;
0198         status = ioread8(&regs->cr_sr);
0199         while (status & M00018_SR_BITMAP_TIP_MSK) {
0200             if (time_after(jiffies, start_time + adap->timeout))
0201                 return -ETIMEDOUT;
0202             cond_resched();
0203             status = ioread8(&regs->cr_sr);
0204         }
0205 
0206         /* Verify arbitration */
0207         if (status & M00018_SR_BITMAP_AL_MSK) {
0208             /* Arbitration lost! */
0209             return -EIO;
0210         }
0211 
0212         /* Store data */
0213         data[i] = ioread8(&regs->txr_rxr);
0214     }
0215     return 0;
0216 }
0217 
0218 /* Generate stop condition on i2c bus.
0219  * The m00018 stop isn't doing the right thing (wrong timing).
0220  * So instead send a start condition, 8 zeroes and a stop condition.
0221  */
0222 static int cobalt_stop(struct cobalt_i2c_regs __iomem *regs,
0223         struct i2c_adapter *adap)
0224 {
0225     u8 data = 0;
0226 
0227     return cobalt_tx_bytes(regs, adap, true, true, &data, 1);
0228 }
0229 
0230 static int cobalt_xfer(struct i2c_adapter *adap,
0231             struct i2c_msg msgs[], int num)
0232 {
0233     struct cobalt_i2c_data *data = adap->algo_data;
0234     struct cobalt_i2c_regs __iomem *regs = data->regs;
0235     struct i2c_msg *pmsg;
0236     unsigned short flags;
0237     int ret = 0;
0238     int i, j;
0239 
0240     for (i = 0; i < num; i++) {
0241         int stop = (i == num - 1);
0242 
0243         pmsg = &msgs[i];
0244         flags = pmsg->flags;
0245 
0246         if (!(pmsg->flags & I2C_M_NOSTART)) {
0247             u8 addr = pmsg->addr << 1;
0248 
0249             if (flags & I2C_M_RD)
0250                 addr |= 1;
0251             if (flags & I2C_M_REV_DIR_ADDR)
0252                 addr ^= 1;
0253             for (j = 0; j < adap->retries; j++) {
0254                 ret = cobalt_tx_bytes(regs, adap, true, false,
0255                               &addr, 1);
0256                 if (!ret)
0257                     break;
0258                 cobalt_stop(regs, adap);
0259             }
0260             if (ret < 0)
0261                 return ret;
0262             ret = 0;
0263         }
0264         if (pmsg->flags & I2C_M_RD) {
0265             /* read bytes into buffer */
0266             ret = cobalt_rx_bytes(regs, adap, false, stop,
0267                     pmsg->buf, pmsg->len);
0268             if (ret < 0)
0269                 goto bailout;
0270         } else {
0271             /* write bytes from buffer */
0272             ret = cobalt_tx_bytes(regs, adap, false, stop,
0273                     pmsg->buf, pmsg->len);
0274             if (ret < 0)
0275                 goto bailout;
0276         }
0277     }
0278     ret = i;
0279 
0280 bailout:
0281     if (ret < 0)
0282         cobalt_stop(regs, adap);
0283     return ret;
0284 }
0285 
0286 static u32 cobalt_func(struct i2c_adapter *adap)
0287 {
0288     return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
0289 }
0290 
0291 /* template for i2c-bit-algo */
0292 static const struct i2c_adapter cobalt_i2c_adap_template = {
0293     .name = "cobalt i2c driver",
0294     .algo = NULL,                   /* set by i2c-algo-bit */
0295     .algo_data = NULL,              /* filled from template */
0296     .owner = THIS_MODULE,
0297 };
0298 
0299 static const struct i2c_algorithm cobalt_algo = {
0300     .master_xfer    = cobalt_xfer,
0301     .functionality  = cobalt_func,
0302 };
0303 
0304 /* init + register i2c algo-bit adapter */
0305 int cobalt_i2c_init(struct cobalt *cobalt)
0306 {
0307     int i, err;
0308     int status;
0309     int prescale;
0310     unsigned long start_time;
0311 
0312     cobalt_dbg(1, "i2c init\n");
0313 
0314     /* Define I2C clock prescaler */
0315     prescale = ((ALT_CPU_FREQ) / (5 * I2C_FREQUENCY)) - 1;
0316 
0317     for (i = 0; i < COBALT_NUM_ADAPTERS; i++) {
0318         struct cobalt_i2c_regs __iomem *regs =
0319             cobalt_i2c_regs(cobalt, i);
0320         struct i2c_adapter *adap = &cobalt->i2c_adap[i];
0321 
0322         /* Disable I2C */
0323         iowrite8(M00018_CTR_BITMAP_EN_MSK, &regs->cr_sr);
0324         iowrite8(0, &regs->ctr);
0325         iowrite8(0, &regs->cr_sr);
0326 
0327         start_time = jiffies;
0328         do {
0329             if (time_after(jiffies, start_time + HZ)) {
0330                 if (cobalt_ignore_err) {
0331                     adap->dev.parent = NULL;
0332                     return 0;
0333                 }
0334                 return -ETIMEDOUT;
0335             }
0336             status = ioread8(&regs->cr_sr);
0337         } while (status & M00018_SR_BITMAP_TIP_MSK);
0338 
0339         /* Disable I2C */
0340         iowrite8(0, &regs->ctr);
0341         iowrite8(0, &regs->cr_sr);
0342 
0343         /* Calculate i2c prescaler */
0344         iowrite8(prescale & 0xff, &regs->prerlo);
0345         iowrite8((prescale >> 8) & 0xff, &regs->prerhi);
0346         /* Enable I2C, interrupts disabled */
0347         iowrite8(M00018_CTR_BITMAP_EN_MSK, &regs->ctr);
0348         /* Setup algorithm for adapter */
0349         cobalt->i2c_data[i].cobalt = cobalt;
0350         cobalt->i2c_data[i].regs = regs;
0351         *adap = cobalt_i2c_adap_template;
0352         adap->algo = &cobalt_algo;
0353         adap->algo_data = &cobalt->i2c_data[i];
0354         adap->retries = 3;
0355         sprintf(adap->name + strlen(adap->name),
0356                 " #%d-%d", cobalt->instance, i);
0357         i2c_set_adapdata(adap, &cobalt->v4l2_dev);
0358         adap->dev.parent = &cobalt->pci_dev->dev;
0359         err = i2c_add_adapter(adap);
0360         if (err) {
0361             if (cobalt_ignore_err) {
0362                 adap->dev.parent = NULL;
0363                 return 0;
0364             }
0365             while (i--)
0366                 i2c_del_adapter(&cobalt->i2c_adap[i]);
0367             return err;
0368         }
0369         cobalt_info("registered bus %s\n", adap->name);
0370     }
0371     return 0;
0372 }
0373 
0374 void cobalt_i2c_exit(struct cobalt *cobalt)
0375 {
0376     int i;
0377 
0378     cobalt_dbg(1, "i2c exit\n");
0379 
0380     for (i = 0; i < COBALT_NUM_ADAPTERS; i++) {
0381         cobalt_err("unregistered bus %s\n", cobalt->i2c_adap[i].name);
0382         i2c_del_adapter(&cobalt->i2c_adap[i]);
0383     }
0384 }