ALSA: usb-audio: add support for Akai MPD16
[safe/jmp/linux-2.6] / drivers / staging / tm6000 / tm6000-i2c.c
index fa11173..94ff489 100644 (file)
@@ -44,6 +44,123 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
                        printk(KERN_DEBUG "%s at %s: " fmt, \
                        dev->name, __FUNCTION__ , ##args); } while (0)
 
+static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
+                               __u8 reg, char *buf, int len)
+{
+       int rc;
+       unsigned int tsleep;
+       unsigned int i2c_packet_limit = 16;
+
+       if (dev->dev_type == TM6010)
+               i2c_packet_limit = 64;
+
+       if (!buf)
+               return -1;
+
+       if (len < 1 || len > i2c_packet_limit) {
+               printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
+                       len, i2c_packet_limit);
+               return -1;
+       }
+
+       /* capture mutex */
+       rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+               USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
+               addr | reg << 8, 0, buf, len);
+
+       if (rc < 0) {
+               /* release mutex */
+               return rc;
+       }
+
+       /* Calculate delay time, 14000us for 64 bytes */
+       tsleep = ((len * 200) + 200 + 1000) / 1000;
+       msleep(tsleep);
+
+       /* release mutex */
+       return rc;
+}
+
+/* Generic read - doesn't work fine with 16bit registers */
+static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr,
+                               __u8 reg, char *buf, int len)
+{
+       int rc;
+       u8 b[2];
+       unsigned int i2c_packet_limit = 16;
+
+       if (dev->dev_type == TM6010)
+               i2c_packet_limit = 64;
+
+       if (!buf)
+               return -1;
+
+       if (len < 1 || len > i2c_packet_limit) {
+               printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
+                       len, i2c_packet_limit);
+               return -1;
+       }
+
+       /* capture mutex */
+       if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) {
+               /*
+                * Workaround an I2C bug when reading from zl10353
+                */
+               reg -= 1;
+               len += 1;
+
+               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len);
+
+               *buf = b[1];
+       } else {
+               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len);
+       }
+
+       /* release mutex */
+       return rc;
+}
+
+/*
+ * read from a 16bit register
+ * for example xc2028, xc3028 or xc3028L
+ */
+static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr,
+                                 __u16 reg, char *buf, int len)
+{
+       int rc;
+       unsigned char ureg;
+
+       if (!buf || len != 2)
+               return -1;
+
+       /* capture mutex */
+       if (dev->dev_type == TM6010) {
+               ureg = reg & 0xFF;
+               rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+                       USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
+                       addr | (reg & 0xFF00), 0, &ureg, 1);
+
+               if (rc < 0) {
+                       /* release mutex */
+                       return rc;
+               }
+
+               msleep(1400 / 1000);
+               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
+                       USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ,
+                       reg, 0, buf, len);
+       } else {
+               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
+                       USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN,
+                       addr, reg, buf, len);
+       }
+
+       /* release mutex */
+       return rc;
+}
+
 static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
                           struct i2c_msg msgs[], int num)
 {
@@ -78,18 +195,21 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
                        i2c_dprintk(2, "; joined to read %s len=%d:",
                                    i == num - 2 ? "stop" : "nonstop",
                                    msgs[i + 1].len);
-                       rc = tm6000_read_write_usb (dev,
-                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               msgs[i].len == 1 ? REQ_16_SET_GET_I2C_WR1_RDN
-                                                : REQ_14_SET_GET_I2C_WR2_RDN,
-                               addr | msgs[i].buf[0] << 8,
-                               msgs[i].len == 1 ? 0 : msgs[i].buf[1],
-                               msgs[i + 1].buf, msgs[i + 1].len);
+
+                       if (msgs[i].len == 2) {
+                               rc = tm6000_i2c_recv_regs16(dev, addr,
+                                       msgs[i].buf[0] << 8 | msgs[i].buf[1],
+                                       msgs[i + 1].buf, msgs[i + 1].len);
+                       } else {
+                               rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0],
+                                       msgs[i + 1].buf, msgs[i + 1].len);
+                       }
+
                        i++;
 
                        if (addr == dev->tuner_addr << 1) {
-                               tm6000_set_reg(dev, 0x32, 0,0);
-                               tm6000_set_reg(dev, 0x33, 0,0);
+                               tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
+                               tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
                        }
                        if (i2c_debug >= 2)
                                for (byte = 0; byte < msgs[i].len; byte++)
@@ -99,15 +219,12 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
                        if (i2c_debug >= 2)
                                for (byte = 0; byte < msgs[i].len; byte++)
                                        printk(" %02x", msgs[i].buf[byte]);
-                       rc = tm6000_read_write_usb(dev,
-                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               REQ_16_SET_GET_I2C_WR1_RDN,
-                               addr | msgs[i].buf[0] << 8, 0,
+                       rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0],
                                msgs[i].buf + 1, msgs[i].len - 1);
 
                        if (addr == dev->tuner_addr  << 1) {
-                               tm6000_set_reg(dev, 0x32, 0,0);
-                               tm6000_set_reg(dev, 0x33, 0,0);
+                               tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
+                               tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
                        }
                }
                if (i2c_debug >= 2)
@@ -134,9 +251,7 @@ static int tm6000_i2c_eeprom(struct tm6000_core *dev,
        bytes[16] = '\0';
        for (i = 0; i < len; ) {
        *p = i;
-       rc = tm6000_read_write_usb (dev,
-               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               REQ_16_SET_GET_I2C_WR1_RDN, 0xa0 | i<<8, 0, p, 1);
+       rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
                if (rc < 1) {
                        if (p == eedata)
                                goto noeeprom;