ALSA: usb-audio: add support for Akai MPD16
[safe/jmp/linux-2.6] / drivers / staging / tm6000 / tm6000-i2c.c
index a532330..94ff489 100644 (file)
@@ -47,8 +47,38 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
                                __u8 reg, char *buf, int len)
 {
-       return 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);
+       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 */
@@ -56,10 +86,39 @@ 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;
 
-       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       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;
 }
 
@@ -70,8 +129,36 @@ static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr,
 static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr,
                                  __u16 reg, char *buf, int len)
 {
-       return 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);
+       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,
@@ -121,8 +208,8 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
                        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++)
@@ -136,8 +223,8 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
                                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)