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