253 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 Mantis PCI bridge driver4 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 1000025 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_336 | MANTIS_I2C_STOP37 | 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_384 | MANTIS_I2C_STOP85 | 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 else180 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