18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/i2c.h> 58c2ecf20Sopenharmony_ci#include <linux/mutex.h> 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "dibx000_common.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistatic int debug; 118c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 128c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do { \ 158c2ecf20Sopenharmony_ci if (debug) \ 168c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: " fmt), \ 178c2ecf20Sopenharmony_ci __func__, ##arg); \ 188c2ecf20Sopenharmony_ci} while (0) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci int ret; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { 258c2ecf20Sopenharmony_ci dprintk("could not acquire lock\n"); 268c2ecf20Sopenharmony_ci return -EINVAL; 278c2ecf20Sopenharmony_ci } 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci mst->i2c_write_buffer[0] = (reg >> 8) & 0xff; 308c2ecf20Sopenharmony_ci mst->i2c_write_buffer[1] = reg & 0xff; 318c2ecf20Sopenharmony_ci mst->i2c_write_buffer[2] = (val >> 8) & 0xff; 328c2ecf20Sopenharmony_ci mst->i2c_write_buffer[3] = val & 0xff; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci memset(mst->msg, 0, sizeof(struct i2c_msg)); 358c2ecf20Sopenharmony_ci mst->msg[0].addr = mst->i2c_addr; 368c2ecf20Sopenharmony_ci mst->msg[0].flags = 0; 378c2ecf20Sopenharmony_ci mst->msg[0].buf = mst->i2c_write_buffer; 388c2ecf20Sopenharmony_ci mst->msg[0].len = 4; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0; 418c2ecf20Sopenharmony_ci mutex_unlock(&mst->i2c_buffer_lock); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return ret; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci u16 ret; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { 518c2ecf20Sopenharmony_ci dprintk("could not acquire lock\n"); 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci mst->i2c_write_buffer[0] = reg >> 8; 568c2ecf20Sopenharmony_ci mst->i2c_write_buffer[1] = reg & 0xff; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci memset(mst->msg, 0, 2 * sizeof(struct i2c_msg)); 598c2ecf20Sopenharmony_ci mst->msg[0].addr = mst->i2c_addr; 608c2ecf20Sopenharmony_ci mst->msg[0].flags = 0; 618c2ecf20Sopenharmony_ci mst->msg[0].buf = mst->i2c_write_buffer; 628c2ecf20Sopenharmony_ci mst->msg[0].len = 2; 638c2ecf20Sopenharmony_ci mst->msg[1].addr = mst->i2c_addr; 648c2ecf20Sopenharmony_ci mst->msg[1].flags = I2C_M_RD; 658c2ecf20Sopenharmony_ci mst->msg[1].buf = mst->i2c_read_buffer; 668c2ecf20Sopenharmony_ci mst->msg[1].len = 2; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2) 698c2ecf20Sopenharmony_ci dprintk("i2c read error on %d\n", reg); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; 728c2ecf20Sopenharmony_ci mutex_unlock(&mst->i2c_buffer_lock); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return ret; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int dibx000_is_i2c_done(struct dibx000_i2c_master *mst) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci int i = 100; 808c2ecf20Sopenharmony_ci u16 status; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0) 838c2ecf20Sopenharmony_ci ; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* i2c timed out */ 868c2ecf20Sopenharmony_ci if (i == 0) 878c2ecf20Sopenharmony_ci return -EREMOTEIO; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* no acknowledge */ 908c2ecf20Sopenharmony_ci if ((status & 0x0080) == 0) 918c2ecf20Sopenharmony_ci return -EREMOTEIO; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_msg *msg, u8 stop) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci u16 data; 998c2ecf20Sopenharmony_ci u16 da; 1008c2ecf20Sopenharmony_ci u16 i; 1018c2ecf20Sopenharmony_ci u16 txlen = msg->len, len; 1028c2ecf20Sopenharmony_ci const u8 *b = msg->buf; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci while (txlen) { 1058c2ecf20Sopenharmony_ci dibx000_read_word(mst, mst->base_reg + 2); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci len = txlen > 8 ? 8 : txlen; 1088c2ecf20Sopenharmony_ci for (i = 0; i < len; i += 2) { 1098c2ecf20Sopenharmony_ci data = *b++ << 8; 1108c2ecf20Sopenharmony_ci if (i+1 < len) 1118c2ecf20Sopenharmony_ci data |= *b++; 1128c2ecf20Sopenharmony_ci dibx000_write_word(mst, mst->base_reg, data); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci da = (((u8) (msg->addr)) << 9) | 1158c2ecf20Sopenharmony_ci (1 << 8) | 1168c2ecf20Sopenharmony_ci (1 << 7) | 1178c2ecf20Sopenharmony_ci (0 << 6) | 1188c2ecf20Sopenharmony_ci (0 << 5) | 1198c2ecf20Sopenharmony_ci ((len & 0x7) << 2) | 1208c2ecf20Sopenharmony_ci (0 << 1) | 1218c2ecf20Sopenharmony_ci (0 << 0); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (txlen == msg->len) 1248c2ecf20Sopenharmony_ci da |= 1 << 5; /* start */ 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (txlen-len == 0 && stop) 1278c2ecf20Sopenharmony_ci da |= 1 << 6; /* stop */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci dibx000_write_word(mst, mst->base_reg+1, da); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (dibx000_is_i2c_done(mst) != 0) 1328c2ecf20Sopenharmony_ci return -EREMOTEIO; 1338c2ecf20Sopenharmony_ci txlen -= len; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_msg *msg) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci u16 da; 1428c2ecf20Sopenharmony_ci u8 *b = msg->buf; 1438c2ecf20Sopenharmony_ci u16 rxlen = msg->len, len; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci while (rxlen) { 1468c2ecf20Sopenharmony_ci len = rxlen > 8 ? 8 : rxlen; 1478c2ecf20Sopenharmony_ci da = (((u8) (msg->addr)) << 9) | 1488c2ecf20Sopenharmony_ci (1 << 8) | 1498c2ecf20Sopenharmony_ci (1 << 7) | 1508c2ecf20Sopenharmony_ci (0 << 6) | 1518c2ecf20Sopenharmony_ci (0 << 5) | 1528c2ecf20Sopenharmony_ci ((len & 0x7) << 2) | 1538c2ecf20Sopenharmony_ci (1 << 1) | 1548c2ecf20Sopenharmony_ci (0 << 0); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (rxlen == msg->len) 1578c2ecf20Sopenharmony_ci da |= 1 << 5; /* start */ 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (rxlen-len == 0) 1608c2ecf20Sopenharmony_ci da |= 1 << 6; /* stop */ 1618c2ecf20Sopenharmony_ci dibx000_write_word(mst, mst->base_reg+1, da); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (dibx000_is_i2c_done(mst) != 0) 1648c2ecf20Sopenharmony_ci return -EREMOTEIO; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci rxlen -= len; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci while (len) { 1698c2ecf20Sopenharmony_ci da = dibx000_read_word(mst, mst->base_reg); 1708c2ecf20Sopenharmony_ci *b++ = (da >> 8) & 0xff; 1718c2ecf20Sopenharmony_ci len--; 1728c2ecf20Sopenharmony_ci if (len >= 1) { 1738c2ecf20Sopenharmony_ci *b++ = da & 0xff; 1748c2ecf20Sopenharmony_ci len--; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciint dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (mst->device_rev < DIB7000MC && speed < 235) 1878c2ecf20Sopenharmony_ci speed = 235; 1888c2ecf20Sopenharmony_ci return dibx000_write_word(mst, mst->base_reg + 3, (u16)(60000 / speed)); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dibx000_i2c_set_speed); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic u32 dibx000_i2c_func(struct i2c_adapter *adapter) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci return I2C_FUNC_I2C; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, 1998c2ecf20Sopenharmony_ci enum dibx000_i2c_interface intf) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { 2028c2ecf20Sopenharmony_ci dprintk("selecting interface: %d\n", intf); 2038c2ecf20Sopenharmony_ci mst->selected_interface = intf; 2048c2ecf20Sopenharmony_ci return dibx000_write_word(mst, mst->base_reg + 4, intf); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); 2128c2ecf20Sopenharmony_ci int msg_index; 2138c2ecf20Sopenharmony_ci int ret = 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2); 2168c2ecf20Sopenharmony_ci for (msg_index = 0; msg_index < num; msg_index++) { 2178c2ecf20Sopenharmony_ci if (msg[msg_index].flags & I2C_M_RD) { 2188c2ecf20Sopenharmony_ci ret = dibx000_master_i2c_read(mst, &msg[msg_index]); 2198c2ecf20Sopenharmony_ci if (ret != 0) 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci } else { 2228c2ecf20Sopenharmony_ci ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1); 2238c2ecf20Sopenharmony_ci if (ret != 0) 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci return num; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int dibx000_i2c_master_xfer_gpio34(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); 2348c2ecf20Sopenharmony_ci int msg_index; 2358c2ecf20Sopenharmony_ci int ret = 0; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_3_4); 2388c2ecf20Sopenharmony_ci for (msg_index = 0; msg_index < num; msg_index++) { 2398c2ecf20Sopenharmony_ci if (msg[msg_index].flags & I2C_M_RD) { 2408c2ecf20Sopenharmony_ci ret = dibx000_master_i2c_read(mst, &msg[msg_index]); 2418c2ecf20Sopenharmony_ci if (ret != 0) 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci } else { 2448c2ecf20Sopenharmony_ci ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1); 2458c2ecf20Sopenharmony_ci if (ret != 0) 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return num; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic struct i2c_algorithm dibx000_i2c_master_gpio12_xfer_algo = { 2548c2ecf20Sopenharmony_ci .master_xfer = dibx000_i2c_master_xfer_gpio12, 2558c2ecf20Sopenharmony_ci .functionality = dibx000_i2c_func, 2568c2ecf20Sopenharmony_ci}; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic struct i2c_algorithm dibx000_i2c_master_gpio34_xfer_algo = { 2598c2ecf20Sopenharmony_ci .master_xfer = dibx000_i2c_master_xfer_gpio34, 2608c2ecf20Sopenharmony_ci .functionality = dibx000_i2c_func, 2618c2ecf20Sopenharmony_ci}; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], 2648c2ecf20Sopenharmony_ci u8 addr, int onoff) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci u16 val; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (onoff) 2708c2ecf20Sopenharmony_ci val = addr << 8; // bit 7 = use master or not, if 0, the gate is open 2718c2ecf20Sopenharmony_ci else 2728c2ecf20Sopenharmony_ci val = 1 << 7; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (mst->device_rev > DIB7000) 2758c2ecf20Sopenharmony_ci val <<= 1; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci tx[0] = (((mst->base_reg + 1) >> 8) & 0xff); 2788c2ecf20Sopenharmony_ci tx[1] = ((mst->base_reg + 1) & 0xff); 2798c2ecf20Sopenharmony_ci tx[2] = val >> 8; 2808c2ecf20Sopenharmony_ci tx[3] = val & 0xff; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, 2868c2ecf20Sopenharmony_ci struct i2c_msg msg[], int num) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); 2898c2ecf20Sopenharmony_ci int ret; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (num > 32) { 2928c2ecf20Sopenharmony_ci dprintk("%s: too much I2C message to be transmitted (%i). Maximum is 32", 2938c2ecf20Sopenharmony_ci __func__, num); 2948c2ecf20Sopenharmony_ci return -ENOMEM; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { 3008c2ecf20Sopenharmony_ci dprintk("could not acquire lock\n"); 3018c2ecf20Sopenharmony_ci return -EINVAL; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* open the gate */ 3078c2ecf20Sopenharmony_ci dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); 3088c2ecf20Sopenharmony_ci mst->msg[0].addr = mst->i2c_addr; 3098c2ecf20Sopenharmony_ci mst->msg[0].buf = &mst->i2c_write_buffer[0]; 3108c2ecf20Sopenharmony_ci mst->msg[0].len = 4; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* close the gate */ 3158c2ecf20Sopenharmony_ci dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0); 3168c2ecf20Sopenharmony_ci mst->msg[num + 1].addr = mst->i2c_addr; 3178c2ecf20Sopenharmony_ci mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; 3188c2ecf20Sopenharmony_ci mst->msg[num + 1].len = 4; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? 3218c2ecf20Sopenharmony_ci num : -EIO); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci mutex_unlock(&mst->i2c_buffer_lock); 3248c2ecf20Sopenharmony_ci return ret; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = { 3288c2ecf20Sopenharmony_ci .master_xfer = dibx000_i2c_gated_gpio67_xfer, 3298c2ecf20Sopenharmony_ci .functionality = dibx000_i2c_func, 3308c2ecf20Sopenharmony_ci}; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, 3338c2ecf20Sopenharmony_ci struct i2c_msg msg[], int num) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); 3368c2ecf20Sopenharmony_ci int ret; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (num > 32) { 3398c2ecf20Sopenharmony_ci dprintk("%s: too much I2C message to be transmitted (%i). Maximum is 32", 3408c2ecf20Sopenharmony_ci __func__, num); 3418c2ecf20Sopenharmony_ci return -ENOMEM; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { 3478c2ecf20Sopenharmony_ci dprintk("could not acquire lock\n"); 3488c2ecf20Sopenharmony_ci return -EINVAL; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* open the gate */ 3538c2ecf20Sopenharmony_ci dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); 3548c2ecf20Sopenharmony_ci mst->msg[0].addr = mst->i2c_addr; 3558c2ecf20Sopenharmony_ci mst->msg[0].buf = &mst->i2c_write_buffer[0]; 3568c2ecf20Sopenharmony_ci mst->msg[0].len = 4; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* close the gate */ 3618c2ecf20Sopenharmony_ci dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0); 3628c2ecf20Sopenharmony_ci mst->msg[num + 1].addr = mst->i2c_addr; 3638c2ecf20Sopenharmony_ci mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; 3648c2ecf20Sopenharmony_ci mst->msg[num + 1].len = 4; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? 3678c2ecf20Sopenharmony_ci num : -EIO); 3688c2ecf20Sopenharmony_ci mutex_unlock(&mst->i2c_buffer_lock); 3698c2ecf20Sopenharmony_ci return ret; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { 3738c2ecf20Sopenharmony_ci .master_xfer = dibx000_i2c_gated_tuner_xfer, 3748c2ecf20Sopenharmony_ci .functionality = dibx000_i2c_func, 3758c2ecf20Sopenharmony_ci}; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistruct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, 3788c2ecf20Sopenharmony_ci enum dibx000_i2c_interface intf, 3798c2ecf20Sopenharmony_ci int gating) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = NULL; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci switch (intf) { 3848c2ecf20Sopenharmony_ci case DIBX000_I2C_INTERFACE_TUNER: 3858c2ecf20Sopenharmony_ci if (gating) 3868c2ecf20Sopenharmony_ci i2c = &mst->gated_tuner_i2c_adap; 3878c2ecf20Sopenharmony_ci break; 3888c2ecf20Sopenharmony_ci case DIBX000_I2C_INTERFACE_GPIO_1_2: 3898c2ecf20Sopenharmony_ci if (!gating) 3908c2ecf20Sopenharmony_ci i2c = &mst->master_i2c_adap_gpio12; 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci case DIBX000_I2C_INTERFACE_GPIO_3_4: 3938c2ecf20Sopenharmony_ci if (!gating) 3948c2ecf20Sopenharmony_ci i2c = &mst->master_i2c_adap_gpio34; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci case DIBX000_I2C_INTERFACE_GPIO_6_7: 3978c2ecf20Sopenharmony_ci if (gating) 3988c2ecf20Sopenharmony_ci i2c = &mst->master_i2c_adap_gpio67; 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci default: 4018c2ecf20Sopenharmony_ci pr_err("incorrect I2C interface selected\n"); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return i2c; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dibx000_get_i2c_adapter); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_civoid dibx000_reset_i2c_master(struct dibx000_i2c_master *mst) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci /* initialize the i2c-master by closing the gate */ 4138c2ecf20Sopenharmony_ci u8 tx[4]; 4148c2ecf20Sopenharmony_ci struct i2c_msg m = {.addr = mst->i2c_addr,.buf = tx,.len = 4 }; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci dibx000_i2c_gate_ctrl(mst, tx, 0, 0); 4178c2ecf20Sopenharmony_ci i2c_transfer(mst->i2c_adap, &m, 1); 4188c2ecf20Sopenharmony_ci mst->selected_interface = 0xff; // the first time force a select of the I2C 4198c2ecf20Sopenharmony_ci dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dibx000_reset_i2c_master); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int i2c_adapter_init(struct i2c_adapter *i2c_adap, 4258c2ecf20Sopenharmony_ci struct i2c_algorithm *algo, const char *name, 4268c2ecf20Sopenharmony_ci struct dibx000_i2c_master *mst) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci strscpy(i2c_adap->name, name, sizeof(i2c_adap->name)); 4298c2ecf20Sopenharmony_ci i2c_adap->algo = algo; 4308c2ecf20Sopenharmony_ci i2c_adap->algo_data = NULL; 4318c2ecf20Sopenharmony_ci i2c_set_adapdata(i2c_adap, mst); 4328c2ecf20Sopenharmony_ci if (i2c_add_adapter(i2c_adap) < 0) 4338c2ecf20Sopenharmony_ci return -ENODEV; 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ciint dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, 4388c2ecf20Sopenharmony_ci struct i2c_adapter *i2c_adap, u8 i2c_addr) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci int ret; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci mutex_init(&mst->i2c_buffer_lock); 4438c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { 4448c2ecf20Sopenharmony_ci dprintk("could not acquire lock\n"); 4458c2ecf20Sopenharmony_ci return -EINVAL; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci memset(mst->msg, 0, sizeof(struct i2c_msg)); 4488c2ecf20Sopenharmony_ci mst->msg[0].addr = i2c_addr >> 1; 4498c2ecf20Sopenharmony_ci mst->msg[0].flags = 0; 4508c2ecf20Sopenharmony_ci mst->msg[0].buf = mst->i2c_write_buffer; 4518c2ecf20Sopenharmony_ci mst->msg[0].len = 4; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci mst->device_rev = device_rev; 4548c2ecf20Sopenharmony_ci mst->i2c_adap = i2c_adap; 4558c2ecf20Sopenharmony_ci mst->i2c_addr = i2c_addr >> 1; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (device_rev == DIB7000P || device_rev == DIB8000) 4588c2ecf20Sopenharmony_ci mst->base_reg = 1024; 4598c2ecf20Sopenharmony_ci else 4608c2ecf20Sopenharmony_ci mst->base_reg = 768; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci mst->gated_tuner_i2c_adap.dev.parent = mst->i2c_adap->dev.parent; 4638c2ecf20Sopenharmony_ci if (i2c_adapter_init 4648c2ecf20Sopenharmony_ci (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, 4658c2ecf20Sopenharmony_ci "DiBX000 tuner I2C bus", mst) != 0) 4668c2ecf20Sopenharmony_ci pr_err("could not initialize the tuner i2c_adapter\n"); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent; 4698c2ecf20Sopenharmony_ci if (i2c_adapter_init 4708c2ecf20Sopenharmony_ci (&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo, 4718c2ecf20Sopenharmony_ci "DiBX000 master GPIO12 I2C bus", mst) != 0) 4728c2ecf20Sopenharmony_ci pr_err("could not initialize the master i2c_adapter\n"); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent; 4758c2ecf20Sopenharmony_ci if (i2c_adapter_init 4768c2ecf20Sopenharmony_ci (&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo, 4778c2ecf20Sopenharmony_ci "DiBX000 master GPIO34 I2C bus", mst) != 0) 4788c2ecf20Sopenharmony_ci pr_err("could not initialize the master i2c_adapter\n"); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent; 4818c2ecf20Sopenharmony_ci if (i2c_adapter_init 4828c2ecf20Sopenharmony_ci (&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo, 4838c2ecf20Sopenharmony_ci "DiBX000 master GPIO67 I2C bus", mst) != 0) 4848c2ecf20Sopenharmony_ci pr_err("could not initialize the master i2c_adapter\n"); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* initialize the i2c-master by closing the gate */ 4878c2ecf20Sopenharmony_ci dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1); 4908c2ecf20Sopenharmony_ci mutex_unlock(&mst->i2c_buffer_lock); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return ret; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dibx000_init_i2c_master); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_civoid dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci i2c_del_adapter(&mst->gated_tuner_i2c_adap); 5008c2ecf20Sopenharmony_ci i2c_del_adapter(&mst->master_i2c_adap_gpio12); 5018c2ecf20Sopenharmony_ci i2c_del_adapter(&mst->master_i2c_adap_gpio34); 5028c2ecf20Sopenharmony_ci i2c_del_adapter(&mst->master_i2c_adap_gpio67); 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dibx000_exit_i2c_master); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 5078c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Common function the DiBcom demodulator family"); 5088c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 509