19701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab/*
2d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices
3d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *
4d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
5d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *
6d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
7d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *	- Fix SMBus Read Byte command
8d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *
9d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  This program is free software; you can redistribute it and/or modify
10d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  it under the terms of the GNU General Public License as published by
11d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  the Free Software Foundation version 2
12d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *
13d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  This program is distributed in the hope that it will be useful,
14d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  GNU General Public License for more details.
17d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *
18d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  You should have received a copy of the GNU General Public License
19d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  along with this program; if not, write to the Free Software
20d0058645c682a04c261516e917414ed8e39b2296Ruslan Pisarev *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
219701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab */
229701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
239701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab#include <linux/module.h>
249701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab#include <linux/kernel.h>
259701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab#include <linux/usb.h>
269701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab#include <linux/i2c.h>
279701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
289701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab#include "tm6000.h"
299701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab#include "tm6000-regs.h"
309701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab#include <media/v4l2-common.h>
319701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab#include <media/tuner.h>
329701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab#include "tuner-xc2028.h"
339701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
349701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
359701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab/* ----------------------------------------------------------- */
369701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
37d7fe4a602df6b31475303a9f9d4d4c9fc6ae34f5Ruslan Pisarevstatic unsigned int i2c_debug;
389701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehabmodule_param(i2c_debug, int, 0644);
399701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho ChehabMODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
409701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
4152e0a72a0c6f61c26a16b5684f4eb30a6fbf8b83Timofey Trofimov#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \
429701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab			printk(KERN_DEBUG "%s at %s: " fmt, \
430f063c68cc871829f75cf2d7d4723a356af58783Curtis McEnroe			dev->name, __func__, ##args); } while (0)
449701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
454e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringelstatic int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
464e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel				__u8 reg, char *buf, int len)
474e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel{
4820dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	int rc;
4920dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	unsigned int i2c_packet_limit = 16;
5020dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
5120dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	if (dev->dev_type == TM6010)
523874cd7796ef1a03cd6d2a2d886e3ac4c35af09cMatthieu CASTET		i2c_packet_limit = 80;
5320dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
5420dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	if (!buf)
5520dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		return -1;
5620dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
5720dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	if (len < 1 || len > i2c_packet_limit) {
5820dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
5920dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov			len, i2c_packet_limit);
6020dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		return -1;
6120dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	}
6220dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
6320dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	/* capture mutex */
6420dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
6520dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
6620dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		addr | reg << 8, 0, buf, len);
6720dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
6820dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	if (rc < 0) {
6920dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		/* release mutex */
7020dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		return rc;
7120dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	}
7220dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
7320dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	/* release mutex */
7420dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	return rc;
754e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel}
764e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel
774e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel/* Generic read - doesn't work fine with 16bit registers */
784e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringelstatic int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr,
794e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel				__u8 reg, char *buf, int len)
804e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel{
814e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel	int rc;
8202512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel	u8 b[2];
8320dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	unsigned int i2c_packet_limit = 16;
8420dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
8520dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	if (dev->dev_type == TM6010)
8620dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		i2c_packet_limit = 64;
8720dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
8820dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	if (!buf)
8920dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		return -1;
9020dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
9120dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	if (len < 1 || len > i2c_packet_limit) {
9220dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
9320dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov			len, i2c_packet_limit);
9420dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		return -1;
9520dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	}
964e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel
9720dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	/* capture mutex */
9802512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel	if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) {
9902512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel		/*
10002512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel		 * Workaround an I2C bug when reading from zl10353
10102512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel		 */
10202512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel		reg -= 1;
10302512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel		len += 1;
10402512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel
10502512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel		rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
10602512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel			REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len);
10702512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel
10802512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel		*buf = b[1];
10902512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel	} else {
11002512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel		rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1114e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel			REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len);
11202512fe33e9162713cd522937aabc81fcd97ad74Stefan Ringel	}
1134e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel
11420dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	/* release mutex */
1154e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel	return rc;
1164e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel}
1174e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel
1184e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel/*
1194e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel * read from a 16bit register
1204e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel * for example xc2028, xc3028 or xc3028L
1214e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel */
1224e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringelstatic int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr,
1234e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel				  __u16 reg, char *buf, int len)
1244e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel{
12520dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	int rc;
12620dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	unsigned char ureg;
12720dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
12820dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	if (!buf || len != 2)
12920dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		return -1;
13020dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
13120dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	/* capture mutex */
13220dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	if (dev->dev_type == TM6010) {
13320dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		ureg = reg & 0xFF;
13420dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
13520dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov			USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
13620dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov			addr | (reg & 0xFF00), 0, &ureg, 1);
13720dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
13820dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		if (rc < 0) {
13920dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov			/* release mutex */
14020dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov			return rc;
14120dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		}
14220dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
14320dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
14420dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov			USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ,
14520dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov			reg, 0, buf, len);
14620dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	} else {
14720dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov		rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
14820dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov			USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN,
14920dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov			addr, reg, buf, len);
15020dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	}
15120dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov
15220dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	/* release mutex */
15320dead8da8b383004e66eaf884cd9e07ceadbd68Dmitri Belimov	return rc;
1544e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel}
1554e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel
1569701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehabstatic int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
1579701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab			   struct i2c_msg msgs[], int num)
1589701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab{
1599701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	struct tm6000_core *dev = i2c_adap->algo_data;
1609701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	int addr, rc, i, byte;
1619701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
1629701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	if (num <= 0)
1639701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab		return 0;
1649701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	for (i = 0; i < num; i++) {
165e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe		addr = (msgs[i].addr << 1) & 0xff;
16652e0a72a0c6f61c26a16b5684f4eb30a6fbf8b83Timofey Trofimov		i2c_dprintk(2, "%s %s addr=0x%x len=%d:",
1679701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab			 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
1689701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab			 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
169427f7facb374b8651ff01b7700e690ef8ccae159Mauro Carvalho Chehab		if (msgs[i].flags & I2C_M_RD) {
170e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			/* read request without preceding register selection */
171e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			/*
172e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			 * The TM6000 only supports a read transaction
173e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			 * immediately after a 1 or 2 byte write to select
174e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			 * a register.  We cannot fulfil this request.
175e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			 */
176e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			i2c_dprintk(2, " read without preceding write not"
177e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe				       " supported");
178e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			rc = -EOPNOTSUPP;
179e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			goto err;
180e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe		} else if (i + 1 < num && msgs[i].len <= 2 &&
181e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			   (msgs[i + 1].flags & I2C_M_RD) &&
182e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			   msgs[i].addr == msgs[i + 1].addr) {
183e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			/* 1 or 2 byte write followed by a read */
184e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			if (i2c_debug >= 2)
185e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe				for (byte = 0; byte < msgs[i].len; byte++)
18645dbf0db5ac974fb699fec39330d01642dff98dcMauro Carvalho Chehab					printk(KERN_CONT " %02x", msgs[i].buf[byte]);
187e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			i2c_dprintk(2, "; joined to read %s len=%d:",
188e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe				    i == num - 2 ? "stop" : "nonstop",
189e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe				    msgs[i + 1].len);
1904e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel
1914e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel			if (msgs[i].len == 2) {
1924e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel				rc = tm6000_i2c_recv_regs16(dev, addr,
1934e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel					msgs[i].buf[0] << 8 | msgs[i].buf[1],
1944e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel					msgs[i + 1].buf, msgs[i + 1].len);
1954e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel			} else {
1964e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel				rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0],
1974e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel					msgs[i + 1].buf, msgs[i + 1].len);
1984e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel			}
1994e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel
200cf9e1509c278c3d5005f222539813933e4dc345cChristopher Pascoe			i++;
20120cabed421399a5f0f1b33742d765cbdfad4ac79Stefan Ringel
202685b122906069f9e7b9995bf2b128137c86b558cStefan Ringel			if (addr == dev->tuner_addr << 1) {
203f1434f4e90cec0bc57616c2f5f7de6985d7920d9Stefan Ringel				tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
204f1434f4e90cec0bc57616c2f5f7de6985d7920d9Stefan Ringel				tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
20520cabed421399a5f0f1b33742d765cbdfad4ac79Stefan Ringel			}
206e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			if (i2c_debug >= 2)
207e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe				for (byte = 0; byte < msgs[i].len; byte++)
20845dbf0db5ac974fb699fec39330d01642dff98dcMauro Carvalho Chehab					printk(KERN_CONT " %02x", msgs[i].buf[byte]);
2099701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab		} else {
2109701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab			/* write bytes */
211e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe			if (i2c_debug >= 2)
2129701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab				for (byte = 0; byte < msgs[i].len; byte++)
21345dbf0db5ac974fb699fec39330d01642dff98dcMauro Carvalho Chehab					printk(KERN_CONT " %02x", msgs[i].buf[byte]);
2144e11502d4597c6252411dc1b5c16b47d08b5f246Stefan Ringel			rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0],
215e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe				msgs[i].buf + 1, msgs[i].len - 1);
2169701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab		}
217e30b9d6c641dbd9687a5605b2151a2a83d2e8770Chris Pascoe		if (i2c_debug >= 2)
21845dbf0db5ac974fb699fec39330d01642dff98dcMauro Carvalho Chehab			printk(KERN_CONT "\n");
2199701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab		if (rc < 0)
2209701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab			goto err;
2219701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	}
2229701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
2239701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	return num;
2249701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehaberr:
22552e0a72a0c6f61c26a16b5684f4eb30a6fbf8b83Timofey Trofimov	i2c_dprintk(2, " ERROR: %i\n", rc);
2269701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	return rc;
2279701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab}
2289701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
229792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehabstatic int tm6000_i2c_eeprom(struct tm6000_core *dev)
2309701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab{
2319701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	int i, rc;
232792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab	unsigned char *p = dev->eedata;
2339701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	unsigned char bytes[17];
2349701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
2359701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	dev->i2c_client.addr = 0xa0 >> 1;
236792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab	dev->eedata_size = 0;
2379701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
238d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab	bytes[16] = '\0';
239792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab	for (i = 0; i < sizeof(dev->eedata); ) {
240792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab		*p = i;
241792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab		rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
242d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab		if (rc < 1) {
243792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab			if (p == dev->eedata)
244d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab				goto noeeprom;
245d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab			else {
2469701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab				printk(KERN_WARNING
2479701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab				"%s: i2c eeprom read error (err=%d)\n",
2489701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab				dev->name, rc);
2499701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab			}
250792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab			return -EINVAL;
2519701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab		}
252792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab		dev->eedata_size++;
2539701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab		p++;
2549701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab		if (0 == (i % 16))
2559701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab			printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
25645dbf0db5ac974fb699fec39330d01642dff98dcMauro Carvalho Chehab		printk(KERN_CONT " %02x", dev->eedata[i]);
257792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab		if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z'))
258792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab			bytes[i%16] = dev->eedata[i];
25952e0a72a0c6f61c26a16b5684f4eb30a6fbf8b83Timofey Trofimov		else
26052e0a72a0c6f61c26a16b5684f4eb30a6fbf8b83Timofey Trofimov			bytes[i%16] = '.';
261d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab
262d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab		i++;
263d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab
264d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab		if (0 == (i % 16)) {
265d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab			bytes[16] = '\0';
26645dbf0db5ac974fb699fec39330d01642dff98dcMauro Carvalho Chehab			printk(KERN_CONT "  %s\n", bytes);
2679701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab		}
2689701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	}
269d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab	if (0 != (i%16)) {
270d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab		bytes[i%16] = '\0';
271d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab		for (i %= 16; i < 16; i++)
27245dbf0db5ac974fb699fec39330d01642dff98dcMauro Carvalho Chehab			printk(KERN_CONT "   ");
27345dbf0db5ac974fb699fec39330d01642dff98dcMauro Carvalho Chehab		printk(KERN_CONT "  %s\n", bytes);
2749701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	}
275d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab
2769701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	return 0;
277d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab
278d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehabnoeeprom:
279d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab	printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
280792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab	       dev->name, rc);
281792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab	return -EINVAL;
2829701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab}
2839701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
2849701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab/* ----------------------------------------------------------- */
2859701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
2869701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab/*
2879701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab * functionality()
2889701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab */
2899701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehabstatic u32 functionality(struct i2c_adapter *adap)
2909701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab{
2919701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	return I2C_FUNC_SMBUS_EMUL;
2929701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab}
2939701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
2947bd444ede7285cad4ed5047ff954432325fe7f95Jean Delvarestatic const struct i2c_algorithm tm6000_algo = {
2959701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	.master_xfer   = tm6000_i2c_xfer,
2969701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	.functionality = functionality,
2979701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab};
2989701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
2999701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab/* ----------------------------------------------------------- */
3009701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
3019701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab/*
3029701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab * tm6000_i2c_register()
3039701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab * register i2c bus
3049701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab */
3059701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehabint tm6000_i2c_register(struct tm6000_core *dev)
3069701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab{
3077bd444ede7285cad4ed5047ff954432325fe7f95Jean Delvare	int rc;
308d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab
3097bd444ede7285cad4ed5047ff954432325fe7f95Jean Delvare	dev->i2c_adap.owner = THIS_MODULE;
3107bd444ede7285cad4ed5047ff954432325fe7f95Jean Delvare	dev->i2c_adap.algo = &tm6000_algo;
3119701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	dev->i2c_adap.dev.parent = &dev->udev->dev;
3127bd444ede7285cad4ed5047ff954432325fe7f95Jean Delvare	strlcpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name));
3139701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	dev->i2c_adap.algo_data = dev;
3147bd444ede7285cad4ed5047ff954432325fe7f95Jean Delvare	i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
3157bd444ede7285cad4ed5047ff954432325fe7f95Jean Delvare	rc = i2c_add_adapter(&dev->i2c_adap);
3167bd444ede7285cad4ed5047ff954432325fe7f95Jean Delvare	if (rc)
3177bd444ede7285cad4ed5047ff954432325fe7f95Jean Delvare		return rc;
3189701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
3199701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	dev->i2c_client.adapter = &dev->i2c_adap;
3207bd444ede7285cad4ed5047ff954432325fe7f95Jean Delvare	strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE);
321792bc09a9896dfbdac575ab4cdcd0f4db96d8ca1Mauro Carvalho Chehab	tm6000_i2c_eeprom(dev);
322d4e15bcd3de4bb5fccf5b1c0f512d57983c09623Mauro Carvalho Chehab
3239701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	return 0;
3249701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab}
3259701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab
3269701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab/*
3279701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab * tm6000_i2c_unregister()
3289701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab * unregister i2c_bus
3299701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab */
3309701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehabint tm6000_i2c_unregister(struct tm6000_core *dev)
3319701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab{
3329701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	i2c_del_adapter(&dev->i2c_adap);
3339701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab	return 0;
3349701dc94a14e54a33c3c99744ec3a761f6385fc6Mauro Carvalho Chehab}
335