Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.18 319 lines 7.8 kB view raw
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 "tuner-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 if (num <= 0) 149 return 0; 150 for (i = 0; i < num; i++) { 151 addr = (msgs[i].addr << 1) & 0xff; 152 i2c_dprintk(2, "%s %s addr=0x%x len=%d:", 153 (msgs[i].flags & I2C_M_RD) ? "read" : "write", 154 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); 155 if (msgs[i].flags & I2C_M_RD) { 156 /* read request without preceding register selection */ 157 /* 158 * The TM6000 only supports a read transaction 159 * immediately after a 1 or 2 byte write to select 160 * a register. We cannot fulfil this request. 161 */ 162 i2c_dprintk(2, " read without preceding write not supported"); 163 rc = -EOPNOTSUPP; 164 goto err; 165 } else if (i + 1 < num && msgs[i].len <= 2 && 166 (msgs[i + 1].flags & I2C_M_RD) && 167 msgs[i].addr == msgs[i + 1].addr) { 168 /* 1 or 2 byte write followed by a read */ 169 if (i2c_debug >= 2) 170 for (byte = 0; byte < msgs[i].len; byte++) 171 printk(KERN_CONT " %02x", msgs[i].buf[byte]); 172 i2c_dprintk(2, "; joined to read %s len=%d:", 173 i == num - 2 ? "stop" : "nonstop", 174 msgs[i + 1].len); 175 176 if (msgs[i].len == 2) { 177 rc = tm6000_i2c_recv_regs16(dev, addr, 178 msgs[i].buf[0] << 8 | msgs[i].buf[1], 179 msgs[i + 1].buf, msgs[i + 1].len); 180 } else { 181 rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0], 182 msgs[i + 1].buf, msgs[i + 1].len); 183 } 184 185 i++; 186 187 if (addr == dev->tuner_addr << 1) { 188 tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); 189 tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); 190 } 191 if (i2c_debug >= 2) 192 for (byte = 0; byte < msgs[i].len; byte++) 193 printk(KERN_CONT " %02x", msgs[i].buf[byte]); 194 } else { 195 /* write bytes */ 196 if (i2c_debug >= 2) 197 for (byte = 0; byte < msgs[i].len; byte++) 198 printk(KERN_CONT " %02x", msgs[i].buf[byte]); 199 rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0], 200 msgs[i].buf + 1, msgs[i].len - 1); 201 } 202 if (i2c_debug >= 2) 203 printk(KERN_CONT "\n"); 204 if (rc < 0) 205 goto err; 206 } 207 208 return num; 209err: 210 i2c_dprintk(2, " ERROR: %i\n", rc); 211 return rc; 212} 213 214static int tm6000_i2c_eeprom(struct tm6000_core *dev) 215{ 216 int i, rc; 217 unsigned char *p = dev->eedata; 218 unsigned char bytes[17]; 219 220 dev->i2c_client.addr = 0xa0 >> 1; 221 dev->eedata_size = 0; 222 223 bytes[16] = '\0'; 224 for (i = 0; i < sizeof(dev->eedata); ) { 225 *p = i; 226 rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1); 227 if (rc < 1) { 228 if (p == dev->eedata) 229 goto noeeprom; 230 else { 231 printk(KERN_WARNING 232 "%s: i2c eeprom read error (err=%d)\n", 233 dev->name, rc); 234 } 235 return -EINVAL; 236 } 237 dev->eedata_size++; 238 p++; 239 if (0 == (i % 16)) 240 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); 241 printk(KERN_CONT " %02x", dev->eedata[i]); 242 if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z')) 243 bytes[i%16] = dev->eedata[i]; 244 else 245 bytes[i%16] = '.'; 246 247 i++; 248 249 if (0 == (i % 16)) { 250 bytes[16] = '\0'; 251 printk(KERN_CONT " %s\n", bytes); 252 } 253 } 254 if (0 != (i%16)) { 255 bytes[i%16] = '\0'; 256 for (i %= 16; i < 16; i++) 257 printk(KERN_CONT " "); 258 printk(KERN_CONT " %s\n", bytes); 259 } 260 261 return 0; 262 263noeeprom: 264 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", 265 dev->name, rc); 266 return -EINVAL; 267} 268 269/* ----------------------------------------------------------- */ 270 271/* 272 * functionality() 273 */ 274static u32 functionality(struct i2c_adapter *adap) 275{ 276 return I2C_FUNC_SMBUS_EMUL; 277} 278 279static const struct i2c_algorithm tm6000_algo = { 280 .master_xfer = tm6000_i2c_xfer, 281 .functionality = functionality, 282}; 283 284/* ----------------------------------------------------------- */ 285 286/* 287 * tm6000_i2c_register() 288 * register i2c bus 289 */ 290int tm6000_i2c_register(struct tm6000_core *dev) 291{ 292 int rc; 293 294 dev->i2c_adap.owner = THIS_MODULE; 295 dev->i2c_adap.algo = &tm6000_algo; 296 dev->i2c_adap.dev.parent = &dev->udev->dev; 297 strlcpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name)); 298 dev->i2c_adap.algo_data = dev; 299 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); 300 rc = i2c_add_adapter(&dev->i2c_adap); 301 if (rc) 302 return rc; 303 304 dev->i2c_client.adapter = &dev->i2c_adap; 305 strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE); 306 tm6000_i2c_eeprom(dev); 307 308 return 0; 309} 310 311/* 312 * tm6000_i2c_unregister() 313 * unregister i2c_bus 314 */ 315int tm6000_i2c_unregister(struct tm6000_core *dev) 316{ 317 i2c_del_adapter(&dev->i2c_adap); 318 return 0; 319}