tm6000-i2c.c (7767B)
1// SPDX-License-Identifier: GPL-2.0 2// tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices 3// 4// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> 5// 6// Copyright (c) 2007 Michel Ludwig <michel.ludwig@gmail.com> 7// - Fix SMBus Read Byte command 8 9#include <linux/module.h> 10#include <linux/kernel.h> 11#include <linux/usb.h> 12#include <linux/i2c.h> 13 14#include "tm6000.h" 15#include "tm6000-regs.h" 16#include <media/v4l2-common.h> 17#include <media/tuner.h> 18#include "xc2028.h" 19 20 21/* ----------------------------------------------------------- */ 22 23static unsigned int i2c_debug; 24module_param(i2c_debug, int, 0644); 25MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); 26 27#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \ 28 printk(KERN_DEBUG "%s at %s: " fmt, \ 29 dev->name, __func__, ##args); } while (0) 30 31static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr, 32 __u8 reg, char *buf, int len) 33{ 34 int rc; 35 unsigned int i2c_packet_limit = 16; 36 37 if (dev->dev_type == TM6010) 38 i2c_packet_limit = 80; 39 40 if (!buf) 41 return -1; 42 43 if (len < 1 || len > i2c_packet_limit) { 44 printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n", 45 len, i2c_packet_limit); 46 return -1; 47 } 48 49 /* capture mutex */ 50 rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | 51 USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN, 52 addr | reg << 8, 0, buf, len); 53 54 if (rc < 0) { 55 /* release mutex */ 56 return rc; 57 } 58 59 /* release mutex */ 60 return rc; 61} 62 63/* Generic read - doesn't work fine with 16bit registers */ 64static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr, 65 __u8 reg, char *buf, int len) 66{ 67 int rc; 68 u8 b[2]; 69 unsigned int i2c_packet_limit = 16; 70 71 if (dev->dev_type == TM6010) 72 i2c_packet_limit = 64; 73 74 if (!buf) 75 return -1; 76 77 if (len < 1 || len > i2c_packet_limit) { 78 printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n", 79 len, i2c_packet_limit); 80 return -1; 81 } 82 83 /* capture mutex */ 84 if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) { 85 /* 86 * Workaround an I2C bug when reading from zl10353 87 */ 88 reg -= 1; 89 len += 1; 90 91 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 92 REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len); 93 94 *buf = b[1]; 95 } else { 96 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 97 REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len); 98 } 99 100 /* release mutex */ 101 return rc; 102} 103 104/* 105 * read from a 16bit register 106 * for example xc2028, xc3028 or xc3028L 107 */ 108static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr, 109 __u16 reg, char *buf, int len) 110{ 111 int rc; 112 unsigned char ureg; 113 114 if (!buf || len != 2) 115 return -1; 116 117 /* capture mutex */ 118 if (dev->dev_type == TM6010) { 119 ureg = reg & 0xFF; 120 rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | 121 USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN, 122 addr | (reg & 0xFF00), 0, &ureg, 1); 123 124 if (rc < 0) { 125 /* release mutex */ 126 return rc; 127 } 128 129 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | 130 USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ, 131 reg, 0, buf, len); 132 } else { 133 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | 134 USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN, 135 addr, reg, buf, len); 136 } 137 138 /* release mutex */ 139 return rc; 140} 141 142static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, 143 struct i2c_msg msgs[], int num) 144{ 145 struct tm6000_core *dev = i2c_adap->algo_data; 146 int addr, rc, i, byte; 147 148 for (i = 0; i < num; i++) { 149 addr = (msgs[i].addr << 1) & 0xff; 150 i2c_dprintk(2, "%s %s addr=0x%x len=%d:", 151 (msgs[i].flags & I2C_M_RD) ? "read" : "write", 152 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); 153 if (msgs[i].flags & I2C_M_RD) { 154 /* read request without preceding register selection */ 155 /* 156 * The TM6000 only supports a read transaction 157 * immediately after a 1 or 2 byte write to select 158 * a register. We cannot fulfill this request. 159 */ 160 i2c_dprintk(2, " read without preceding write not supported"); 161 rc = -EOPNOTSUPP; 162 goto err; 163 } else if (i + 1 < num && msgs[i].len <= 2 && 164 (msgs[i + 1].flags & I2C_M_RD) && 165 msgs[i].addr == msgs[i + 1].addr) { 166 /* 1 or 2 byte write followed by a read */ 167 if (i2c_debug >= 2) 168 for (byte = 0; byte < msgs[i].len; byte++) 169 printk(KERN_CONT " %02x", msgs[i].buf[byte]); 170 i2c_dprintk(2, "; joined to read %s len=%d:", 171 i == num - 2 ? "stop" : "nonstop", 172 msgs[i + 1].len); 173 174 if (msgs[i].len == 2) { 175 rc = tm6000_i2c_recv_regs16(dev, addr, 176 msgs[i].buf[0] << 8 | msgs[i].buf[1], 177 msgs[i + 1].buf, msgs[i + 1].len); 178 } else { 179 rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0], 180 msgs[i + 1].buf, msgs[i + 1].len); 181 } 182 183 i++; 184 185 if (addr == dev->tuner_addr << 1) { 186 tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); 187 tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); 188 } 189 if (i2c_debug >= 2) 190 for (byte = 0; byte < msgs[i].len; byte++) 191 printk(KERN_CONT " %02x", msgs[i].buf[byte]); 192 } else { 193 /* write bytes */ 194 if (i2c_debug >= 2) 195 for (byte = 0; byte < msgs[i].len; byte++) 196 printk(KERN_CONT " %02x", msgs[i].buf[byte]); 197 rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0], 198 msgs[i].buf + 1, msgs[i].len - 1); 199 } 200 if (i2c_debug >= 2) 201 printk(KERN_CONT "\n"); 202 if (rc < 0) 203 goto err; 204 } 205 206 return num; 207err: 208 i2c_dprintk(2, " ERROR: %i\n", rc); 209 return rc; 210} 211 212static int tm6000_i2c_eeprom(struct tm6000_core *dev) 213{ 214 int i, rc; 215 unsigned char *p = dev->eedata; 216 unsigned char bytes[17]; 217 218 dev->i2c_client.addr = 0xa0 >> 1; 219 dev->eedata_size = 0; 220 221 bytes[16] = '\0'; 222 for (i = 0; i < sizeof(dev->eedata); ) { 223 *p = i; 224 rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1); 225 if (rc < 1) { 226 if (p == dev->eedata) 227 goto noeeprom; 228 else { 229 printk(KERN_WARNING 230 "%s: i2c eeprom read error (err=%d)\n", 231 dev->name, rc); 232 } 233 return -EINVAL; 234 } 235 dev->eedata_size++; 236 p++; 237 if (0 == (i % 16)) 238 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); 239 printk(KERN_CONT " %02x", dev->eedata[i]); 240 if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z')) 241 bytes[i%16] = dev->eedata[i]; 242 else 243 bytes[i%16] = '.'; 244 245 i++; 246 247 if (0 == (i % 16)) { 248 bytes[16] = '\0'; 249 printk(KERN_CONT " %s\n", bytes); 250 } 251 } 252 if (0 != (i%16)) { 253 bytes[i%16] = '\0'; 254 for (i %= 16; i < 16; i++) 255 printk(KERN_CONT " "); 256 printk(KERN_CONT " %s\n", bytes); 257 } 258 259 return 0; 260 261noeeprom: 262 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", 263 dev->name, rc); 264 return -EINVAL; 265} 266 267/* ----------------------------------------------------------- */ 268 269/* 270 * functionality() 271 */ 272static u32 functionality(struct i2c_adapter *adap) 273{ 274 return I2C_FUNC_SMBUS_EMUL; 275} 276 277static const struct i2c_algorithm tm6000_algo = { 278 .master_xfer = tm6000_i2c_xfer, 279 .functionality = functionality, 280}; 281 282/* ----------------------------------------------------------- */ 283 284/* 285 * tm6000_i2c_register() 286 * register i2c bus 287 */ 288int tm6000_i2c_register(struct tm6000_core *dev) 289{ 290 int rc; 291 292 dev->i2c_adap.owner = THIS_MODULE; 293 dev->i2c_adap.algo = &tm6000_algo; 294 dev->i2c_adap.dev.parent = &dev->udev->dev; 295 strscpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name)); 296 dev->i2c_adap.algo_data = dev; 297 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); 298 rc = i2c_add_adapter(&dev->i2c_adap); 299 if (rc) 300 return rc; 301 302 dev->i2c_client.adapter = &dev->i2c_adap; 303 strscpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE); 304 tm6000_i2c_eeprom(dev); 305 306 return 0; 307} 308 309/* 310 * tm6000_i2c_unregister() 311 * unregister i2c_bus 312 */ 313int tm6000_i2c_unregister(struct tm6000_core *dev) 314{ 315 i2c_del_adapter(&dev->i2c_adap); 316 return 0; 317}