162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci Mantis PCI bridge driver 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci Copyright (C) Manu Abraham (abraham.manu@gmail.com) 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci*/ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/io.h> 1062306a36Sopenharmony_ci#include <linux/ioport.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci#include <linux/i2c.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <media/dmxdev.h> 1562306a36Sopenharmony_ci#include <media/dvbdev.h> 1662306a36Sopenharmony_ci#include <media/dvb_demux.h> 1762306a36Sopenharmony_ci#include <media/dvb_frontend.h> 1862306a36Sopenharmony_ci#include <media/dvb_net.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "mantis_common.h" 2162306a36Sopenharmony_ci#include "mantis_reg.h" 2262306a36Sopenharmony_ci#include "mantis_i2c.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define TRIALS 10000 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci u32 rxd, i, stat, trials; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <R>[ ", 3162306a36Sopenharmony_ci __func__, msg->addr); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci for (i = 0; i < msg->len; i++) { 3462306a36Sopenharmony_ci rxd = (msg->addr << 25) | (1 << 24) 3562306a36Sopenharmony_ci | MANTIS_I2C_RATE_3 3662306a36Sopenharmony_ci | MANTIS_I2C_STOP 3762306a36Sopenharmony_ci | MANTIS_I2C_PGMODE; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (i == (msg->len - 1)) 4062306a36Sopenharmony_ci rxd &= ~MANTIS_I2C_STOP; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); 4362306a36Sopenharmony_ci mmwrite(rxd, MANTIS_I2CDATA_CTL); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* wait for xfer completion */ 4662306a36Sopenharmony_ci for (trials = 0; trials < TRIALS; trials++) { 4762306a36Sopenharmony_ci stat = mmread(MANTIS_INT_STAT); 4862306a36Sopenharmony_ci if (stat & MANTIS_INT_I2CDONE) 4962306a36Sopenharmony_ci break; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* wait for xfer completion */ 5562306a36Sopenharmony_ci for (trials = 0; trials < TRIALS; trials++) { 5662306a36Sopenharmony_ci stat = mmread(MANTIS_INT_STAT); 5762306a36Sopenharmony_ci if (stat & MANTIS_INT_I2CRACK) 5862306a36Sopenharmony_ci break; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci rxd = mmread(MANTIS_I2CDATA_CTL); 6462306a36Sopenharmony_ci msg->buf[i] = (u8)((rxd >> 8) & 0xFF); 6562306a36Sopenharmony_ci dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci dprintk(MANTIS_INFO, 0, "]\n"); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci int i; 7562306a36Sopenharmony_ci u32 txd = 0, stat, trials; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <W>[ ", 7862306a36Sopenharmony_ci __func__, msg->addr); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci for (i = 0; i < msg->len; i++) { 8162306a36Sopenharmony_ci dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); 8262306a36Sopenharmony_ci txd = (msg->addr << 25) | (msg->buf[i] << 8) 8362306a36Sopenharmony_ci | MANTIS_I2C_RATE_3 8462306a36Sopenharmony_ci | MANTIS_I2C_STOP 8562306a36Sopenharmony_ci | MANTIS_I2C_PGMODE; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (i == (msg->len - 1)) 8862306a36Sopenharmony_ci txd &= ~MANTIS_I2C_STOP; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); 9162306a36Sopenharmony_ci mmwrite(txd, MANTIS_I2CDATA_CTL); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* wait for xfer completion */ 9462306a36Sopenharmony_ci for (trials = 0; trials < TRIALS; trials++) { 9562306a36Sopenharmony_ci stat = mmread(MANTIS_INT_STAT); 9662306a36Sopenharmony_ci if (stat & MANTIS_INT_I2CDONE) 9762306a36Sopenharmony_ci break; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* wait for xfer completion */ 10362306a36Sopenharmony_ci for (trials = 0; trials < TRIALS; trials++) { 10462306a36Sopenharmony_ci stat = mmread(MANTIS_INT_STAT); 10562306a36Sopenharmony_ci if (stat & MANTIS_INT_I2CRACK) 10662306a36Sopenharmony_ci break; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci dprintk(MANTIS_INFO, 0, "]\n"); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci int ret = 0, i = 0, trials; 11962306a36Sopenharmony_ci u32 stat, data, txd; 12062306a36Sopenharmony_ci struct mantis_pci *mantis; 12162306a36Sopenharmony_ci struct mantis_hwconfig *config; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci mantis = i2c_get_adapdata(adapter); 12462306a36Sopenharmony_ci BUG_ON(!mantis); 12562306a36Sopenharmony_ci config = mantis->hwconfig; 12662306a36Sopenharmony_ci BUG_ON(!config); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Messages:%d", num); 12962306a36Sopenharmony_ci mutex_lock(&mantis->i2c_lock); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci while (i < num) { 13262306a36Sopenharmony_ci /* Byte MODE */ 13362306a36Sopenharmony_ci if ((config->i2c_mode & MANTIS_BYTE_MODE) && 13462306a36Sopenharmony_ci ((i + 1) < num) && 13562306a36Sopenharmony_ci (msgs[i].len < 2) && 13662306a36Sopenharmony_ci (msgs[i + 1].len < 2) && 13762306a36Sopenharmony_ci (msgs[i + 1].flags & I2C_M_RD)) { 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci dprintk(MANTIS_DEBUG, 0, " Byte MODE:\n"); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Read operation */ 14262306a36Sopenharmony_ci txd = msgs[i].addr << 25 | (0x1 << 24) 14362306a36Sopenharmony_ci | (msgs[i].buf[0] << 16) 14462306a36Sopenharmony_ci | MANTIS_I2C_RATE_3; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci mmwrite(txd, MANTIS_I2CDATA_CTL); 14762306a36Sopenharmony_ci /* wait for xfer completion */ 14862306a36Sopenharmony_ci for (trials = 0; trials < TRIALS; trials++) { 14962306a36Sopenharmony_ci stat = mmread(MANTIS_INT_STAT); 15062306a36Sopenharmony_ci if (stat & MANTIS_INT_I2CDONE) 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* check for xfer completion */ 15562306a36Sopenharmony_ci if (stat & MANTIS_INT_I2CDONE) { 15662306a36Sopenharmony_ci /* check xfer was acknowledged */ 15762306a36Sopenharmony_ci if (stat & MANTIS_INT_I2CRACK) { 15862306a36Sopenharmony_ci data = mmread(MANTIS_I2CDATA_CTL); 15962306a36Sopenharmony_ci msgs[i + 1].buf[0] = (data >> 8) & 0xff; 16062306a36Sopenharmony_ci dprintk(MANTIS_DEBUG, 0, " Byte <%d> RXD=0x%02x [%02x]\n", 0x0, data, msgs[i + 1].buf[0]); 16162306a36Sopenharmony_ci } else { 16262306a36Sopenharmony_ci /* I/O error */ 16362306a36Sopenharmony_ci dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); 16462306a36Sopenharmony_ci ret = -EIO; 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci } else { 16862306a36Sopenharmony_ci /* I/O error */ 16962306a36Sopenharmony_ci dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); 17062306a36Sopenharmony_ci ret = -EIO; 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci i += 2; /* Write/Read operation in one go */ 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (i < num) { 17762306a36Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) 17862306a36Sopenharmony_ci ret = mantis_i2c_read(mantis, &msgs[i]); 17962306a36Sopenharmony_ci else 18062306a36Sopenharmony_ci ret = mantis_i2c_write(mantis, &msgs[i]); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci i++; 18362306a36Sopenharmony_ci if (ret < 0) 18462306a36Sopenharmony_ci goto bail_out; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci mutex_unlock(&mantis->i2c_lock); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return num; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cibail_out: 19462306a36Sopenharmony_ci mutex_unlock(&mantis->i2c_lock); 19562306a36Sopenharmony_ci return ret; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic u32 mantis_i2c_func(struct i2c_adapter *adapter) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci return I2C_FUNC_SMBUS_EMUL; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic const struct i2c_algorithm mantis_algo = { 20462306a36Sopenharmony_ci .master_xfer = mantis_i2c_xfer, 20562306a36Sopenharmony_ci .functionality = mantis_i2c_func, 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciint mantis_i2c_init(struct mantis_pci *mantis) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci u32 intstat; 21162306a36Sopenharmony_ci struct i2c_adapter *i2c_adapter = &mantis->adapter; 21262306a36Sopenharmony_ci struct pci_dev *pdev = mantis->pdev; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci init_waitqueue_head(&mantis->i2c_wq); 21562306a36Sopenharmony_ci mutex_init(&mantis->i2c_lock); 21662306a36Sopenharmony_ci strscpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); 21762306a36Sopenharmony_ci i2c_set_adapdata(i2c_adapter, mantis); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci i2c_adapter->owner = THIS_MODULE; 22062306a36Sopenharmony_ci i2c_adapter->algo = &mantis_algo; 22162306a36Sopenharmony_ci i2c_adapter->algo_data = NULL; 22262306a36Sopenharmony_ci i2c_adapter->timeout = 500; 22362306a36Sopenharmony_ci i2c_adapter->retries = 3; 22462306a36Sopenharmony_ci i2c_adapter->dev.parent = &pdev->dev; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci mantis->i2c_rc = i2c_add_adapter(i2c_adapter); 22762306a36Sopenharmony_ci if (mantis->i2c_rc < 0) 22862306a36Sopenharmony_ci return mantis->i2c_rc; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci intstat = mmread(MANTIS_INT_STAT); 23362306a36Sopenharmony_ci mmread(MANTIS_INT_MASK); 23462306a36Sopenharmony_ci mmwrite(intstat, MANTIS_INT_STAT); 23562306a36Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); 23662306a36Sopenharmony_ci mantis_mask_ints(mantis, MANTIS_INT_I2CDONE); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mantis_i2c_init); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ciint mantis_i2c_exit(struct mantis_pci *mantis) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); 24562306a36Sopenharmony_ci mantis_mask_ints(mantis, MANTIS_INT_I2CDONE); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); 24862306a36Sopenharmony_ci i2c_del_adapter(&mantis->adapter); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mantis_i2c_exit); 253