14c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky/*
24c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  mxl111sf-i2c.c - driver for the MaxLinear MXL111SF
34c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *
44c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
54c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *
64c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  This program is free software; you can redistribute it and/or modify
74c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  it under the terms of the GNU General Public License as published by
84c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  the Free Software Foundation; either version 2 of the License, or
94c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  (at your option) any later version.
104c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *
114c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  This program is distributed in the hope that it will be useful,
124c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  but WITHOUT ANY WARRANTY; without even the implied warranty of
134c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
144c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  GNU General Public License for more details.
154c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *
164c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  You should have received a copy of the GNU General Public License
174c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  along with this program; if not, write to the Free Software
184c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
194c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky */
204c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
214c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#include "mxl111sf-i2c.h"
224c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#include "mxl111sf.h"
234c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
244c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky/* SW-I2C ----------------------------------------------------------------- */
254c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
264c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define SW_I2C_ADDR		0x1a
274c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define SW_I2C_EN		0x02
284c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define SW_SCL_OUT		0x04
294c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define SW_SDA_OUT		0x08
304c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define SW_SDA_IN		0x04
314c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
324c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define SW_I2C_BUSY_ADDR	0x2f
334c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define SW_I2C_BUSY		0x02
344c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
354c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state,
364c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					 u8 byte)
374c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
384c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int i, ret;
394c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 data = 0;
404c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
414c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c("(0x%02x)", byte);
424c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
434c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
444c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
454c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
464c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
474c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	for (i = 0; i < 8; i++) {
484c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
494c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0;
504c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
514c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
524c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					 0x10 | SW_I2C_EN | data);
534c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret))
544c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
554c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
564c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
574c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					 0x10 | SW_I2C_EN | data | SW_SCL_OUT);
584c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret))
594c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
604c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
614c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
624c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					 0x10 | SW_I2C_EN | data);
634c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret))
644c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
654c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	}
664c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
674c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* last bit was 0 so we need to release SDA */
684c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (!(byte & 1)) {
694c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
704c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					 0x10 | SW_I2C_EN | SW_SDA_OUT);
714c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret))
724c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
734c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	}
744c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
754c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* CLK high for ACK readback */
764c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
774c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
784c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
794c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
804c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
814c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
824c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
834c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
844c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
854c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* drop the CLK after getting ACK, SDA will go high right away */
864c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
874c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SDA_OUT);
884c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
894c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
904c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
914c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (data & SW_SDA_IN)
924c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = -EIO;
934c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkyfail:
944c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return ret;
954c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
964c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
974c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state,
984c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					 u8 *pbyte)
994c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
1004c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int i, ret;
1014c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 byte = 0;
1024c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 data = 0;
1034c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1044c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c("()");
1054c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1064c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	*pbyte = 0;
1074c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1084c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1094c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SDA_OUT);
1104c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
1114c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
1124c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1134c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	for (i = 0; i < 8; i++) {
1144c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1154c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					 0x10 | SW_I2C_EN |
1164c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					 SW_SCL_OUT | SW_SDA_OUT);
1174c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret))
1184c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
1194c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1204c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
1214c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret))
1224c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
1234c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1244c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (data & SW_SDA_IN)
1254c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			byte |= (0x80 >> i);
1264c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1274c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1284c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					 0x10 | SW_I2C_EN | SW_SDA_OUT);
1294c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret))
1304c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
1314c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	}
1324c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	*pbyte = byte;
1334c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkyfail:
1344c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return ret;
1354c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
1364c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1374c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_start(struct mxl111sf_state *state)
1384c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
1394c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int ret;
1404c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1414c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c("()");
1424c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1434c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1444c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
1454c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
1464c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
1474c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1484c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1494c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SCL_OUT);
1504c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
1514c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
1524c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1534c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1544c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN); /* start */
1554c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_fail(ret);
1564c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkyfail:
1574c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return ret;
1584c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
1594c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1604c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_stop(struct mxl111sf_state *state)
1614c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
1624c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int ret;
1634c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1644c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c("()");
1654c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1664c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1674c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN); /* stop */
1684c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
1694c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
1704c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1714c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1724c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SCL_OUT);
1734c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
1744c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
1754c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1764c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1774c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
1784c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
1794c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
1804c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1814c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
1824c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_SCL_OUT | SW_SDA_OUT);
1834c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_fail(ret);
1844c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkyfail:
1854c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return ret;
1864c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
1874c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1884c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_ack(struct mxl111sf_state *state)
1894c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
1904c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int ret;
1914c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 b = 0;
1924c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1934c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c("()");
1944c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1954c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b);
1964c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
1974c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
1984c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
1994c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
2004c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN);
2014c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
2024c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
2034c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2044c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* pull SDA low */
2054c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
2064c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SCL_OUT);
2074c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
2084c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
2094c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2104c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
2114c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SDA_OUT);
2124c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_fail(ret);
2134c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkyfail:
2144c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return ret;
2154c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
2164c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2174c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_nack(struct mxl111sf_state *state)
2184c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
2194c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int ret;
2204c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2214c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c("()");
2224c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2234c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* SDA high to signal last byte read from slave */
2244c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
2254c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
2264c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl_fail(ret))
2274c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		goto fail;
2284c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2294c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
2304c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 0x10 | SW_I2C_EN | SW_SDA_OUT);
2314c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_fail(ret);
2324c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkyfail:
2334c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return ret;
2344c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
2354c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2364c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky/* ------------------------------------------------------------------------ */
2374c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2384c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state,
2394c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				    struct i2c_msg *msg)
2404c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
2414c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int i, ret;
2424c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2434c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c("()");
2444c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2454c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (msg->flags & I2C_M_RD) {
2464c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2474c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_i2c_start(state);
2484c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret))
2494c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
2504c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2514c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_i2c_bitbang_sendbyte(state,
2524c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						    (msg->addr << 1) | 0x01);
2534c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret)) {
2544c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			mxl111sf_i2c_stop(state);
2554c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
2564c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
2574c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2584c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		for (i = 0; i < msg->len; i++) {
2594c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			ret = mxl111sf_i2c_bitbang_recvbyte(state,
2604c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							    &msg->buf[i]);
2614c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			if (mxl_fail(ret)) {
2624c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				mxl111sf_i2c_stop(state);
2634c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				goto fail;
2644c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
2654c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2664c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			if (i < msg->len - 1)
2674c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				mxl111sf_i2c_ack(state);
2684c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
2694c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2704c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		mxl111sf_i2c_nack(state);
2714c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2724c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_i2c_stop(state);
2734c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret))
2744c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
2754c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2764c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	} else {
2774c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2784c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_i2c_start(state);
2794c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret))
2804c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
2814c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2824c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_i2c_bitbang_sendbyte(state,
2834c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						    (msg->addr << 1) & 0xfe);
2844c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret)) {
2854c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			mxl111sf_i2c_stop(state);
2864c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto fail;
2874c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
2884c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2894c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		for (i = 0; i < msg->len; i++) {
2904c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			ret = mxl111sf_i2c_bitbang_sendbyte(state,
2914c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							    msg->buf[i]);
2924c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			if (mxl_fail(ret)) {
2934c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				mxl111sf_i2c_stop(state);
2944c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				goto fail;
2954c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
2964c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
2974c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
2984c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* FIXME: we only want to do this on the last transaction */
2994c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		mxl111sf_i2c_stop(state);
3004c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	}
3014c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkyfail:
3024c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return ret;
3034c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
3044c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3054c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky/* HW-I2C ----------------------------------------------------------------- */
3064c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3074c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define USB_WRITE_I2C_CMD     0x99
3084c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define USB_READ_I2C_CMD      0xdd
3094c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define USB_END_I2C_CMD       0xfe
3104c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3114c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define USB_WRITE_I2C_CMD_LEN   26
3124c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define USB_READ_I2C_CMD_LEN    24
3134c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3144c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define I2C_MUX_REG           0x30
3154c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define I2C_CONTROL_REG       0x00
3164c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define I2C_SLAVE_ADDR_REG    0x08
3174c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define I2C_DATA_REG          0x0c
3184c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define I2C_INT_STATUS_REG    0x10
3194c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3204c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_send_data(struct mxl111sf_state *state,
3214c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				  u8 index, u8 *wdata)
3224c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
3234c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
3244c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				    &wdata[1], 25, NULL, 0);
3254c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_fail(ret);
3264c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3274c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return ret;
3284c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
3294c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3304c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_get_data(struct mxl111sf_state *state,
3314c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				 u8 index, u8 *wdata, u8 *rdata)
3324c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
3334c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
3344c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				    &wdata[1], 25, rdata, 24);
3354c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_fail(ret);
3364c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3374c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return ret;
3384c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
3394c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3404c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state)
3414c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
3424c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 status = 0;
3434c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 buf[26];
3444c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3454c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c_adv("()");
3464c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3474c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[0] = USB_READ_I2C_CMD;
3484c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[1] = 0x00;
3494c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3504c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[2] = I2C_INT_STATUS_REG;
3514c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[3] = 0x00;
3524c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[4] = 0x00;
3534c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3544c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[5] = USB_END_I2C_CMD;
3554c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3564c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl111sf_i2c_get_data(state, 0, buf, buf);
3574c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3584c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (buf[1] & 0x04)
3594c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		status = 1;
3604c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3614c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return status;
3624c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
3634c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3644c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state)
3654c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
3664c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 status = 0;
3674c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 buf[26];
3684c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3694c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c("()");
3704c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3714c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[0] = USB_READ_I2C_CMD;
3724c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[1] = 0x00;
3734c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3744c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[2] = I2C_MUX_REG;
3754c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[3] = 0x00;
3764c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[4] = 0x00;
3774c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3784c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[5] = I2C_INT_STATUS_REG;
3794c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[6] = 0x00;
3804c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[7] = 0x00;
3814c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[8] = USB_END_I2C_CMD;
3824c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3834c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl111sf_i2c_get_data(state, 0, buf, buf);
3844c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3854c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (0x08 == (buf[1] & 0x08))
3864c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		status = 1;
3874c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3884c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if ((buf[5] & 0x02) == 0x02)
3894c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */
3904c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3914c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return status;
3924c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
3934c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
3944c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_readagain(struct mxl111sf_state *state,
3954c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				  u8 count, u8 *rbuf)
3964c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
3974c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 i2c_w_data[26];
3984c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 i2c_r_data[24];
3994c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 i = 0;
4004c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 fifo_status = 0;
4014c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int status = 0;
4024c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4034c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c("read %d bytes", count);
4044c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4054c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	while ((fifo_status == 0) && (i++ < 5))
4064c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		fifo_status = mxl111sf_i2c_check_fifo(state);
4074c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4084c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	i2c_w_data[0] = 0xDD;
4094c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	i2c_w_data[1] = 0x00;
4104c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4114c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	for (i = 2; i < 26; i++)
4124c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		i2c_w_data[i] = 0xFE;
4134c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4144c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	for (i = 0; i < count; i++) {
4154c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		i2c_w_data[2+(i*3)] = 0x0C;
4164c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		i2c_w_data[3+(i*3)] = 0x00;
4174c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		i2c_w_data[4+(i*3)] = 0x00;
4184c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	}
4194c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
420e836a1c078e230dd5a94bb086b186c2be3ec6a84Michael Krufky	mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data);
4214c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4224c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* Check for I2C NACK status */
4234c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mxl111sf_i2c_check_status(state) == 1) {
4244c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		mxl_i2c("error!");
4254c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	} else {
4264c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		for (i = 0; i < count; i++) {
4274c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			rbuf[i] = i2c_r_data[(i*3)+1];
4284c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			mxl_i2c("%02x\t %02x",
4294c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				i2c_r_data[(i*3)+1],
4304c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				i2c_r_data[(i*3)+2]);
4314c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
4324c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4334c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		status = 1;
4344c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	}
4354c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4364c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return status;
4374c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
4384c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4394c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#define HWI2C400 1
4404c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystatic int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state,
4414c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				    struct i2c_msg *msg)
4424c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
4434c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int i, k, ret = 0;
4444c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u16 index = 0;
4454c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 buf[26];
4464c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 i2c_r_data[24];
4474c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u16 block_len;
4484c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u16 left_over_len;
4494c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 rd_status[8];
4504c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 ret_status;
4514c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	u8 readbuff[26];
4524c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4534c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d",
4544c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0,
4554c4364e022f8422e602edbb97a2d873dc0b6c769Dan Carpenter		(!(msg->flags & I2C_M_RD)) ? msg->len : 0);
4564c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4574c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	for (index = 0; index < 26; index++)
4584c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[index] = USB_END_I2C_CMD;
4594c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4604c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* command to indicate data payload is destined for I2C interface */
4614c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[0] = USB_WRITE_I2C_CMD;
4624c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[1] = 0x00;
4634c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4644c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* enable I2C interface */
4654c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[2] = I2C_MUX_REG;
4664c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[3] = 0x80;
4674c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[4] = 0x00;
4684c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4694c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* enable I2C interface */
4704c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[5] = I2C_MUX_REG;
4714c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[6] = 0x81;
4724c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[7] = 0x00;
4734c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4744c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* set Timeout register on I2C interface */
4754c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[8] = 0x14;
4764c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[9] = 0xff;
4774c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[10] = 0x00;
4784c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#if 0
4794c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* enable Interrupts on I2C interface */
4804c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[8] = 0x24;
4814c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[9] = 0xF7;
4824c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[10] = 0x00;
4834c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky#endif
4844c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[11] = 0x24;
4854c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[12] = 0xF7;
4864c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[13] = 0x00;
4874c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4884c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	ret = mxl111sf_i2c_send_data(state, 0, buf);
4894c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4904c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* write data on I2C bus */
4914c4364e022f8422e602edbb97a2d873dc0b6c769Dan Carpenter	if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) {
4924c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		mxl_i2c("%d\t%02x", msg->len, msg->buf[0]);
4934c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4944c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* control register on I2C interface to initialize I2C bus */
4954c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[2] = I2C_CONTROL_REG;
4964c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[3] = 0x5E;
4974c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
4984c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
4994c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* I2C Slave device Address */
5004c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[5] = I2C_SLAVE_ADDR_REG;
5014c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[6] = (msg->addr);
5024c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[7] = 0x00;
5034c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[8] = USB_END_I2C_CMD;
5044c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_i2c_send_data(state, 0, buf);
5054c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5064c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* check for slave device status */
5074c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl111sf_i2c_check_status(state) == 1) {
5084c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			mxl_i2c("NACK writing slave address %02x",
5094c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				msg->addr);
5104c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			/* if NACK, stop I2C bus and exit */
5114c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			buf[2] = I2C_CONTROL_REG;
5124c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			buf[3] = 0x4E;
5134c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			buf[4] = (HWI2C400) ? 0x03 : 0x0D;
5144c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			ret = -EIO;
5154c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto exit;
5164c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
5174c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5184c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* I2C interface can do I2C operations in block of 8 bytes of
5194c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		   I2C data. calculation to figure out number of blocks of i2c
5204c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		   data required to program */
5214c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		block_len = (msg->len / 8);
5224c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		left_over_len = (msg->len % 8);
5234c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		index = 0;
5244c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5254c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		mxl_i2c("block_len %d, left_over_len %d",
5264c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			block_len, left_over_len);
5274c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5284c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		for (index = 0; index < block_len; index++) {
5294c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			for (i = 0; i < 8; i++) {
5304c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				/* write data on I2C interface */
5314c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[2+(i*3)] = I2C_DATA_REG;
5324c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[3+(i*3)] = msg->buf[(index*8)+i];
5334c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[4+(i*3)] = 0x00;
5344c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
5354c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5364c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			ret = mxl111sf_i2c_send_data(state, 0, buf);
5374c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5384c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			/* check for I2C NACK status */
5394c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			if (mxl111sf_i2c_check_status(state) == 1) {
5404c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				mxl_i2c("NACK writing slave address %02x",
5414c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					msg->addr);
5424c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5434c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				/* if NACK, stop I2C bus and exit */
5444c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[2] = I2C_CONTROL_REG;
5454c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[3] = 0x4E;
5464c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
5474c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				ret = -EIO;
5484c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				goto exit;
5494c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
5504c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5514c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
5524c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5534c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (left_over_len) {
5544c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			for (k = 0; k < 26; k++)
5554c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[k] = USB_END_I2C_CMD;
5564c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5574c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			buf[0] = 0x99;
5584c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			buf[1] = 0x00;
5594c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5604c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			for (i = 0; i < left_over_len; i++) {
5614c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[2+(i*3)] = I2C_DATA_REG;
5624c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[3+(i*3)] = msg->buf[(index*8)+i];
5634c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				mxl_i2c("index = %d %d data %d",
5644c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					index, i, msg->buf[(index*8)+i]);
5654c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[4+(i*3)] = 0x00;
5664c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
5674c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			ret = mxl111sf_i2c_send_data(state, 0, buf);
5684c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5694c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			/* check for I2C NACK status */
5704c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			if (mxl111sf_i2c_check_status(state) == 1) {
5714c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				mxl_i2c("NACK writing slave address %02x",
5724c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					msg->addr);
5734c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5744c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				/* if NACK, stop I2C bus and exit */
5754c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[2] = I2C_CONTROL_REG;
5764c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[3] = 0x4E;
5774c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
5784c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				ret = -EIO;
5794c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				goto exit;
5804c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
5814c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5824c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
5834c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5844c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* issue I2C STOP after write */
5854c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[2] = I2C_CONTROL_REG;
5864c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[3] = 0x4E;
5874c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
5884c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5894c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	}
5904c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5914c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* read data from I2C bus */
5924c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if ((msg->flags & I2C_M_RD) && (msg->len > 0)) {
5934c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		mxl_i2c("read buf len %d", msg->len);
5944c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
5954c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* command to indicate data payload is
5964c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		   destined for I2C interface */
5974c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[2] = I2C_CONTROL_REG;
5984c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[3] = 0xDF;
5994c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
6004c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6014c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* I2C xfer length */
6024c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[5] = 0x14;
6034c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[6] = (msg->len & 0xFF);
6044c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[7] = 0;
6054c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6064c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* I2C slave device Address */
6074c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[8] = I2C_SLAVE_ADDR_REG;
6084c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[9] = msg->addr;
6094c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[10] = 0x00;
6104c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[11] = USB_END_I2C_CMD;
6114c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_i2c_send_data(state, 0, buf);
6124c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6134c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* check for I2C NACK status */
6144c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl111sf_i2c_check_status(state) == 1) {
6154c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			mxl_i2c("NACK reading slave address %02x",
6164c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				msg->addr);
6174c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6184c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			/* if NACK, stop I2C bus and exit */
6194c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			buf[2] = I2C_CONTROL_REG;
6204c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			buf[3] = 0xC7;
6214c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			buf[4] = (HWI2C400) ? 0x03 : 0x0D;
6224c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			ret = -EIO;
6234c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			goto exit;
6244c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
6254c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6264c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* I2C interface can do I2C operations in block of 8 bytes of
6274c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		   I2C data. calculation to figure out number of blocks of
6284c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		   i2c data required to program */
6294c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		block_len = ((msg->len) / 8);
6304c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		left_over_len = ((msg->len) % 8);
6314c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		index = 0;
6324c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6334c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		mxl_i2c("block_len %d, left_over_len %d",
6344c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			block_len, left_over_len);
6354c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6364c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* command to read data from I2C interface */
6374c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[0] = USB_READ_I2C_CMD;
6384c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[1] = 0x00;
6394c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6404c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		for (index = 0; index < block_len; index++) {
6414c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			/* setup I2C read request packet on I2C interface */
6424c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			for (i = 0; i < 8; i++) {
6434c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[2+(i*3)] = I2C_DATA_REG;
6444c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[3+(i*3)] = 0x00;
6454c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[4+(i*3)] = 0x00;
6464c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
6474c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6484c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data);
6494c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6504c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			/* check for I2C NACK status */
6514c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			if (mxl111sf_i2c_check_status(state) == 1) {
6524c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				mxl_i2c("NACK reading slave address %02x",
6534c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					msg->addr);
6544c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6554c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				/* if NACK, stop I2C bus and exit */
6564c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[2] = I2C_CONTROL_REG;
6574c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[3] = 0xC7;
6584c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
6594c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				ret = -EIO;
6604c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				goto exit;
6614c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
6624c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6634c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			/* copy data from i2c data payload to read buffer */
6644c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			for (i = 0; i < 8; i++) {
6654c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				rd_status[i] = i2c_r_data[(i*3)+2];
6664c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6674c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				if (rd_status[i] == 0x04) {
6684c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					if (i < 7) {
6694c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						mxl_i2c("i2c fifo empty!"
6704c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							" @ %d", i);
6714c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						msg->buf[(index*8)+i] =
6724c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							i2c_r_data[(i*3)+1];
6734c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						/* read again */
6744c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						ret_status =
6754c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							mxl111sf_i2c_readagain(
6764c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky								state, 8-(i+1),
6774c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky								readbuff);
6784c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						if (ret_status == 1) {
6794c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							for (k = 0;
6804c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							     k < 8-(i+1);
6814c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							     k++) {
6824c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6834c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					msg->buf[(index*8)+(k+i+1)] =
6844c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						readbuff[k];
6854c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					mxl_i2c("read data: %02x\t %02x",
6864c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						msg->buf[(index*8)+(k+i)],
6874c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						(index*8)+(k+i));
6884c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					mxl_i2c("read data: %02x\t %02x",
6894c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						msg->buf[(index*8)+(k+i+1)],
6904c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						readbuff[k]);
6914c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
6924c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							}
6934c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							goto stop_copy;
6944c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						} else {
6954c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							mxl_i2c("readagain "
6964c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky								"ERROR!");
6974c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						}
6984c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					} else {
6994c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						msg->buf[(index*8)+i] =
7004c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky							i2c_r_data[(i*3)+1];
7014c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					}
7024c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				} else {
7034c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					msg->buf[(index*8)+i] =
7044c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						i2c_r_data[(i*3)+1];
7054c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				}
7064c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
7074c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkystop_copy:
7084c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			;
7094c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7104c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
7114c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7124c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (left_over_len) {
7134c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			for (k = 0; k < 26; k++)
7144c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[k] = USB_END_I2C_CMD;
7154c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7164c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			buf[0] = 0xDD;
7174c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			buf[1] = 0x00;
7184c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7194c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			for (i = 0; i < left_over_len; i++) {
7204c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[2+(i*3)] = I2C_DATA_REG;
7214c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[3+(i*3)] = 0x00;
7224c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[4+(i*3)] = 0x00;
7234c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
7244c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			ret = mxl111sf_i2c_get_data(state, 0, buf,
7254c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky						    i2c_r_data);
7264c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7274c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			/* check for I2C NACK status */
7284c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			if (mxl111sf_i2c_check_status(state) == 1) {
7294c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				mxl_i2c("NACK reading slave address %02x",
7304c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					msg->addr);
7314c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7324c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				/* if NACK, stop I2C bus and exit */
7334c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[2] = I2C_CONTROL_REG;
7344c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[3] = 0xC7;
7354c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
7364c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				ret = -EIO;
7374c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				goto exit;
7384c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
7394c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7404c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			for (i = 0; i < left_over_len; i++) {
7414c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				msg->buf[(block_len*8)+i] =
7424c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					i2c_r_data[(i*3)+1];
7434c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				mxl_i2c("read data: %02x\t %02x",
7444c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					i2c_r_data[(i*3)+1],
7454c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky					i2c_r_data[(i*3)+2]);
7464c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			}
7474c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
7484c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7494c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* indicate I2C interface to issue NACK
7504c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		   after next I2C read op */
7514c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[0] = USB_WRITE_I2C_CMD;
7524c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[1] = 0x00;
7534c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7544c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* control register */
7554c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[2] = I2C_CONTROL_REG;
7564c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[3] = 0x17;
7574c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
7584c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7594c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[5] = USB_END_I2C_CMD;
7604c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = mxl111sf_i2c_send_data(state, 0, buf);
7614c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7624c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		/* control register */
7634c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[2] = I2C_CONTROL_REG;
7644c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[3] = 0xC7;
7654c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
7664c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7674c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	}
7684c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkyexit:
7694c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* STOP and disable I2C MUX */
7704c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[0] = USB_WRITE_I2C_CMD;
7714c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[1] = 0x00;
7724c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7734c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* de-initilize I2C BUS */
7744c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[5] = USB_END_I2C_CMD;
7754c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl111sf_i2c_send_data(state, 0, buf);
7764c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7774c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* Control Register */
7784c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[2] = I2C_CONTROL_REG;
7794c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[3] = 0xDF;
7804c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[4] = 0x03;
7814c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7824c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* disable I2C interface */
7834c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[5] = I2C_MUX_REG;
7844c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[6] = 0x00;
7854c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[7] = 0x00;
7864c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7874c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* de-initilize I2C BUS */
7884c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[8] = USB_END_I2C_CMD;
7894c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl111sf_i2c_send_data(state, 0, buf);
7904c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7914c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* disable I2C interface */
7924c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[2] = I2C_MUX_REG;
7934c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[3] = 0x81;
7944c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[4] = 0x00;
7954c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
7964c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* disable I2C interface */
7974c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[5] = I2C_MUX_REG;
7984c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[6] = 0x00;
7994c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[7] = 0x00;
8004c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8014c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	/* disable I2C interface */
8024c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[8] = I2C_MUX_REG;
8034c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[9] = 0x00;
8044c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[10] = 0x00;
8054c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8064c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	buf[11] = USB_END_I2C_CMD;
8074c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mxl111sf_i2c_send_data(state, 0, buf);
8084c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8094c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return ret;
8104c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
8114c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8124c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky/* ------------------------------------------------------------------------ */
8134c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8144c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufkyint mxl111sf_i2c_xfer(struct i2c_adapter *adap,
8154c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		      struct i2c_msg msg[], int num)
8164c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky{
8174c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	struct dvb_usb_device *d = i2c_get_adapdata(adap);
8184c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	struct mxl111sf_state *state = d->priv;
8194c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int hwi2c = (state->chip_rev > MXL111SF_V6);
8204c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	int i, ret;
8214c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8224c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
8234c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		return -EAGAIN;
8244c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8254c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	for (i = 0; i < num; i++) {
8264c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		ret = (hwi2c) ?
8274c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) :
8284c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			mxl111sf_i2c_sw_xfer_msg(state, &msg[i]);
8294c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		if (mxl_fail(ret)) {
8304c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			mxl_debug_adv("failed with error %d on i2c "
8314c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				      "transaction %d of %d, %sing %d bytes "
8324c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				      "to/from 0x%02x", ret, i+1, num,
8334c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				      (msg[i].flags & I2C_M_RD) ?
8344c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				      "read" : "writ",
8354c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky				      msg[i].len, msg[i].addr);
8364c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8374c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky			break;
8384c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky		}
8394c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	}
8404c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8414c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	mutex_unlock(&d->i2c_mutex);
8424c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8434c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky	return i == num ? num : -EREMOTEIO;
8444c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky}
8454c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky
8464c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky/*
8474c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky * Local variables:
8484c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky * c-basic-offset: 8
8494c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky * End:
8504c66c9205c0788e18eb09d482461aa2f551ee046Michael Krufky */
851