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