162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci   cx231xx-i2c.c - driver for Conexant Cx23100/101/102 USB video capture devices
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
662306a36Sopenharmony_ci		Based on em28xx driver
762306a36Sopenharmony_ci		Based on Cx23885 driver
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "cx231xx.h"
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/i2c.h>
1562306a36Sopenharmony_ci#include <linux/i2c-mux.h>
1662306a36Sopenharmony_ci#include <media/v4l2-common.h>
1762306a36Sopenharmony_ci#include <media/tuner.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* ----------------------------------------------------------- */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic unsigned int i2c_scan;
2362306a36Sopenharmony_cimodule_param(i2c_scan, int, 0444);
2462306a36Sopenharmony_ciMODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic unsigned int i2c_debug;
2762306a36Sopenharmony_cimodule_param(i2c_debug, int, 0644);
2862306a36Sopenharmony_ciMODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define dprintk1(lvl, fmt, args...)			\
3162306a36Sopenharmony_cido {							\
3262306a36Sopenharmony_ci	if (i2c_debug >= lvl) {				\
3362306a36Sopenharmony_ci		printk(fmt, ##args);			\
3462306a36Sopenharmony_ci		}					\
3562306a36Sopenharmony_ci} while (0)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define dprintk2(lvl, fmt, args...)			\
3862306a36Sopenharmony_cido {							\
3962306a36Sopenharmony_ci	if (i2c_debug >= lvl) {				\
4062306a36Sopenharmony_ci		printk(KERN_DEBUG "%s at %s: " fmt,	\
4162306a36Sopenharmony_ci		       dev->name, __func__ , ##args);	\
4262306a36Sopenharmony_ci      }							\
4362306a36Sopenharmony_ci} while (0)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic inline int get_real_i2c_port(struct cx231xx *dev, int bus_nr)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	if (bus_nr == 1)
4862306a36Sopenharmony_ci		return dev->port_3_switch_enabled ? I2C_1_MUX_3 : I2C_1_MUX_1;
4962306a36Sopenharmony_ci	return bus_nr;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus,
5362306a36Sopenharmony_ci			const struct i2c_msg *msg, int tuner_type)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	int i2c_port = get_real_i2c_port(dev, bus->nr);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (i2c_port != dev->board.tuner_i2c_master)
5862306a36Sopenharmony_ci		return false;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (msg->addr != dev->board.tuner_addr)
6162306a36Sopenharmony_ci		return false;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (dev->tuner_type != tuner_type)
6462306a36Sopenharmony_ci		return false;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return true;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/*
7062306a36Sopenharmony_ci * cx231xx_i2c_send_bytes()
7162306a36Sopenharmony_ci */
7262306a36Sopenharmony_cistatic int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap,
7362306a36Sopenharmony_ci				  const struct i2c_msg *msg)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct cx231xx_i2c *bus = i2c_adap->algo_data;
7662306a36Sopenharmony_ci	struct cx231xx *dev = bus->dev;
7762306a36Sopenharmony_ci	struct cx231xx_i2c_xfer_data req_data;
7862306a36Sopenharmony_ci	int status = 0;
7962306a36Sopenharmony_ci	u16 size = 0;
8062306a36Sopenharmony_ci	u8 loop = 0;
8162306a36Sopenharmony_ci	u8 saddr_len = 1;
8262306a36Sopenharmony_ci	u8 *buf_ptr = NULL;
8362306a36Sopenharmony_ci	u16 saddr = 0;
8462306a36Sopenharmony_ci	u8 need_gpio = 0;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	if (is_tuner(dev, bus, msg, TUNER_XC5000)) {
8762306a36Sopenharmony_ci		size = msg->len;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		if (size == 2) {	/* register write sub addr */
9062306a36Sopenharmony_ci			/* Just writing sub address will cause problem
9162306a36Sopenharmony_ci			* to XC5000. So ignore the request */
9262306a36Sopenharmony_ci			return 0;
9362306a36Sopenharmony_ci		} else if (size == 4) {	/* register write with sub addr */
9462306a36Sopenharmony_ci			if (msg->len >= 2)
9562306a36Sopenharmony_ci				saddr = msg->buf[0] << 8 | msg->buf[1];
9662306a36Sopenharmony_ci			else if (msg->len == 1)
9762306a36Sopenharmony_ci				saddr = msg->buf[0];
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci			switch (saddr) {
10062306a36Sopenharmony_ci			case 0x0000:	/* start tuner calibration mode */
10162306a36Sopenharmony_ci				need_gpio = 1;
10262306a36Sopenharmony_ci				/* FW Loading is done */
10362306a36Sopenharmony_ci				dev->xc_fw_load_done = 1;
10462306a36Sopenharmony_ci				break;
10562306a36Sopenharmony_ci			case 0x000D:	/* Set signal source */
10662306a36Sopenharmony_ci			case 0x0001:	/* Set TV standard - Video */
10762306a36Sopenharmony_ci			case 0x0002:	/* Set TV standard - Audio */
10862306a36Sopenharmony_ci			case 0x0003:	/* Set RF Frequency */
10962306a36Sopenharmony_ci				need_gpio = 1;
11062306a36Sopenharmony_ci				break;
11162306a36Sopenharmony_ci			default:
11262306a36Sopenharmony_ci				if (dev->xc_fw_load_done)
11362306a36Sopenharmony_ci					need_gpio = 1;
11462306a36Sopenharmony_ci				break;
11562306a36Sopenharmony_ci			}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci			if (need_gpio) {
11862306a36Sopenharmony_ci				dprintk1(1,
11962306a36Sopenharmony_ci				"GPIO WRITE: addr 0x%x, len %d, saddr 0x%x\n",
12062306a36Sopenharmony_ci				msg->addr, msg->len, saddr);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci				return dev->cx231xx_gpio_i2c_write(dev,
12362306a36Sopenharmony_ci								   msg->addr,
12462306a36Sopenharmony_ci								   msg->buf,
12562306a36Sopenharmony_ci								   msg->len);
12662306a36Sopenharmony_ci			}
12762306a36Sopenharmony_ci		}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci		/* special case for Xc5000 tuner case */
13062306a36Sopenharmony_ci		saddr_len = 1;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		/* adjust the length to correct length */
13362306a36Sopenharmony_ci		size -= saddr_len;
13462306a36Sopenharmony_ci		buf_ptr = (u8 *) (msg->buf + 1);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		do {
13762306a36Sopenharmony_ci			/* prepare xfer_data struct */
13862306a36Sopenharmony_ci			req_data.dev_addr = msg->addr;
13962306a36Sopenharmony_ci			req_data.direction = msg->flags;
14062306a36Sopenharmony_ci			req_data.saddr_len = saddr_len;
14162306a36Sopenharmony_ci			req_data.saddr_dat = msg->buf[0];
14262306a36Sopenharmony_ci			req_data.buf_size = size > 16 ? 16 : size;
14362306a36Sopenharmony_ci			req_data.p_buffer = (u8 *) (buf_ptr + loop * 16);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci			bus->i2c_nostop = (size > 16) ? 1 : 0;
14662306a36Sopenharmony_ci			bus->i2c_reserve = (loop == 0) ? 0 : 1;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci			/* usb send command */
14962306a36Sopenharmony_ci			status = dev->cx231xx_send_usb_command(bus, &req_data);
15062306a36Sopenharmony_ci			loop++;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci			if (size >= 16)
15362306a36Sopenharmony_ci				size -= 16;
15462306a36Sopenharmony_ci			else
15562306a36Sopenharmony_ci				size = 0;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		} while (size > 0);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		bus->i2c_nostop = 0;
16062306a36Sopenharmony_ci		bus->i2c_reserve = 0;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	} else {		/* regular case */
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		/* prepare xfer_data struct */
16562306a36Sopenharmony_ci		req_data.dev_addr = msg->addr;
16662306a36Sopenharmony_ci		req_data.direction = msg->flags;
16762306a36Sopenharmony_ci		req_data.saddr_len = 0;
16862306a36Sopenharmony_ci		req_data.saddr_dat = 0;
16962306a36Sopenharmony_ci		req_data.buf_size = msg->len;
17062306a36Sopenharmony_ci		req_data.p_buffer = msg->buf;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci		/* usb send command */
17362306a36Sopenharmony_ci		status = dev->cx231xx_send_usb_command(bus, &req_data);
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	return status < 0 ? status : 0;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/*
18062306a36Sopenharmony_ci * cx231xx_i2c_recv_bytes()
18162306a36Sopenharmony_ci * read a byte from the i2c device
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_cistatic int cx231xx_i2c_recv_bytes(struct i2c_adapter *i2c_adap,
18462306a36Sopenharmony_ci				  const struct i2c_msg *msg)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	struct cx231xx_i2c *bus = i2c_adap->algo_data;
18762306a36Sopenharmony_ci	struct cx231xx *dev = bus->dev;
18862306a36Sopenharmony_ci	struct cx231xx_i2c_xfer_data req_data;
18962306a36Sopenharmony_ci	int status = 0;
19062306a36Sopenharmony_ci	u16 saddr = 0;
19162306a36Sopenharmony_ci	u8 need_gpio = 0;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (is_tuner(dev, bus, msg, TUNER_XC5000)) {
19462306a36Sopenharmony_ci		if (msg->len == 2)
19562306a36Sopenharmony_ci			saddr = msg->buf[0] << 8 | msg->buf[1];
19662306a36Sopenharmony_ci		else if (msg->len == 1)
19762306a36Sopenharmony_ci			saddr = msg->buf[0];
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		if (dev->xc_fw_load_done) {
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci			switch (saddr) {
20262306a36Sopenharmony_ci			case 0x0009:	/* BUSY check */
20362306a36Sopenharmony_ci				dprintk1(1,
20462306a36Sopenharmony_ci				"GPIO R E A D: Special case BUSY check \n");
20562306a36Sopenharmony_ci				/*Try read BUSY register, just set it to zero*/
20662306a36Sopenharmony_ci				msg->buf[0] = 0;
20762306a36Sopenharmony_ci				if (msg->len == 2)
20862306a36Sopenharmony_ci					msg->buf[1] = 0;
20962306a36Sopenharmony_ci				return 0;
21062306a36Sopenharmony_ci			case 0x0004:	/* read Lock status */
21162306a36Sopenharmony_ci				need_gpio = 1;
21262306a36Sopenharmony_ci				break;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci			}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci			if (need_gpio) {
21762306a36Sopenharmony_ci				/* this is a special case to handle Xceive tuner
21862306a36Sopenharmony_ci				clock stretch issue with gpio based I2C */
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci				dprintk1(1,
22162306a36Sopenharmony_ci				"GPIO R E A D: addr 0x%x, len %d, saddr 0x%x\n",
22262306a36Sopenharmony_ci				msg->addr, msg->len,
22362306a36Sopenharmony_ci				msg->buf[0] << 8 | msg->buf[1]);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci				status =
22662306a36Sopenharmony_ci				    dev->cx231xx_gpio_i2c_write(dev, msg->addr,
22762306a36Sopenharmony_ci								msg->buf,
22862306a36Sopenharmony_ci								msg->len);
22962306a36Sopenharmony_ci				status =
23062306a36Sopenharmony_ci				    dev->cx231xx_gpio_i2c_read(dev, msg->addr,
23162306a36Sopenharmony_ci							       msg->buf,
23262306a36Sopenharmony_ci							       msg->len);
23362306a36Sopenharmony_ci				return status;
23462306a36Sopenharmony_ci			}
23562306a36Sopenharmony_ci		}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		/* prepare xfer_data struct */
23862306a36Sopenharmony_ci		req_data.dev_addr = msg->addr;
23962306a36Sopenharmony_ci		req_data.direction = msg->flags;
24062306a36Sopenharmony_ci		req_data.saddr_len = msg->len;
24162306a36Sopenharmony_ci		req_data.saddr_dat = msg->buf[0] << 8 | msg->buf[1];
24262306a36Sopenharmony_ci		req_data.buf_size = msg->len;
24362306a36Sopenharmony_ci		req_data.p_buffer = msg->buf;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		/* usb send command */
24662306a36Sopenharmony_ci		status = dev->cx231xx_send_usb_command(bus, &req_data);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	} else {
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		/* prepare xfer_data struct */
25162306a36Sopenharmony_ci		req_data.dev_addr = msg->addr;
25262306a36Sopenharmony_ci		req_data.direction = msg->flags;
25362306a36Sopenharmony_ci		req_data.saddr_len = 0;
25462306a36Sopenharmony_ci		req_data.saddr_dat = 0;
25562306a36Sopenharmony_ci		req_data.buf_size = msg->len;
25662306a36Sopenharmony_ci		req_data.p_buffer = msg->buf;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		/* usb send command */
25962306a36Sopenharmony_ci		status = dev->cx231xx_send_usb_command(bus, &req_data);
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return status < 0 ? status : 0;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci/*
26662306a36Sopenharmony_ci * cx231xx_i2c_recv_bytes_with_saddr()
26762306a36Sopenharmony_ci * read a byte from the i2c device
26862306a36Sopenharmony_ci */
26962306a36Sopenharmony_cistatic int cx231xx_i2c_recv_bytes_with_saddr(struct i2c_adapter *i2c_adap,
27062306a36Sopenharmony_ci					     const struct i2c_msg *msg1,
27162306a36Sopenharmony_ci					     const struct i2c_msg *msg2)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct cx231xx_i2c *bus = i2c_adap->algo_data;
27462306a36Sopenharmony_ci	struct cx231xx *dev = bus->dev;
27562306a36Sopenharmony_ci	struct cx231xx_i2c_xfer_data req_data;
27662306a36Sopenharmony_ci	int status = 0;
27762306a36Sopenharmony_ci	u16 saddr = 0;
27862306a36Sopenharmony_ci	u8 need_gpio = 0;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (msg1->len == 2)
28162306a36Sopenharmony_ci		saddr = msg1->buf[0] << 8 | msg1->buf[1];
28262306a36Sopenharmony_ci	else if (msg1->len == 1)
28362306a36Sopenharmony_ci		saddr = msg1->buf[0];
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (is_tuner(dev, bus, msg2, TUNER_XC5000)) {
28662306a36Sopenharmony_ci		if ((msg2->len < 16)) {
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci			dprintk1(1,
28962306a36Sopenharmony_ci			"i2c_read: addr 0x%x, len %d, saddr 0x%x, len %d\n",
29062306a36Sopenharmony_ci			msg2->addr, msg2->len, saddr, msg1->len);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci			switch (saddr) {
29362306a36Sopenharmony_ci			case 0x0008:	/* read FW load status */
29462306a36Sopenharmony_ci				need_gpio = 1;
29562306a36Sopenharmony_ci				break;
29662306a36Sopenharmony_ci			case 0x0004:	/* read Lock status */
29762306a36Sopenharmony_ci				need_gpio = 1;
29862306a36Sopenharmony_ci				break;
29962306a36Sopenharmony_ci			}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci			if (need_gpio) {
30262306a36Sopenharmony_ci				status =
30362306a36Sopenharmony_ci				    dev->cx231xx_gpio_i2c_write(dev, msg1->addr,
30462306a36Sopenharmony_ci								msg1->buf,
30562306a36Sopenharmony_ci								msg1->len);
30662306a36Sopenharmony_ci				status =
30762306a36Sopenharmony_ci				    dev->cx231xx_gpio_i2c_read(dev, msg2->addr,
30862306a36Sopenharmony_ci							       msg2->buf,
30962306a36Sopenharmony_ci							       msg2->len);
31062306a36Sopenharmony_ci				return status;
31162306a36Sopenharmony_ci			}
31262306a36Sopenharmony_ci		}
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* prepare xfer_data struct */
31662306a36Sopenharmony_ci	req_data.dev_addr = msg2->addr;
31762306a36Sopenharmony_ci	req_data.direction = msg2->flags;
31862306a36Sopenharmony_ci	req_data.saddr_len = msg1->len;
31962306a36Sopenharmony_ci	req_data.saddr_dat = saddr;
32062306a36Sopenharmony_ci	req_data.buf_size = msg2->len;
32162306a36Sopenharmony_ci	req_data.p_buffer = msg2->buf;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* usb send command */
32462306a36Sopenharmony_ci	status = dev->cx231xx_send_usb_command(bus, &req_data);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return status < 0 ? status : 0;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci/*
33062306a36Sopenharmony_ci * cx231xx_i2c_check_for_device()
33162306a36Sopenharmony_ci * check if there is a i2c_device at the supplied address
33262306a36Sopenharmony_ci */
33362306a36Sopenharmony_cistatic int cx231xx_i2c_check_for_device(struct i2c_adapter *i2c_adap,
33462306a36Sopenharmony_ci					const struct i2c_msg *msg)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct cx231xx_i2c *bus = i2c_adap->algo_data;
33762306a36Sopenharmony_ci	struct cx231xx *dev = bus->dev;
33862306a36Sopenharmony_ci	struct cx231xx_i2c_xfer_data req_data;
33962306a36Sopenharmony_ci	int status = 0;
34062306a36Sopenharmony_ci	u8 buf[1];
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* prepare xfer_data struct */
34362306a36Sopenharmony_ci	req_data.dev_addr = msg->addr;
34462306a36Sopenharmony_ci	req_data.direction = I2C_M_RD;
34562306a36Sopenharmony_ci	req_data.saddr_len = 0;
34662306a36Sopenharmony_ci	req_data.saddr_dat = 0;
34762306a36Sopenharmony_ci	req_data.buf_size = 1;
34862306a36Sopenharmony_ci	req_data.p_buffer = buf;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/* usb send command */
35162306a36Sopenharmony_ci	status = dev->cx231xx_send_usb_command(bus, &req_data);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return status < 0 ? status : 0;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/*
35762306a36Sopenharmony_ci * cx231xx_i2c_xfer()
35862306a36Sopenharmony_ci * the main i2c transfer function
35962306a36Sopenharmony_ci */
36062306a36Sopenharmony_cistatic int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
36162306a36Sopenharmony_ci			    struct i2c_msg msgs[], int num)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	struct cx231xx_i2c *bus = i2c_adap->algo_data;
36462306a36Sopenharmony_ci	struct cx231xx *dev = bus->dev;
36562306a36Sopenharmony_ci	int addr, rc, i, byte;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	mutex_lock(&dev->i2c_lock);
36862306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		addr = msgs[i].addr;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		dprintk2(2, "%s %s addr=0x%x len=%d:",
37362306a36Sopenharmony_ci			 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
37462306a36Sopenharmony_ci			 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
37562306a36Sopenharmony_ci		if (!msgs[i].len) {
37662306a36Sopenharmony_ci			/* no len: check only for device presence */
37762306a36Sopenharmony_ci			rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]);
37862306a36Sopenharmony_ci			if (rc < 0) {
37962306a36Sopenharmony_ci				dprintk2(2, " no device\n");
38062306a36Sopenharmony_ci				mutex_unlock(&dev->i2c_lock);
38162306a36Sopenharmony_ci				return rc;
38262306a36Sopenharmony_ci			}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		} else if (msgs[i].flags & I2C_M_RD) {
38562306a36Sopenharmony_ci			/* read bytes */
38662306a36Sopenharmony_ci			rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]);
38762306a36Sopenharmony_ci			if (i2c_debug >= 2) {
38862306a36Sopenharmony_ci				for (byte = 0; byte < msgs[i].len; byte++)
38962306a36Sopenharmony_ci					printk(KERN_CONT " %02x", msgs[i].buf[byte]);
39062306a36Sopenharmony_ci			}
39162306a36Sopenharmony_ci		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
39262306a36Sopenharmony_ci			   msgs[i].addr == msgs[i + 1].addr
39362306a36Sopenharmony_ci			   && (msgs[i].len <= 2) && (bus->nr < 3)) {
39462306a36Sopenharmony_ci			/* write bytes */
39562306a36Sopenharmony_ci			if (i2c_debug >= 2) {
39662306a36Sopenharmony_ci				for (byte = 0; byte < msgs[i].len; byte++)
39762306a36Sopenharmony_ci					printk(KERN_CONT " %02x", msgs[i].buf[byte]);
39862306a36Sopenharmony_ci				printk(KERN_CONT "\n");
39962306a36Sopenharmony_ci			}
40062306a36Sopenharmony_ci			/* read bytes */
40162306a36Sopenharmony_ci			dprintk2(2, "plus %s %s addr=0x%x len=%d:",
40262306a36Sopenharmony_ci				(msgs[i+1].flags & I2C_M_RD) ? "read" : "write",
40362306a36Sopenharmony_ci				i+1 == num - 1 ? "stop" : "nonstop", addr, msgs[i+1].len);
40462306a36Sopenharmony_ci			rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap,
40562306a36Sopenharmony_ci							       &msgs[i],
40662306a36Sopenharmony_ci							       &msgs[i + 1]);
40762306a36Sopenharmony_ci			if (i2c_debug >= 2) {
40862306a36Sopenharmony_ci				for (byte = 0; byte < msgs[i+1].len; byte++)
40962306a36Sopenharmony_ci					printk(KERN_CONT " %02x", msgs[i+1].buf[byte]);
41062306a36Sopenharmony_ci			}
41162306a36Sopenharmony_ci			i++;
41262306a36Sopenharmony_ci		} else {
41362306a36Sopenharmony_ci			/* write bytes */
41462306a36Sopenharmony_ci			if (i2c_debug >= 2) {
41562306a36Sopenharmony_ci				for (byte = 0; byte < msgs[i].len; byte++)
41662306a36Sopenharmony_ci					printk(KERN_CONT " %02x", msgs[i].buf[byte]);
41762306a36Sopenharmony_ci			}
41862306a36Sopenharmony_ci			rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]);
41962306a36Sopenharmony_ci		}
42062306a36Sopenharmony_ci		if (rc < 0)
42162306a36Sopenharmony_ci			goto err;
42262306a36Sopenharmony_ci		if (i2c_debug >= 2)
42362306a36Sopenharmony_ci			printk(KERN_CONT "\n");
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci	mutex_unlock(&dev->i2c_lock);
42662306a36Sopenharmony_ci	return num;
42762306a36Sopenharmony_cierr:
42862306a36Sopenharmony_ci	dprintk2(2, " ERROR: %i\n", rc);
42962306a36Sopenharmony_ci	mutex_unlock(&dev->i2c_lock);
43062306a36Sopenharmony_ci	return rc;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci/* ----------------------------------------------------------- */
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci/*
43662306a36Sopenharmony_ci * functionality()
43762306a36Sopenharmony_ci */
43862306a36Sopenharmony_cistatic u32 functionality(struct i2c_adapter *adap)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic const struct i2c_algorithm cx231xx_algo = {
44462306a36Sopenharmony_ci	.master_xfer = cx231xx_i2c_xfer,
44562306a36Sopenharmony_ci	.functionality = functionality,
44662306a36Sopenharmony_ci};
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic const struct i2c_adapter cx231xx_adap_template = {
44962306a36Sopenharmony_ci	.owner = THIS_MODULE,
45062306a36Sopenharmony_ci	.name = "cx231xx",
45162306a36Sopenharmony_ci	.algo = &cx231xx_algo,
45262306a36Sopenharmony_ci};
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci/* ----------------------------------------------------------- */
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci/*
45762306a36Sopenharmony_ci * i2c_devs
45862306a36Sopenharmony_ci * incomplete list of known devices
45962306a36Sopenharmony_ci */
46062306a36Sopenharmony_cistatic const char *i2c_devs[128] = {
46162306a36Sopenharmony_ci	[0x20 >> 1] = "demod",
46262306a36Sopenharmony_ci	[0x60 >> 1] = "colibri",
46362306a36Sopenharmony_ci	[0x88 >> 1] = "hammerhead",
46462306a36Sopenharmony_ci	[0x8e >> 1] = "CIR",
46562306a36Sopenharmony_ci	[0x32 >> 1] = "GeminiIII",
46662306a36Sopenharmony_ci	[0x02 >> 1] = "Aquarius",
46762306a36Sopenharmony_ci	[0xa0 >> 1] = "eeprom",
46862306a36Sopenharmony_ci	[0xc0 >> 1] = "tuner",
46962306a36Sopenharmony_ci	[0xc2 >> 1] = "tuner",
47062306a36Sopenharmony_ci};
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci/*
47362306a36Sopenharmony_ci * cx231xx_do_i2c_scan()
47462306a36Sopenharmony_ci * check i2c address range for devices
47562306a36Sopenharmony_ci */
47662306a36Sopenharmony_civoid cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	unsigned char buf;
47962306a36Sopenharmony_ci	int i, rc;
48062306a36Sopenharmony_ci	struct i2c_adapter *adap;
48162306a36Sopenharmony_ci	struct i2c_msg msg = {
48262306a36Sopenharmony_ci		.flags = I2C_M_RD,
48362306a36Sopenharmony_ci		.len = 1,
48462306a36Sopenharmony_ci		.buf = &buf,
48562306a36Sopenharmony_ci	};
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (!i2c_scan)
48862306a36Sopenharmony_ci		return;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* Don't generate I2C errors during scan */
49162306a36Sopenharmony_ci	dev->i2c_scan_running = true;
49262306a36Sopenharmony_ci	adap = cx231xx_get_i2c_adap(dev, i2c_port);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	for (i = 0; i < 128; i++) {
49562306a36Sopenharmony_ci		msg.addr = i;
49662306a36Sopenharmony_ci		rc = i2c_transfer(adap, &msg, 1);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci		if (rc < 0)
49962306a36Sopenharmony_ci			continue;
50062306a36Sopenharmony_ci		dev_info(dev->dev,
50162306a36Sopenharmony_ci			 "i2c scan: found device @ port %d addr 0x%x  [%s]\n",
50262306a36Sopenharmony_ci			 i2c_port,
50362306a36Sopenharmony_ci			 i << 1,
50462306a36Sopenharmony_ci			 i2c_devs[i] ? i2c_devs[i] : "???");
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	dev->i2c_scan_running = false;
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci/*
51162306a36Sopenharmony_ci * cx231xx_i2c_register()
51262306a36Sopenharmony_ci * register i2c bus
51362306a36Sopenharmony_ci */
51462306a36Sopenharmony_ciint cx231xx_i2c_register(struct cx231xx_i2c *bus)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct cx231xx *dev = bus->dev;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (!dev->cx231xx_send_usb_command)
51962306a36Sopenharmony_ci		return -EINVAL;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	bus->i2c_adap = cx231xx_adap_template;
52262306a36Sopenharmony_ci	bus->i2c_adap.dev.parent = dev->dev;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	snprintf(bus->i2c_adap.name, sizeof(bus->i2c_adap.name), "%s-%d", bus->dev->name, bus->nr);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	bus->i2c_adap.algo_data = bus;
52762306a36Sopenharmony_ci	i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
52862306a36Sopenharmony_ci	bus->i2c_rc = i2c_add_adapter(&bus->i2c_adap);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (0 != bus->i2c_rc)
53162306a36Sopenharmony_ci		dev_warn(dev->dev,
53262306a36Sopenharmony_ci			 "i2c bus %d register FAILED\n", bus->nr);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	return bus->i2c_rc;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci/*
53862306a36Sopenharmony_ci * cx231xx_i2c_unregister()
53962306a36Sopenharmony_ci * unregister i2c_bus
54062306a36Sopenharmony_ci */
54162306a36Sopenharmony_civoid cx231xx_i2c_unregister(struct cx231xx_i2c *bus)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	if (!bus->i2c_rc)
54462306a36Sopenharmony_ci		i2c_del_adapter(&bus->i2c_adap);
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci/*
54862306a36Sopenharmony_ci * cx231xx_i2c_mux_select()
54962306a36Sopenharmony_ci * switch i2c master number 1 between port1 and port3
55062306a36Sopenharmony_ci */
55162306a36Sopenharmony_cistatic int cx231xx_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan_id)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct cx231xx *dev = i2c_mux_priv(muxc);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	return cx231xx_enable_i2c_port_3(dev, chan_id);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ciint cx231xx_i2c_mux_create(struct cx231xx *dev)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	dev->muxc = i2c_mux_alloc(&dev->i2c_bus[1].i2c_adap, dev->dev, 2, 0, 0,
56162306a36Sopenharmony_ci				  cx231xx_i2c_mux_select, NULL);
56262306a36Sopenharmony_ci	if (!dev->muxc)
56362306a36Sopenharmony_ci		return -ENOMEM;
56462306a36Sopenharmony_ci	dev->muxc->priv = dev;
56562306a36Sopenharmony_ci	return 0;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ciint cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	return i2c_mux_add_adapter(dev->muxc,
57162306a36Sopenharmony_ci				   0,
57262306a36Sopenharmony_ci				   mux_no /* chan_id */,
57362306a36Sopenharmony_ci				   0 /* class */);
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_civoid cx231xx_i2c_mux_unregister(struct cx231xx *dev)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	i2c_mux_del_adapters(dev->muxc);
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistruct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	switch (i2c_port) {
58462306a36Sopenharmony_ci	case I2C_0:
58562306a36Sopenharmony_ci		return &dev->i2c_bus[0].i2c_adap;
58662306a36Sopenharmony_ci	case I2C_1:
58762306a36Sopenharmony_ci		return &dev->i2c_bus[1].i2c_adap;
58862306a36Sopenharmony_ci	case I2C_2:
58962306a36Sopenharmony_ci		return &dev->i2c_bus[2].i2c_adap;
59062306a36Sopenharmony_ci	case I2C_1_MUX_1:
59162306a36Sopenharmony_ci		return dev->muxc->adapter[0];
59262306a36Sopenharmony_ci	case I2C_1_MUX_3:
59362306a36Sopenharmony_ci		return dev->muxc->adapter[1];
59462306a36Sopenharmony_ci	default:
59562306a36Sopenharmony_ci		BUG();
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cx231xx_get_i2c_adap);
599