[media] af9035: add support for 1st gen it9135
[firefly-linux-kernel-4.4.55.git] / drivers / media / usb / dvb-usb-v2 / af9035.c
index f11cc42454f069692389f592ea986f9c9c69a488..f43e83c4122a8f41e726b1b555eb61b035f7d0a6 100644 (file)
@@ -41,43 +41,45 @@ static u16 af9035_checksum(const u8 *buf, size_t len)
 
 static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
 {
-#define BUF_LEN 64
 #define REQ_HDR_LEN 4 /* send header size */
 #define ACK_HDR_LEN 3 /* rece header size */
 #define CHECKSUM_LEN 2
 #define USB_TIMEOUT 2000
        struct state *state = d_to_priv(d);
        int ret, wlen, rlen;
-       u8 buf[BUF_LEN];
        u16 checksum, tmp_checksum;
 
+       mutex_lock(&d->usb_mutex);
+
        /* buffer overflow check */
        if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
                        req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
                dev_err(&d->udev->dev, "%s: too much data wlen=%d rlen=%d\n",
                                __func__, req->wlen, req->rlen);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err;
        }
 
-       buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
-       buf[1] = req->mbox;
-       buf[2] = req->cmd;
-       buf[3] = state->seq++;
-       memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen);
+       state->buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
+       state->buf[1] = req->mbox;
+       state->buf[2] = req->cmd;
+       state->buf[3] = state->seq++;
+       memcpy(&state->buf[REQ_HDR_LEN], req->wbuf, req->wlen);
 
        wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN;
        rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
 
        /* calc and add checksum */
-       checksum = af9035_checksum(buf, buf[0] - 1);
-       buf[buf[0] - 1] = (checksum >> 8);
-       buf[buf[0] - 0] = (checksum & 0xff);
+       checksum = af9035_checksum(state->buf, state->buf[0] - 1);
+       state->buf[state->buf[0] - 1] = (checksum >> 8);
+       state->buf[state->buf[0] - 0] = (checksum & 0xff);
 
        /* no ack for these packets */
        if (req->cmd == CMD_FW_DL)
                rlen = 0;
 
-       ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+       ret = dvb_usbv2_generic_rw_locked(d,
+                       state->buf, wlen, state->buf, rlen);
        if (ret)
                goto err;
 
@@ -86,8 +88,8 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
                goto exit;
 
        /* verify checksum */
-       checksum = af9035_checksum(buf, rlen - 2);
-       tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1];
+       checksum = af9035_checksum(state->buf, rlen - 2);
+       tmp_checksum = (state->buf[rlen - 2] << 8) | state->buf[rlen - 1];
        if (tmp_checksum != checksum) {
                dev_err(&d->udev->dev, "%s: command=%02x checksum mismatch " \
                                "(%04x != %04x)\n", KBUILD_MODNAME, req->cmd,
@@ -97,23 +99,21 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
        }
 
        /* check status */
-       if (buf[2]) {
+       if (state->buf[2]) {
                dev_dbg(&d->udev->dev, "%s: command=%02x failed fw error=%d\n",
-                               __func__, req->cmd, buf[2]);
+                               __func__, req->cmd, state->buf[2]);
                ret = -EIO;
                goto err;
        }
 
        /* read request, copy returned data to return buf */
        if (req->rlen)
-               memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
-
+               memcpy(req->rbuf, &state->buf[ACK_HDR_LEN], req->rlen);
 exit:
-       return 0;
-
 err:
-       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
-
+       mutex_unlock(&d->usb_mutex);
+       if (ret)
+               dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -652,6 +652,10 @@ static int af9035_read_config_it9135(struct dvb_usb_device *d)
        int ret, i;
        u8 tmp;
 
+       /* demod I2C "address" */
+       state->af9033_config[0].i2c_addr = 0x38;
+       state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38;
+       state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
        state->dual_mode = false;
 
        /* get demod clock */
@@ -920,6 +924,20 @@ static const struct fc0012_config af9035_fc0012_config[] = {
        }
 };
 
+static struct ite_config af9035_it913x_config = {
+       .chip_ver = 0x01,
+       .chip_type = 0x9135,
+       .firmware = 0x00000000,
+       .firmware_ver = 1,
+       .adc_x2 = 1,
+       .tuner_id_0 = AF9033_TUNER_IT9135_38,
+       .tuner_id_1 = 0x00,
+       .dual_mode = 0x00,
+       .adf = 0x00,
+       /* option to read SIGNAL_LEVEL */
+       .read_slevel = 0,
+};
+
 static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct state *state = adap_to_priv(adap);
@@ -1082,6 +1100,11 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
                fe = dvb_attach(fc0012_attach, adap->fe[0], &d->i2c_adap,
                                &af9035_fc0012_config[adap->id]);
                break;
+       case AF9033_TUNER_IT9135_38:
+               /* attach tuner */
+               fe = dvb_attach(it913x_attach, adap->fe[0],
+                               &d->i2c_adap, 0x38, &af9035_it913x_config);
+               break;
        default:
                fe = NULL;
        }
@@ -1275,7 +1298,6 @@ static const struct dvb_usb_device_properties it9135_props = {
        .frontend_attach = af9035_frontend_attach,
        .tuner_attach = af9035_tuner_attach,
        .init = af9035_init,
-       .get_rc_config = af9035_get_rc_config,
 
        .num_adapters = 1,
        .adapter = {
@@ -1312,6 +1334,8 @@ static const struct usb_device_id af9035_id_table[] = {
                &af9035_props, "AVerMedia Twinstar (A825)", NULL) },
        { DVB_USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100MINI_PLUS,
                &af9035_props, "Asus U3100Mini Plus", NULL) },
+        { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa,
+               &af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) },
        { }
 };
 MODULE_DEVICE_TABLE(usb, af9035_id_table);