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