Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux.git] / drivers / media / usb / dvb-usb-v2 / rtl28xxu.c
index fda5c64ba0e8220f0876e56ad3bf0d328361edf5..61d196e8b3abde6dc0d97e26fe3ca7cae9292957 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "rtl2830.h"
 #include "rtl2832.h"
+#include "rtl2832_sdr.h"
 
 #include "qt1010.h"
 #include "mt2060.h"
@@ -35,6 +36,9 @@
 #include "tua9001.h"
 #include "r820t.h"
 
+static int rtl28xxu_disable_rc;
+module_param_named(disable_rc, rtl28xxu_disable_rc, int, 0644);
+MODULE_PARM_DESC(disable_rc, "disable RTL2832U remote controller");
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
@@ -513,7 +517,7 @@ err:
        return ret;
 }
 
-static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
        .i2c_addr = 0x10, /* 0x20 */
        .xtal = 28800000,
        .ts_mode = 0,
@@ -524,7 +528,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
 
 };
 
-static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
        .i2c_addr = 0x10, /* 0x20 */
        .xtal = 28800000,
        .ts_mode = 0,
@@ -534,7 +538,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
        .agc_targ_val = 0x2d,
 };
 
-static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
        .i2c_addr = 0x10, /* 0x20 */
        .xtal = 28800000,
        .ts_mode = 0,
@@ -548,7 +552,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
 {
        struct dvb_usb_device *d = adap_to_d(adap);
        struct rtl28xxu_priv *priv = d_to_priv(d);
-       struct rtl2830_config *rtl2830_config;
+       const struct rtl2830_config *rtl2830_config;
        int ret;
 
        dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -583,33 +587,31 @@ err:
        return ret;
 }
 
-static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
        .i2c_addr = 0x10, /* 0x20 */
        .xtal = 28800000,
-       .if_dvbt = 0,
        .tuner = TUNER_RTL2832_FC0012
 };
 
-static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
        .i2c_addr = 0x10, /* 0x20 */
        .xtal = 28800000,
-       .if_dvbt = 0,
        .tuner = TUNER_RTL2832_FC0013
 };
 
-static struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = {
        .i2c_addr = 0x10, /* 0x20 */
        .xtal = 28800000,
        .tuner = TUNER_RTL2832_TUA9001,
 };
 
-static struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
        .i2c_addr = 0x10, /* 0x20 */
        .xtal = 28800000,
        .tuner = TUNER_RTL2832_E4000,
 };
 
-static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
        .i2c_addr = 0x10,
        .xtal = 28800000,
        .tuner = TUNER_RTL2832_R820T,
@@ -733,7 +735,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
        int ret;
        struct dvb_usb_device *d = adap_to_d(adap);
        struct rtl28xxu_priv *priv = d_to_priv(d);
-       struct rtl2832_config *rtl2832_config;
+       const struct rtl2832_config *rtl2832_config;
 
        dev_dbg(&d->udev->dev, "%s:\n", __func__);
 
@@ -772,6 +774,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
                goto err;
        }
 
+       /* RTL2832 I2C repeater */
+       priv->demod_i2c_adapter = rtl2832_get_i2c_adapter(adap->fe[0]);
+
        /* set fe callback */
        adap->fe[0]->callback = rtl2832u_frontend_callback;
 
@@ -851,11 +856,6 @@ err:
        return ret;
 }
 
