mantis_i2c.c (6037B)
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);