linux/drivers/media/pci/mantis/mantis_i2c.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3        Mantis PCI bridge driver
   4
   5        Copyright (C) Manu Abraham (abraham.manu@gmail.com)
   6
   7*/
   8
   9#include <asm/io.h>
  10#include <linux/ioport.h>
  11#include <linux/pci.h>
  12#include <linux/i2c.h>
  13
  14#include <media/dmxdev.h>
  15#include <media/dvbdev.h>
  16#include <media/dvb_demux.h>
  17#include <media/dvb_frontend.h>
  18#include <media/dvb_net.h>
  19
  20#include "mantis_common.h"
  21#include "mantis_reg.h"
  22#include "mantis_i2c.h"
  23
  24#define TRIALS                  10000
  25
  26static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg)
  27{
  28        u32 rxd, i, stat, trials;
  29
  30        dprintk(MANTIS_INFO, 0, "        %s:  Address=[0x%02x] <R>[ ",
  31                __func__, msg->addr);
  32
  33        for (i = 0; i < msg->len; i++) {
  34                rxd = (msg->addr << 25) | (1 << 24)
  35                                        | MANTIS_I2C_RATE_3
  36                                        | MANTIS_I2C_STOP
  37                                        | MANTIS_I2C_PGMODE;
  38
  39                if (i == (msg->len - 1))
  40                        rxd &= ~MANTIS_I2C_STOP;
  41
  42                mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
  43                mmwrite(rxd, MANTIS_I2CDATA_CTL);
  44
  45                /* wait for xfer completion */
  46                for (trials = 0; trials < TRIALS; trials++) {
  47                        stat = mmread(MANTIS_INT_STAT);
  48                        if (stat & MANTIS_INT_I2CDONE)
  49                                break;
  50                }
  51
  52                dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
  53
  54                /* wait for xfer completion */
  55                for (trials = 0; trials < TRIALS; trials++) {
  56                        stat = mmread(MANTIS_INT_STAT);
  57                        if (stat & MANTIS_INT_I2CRACK)
  58                                break;
  59                }
  60
  61                dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
  62
  63                rxd = mmread(MANTIS_I2CDATA_CTL);
  64                msg->buf[i] = (u8)((rxd >> 8) & 0xFF);
  65                dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
  66        }
  67        dprintk(MANTIS_INFO, 0, "]\n");
  68
  69        return 0;
  70}
  71
  72static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg)
  73{
  74        int i;
  75        u32 txd = 0, stat, trials;
  76
  77        dprintk(MANTIS_INFO, 0, "        %s: Address=[0x%02x] <W>[ ",
  78                __func__, msg->addr);
  79
  80        for (i = 0; i < msg->len; i++) {
  81                dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
  82                txd = (msg->addr << 25) | (msg->buf[i] << 8)
  83                                        | MANTIS_I2C_RATE_3
  84                                        | MANTIS_I2C_STOP
  85                                        | MANTIS_I2C_PGMODE;
  86
  87                if (i == (msg->len - 1))
  88                        txd &= ~MANTIS_I2C_STOP;
  89
  90                mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
  91                mmwrite(txd, MANTIS_I2CDATA_CTL);
  92
  93                /* wait for xfer completion */
  94                for (trials = 0; trials < TRIALS; trials++) {
  95                        stat = mmread(MANTIS_INT_STAT);
  96                        if (stat & MANTIS_INT_I2CDONE)
  97                                break;
  98                }
  99
 100                dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
 101
 102                /* wait for xfer completion */
 103                for (trials = 0; trials < TRIALS; trials++) {
 104                        stat = mmread(MANTIS_INT_STAT);
 105                        if (stat & MANTIS_INT_I2CRACK)
 106                                break;
 107                }
 108
 109                dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
 110        }
 111        dprintk(MANTIS_INFO, 0, "]\n");
 112
 113        return 0;
 114}
 115
 116static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
 117{
 118        int ret = 0, i = 0, trials;
 119        u32 stat, data, txd;
 120        struct mantis_pci *mantis;
 121        struct mantis_hwconfig *config;
 122
 123        mantis = i2c_get_adapdata(adapter);
 124        BUG_ON(!mantis);
 125        config = mantis->hwconfig;
 126        BUG_ON(!config);
 127
 128        dprintk(MANTIS_DEBUG, 1, "Messages:%d", num);
 129        mutex_lock(&mantis->i2c_lock);
 130
 131        while (i < num) {
 132                /* Byte MODE */
 133                if ((config->i2c_mode & MANTIS_BYTE_MODE) &&
 134                    ((i + 1) < num)                     &&
 135                    (msgs[i].len < 2)                   &&
 136                    (msgs[i + 1].len < 2)               &&
 137                    (msgs[i + 1].flags & I2C_M_RD)) {
 138
 139                        dprintk(MANTIS_DEBUG, 0, "        Byte MODE:\n");
 140
 141                        /* Read operation */
 142                        txd = msgs[i].addr << 25 | (0x1 << 24)
 143                                                 | (msgs[i].buf[0] << 16)
 144                                                 | MANTIS_I2C_RATE_3;
 145
 146                        mmwrite(txd, MANTIS_I2CDATA_CTL);
 147                        /* wait for xfer completion */
 148                        for (trials = 0; trials < TRIALS; trials++) {
 149                                stat = mmread(MANTIS_INT_STAT);
 150                                if (stat & MANTIS_INT_I2CDONE)
 151                                        break;
 152                        }
 153
 154                        /* check for xfer completion */
 155                        if (stat & MANTIS_INT_I2CDONE) {
 156                                /* check xfer was acknowledged */
 157                                if (stat & MANTIS_INT_I2CRACK) {
 158                                        data = mmread(MANTIS_I2CDATA_CTL);
 159                                        msgs[i + 1].buf[0] = (data >> 8) & 0xff;
 160                                        dprintk(MANTIS_DEBUG, 0, "        Byte <%d> RXD=0x%02x  [%02x]\n", 0x0, data, msgs[i + 1].buf[0]);
 161                                } else {
 162                                        /* I/O error */
 163                                        dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
 164                                        ret = -EIO;
 165                                        break;
 166                                }
 167                        } else {
 168                                /* I/O error */
 169                                dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
 170                                ret = -EIO;
 171                                break;
 172                        }
 173                        i += 2; /* Write/Read operation in one go */
 174                }
 175
 176                if (i < num) {
 177                        if (msgs[i].flags & I2C_M_RD)
 178                                ret = mantis_i2c_read(mantis, &msgs[i]);
 179                        else
 180                                ret = mantis_i2c_write(mantis, &msgs[i]);
 181
 182                        i++;
 183                        if (ret < 0)
 184                                goto bail_out;
 185                }
 186
 187        }
 188
 189        mutex_unlock(&mantis->i2c_lock);
 190
 191        return num;
 192
 193bail_out:
 194        mutex_unlock(&mantis->i2c_lock);
 195        return ret;
 196}
 197
 198static u32 mantis_i2c_func(struct i2c_adapter *adapter)
 199{
 200        return I2C_FUNC_SMBUS_EMUL;
 201}
 202
 203static const struct i2c_algorithm mantis_algo = {
 204        .master_xfer            = mantis_i2c_xfer,
 205        .functionality          = mantis_i2c_func,
 206};
 207
 208int mantis_i2c_init(struct mantis_pci *mantis)
 209{
 210        u32 intstat;
 211        struct i2c_adapter *i2c_adapter = &mantis->adapter;
 212        struct pci_dev *pdev            = mantis->pdev;
 213
 214        init_waitqueue_head(&mantis->i2c_wq);
 215        mutex_init(&mantis->i2c_lock);
 216        strscpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name));
 217        i2c_set_adapdata(i2c_adapter, mantis);
 218
 219        i2c_adapter->owner      = THIS_MODULE;
 220        i2c_adapter->algo       = &mantis_algo;
 221        i2c_adapter->algo_data  = NULL;
 222        i2c_adapter->timeout    = 500;
 223        i2c_adapter->retries    = 3;
 224        i2c_adapter->dev.parent = &pdev->dev;
 225
 226        mantis->i2c_rc          = i2c_add_adapter(i2c_adapter);
 227        if (mantis->i2c_rc < 0)
 228                return mantis->i2c_rc;
 229
 230        dprintk(MANTIS_DEBUG, 1, "Initializing I2C ..");
 231
 232        intstat = mmread(MANTIS_INT_STAT);
 233        mmread(MANTIS_INT_MASK);
 234        mmwrite(intstat, MANTIS_INT_STAT);
 235        dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
 236        mantis_mask_ints(mantis, MANTIS_INT_I2CDONE);
 237
 238        return 0;
 239}
 240EXPORT_SYMBOL_GPL(mantis_i2c_init);
 241
 242int mantis_i2c_exit(struct mantis_pci *mantis)
 243{
 244        dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
 245        mantis_mask_ints(mantis, MANTIS_INT_I2CDONE);
 246
 247        dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
 248        i2c_del_adapter(&mantis->adapter);
 249
 250        return 0;
 251}
 252EXPORT_SYMBOL_GPL(mantis_i2c_exit);
 253