18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Mantis PCI bridge driver 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Copyright (C) Manu Abraham (abraham.manu@gmail.com) 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci*/ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <asm/io.h> 108c2ecf20Sopenharmony_ci#include <linux/ioport.h> 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci#include <linux/i2c.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <media/dmxdev.h> 158c2ecf20Sopenharmony_ci#include <media/dvbdev.h> 168c2ecf20Sopenharmony_ci#include <media/dvb_demux.h> 178c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 188c2ecf20Sopenharmony_ci#include <media/dvb_net.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "mantis_common.h" 218c2ecf20Sopenharmony_ci#include "mantis_reg.h" 228c2ecf20Sopenharmony_ci#include "mantis_i2c.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define TRIALS 10000 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci u32 rxd, i, stat, trials; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <R>[ ", 318c2ecf20Sopenharmony_ci __func__, msg->addr); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci for (i = 0; i < msg->len; i++) { 348c2ecf20Sopenharmony_ci rxd = (msg->addr << 25) | (1 << 24) 358c2ecf20Sopenharmony_ci | MANTIS_I2C_RATE_3 368c2ecf20Sopenharmony_ci | MANTIS_I2C_STOP 378c2ecf20Sopenharmony_ci | MANTIS_I2C_PGMODE; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (i == (msg->len - 1)) 408c2ecf20Sopenharmony_ci rxd &= ~MANTIS_I2C_STOP; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); 438c2ecf20Sopenharmony_ci mmwrite(rxd, MANTIS_I2CDATA_CTL); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* wait for xfer completion */ 468c2ecf20Sopenharmony_ci for (trials = 0; trials < TRIALS; trials++) { 478c2ecf20Sopenharmony_ci stat = mmread(MANTIS_INT_STAT); 488c2ecf20Sopenharmony_ci if (stat & MANTIS_INT_I2CDONE) 498c2ecf20Sopenharmony_ci break; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* wait for xfer completion */ 558c2ecf20Sopenharmony_ci for (trials = 0; trials < TRIALS; trials++) { 568c2ecf20Sopenharmony_ci stat = mmread(MANTIS_INT_STAT); 578c2ecf20Sopenharmony_ci if (stat & MANTIS_INT_I2CRACK) 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci rxd = mmread(MANTIS_I2CDATA_CTL); 648c2ecf20Sopenharmony_ci msg->buf[i] = (u8)((rxd >> 8) & 0xFF); 658c2ecf20Sopenharmony_ci dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci dprintk(MANTIS_INFO, 0, "]\n"); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return 0; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci int i; 758c2ecf20Sopenharmony_ci u32 txd = 0, stat, trials; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <W>[ ", 788c2ecf20Sopenharmony_ci __func__, msg->addr); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci for (i = 0; i < msg->len; i++) { 818c2ecf20Sopenharmony_ci dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); 828c2ecf20Sopenharmony_ci txd = (msg->addr << 25) | (msg->buf[i] << 8) 838c2ecf20Sopenharmony_ci | MANTIS_I2C_RATE_3 848c2ecf20Sopenharmony_ci | MANTIS_I2C_STOP 858c2ecf20Sopenharmony_ci | MANTIS_I2C_PGMODE; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (i == (msg->len - 1)) 888c2ecf20Sopenharmony_ci txd &= ~MANTIS_I2C_STOP; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); 918c2ecf20Sopenharmony_ci mmwrite(txd, MANTIS_I2CDATA_CTL); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* wait for xfer completion */ 948c2ecf20Sopenharmony_ci for (trials = 0; trials < TRIALS; trials++) { 958c2ecf20Sopenharmony_ci stat = mmread(MANTIS_INT_STAT); 968c2ecf20Sopenharmony_ci if (stat & MANTIS_INT_I2CDONE) 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* wait for xfer completion */ 1038c2ecf20Sopenharmony_ci for (trials = 0; trials < TRIALS; trials++) { 1048c2ecf20Sopenharmony_ci stat = mmread(MANTIS_INT_STAT); 1058c2ecf20Sopenharmony_ci if (stat & MANTIS_INT_I2CRACK) 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci dprintk(MANTIS_INFO, 0, "]\n"); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int ret = 0, i = 0, trials; 1198c2ecf20Sopenharmony_ci u32 stat, data, txd; 1208c2ecf20Sopenharmony_ci struct mantis_pci *mantis; 1218c2ecf20Sopenharmony_ci struct mantis_hwconfig *config; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci mantis = i2c_get_adapdata(adapter); 1248c2ecf20Sopenharmony_ci BUG_ON(!mantis); 1258c2ecf20Sopenharmony_ci config = mantis->hwconfig; 1268c2ecf20Sopenharmony_ci BUG_ON(!config); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Messages:%d", num); 1298c2ecf20Sopenharmony_ci mutex_lock(&mantis->i2c_lock); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci while (i < num) { 1328c2ecf20Sopenharmony_ci /* Byte MODE */ 1338c2ecf20Sopenharmony_ci if ((config->i2c_mode & MANTIS_BYTE_MODE) && 1348c2ecf20Sopenharmony_ci ((i + 1) < num) && 1358c2ecf20Sopenharmony_ci (msgs[i].len < 2) && 1368c2ecf20Sopenharmony_ci (msgs[i + 1].len < 2) && 1378c2ecf20Sopenharmony_ci (msgs[i + 1].flags & I2C_M_RD)) { 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci dprintk(MANTIS_DEBUG, 0, " Byte MODE:\n"); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* Read operation */ 1428c2ecf20Sopenharmony_ci txd = msgs[i].addr << 25 | (0x1 << 24) 1438c2ecf20Sopenharmony_ci | (msgs[i].buf[0] << 16) 1448c2ecf20Sopenharmony_ci | MANTIS_I2C_RATE_3; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci mmwrite(txd, MANTIS_I2CDATA_CTL); 1478c2ecf20Sopenharmony_ci /* wait for xfer completion */ 1488c2ecf20Sopenharmony_ci for (trials = 0; trials < TRIALS; trials++) { 1498c2ecf20Sopenharmony_ci stat = mmread(MANTIS_INT_STAT); 1508c2ecf20Sopenharmony_ci if (stat & MANTIS_INT_I2CDONE) 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* check for xfer completion */ 1558c2ecf20Sopenharmony_ci if (stat & MANTIS_INT_I2CDONE) { 1568c2ecf20Sopenharmony_ci /* check xfer was acknowledged */ 1578c2ecf20Sopenharmony_ci if (stat & MANTIS_INT_I2CRACK) { 1588c2ecf20Sopenharmony_ci data = mmread(MANTIS_I2CDATA_CTL); 1598c2ecf20Sopenharmony_ci msgs[i + 1].buf[0] = (data >> 8) & 0xff; 1608c2ecf20Sopenharmony_ci dprintk(MANTIS_DEBUG, 0, " Byte <%d> RXD=0x%02x [%02x]\n", 0x0, data, msgs[i + 1].buf[0]); 1618c2ecf20Sopenharmony_ci } else { 1628c2ecf20Sopenharmony_ci /* I/O error */ 1638c2ecf20Sopenharmony_ci dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); 1648c2ecf20Sopenharmony_ci ret = -EIO; 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci } else { 1688c2ecf20Sopenharmony_ci /* I/O error */ 1698c2ecf20Sopenharmony_ci dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); 1708c2ecf20Sopenharmony_ci ret = -EIO; 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci i += 2; /* Write/Read operation in one go */ 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (i < num) { 1778c2ecf20Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) 1788c2ecf20Sopenharmony_ci ret = mantis_i2c_read(mantis, &msgs[i]); 1798c2ecf20Sopenharmony_ci else 1808c2ecf20Sopenharmony_ci ret = mantis_i2c_write(mantis, &msgs[i]); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci i++; 1838c2ecf20Sopenharmony_ci if (ret < 0) 1848c2ecf20Sopenharmony_ci goto bail_out; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci mutex_unlock(&mantis->i2c_lock); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return num; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cibail_out: 1948c2ecf20Sopenharmony_ci mutex_unlock(&mantis->i2c_lock); 1958c2ecf20Sopenharmony_ci return ret; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic u32 mantis_i2c_func(struct i2c_adapter *adapter) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci return I2C_FUNC_SMBUS_EMUL; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic const struct i2c_algorithm mantis_algo = { 2048c2ecf20Sopenharmony_ci .master_xfer = mantis_i2c_xfer, 2058c2ecf20Sopenharmony_ci .functionality = mantis_i2c_func, 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ciint mantis_i2c_init(struct mantis_pci *mantis) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci u32 intstat; 2118c2ecf20Sopenharmony_ci struct i2c_adapter *i2c_adapter = &mantis->adapter; 2128c2ecf20Sopenharmony_ci struct pci_dev *pdev = mantis->pdev; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci init_waitqueue_head(&mantis->i2c_wq); 2158c2ecf20Sopenharmony_ci mutex_init(&mantis->i2c_lock); 2168c2ecf20Sopenharmony_ci strscpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); 2178c2ecf20Sopenharmony_ci i2c_set_adapdata(i2c_adapter, mantis); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci i2c_adapter->owner = THIS_MODULE; 2208c2ecf20Sopenharmony_ci i2c_adapter->algo = &mantis_algo; 2218c2ecf20Sopenharmony_ci i2c_adapter->algo_data = NULL; 2228c2ecf20Sopenharmony_ci i2c_adapter->timeout = 500; 2238c2ecf20Sopenharmony_ci i2c_adapter->retries = 3; 2248c2ecf20Sopenharmony_ci i2c_adapter->dev.parent = &pdev->dev; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci mantis->i2c_rc = i2c_add_adapter(i2c_adapter); 2278c2ecf20Sopenharmony_ci if (mantis->i2c_rc < 0) 2288c2ecf20Sopenharmony_ci return mantis->i2c_rc; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci intstat = mmread(MANTIS_INT_STAT); 2338c2ecf20Sopenharmony_ci mmread(MANTIS_INT_MASK); 2348c2ecf20Sopenharmony_ci mmwrite(intstat, MANTIS_INT_STAT); 2358c2ecf20Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); 2368c2ecf20Sopenharmony_ci mantis_mask_ints(mantis, MANTIS_INT_I2CDONE); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mantis_i2c_init); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciint mantis_i2c_exit(struct mantis_pci *mantis) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); 2458c2ecf20Sopenharmony_ci mantis_mask_ints(mantis, MANTIS_INT_I2CDONE); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); 2488c2ecf20Sopenharmony_ci i2c_del_adapter(&mantis->adapter); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mantis_i2c_exit); 253