-static const struct e4000_config rtl2832u_e4000_config = {
-       .i2c_addr = 0x64,
-       .clock = 28800000,
-};
-
 static const struct fc2580_config rtl2832u_fc2580_config = {
        .i2c_addr = 0x56,
        .clock = 16384000,
@@ -889,10 +889,14 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
        int ret;
        struct dvb_usb_device *d = adap_to_d(adap);
        struct rtl28xxu_priv *priv = d_to_priv(d);
-       struct dvb_frontend *fe;
+       struct dvb_frontend *fe = NULL;
+       struct i2c_board_info info;
+       struct i2c_client *client;
 
        dev_dbg(&d->udev->dev, "%s:\n", __func__);
 
+       memset(&info, 0, sizeof(struct i2c_board_info));
+
        switch (priv->tuner) {
        case TUNER_RTL2832_FC0012:
                fe = dvb_attach(fc0012_attach, adap->fe[0],
@@ -902,7 +906,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
                 * that to the tuner driver */
                adap->fe[0]->ops.read_signal_strength =
                                adap->fe[0]->ops.tuner_ops.get_rf_strength;
-               return 0;
+
+               /* attach SDR */
+               dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+                               &rtl28xxu_rtl2832_fc0012_config, NULL);
                break;
        case TUNER_RTL2832_FC0013:
                fe = dvb_attach(fc0013_attach, adap->fe[0],
@@ -911,10 +918,43 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
                /* fc0013 also supports signal strength reading */
                adap->fe[0]->ops.read_signal_strength =
                                adap->fe[0]->ops.tuner_ops.get_rf_strength;
-               return 0;
-       case TUNER_RTL2832_E4000:
-               fe = dvb_attach(e4000_attach, adap->fe[0], &d->i2c_adap,
-                               &rtl2832u_e4000_config);
+
+               /* attach SDR */
+               dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+                               &rtl28xxu_rtl2832_fc0013_config, NULL);
+               break;
+       case TUNER_RTL2832_E4000: {
+                       struct v4l2_subdev *sd;
+                       struct i2c_adapter *i2c_adap_internal =
+                                       rtl2832_get_private_i2c_adapter(adap->fe[0]);
+                       struct e4000_config e4000_config = {
+                               .fe = adap->fe[0],
+                               .clock = 28800000,
+                       };
+
+                       strlcpy(info.type, "e4000", I2C_NAME_SIZE);
+                       info.addr = 0x64;
+                       info.platform_data = &e4000_config;
+
+                       request_module(info.type);
+                       client = i2c_new_device(priv->demod_i2c_adapter, &info);
+                       if (client == NULL || client->dev.driver == NULL)
+                               break;
+
+                       if (!try_module_get(client->dev.driver->owner)) {
+                               i2c_unregister_device(client);
+                               break;
+                       }
+
+                       priv->client = client;
+                       sd = i2c_get_clientdata(client);
+                       i2c_set_adapdata(i2c_adap_internal, d);
+
+                       /* attach SDR */
+                       dvb_attach(rtl2832_sdr_attach, adap->fe[0],
+                                       i2c_adap_internal,
+                                       &rtl28xxu_rtl2832_e4000_config, sd);
+               }
                break;
        case TUNER_RTL2832_FC2580:
                fe = dvb_attach(fc2580_attach, adap->fe[0], &d->i2c_adap,
@@ -940,6 +980,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
                /* Use tuner to get the signal strength */
                adap->fe[0]->ops.read_signal_strength =
                                adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+               /* attach SDR */
+               dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+                               &rtl28xxu_rtl2832_r820t_config, NULL);
                break;
        case TUNER_RTL2832_R828D:
                /* power off mn88472 demod on GPIO0 */
@@ -963,12 +1007,11 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
                                adap->fe[0]->ops.tuner_ops.get_rf_strength;
                break;
        default:
-               fe = NULL;
                dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
                                priv->tuner);
        }
 
-       if (fe == NULL) {
+       if (fe == NULL && priv->client == NULL) {
                ret = -ENODEV;
                goto err;
        }
@@ -1013,6 +1056,22 @@ err:
        return ret;
 }
 
+static void rtl28xxu_exit(struct dvb_usb_device *d)
+{
+       struct rtl28xxu_priv *priv = d->priv;
+       struct i2c_client *client = priv->client;
+
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       /* remove I2C tuner */
+       if (client) {
+               module_put(client->dev.driver->owner);
+               i2c_unregister_device(client);
+       }
+
+       return;
+}
+
 static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
        int ret;
@@ -1322,6 +1381,10 @@ err:
 static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
                struct dvb_usb_rc *rc)
 {
+       /* disable IR interrupts in order to avoid SDR sample loss */
+       if (rtl28xxu_disable_rc)
+               return rtl28xx_wr_reg(d, IR_RX_IE, 0x00);
+
        /* load empty to enable rc */
        if (!rc->map_name)
                rc->map_name = RC_MAP_EMPTY;
@@ -1371,6 +1434,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
        .frontend_attach = rtl2832u_frontend_attach,
        .tuner_attach = rtl2832u_tuner_attach,
        .init = rtl28xxu_init,
+       .exit = rtl28xxu_exit,
        .get_rc_config = rtl2832u_get_rc_config,
 
        .num_adapters = 1,
@@ -1382,6 +1446,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
 };
 
 static const struct usb_device_id rtl28xxu_id_table[] = {
+       /* RTL2831U devices: */
        { DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U,
                &rtl2831u_props, "Realtek RTL2831U reference design", NULL) },
        { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT,
@@ -1389,6 +1454,7 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
        { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2,
                &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) },
 
+       /* RTL2832U devices: */
        { DVB_USB_DEVICE(USB_VID_REALTEK, 0x2832,
                &rtl2832u_props, "Realtek RTL2832U reference design", NULL) },
        { DVB_USB_DEVICE(USB_VID_REALTEK, 0x2838,
@@ -1401,6 +1467,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
                &rtl2832u_props, "TerraTec NOXON DAB Stick", NULL) },
        { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV2,
                &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 2)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV3,
+               &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 3)", NULL) },
        { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TREKSTOR_TERRES_2_0,
                &rtl2832u_props, "Trekstor DVB-T Stick Terres 2.0", NULL) },
        { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1101,
@@ -1429,7 +1497,10 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
                &rtl2832u_props, "Leadtek WinFast DTV Dongle mini", NULL) },
        { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
                &rtl2832u_props, "Crypto ReDi PC 50 A", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KYE, 0x707f,
+               &rtl2832u_props, "Genius TVGo DVB-T03", NULL) },
 
+       /* RTL2832P devices: */
        { DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131,
                &rtl2832u_props, "Astrometa DVB-T2", NULL) },
        { }