18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  mxl111sf-i2c.c - driver for the MaxLinear MXL111SF
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "mxl111sf-i2c.h"
98c2ecf20Sopenharmony_ci#include "mxl111sf.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/* SW-I2C ----------------------------------------------------------------- */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define SW_I2C_ADDR		0x1a
148c2ecf20Sopenharmony_ci#define SW_I2C_EN		0x02
158c2ecf20Sopenharmony_ci#define SW_SCL_OUT		0x04
168c2ecf20Sopenharmony_ci#define SW_SDA_OUT		0x08
178c2ecf20Sopenharmony_ci#define SW_SDA_IN		0x04
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define SW_I2C_BUSY_ADDR	0x2f
208c2ecf20Sopenharmony_ci#define SW_I2C_BUSY		0x02
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state,
238c2ecf20Sopenharmony_ci					 u8 byte)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	int i, ret;
268c2ecf20Sopenharmony_ci	u8 data = 0;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	mxl_i2c("(0x%02x)", byte);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
318c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
328c2ecf20Sopenharmony_ci		goto fail;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci		data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
398c2ecf20Sopenharmony_ci					 0x10 | SW_I2C_EN | data);
408c2ecf20Sopenharmony_ci		if (mxl_fail(ret))
418c2ecf20Sopenharmony_ci			goto fail;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
448c2ecf20Sopenharmony_ci					 0x10 | SW_I2C_EN | data | SW_SCL_OUT);
458c2ecf20Sopenharmony_ci		if (mxl_fail(ret))
468c2ecf20Sopenharmony_ci			goto fail;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
498c2ecf20Sopenharmony_ci					 0x10 | SW_I2C_EN | data);
508c2ecf20Sopenharmony_ci		if (mxl_fail(ret))
518c2ecf20Sopenharmony_ci			goto fail;
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* last bit was 0 so we need to release SDA */
558c2ecf20Sopenharmony_ci	if (!(byte & 1)) {
568c2ecf20Sopenharmony_ci		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
578c2ecf20Sopenharmony_ci					 0x10 | SW_I2C_EN | SW_SDA_OUT);
588c2ecf20Sopenharmony_ci		if (mxl_fail(ret))
598c2ecf20Sopenharmony_ci			goto fail;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* CLK high for ACK readback */
638c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
648c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
658c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
668c2ecf20Sopenharmony_ci		goto fail;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
698c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
708c2ecf20Sopenharmony_ci		goto fail;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/* drop the CLK after getting ACK, SDA will go high right away */
738c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
748c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SDA_OUT);
758c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
768c2ecf20Sopenharmony_ci		goto fail;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (data & SW_SDA_IN)
798c2ecf20Sopenharmony_ci		ret = -EIO;
808c2ecf20Sopenharmony_cifail:
818c2ecf20Sopenharmony_ci	return ret;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state,
858c2ecf20Sopenharmony_ci					 u8 *pbyte)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	int i, ret;
888c2ecf20Sopenharmony_ci	u8 byte = 0;
898c2ecf20Sopenharmony_ci	u8 data = 0;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	mxl_i2c("()");
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	*pbyte = 0;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
968c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SDA_OUT);
978c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
988c2ecf20Sopenharmony_ci		goto fail;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
1018c2ecf20Sopenharmony_ci		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1028c2ecf20Sopenharmony_ci					 0x10 | SW_I2C_EN |
1038c2ecf20Sopenharmony_ci					 SW_SCL_OUT | SW_SDA_OUT);
1048c2ecf20Sopenharmony_ci		if (mxl_fail(ret))
1058c2ecf20Sopenharmony_ci			goto fail;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci		ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
1088c2ecf20Sopenharmony_ci		if (mxl_fail(ret))
1098c2ecf20Sopenharmony_ci			goto fail;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		if (data & SW_SDA_IN)
1128c2ecf20Sopenharmony_ci			byte |= (0x80 >> i);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1158c2ecf20Sopenharmony_ci					 0x10 | SW_I2C_EN | SW_SDA_OUT);
1168c2ecf20Sopenharmony_ci		if (mxl_fail(ret))
1178c2ecf20Sopenharmony_ci			goto fail;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci	*pbyte = byte;
1208c2ecf20Sopenharmony_cifail:
1218c2ecf20Sopenharmony_ci	return ret;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_start(struct mxl111sf_state *state)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	int ret;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	mxl_i2c("()");
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1318c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
1328c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
1338c2ecf20Sopenharmony_ci		goto fail;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1368c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SCL_OUT);
1378c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
1388c2ecf20Sopenharmony_ci		goto fail;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1418c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN); /* start */
1428c2ecf20Sopenharmony_ci	mxl_fail(ret);
1438c2ecf20Sopenharmony_cifail:
1448c2ecf20Sopenharmony_ci	return ret;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_stop(struct mxl111sf_state *state)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	int ret;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	mxl_i2c("()");
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1548c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN); /* stop */
1558c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
1568c2ecf20Sopenharmony_ci		goto fail;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1598c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SCL_OUT);
1608c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
1618c2ecf20Sopenharmony_ci		goto fail;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1648c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
1658c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
1668c2ecf20Sopenharmony_ci		goto fail;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1698c2ecf20Sopenharmony_ci				 0x10 | SW_SCL_OUT | SW_SDA_OUT);
1708c2ecf20Sopenharmony_ci	mxl_fail(ret);
1718c2ecf20Sopenharmony_cifail:
1728c2ecf20Sopenharmony_ci	return ret;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_ack(struct mxl111sf_state *state)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	int ret;
1788c2ecf20Sopenharmony_ci	u8 b = 0;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	mxl_i2c("()");
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b);
1838c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
1848c2ecf20Sopenharmony_ci		goto fail;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1878c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN);
1888c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
1898c2ecf20Sopenharmony_ci		goto fail;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	/* pull SDA low */
1928c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1938c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SCL_OUT);
1948c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
1958c2ecf20Sopenharmony_ci		goto fail;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1988c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SDA_OUT);
1998c2ecf20Sopenharmony_ci	mxl_fail(ret);
2008c2ecf20Sopenharmony_cifail:
2018c2ecf20Sopenharmony_ci	return ret;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_nack(struct mxl111sf_state *state)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	int ret;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	mxl_i2c("()");
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	/* SDA high to signal last byte read from slave */
2118c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
2128c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
2138c2ecf20Sopenharmony_ci	if (mxl_fail(ret))
2148c2ecf20Sopenharmony_ci		goto fail;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
2178c2ecf20Sopenharmony_ci				 0x10 | SW_I2C_EN | SW_SDA_OUT);
2188c2ecf20Sopenharmony_ci	mxl_fail(ret);
2198c2ecf20Sopenharmony_cifail:
2208c2ecf20Sopenharmony_ci	return ret;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------ */
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state,
2268c2ecf20Sopenharmony_ci				    struct i2c_msg *msg)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	int i, ret;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	mxl_i2c("()");
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (msg->flags & I2C_M_RD) {
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		ret = mxl111sf_i2c_start(state);
2358c2ecf20Sopenharmony_ci		if (mxl_fail(ret))
2368c2ecf20Sopenharmony_ci			goto fail;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci		ret = mxl111sf_i2c_bitbang_sendbyte(state,
2398c2ecf20Sopenharmony_ci						    (msg->addr << 1) | 0x01);
2408c2ecf20Sopenharmony_ci		if (mxl_fail(ret)) {
2418c2ecf20Sopenharmony_ci			mxl111sf_i2c_stop(state);
2428c2ecf20Sopenharmony_ci			goto fail;
2438c2ecf20Sopenharmony_ci		}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		for (i = 0; i < msg->len; i++) {
2468c2ecf20Sopenharmony_ci			ret = mxl111sf_i2c_bitbang_recvbyte(state,
2478c2ecf20Sopenharmony_ci							    &msg->buf[i]);
2488c2ecf20Sopenharmony_ci			if (mxl_fail(ret)) {
2498c2ecf20Sopenharmony_ci				mxl111sf_i2c_stop(state);
2508c2ecf20Sopenharmony_ci				goto fail;
2518c2ecf20Sopenharmony_ci			}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci			if (i < msg->len - 1)
2548c2ecf20Sopenharmony_ci				mxl111sf_i2c_ack(state);
2558c2ecf20Sopenharmony_ci		}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci		mxl111sf_i2c_nack(state);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci		ret = mxl111sf_i2c_stop(state);
2608c2ecf20Sopenharmony_ci		if (mxl_fail(ret))
2618c2ecf20Sopenharmony_ci			goto fail;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	} else {
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		ret = mxl111sf_i2c_start(state);
2668c2ecf20Sopenharmony_ci		if (mxl_fail(ret))
2678c2ecf20Sopenharmony_ci			goto fail;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci		ret = mxl111sf_i2c_bitbang_sendbyte(state,
2708c2ecf20Sopenharmony_ci						    (msg->addr << 1) & 0xfe);
2718c2ecf20Sopenharmony_ci		if (mxl_fail(ret)) {
2728c2ecf20Sopenharmony_ci			mxl111sf_i2c_stop(state);
2738c2ecf20Sopenharmony_ci			goto fail;
2748c2ecf20Sopenharmony_ci		}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci		for (i = 0; i < msg->len; i++) {
2778c2ecf20Sopenharmony_ci			ret = mxl111sf_i2c_bitbang_sendbyte(state,
2788c2ecf20Sopenharmony_ci							    msg->buf[i]);
2798c2ecf20Sopenharmony_ci			if (mxl_fail(ret)) {
2808c2ecf20Sopenharmony_ci				mxl111sf_i2c_stop(state);
2818c2ecf20Sopenharmony_ci				goto fail;
2828c2ecf20Sopenharmony_ci			}
2838c2ecf20Sopenharmony_ci		}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		/* FIXME: we only want to do this on the last transaction */
2868c2ecf20Sopenharmony_ci		mxl111sf_i2c_stop(state);
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_cifail:
2898c2ecf20Sopenharmony_ci	return ret;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci/* HW-I2C ----------------------------------------------------------------- */
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci#define USB_WRITE_I2C_CMD     0x99
2958c2ecf20Sopenharmony_ci#define USB_READ_I2C_CMD      0xdd
2968c2ecf20Sopenharmony_ci#define USB_END_I2C_CMD       0xfe
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci#define USB_WRITE_I2C_CMD_LEN   26
2998c2ecf20Sopenharmony_ci#define USB_READ_I2C_CMD_LEN    24
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci#define I2C_MUX_REG           0x30
3028c2ecf20Sopenharmony_ci#define I2C_CONTROL_REG       0x00
3038c2ecf20Sopenharmony_ci#define I2C_SLAVE_ADDR_REG    0x08
3048c2ecf20Sopenharmony_ci#define I2C_DATA_REG          0x0c
3058c2ecf20Sopenharmony_ci#define I2C_INT_STATUS_REG    0x10
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_send_data(struct mxl111sf_state *state,
3088c2ecf20Sopenharmony_ci				  u8 index, u8 *wdata)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	int ret = mxl111sf_ctrl_msg(state, wdata[0],
3118c2ecf20Sopenharmony_ci				    &wdata[1], 25, NULL, 0);
3128c2ecf20Sopenharmony_ci	mxl_fail(ret);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return ret;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_get_data(struct mxl111sf_state *state,
3188c2ecf20Sopenharmony_ci				 u8 index, u8 *wdata, u8 *rdata)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	int ret = mxl111sf_ctrl_msg(state, wdata[0],
3218c2ecf20Sopenharmony_ci				    &wdata[1], 25, rdata, 24);
3228c2ecf20Sopenharmony_ci	mxl_fail(ret);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	return ret;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	u8 status = 0;
3308c2ecf20Sopenharmony_ci	u8 buf[26];
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	mxl_i2c_adv("()");
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	buf[0] = USB_READ_I2C_CMD;
3358c2ecf20Sopenharmony_ci	buf[1] = 0x00;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	buf[2] = I2C_INT_STATUS_REG;
3388c2ecf20Sopenharmony_ci	buf[3] = 0x00;
3398c2ecf20Sopenharmony_ci	buf[4] = 0x00;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	buf[5] = USB_END_I2C_CMD;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	mxl111sf_i2c_get_data(state, 0, buf, buf);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (buf[1] & 0x04)
3468c2ecf20Sopenharmony_ci		status = 1;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return status;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	u8 status = 0;
3548c2ecf20Sopenharmony_ci	u8 buf[26];
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	mxl_i2c("()");
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	buf[0] = USB_READ_I2C_CMD;
3598c2ecf20Sopenharmony_ci	buf[1] = 0x00;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	buf[2] = I2C_MUX_REG;
3628c2ecf20Sopenharmony_ci	buf[3] = 0x00;
3638c2ecf20Sopenharmony_ci	buf[4] = 0x00;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	buf[5] = I2C_INT_STATUS_REG;
3668c2ecf20Sopenharmony_ci	buf[6] = 0x00;
3678c2ecf20Sopenharmony_ci	buf[7] = 0x00;
3688c2ecf20Sopenharmony_ci	buf[8] = USB_END_I2C_CMD;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	mxl111sf_i2c_get_data(state, 0, buf, buf);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (0x08 == (buf[1] & 0x08))
3738c2ecf20Sopenharmony_ci		status = 1;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if ((buf[5] & 0x02) == 0x02)
3768c2ecf20Sopenharmony_ci		mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	return status;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_readagain(struct mxl111sf_state *state,
3828c2ecf20Sopenharmony_ci				  u8 count, u8 *rbuf)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	u8 i2c_w_data[26];
3858c2ecf20Sopenharmony_ci	u8 i2c_r_data[24];
3868c2ecf20Sopenharmony_ci	u8 i = 0;
3878c2ecf20Sopenharmony_ci	u8 fifo_status = 0;
3888c2ecf20Sopenharmony_ci	int status = 0;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	mxl_i2c("read %d bytes", count);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	while ((fifo_status == 0) && (i++ < 5))
3938c2ecf20Sopenharmony_ci		fifo_status = mxl111sf_i2c_check_fifo(state);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	i2c_w_data[0] = 0xDD;
3968c2ecf20Sopenharmony_ci	i2c_w_data[1] = 0x00;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	for (i = 2; i < 26; i++)
3998c2ecf20Sopenharmony_ci		i2c_w_data[i] = 0xFE;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
4028c2ecf20Sopenharmony_ci		i2c_w_data[2+(i*3)] = 0x0C;
4038c2ecf20Sopenharmony_ci		i2c_w_data[3+(i*3)] = 0x00;
4048c2ecf20Sopenharmony_ci		i2c_w_data[4+(i*3)] = 0x00;
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* Check for I2C NACK status */
4108c2ecf20Sopenharmony_ci	if (mxl111sf_i2c_check_status(state) == 1) {
4118c2ecf20Sopenharmony_ci		mxl_i2c("error!");
4128c2ecf20Sopenharmony_ci	} else {
4138c2ecf20Sopenharmony_ci		for (i = 0; i < count; i++) {
4148c2ecf20Sopenharmony_ci			rbuf[i] = i2c_r_data[(i*3)+1];
4158c2ecf20Sopenharmony_ci			mxl_i2c("%02x\t %02x",
4168c2ecf20Sopenharmony_ci				i2c_r_data[(i*3)+1],
4178c2ecf20Sopenharmony_ci				i2c_r_data[(i*3)+2]);
4188c2ecf20Sopenharmony_ci		}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci		status = 1;
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	return status;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci#define HWI2C400 1
4278c2ecf20Sopenharmony_cistatic int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state,
4288c2ecf20Sopenharmony_ci				    struct i2c_msg *msg)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	int i, k, ret = 0;
4318c2ecf20Sopenharmony_ci	u16 index = 0;
4328c2ecf20Sopenharmony_ci	u8 buf[26];
4338c2ecf20Sopenharmony_ci	u8 i2c_r_data[24];
4348c2ecf20Sopenharmony_ci	u16 block_len;
4358c2ecf20Sopenharmony_ci	u16 left_over_len;
4368c2ecf20Sopenharmony_ci	u8 rd_status[8];
4378c2ecf20Sopenharmony_ci	u8 ret_status;
4388c2ecf20Sopenharmony_ci	u8 readbuff[26];
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d",
4418c2ecf20Sopenharmony_ci		msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0,
4428c2ecf20Sopenharmony_ci		(!(msg->flags & I2C_M_RD)) ? msg->len : 0);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	for (index = 0; index < 26; index++)
4458c2ecf20Sopenharmony_ci		buf[index] = USB_END_I2C_CMD;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/* command to indicate data payload is destined for I2C interface */
4488c2ecf20Sopenharmony_ci	buf[0] = USB_WRITE_I2C_CMD;
4498c2ecf20Sopenharmony_ci	buf[1] = 0x00;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	/* enable I2C interface */
4528c2ecf20Sopenharmony_ci	buf[2] = I2C_MUX_REG;
4538c2ecf20Sopenharmony_ci	buf[3] = 0x80;
4548c2ecf20Sopenharmony_ci	buf[4] = 0x00;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* enable I2C interface */
4578c2ecf20Sopenharmony_ci	buf[5] = I2C_MUX_REG;
4588c2ecf20Sopenharmony_ci	buf[6] = 0x81;
4598c2ecf20Sopenharmony_ci	buf[7] = 0x00;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* set Timeout register on I2C interface */
4628c2ecf20Sopenharmony_ci	buf[8] = 0x14;
4638c2ecf20Sopenharmony_ci	buf[9] = 0xff;
4648c2ecf20Sopenharmony_ci	buf[10] = 0x00;
4658c2ecf20Sopenharmony_ci#if 0
4668c2ecf20Sopenharmony_ci	/* enable Interrupts on I2C interface */
4678c2ecf20Sopenharmony_ci	buf[8] = 0x24;
4688c2ecf20Sopenharmony_ci	buf[9] = 0xF7;
4698c2ecf20Sopenharmony_ci	buf[10] = 0x00;
4708c2ecf20Sopenharmony_ci#endif
4718c2ecf20Sopenharmony_ci	buf[11] = 0x24;
4728c2ecf20Sopenharmony_ci	buf[12] = 0xF7;
4738c2ecf20Sopenharmony_ci	buf[13] = 0x00;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	ret = mxl111sf_i2c_send_data(state, 0, buf);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	/* write data on I2C bus */
4788c2ecf20Sopenharmony_ci	if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) {
4798c2ecf20Sopenharmony_ci		mxl_i2c("%d\t%02x", msg->len, msg->buf[0]);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci		/* control register on I2C interface to initialize I2C bus */
4828c2ecf20Sopenharmony_ci		buf[2] = I2C_CONTROL_REG;
4838c2ecf20Sopenharmony_ci		buf[3] = 0x5E;
4848c2ecf20Sopenharmony_ci		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		/* I2C Slave device Address */
4878c2ecf20Sopenharmony_ci		buf[5] = I2C_SLAVE_ADDR_REG;
4888c2ecf20Sopenharmony_ci		buf[6] = (msg->addr);
4898c2ecf20Sopenharmony_ci		buf[7] = 0x00;
4908c2ecf20Sopenharmony_ci		buf[8] = USB_END_I2C_CMD;
4918c2ecf20Sopenharmony_ci		ret = mxl111sf_i2c_send_data(state, 0, buf);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci		/* check for slave device status */
4948c2ecf20Sopenharmony_ci		if (mxl111sf_i2c_check_status(state) == 1) {
4958c2ecf20Sopenharmony_ci			mxl_i2c("NACK writing slave address %02x",
4968c2ecf20Sopenharmony_ci				msg->addr);
4978c2ecf20Sopenharmony_ci			/* if NACK, stop I2C bus and exit */
4988c2ecf20Sopenharmony_ci			buf[2] = I2C_CONTROL_REG;
4998c2ecf20Sopenharmony_ci			buf[3] = 0x4E;
5008c2ecf20Sopenharmony_ci			buf[4] = (HWI2C400) ? 0x03 : 0x0D;
5018c2ecf20Sopenharmony_ci			ret = -EIO;
5028c2ecf20Sopenharmony_ci			goto exit;
5038c2ecf20Sopenharmony_ci		}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		/* I2C interface can do I2C operations in block of 8 bytes of
5068c2ecf20Sopenharmony_ci		   I2C data. calculation to figure out number of blocks of i2c
5078c2ecf20Sopenharmony_ci		   data required to program */
5088c2ecf20Sopenharmony_ci		block_len = (msg->len / 8);
5098c2ecf20Sopenharmony_ci		left_over_len = (msg->len % 8);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci		mxl_i2c("block_len %d, left_over_len %d",
5128c2ecf20Sopenharmony_ci			block_len, left_over_len);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		for (index = 0; index < block_len; index++) {
5158c2ecf20Sopenharmony_ci			for (i = 0; i < 8; i++) {
5168c2ecf20Sopenharmony_ci				/* write data on I2C interface */
5178c2ecf20Sopenharmony_ci				buf[2+(i*3)] = I2C_DATA_REG;
5188c2ecf20Sopenharmony_ci				buf[3+(i*3)] = msg->buf[(index*8)+i];
5198c2ecf20Sopenharmony_ci				buf[4+(i*3)] = 0x00;
5208c2ecf20Sopenharmony_ci			}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci			ret = mxl111sf_i2c_send_data(state, 0, buf);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci			/* check for I2C NACK status */
5258c2ecf20Sopenharmony_ci			if (mxl111sf_i2c_check_status(state) == 1) {
5268c2ecf20Sopenharmony_ci				mxl_i2c("NACK writing slave address %02x",
5278c2ecf20Sopenharmony_ci					msg->addr);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci				/* if NACK, stop I2C bus and exit */
5308c2ecf20Sopenharmony_ci				buf[2] = I2C_CONTROL_REG;
5318c2ecf20Sopenharmony_ci				buf[3] = 0x4E;
5328c2ecf20Sopenharmony_ci				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
5338c2ecf20Sopenharmony_ci				ret = -EIO;
5348c2ecf20Sopenharmony_ci				goto exit;
5358c2ecf20Sopenharmony_ci			}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci		}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		if (left_over_len) {
5408c2ecf20Sopenharmony_ci			for (k = 0; k < 26; k++)
5418c2ecf20Sopenharmony_ci				buf[k] = USB_END_I2C_CMD;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci			buf[0] = 0x99;
5448c2ecf20Sopenharmony_ci			buf[1] = 0x00;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci			for (i = 0; i < left_over_len; i++) {
5478c2ecf20Sopenharmony_ci				buf[2+(i*3)] = I2C_DATA_REG;
5488c2ecf20Sopenharmony_ci				buf[3+(i*3)] = msg->buf[(index*8)+i];
5498c2ecf20Sopenharmony_ci				mxl_i2c("index = %d %d data %d",
5508c2ecf20Sopenharmony_ci					index, i, msg->buf[(index*8)+i]);
5518c2ecf20Sopenharmony_ci				buf[4+(i*3)] = 0x00;
5528c2ecf20Sopenharmony_ci			}
5538c2ecf20Sopenharmony_ci			ret = mxl111sf_i2c_send_data(state, 0, buf);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci			/* check for I2C NACK status */
5568c2ecf20Sopenharmony_ci			if (mxl111sf_i2c_check_status(state) == 1) {
5578c2ecf20Sopenharmony_ci				mxl_i2c("NACK writing slave address %02x",
5588c2ecf20Sopenharmony_ci					msg->addr);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci				/* if NACK, stop I2C bus and exit */
5618c2ecf20Sopenharmony_ci				buf[2] = I2C_CONTROL_REG;
5628c2ecf20Sopenharmony_ci				buf[3] = 0x4E;
5638c2ecf20Sopenharmony_ci				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
5648c2ecf20Sopenharmony_ci				ret = -EIO;
5658c2ecf20Sopenharmony_ci				goto exit;
5668c2ecf20Sopenharmony_ci			}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci		}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		/* issue I2C STOP after write */
5718c2ecf20Sopenharmony_ci		buf[2] = I2C_CONTROL_REG;
5728c2ecf20Sopenharmony_ci		buf[3] = 0x4E;
5738c2ecf20Sopenharmony_ci		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	/* read data from I2C bus */
5788c2ecf20Sopenharmony_ci	if ((msg->flags & I2C_M_RD) && (msg->len > 0)) {
5798c2ecf20Sopenharmony_ci		mxl_i2c("read buf len %d", msg->len);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci		/* command to indicate data payload is
5828c2ecf20Sopenharmony_ci		   destined for I2C interface */
5838c2ecf20Sopenharmony_ci		buf[2] = I2C_CONTROL_REG;
5848c2ecf20Sopenharmony_ci		buf[3] = 0xDF;
5858c2ecf20Sopenharmony_ci		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		/* I2C xfer length */
5888c2ecf20Sopenharmony_ci		buf[5] = 0x14;
5898c2ecf20Sopenharmony_ci		buf[6] = (msg->len & 0xFF);
5908c2ecf20Sopenharmony_ci		buf[7] = 0;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci		/* I2C slave device Address */
5938c2ecf20Sopenharmony_ci		buf[8] = I2C_SLAVE_ADDR_REG;
5948c2ecf20Sopenharmony_ci		buf[9] = msg->addr;
5958c2ecf20Sopenharmony_ci		buf[10] = 0x00;
5968c2ecf20Sopenharmony_ci		buf[11] = USB_END_I2C_CMD;
5978c2ecf20Sopenharmony_ci		ret = mxl111sf_i2c_send_data(state, 0, buf);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci		/* check for I2C NACK status */
6008c2ecf20Sopenharmony_ci		if (mxl111sf_i2c_check_status(state) == 1) {
6018c2ecf20Sopenharmony_ci			mxl_i2c("NACK reading slave address %02x",
6028c2ecf20Sopenharmony_ci				msg->addr);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci			/* if NACK, stop I2C bus and exit */
6058c2ecf20Sopenharmony_ci			buf[2] = I2C_CONTROL_REG;
6068c2ecf20Sopenharmony_ci			buf[3] = 0xC7;
6078c2ecf20Sopenharmony_ci			buf[4] = (HWI2C400) ? 0x03 : 0x0D;
6088c2ecf20Sopenharmony_ci			ret = -EIO;
6098c2ecf20Sopenharmony_ci			goto exit;
6108c2ecf20Sopenharmony_ci		}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci		/* I2C interface can do I2C operations in block of 8 bytes of
6138c2ecf20Sopenharmony_ci		   I2C data. calculation to figure out number of blocks of
6148c2ecf20Sopenharmony_ci		   i2c data required to program */
6158c2ecf20Sopenharmony_ci		block_len = ((msg->len) / 8);
6168c2ecf20Sopenharmony_ci		left_over_len = ((msg->len) % 8);
6178c2ecf20Sopenharmony_ci		index = 0;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		mxl_i2c("block_len %d, left_over_len %d",
6208c2ecf20Sopenharmony_ci			block_len, left_over_len);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci		/* command to read data from I2C interface */
6238c2ecf20Sopenharmony_ci		buf[0] = USB_READ_I2C_CMD;
6248c2ecf20Sopenharmony_ci		buf[1] = 0x00;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci		for (index = 0; index < block_len; index++) {
6278c2ecf20Sopenharmony_ci			/* setup I2C read request packet on I2C interface */
6288c2ecf20Sopenharmony_ci			for (i = 0; i < 8; i++) {
6298c2ecf20Sopenharmony_ci				buf[2+(i*3)] = I2C_DATA_REG;
6308c2ecf20Sopenharmony_ci				buf[3+(i*3)] = 0x00;
6318c2ecf20Sopenharmony_ci				buf[4+(i*3)] = 0x00;
6328c2ecf20Sopenharmony_ci			}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci			ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci			/* check for I2C NACK status */
6378c2ecf20Sopenharmony_ci			if (mxl111sf_i2c_check_status(state) == 1) {
6388c2ecf20Sopenharmony_ci				mxl_i2c("NACK reading slave address %02x",
6398c2ecf20Sopenharmony_ci					msg->addr);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci				/* if NACK, stop I2C bus and exit */
6428c2ecf20Sopenharmony_ci				buf[2] = I2C_CONTROL_REG;
6438c2ecf20Sopenharmony_ci				buf[3] = 0xC7;
6448c2ecf20Sopenharmony_ci				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
6458c2ecf20Sopenharmony_ci				ret = -EIO;
6468c2ecf20Sopenharmony_ci				goto exit;
6478c2ecf20Sopenharmony_ci			}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci			/* copy data from i2c data payload to read buffer */
6508c2ecf20Sopenharmony_ci			for (i = 0; i < 8; i++) {
6518c2ecf20Sopenharmony_ci				rd_status[i] = i2c_r_data[(i*3)+2];
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci				if (rd_status[i] == 0x04) {
6548c2ecf20Sopenharmony_ci					if (i < 7) {
6558c2ecf20Sopenharmony_ci						mxl_i2c("i2c fifo empty! @ %d",
6568c2ecf20Sopenharmony_ci							i);
6578c2ecf20Sopenharmony_ci						msg->buf[(index*8)+i] =
6588c2ecf20Sopenharmony_ci							i2c_r_data[(i*3)+1];
6598c2ecf20Sopenharmony_ci						/* read again */
6608c2ecf20Sopenharmony_ci						ret_status =
6618c2ecf20Sopenharmony_ci							mxl111sf_i2c_readagain(
6628c2ecf20Sopenharmony_ci								state, 8-(i+1),
6638c2ecf20Sopenharmony_ci								readbuff);
6648c2ecf20Sopenharmony_ci						if (ret_status == 1) {
6658c2ecf20Sopenharmony_ci							for (k = 0;
6668c2ecf20Sopenharmony_ci							     k < 8-(i+1);
6678c2ecf20Sopenharmony_ci							     k++) {
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci					msg->buf[(index*8)+(k+i+1)] =
6708c2ecf20Sopenharmony_ci						readbuff[k];
6718c2ecf20Sopenharmony_ci					mxl_i2c("read data: %02x\t %02x",
6728c2ecf20Sopenharmony_ci						msg->buf[(index*8)+(k+i)],
6738c2ecf20Sopenharmony_ci						(index*8)+(k+i));
6748c2ecf20Sopenharmony_ci					mxl_i2c("read data: %02x\t %02x",
6758c2ecf20Sopenharmony_ci						msg->buf[(index*8)+(k+i+1)],
6768c2ecf20Sopenharmony_ci						readbuff[k]);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci							}
6798c2ecf20Sopenharmony_ci							goto stop_copy;
6808c2ecf20Sopenharmony_ci						} else {
6818c2ecf20Sopenharmony_ci							mxl_i2c("readagain ERROR!");
6828c2ecf20Sopenharmony_ci						}
6838c2ecf20Sopenharmony_ci					} else {
6848c2ecf20Sopenharmony_ci						msg->buf[(index*8)+i] =
6858c2ecf20Sopenharmony_ci							i2c_r_data[(i*3)+1];
6868c2ecf20Sopenharmony_ci					}
6878c2ecf20Sopenharmony_ci				} else {
6888c2ecf20Sopenharmony_ci					msg->buf[(index*8)+i] =
6898c2ecf20Sopenharmony_ci						i2c_r_data[(i*3)+1];
6908c2ecf20Sopenharmony_ci				}
6918c2ecf20Sopenharmony_ci			}
6928c2ecf20Sopenharmony_cistop_copy:
6938c2ecf20Sopenharmony_ci			;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci		}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci		if (left_over_len) {
6988c2ecf20Sopenharmony_ci			for (k = 0; k < 26; k++)
6998c2ecf20Sopenharmony_ci				buf[k] = USB_END_I2C_CMD;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci			buf[0] = 0xDD;
7028c2ecf20Sopenharmony_ci			buf[1] = 0x00;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci			for (i = 0; i < left_over_len; i++) {
7058c2ecf20Sopenharmony_ci				buf[2+(i*3)] = I2C_DATA_REG;
7068c2ecf20Sopenharmony_ci				buf[3+(i*3)] = 0x00;
7078c2ecf20Sopenharmony_ci				buf[4+(i*3)] = 0x00;
7088c2ecf20Sopenharmony_ci			}
7098c2ecf20Sopenharmony_ci			ret = mxl111sf_i2c_get_data(state, 0, buf,
7108c2ecf20Sopenharmony_ci						    i2c_r_data);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci			/* check for I2C NACK status */
7138c2ecf20Sopenharmony_ci			if (mxl111sf_i2c_check_status(state) == 1) {
7148c2ecf20Sopenharmony_ci				mxl_i2c("NACK reading slave address %02x",
7158c2ecf20Sopenharmony_ci					msg->addr);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci				/* if NACK, stop I2C bus and exit */
7188c2ecf20Sopenharmony_ci				buf[2] = I2C_CONTROL_REG;
7198c2ecf20Sopenharmony_ci				buf[3] = 0xC7;
7208c2ecf20Sopenharmony_ci				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
7218c2ecf20Sopenharmony_ci				ret = -EIO;
7228c2ecf20Sopenharmony_ci				goto exit;
7238c2ecf20Sopenharmony_ci			}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci			for (i = 0; i < left_over_len; i++) {
7268c2ecf20Sopenharmony_ci				msg->buf[(block_len*8)+i] =
7278c2ecf20Sopenharmony_ci					i2c_r_data[(i*3)+1];
7288c2ecf20Sopenharmony_ci				mxl_i2c("read data: %02x\t %02x",
7298c2ecf20Sopenharmony_ci					i2c_r_data[(i*3)+1],
7308c2ecf20Sopenharmony_ci					i2c_r_data[(i*3)+2]);
7318c2ecf20Sopenharmony_ci			}
7328c2ecf20Sopenharmony_ci		}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci		/* indicate I2C interface to issue NACK
7358c2ecf20Sopenharmony_ci		   after next I2C read op */
7368c2ecf20Sopenharmony_ci		buf[0] = USB_WRITE_I2C_CMD;
7378c2ecf20Sopenharmony_ci		buf[1] = 0x00;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		/* control register */
7408c2ecf20Sopenharmony_ci		buf[2] = I2C_CONTROL_REG;
7418c2ecf20Sopenharmony_ci		buf[3] = 0x17;
7428c2ecf20Sopenharmony_ci		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci		buf[5] = USB_END_I2C_CMD;
7458c2ecf20Sopenharmony_ci		ret = mxl111sf_i2c_send_data(state, 0, buf);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci		/* control register */
7488c2ecf20Sopenharmony_ci		buf[2] = I2C_CONTROL_REG;
7498c2ecf20Sopenharmony_ci		buf[3] = 0xC7;
7508c2ecf20Sopenharmony_ci		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	}
7538c2ecf20Sopenharmony_ciexit:
7548c2ecf20Sopenharmony_ci	/* STOP and disable I2C MUX */
7558c2ecf20Sopenharmony_ci	buf[0] = USB_WRITE_I2C_CMD;
7568c2ecf20Sopenharmony_ci	buf[1] = 0x00;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	/* de-initilize I2C BUS */
7598c2ecf20Sopenharmony_ci	buf[5] = USB_END_I2C_CMD;
7608c2ecf20Sopenharmony_ci	mxl111sf_i2c_send_data(state, 0, buf);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/* Control Register */
7638c2ecf20Sopenharmony_ci	buf[2] = I2C_CONTROL_REG;
7648c2ecf20Sopenharmony_ci	buf[3] = 0xDF;
7658c2ecf20Sopenharmony_ci	buf[4] = 0x03;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	/* disable I2C interface */
7688c2ecf20Sopenharmony_ci	buf[5] = I2C_MUX_REG;
7698c2ecf20Sopenharmony_ci	buf[6] = 0x00;
7708c2ecf20Sopenharmony_ci	buf[7] = 0x00;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	/* de-initilize I2C BUS */
7738c2ecf20Sopenharmony_ci	buf[8] = USB_END_I2C_CMD;
7748c2ecf20Sopenharmony_ci	mxl111sf_i2c_send_data(state, 0, buf);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	/* disable I2C interface */
7778c2ecf20Sopenharmony_ci	buf[2] = I2C_MUX_REG;
7788c2ecf20Sopenharmony_ci	buf[3] = 0x81;
7798c2ecf20Sopenharmony_ci	buf[4] = 0x00;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	/* disable I2C interface */
7828c2ecf20Sopenharmony_ci	buf[5] = I2C_MUX_REG;
7838c2ecf20Sopenharmony_ci	buf[6] = 0x00;
7848c2ecf20Sopenharmony_ci	buf[7] = 0x00;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	/* disable I2C interface */
7878c2ecf20Sopenharmony_ci	buf[8] = I2C_MUX_REG;
7888c2ecf20Sopenharmony_ci	buf[9] = 0x00;
7898c2ecf20Sopenharmony_ci	buf[10] = 0x00;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	buf[11] = USB_END_I2C_CMD;
7928c2ecf20Sopenharmony_ci	mxl111sf_i2c_send_data(state, 0, buf);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	return ret;
7958c2ecf20Sopenharmony_ci}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------ */
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ciint mxl111sf_i2c_xfer(struct i2c_adapter *adap,
8008c2ecf20Sopenharmony_ci		      struct i2c_msg msg[], int num)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
8038c2ecf20Sopenharmony_ci	struct mxl111sf_state *state = d->priv;
8048c2ecf20Sopenharmony_ci	int hwi2c = (state->chip_rev > MXL111SF_V6);
8058c2ecf20Sopenharmony_ci	int i, ret;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
8088c2ecf20Sopenharmony_ci		return -EAGAIN;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
8118c2ecf20Sopenharmony_ci		ret = (hwi2c) ?
8128c2ecf20Sopenharmony_ci			mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) :
8138c2ecf20Sopenharmony_ci			mxl111sf_i2c_sw_xfer_msg(state, &msg[i]);
8148c2ecf20Sopenharmony_ci		if (mxl_fail(ret)) {
8158c2ecf20Sopenharmony_ci			mxl_debug_adv("failed with error %d on i2c transaction %d of %d, %sing %d bytes to/from 0x%02x",
8168c2ecf20Sopenharmony_ci				      ret, i+1, num,
8178c2ecf20Sopenharmony_ci				      (msg[i].flags & I2C_M_RD) ?
8188c2ecf20Sopenharmony_ci				      "read" : "writ",
8198c2ecf20Sopenharmony_ci				      msg[i].len, msg[i].addr);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci			break;
8228c2ecf20Sopenharmony_ci		}
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	return i == num ? num : -EREMOTEIO;
8288c2ecf20Sopenharmony_ci}
829