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