V4L/DVB: cx23885: Add preliminary IR Rx support for the HVR-1250 and TeVii S470
authorAndy Walls <awalls@md.metrocast.net>
Mon, 19 Jul 2010 03:41:41 +0000 (00:41 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 9 Aug 2010 02:42:55 +0000 (23:42 -0300)
Add initial IR Rx support using the intergrated IR controller in the
A/V core of the CX23885 bridge chip.

This initial support is flawed in that I2C transactions should not
be performed in a hard irq context.  That will be fixed in a
follow on patch.

The TeVii S470 support is reported to generate perptual interrupts
that renders a user' system nearly unusable.  The TeVii S470 IR
will be disabled by default in a follow on patch.

Signed-off-by: Andy Walls <awalls@md.metrocast.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-input.c
drivers/media/video/cx23885/cx23885-reg.h

index b083e5dfb715b020e79deb5a3c6e817607f79cbf..294a7530caf7b14c2c71d4ac0042b0386a77b94f 100644 (file)
@@ -962,7 +962,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
 
 int cx23885_ir_init(struct cx23885_dev *dev)
 {
-       static struct v4l2_subdev_io_pin_config ir_pin_cfg[] = {
+       static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = {
                {
                        .flags    = V4L2_SUBDEV_IO_PIN_INPUT,
                        .pin      = CX23885_PIN_IR_RX_GPIO19,
@@ -977,12 +977,22 @@ int cx23885_ir_init(struct cx23885_dev *dev)
                        .strength = CX25840_PIN_DRIVE_MEDIUM,
                }
        };
-       const size_t ir_pin_cfg_count = ARRAY_SIZE(ir_pin_cfg);
+       const size_t ir_rxtx_pin_cfg_count = ARRAY_SIZE(ir_rxtx_pin_cfg);
+
+       static struct v4l2_subdev_io_pin_config ir_rx_pin_cfg[] = {
+               {
+                       .flags    = V4L2_SUBDEV_IO_PIN_INPUT,
+                       .pin      = CX23885_PIN_IR_RX_GPIO19,
+                       .function = CX23885_PAD_IR_RX,
+                       .value    = 0,
+                       .strength = CX25840_PIN_DRIVE_MEDIUM,
+               }
+       };
+       const size_t ir_rx_pin_cfg_count = ARRAY_SIZE(ir_rx_pin_cfg);
 
        struct v4l2_subdev_ir_parameters params;
        int ret = 0;
        switch (dev->board) {
-       case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
@@ -1001,7 +1011,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
                        break;
                dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
                v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
-                                ir_pin_cfg_count, ir_pin_cfg);
+                                ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
                dev->pci_irqmask |= PCI_MSK_IR;
                /*
                 * For these boards we need to invert the Tx output via the
@@ -1015,6 +1025,26 @@ int cx23885_ir_init(struct cx23885_dev *dev)
                params.shutdown = true;
                v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
                break;
+       case CX23885_BOARD_TEVII_S470:
+               dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
+               if (dev->sd_ir == NULL) {
+                       ret = -ENODEV;
+                       break;
+               }
+               v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+                                ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+               dev->pci_irqmask |= PCI_MSK_AV_CORE;
+               break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1250:
+               dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
+               if (dev->sd_ir == NULL) {
+                       ret = -ENODEV;
+                       break;
+               }
+               v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+                                ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
+               dev->pci_irqmask |= PCI_MSK_AV_CORE;
+               break;
        case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
                request_module("ir-kbd-i2c");
                break;
@@ -1033,6 +1063,13 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
                cx23888_ir_remove(dev);
                dev->sd_ir = NULL;
                break;
+       case CX23885_BOARD_TEVII_S470:
+       case CX23885_BOARD_HAUPPAUGE_HVR1250:
+               dev->pci_irqmask &= ~PCI_MSK_AV_CORE;
+               cx_clear(PCI_INT_MSK, PCI_MSK_AV_CORE);
+               /* sd_ir is a duplicate pointer to the AV Core, just clear it */
+               dev->sd_ir = NULL;
+               break;
        }
 }
 
@@ -1044,6 +1081,11 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
                if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_IR))
                        cx_set(PCI_INT_MSK, PCI_MSK_IR);
                break;
+       case CX23885_BOARD_TEVII_S470:
+       case CX23885_BOARD_HAUPPAUGE_HVR1250:
+               if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_AV_CORE))
+                       cx_set(PCI_INT_MSK, PCI_MSK_AV_CORE);
+               break;
        }
 }
 
@@ -1189,6 +1231,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_MAGICPRO_PROHDTVE2:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
+       case CX23885_BOARD_TEVII_S470:
+       case CX23885_BOARD_HAUPPAUGE_HVR1250:
                dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
                                &dev->i2c_bus[2].i2c_adap,
                                "cx25840", "cx25840", 0x88 >> 1, NULL);
index a74c0ab859ed0823904f1489d186585a2bdcde2c..93e7afb98889c8d1e49218b74076392c67a289e5 100644 (file)
@@ -1650,7 +1650,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
        u32 ts1_status, ts1_mask;
        u32 ts2_status, ts2_mask;
        int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
-       bool ir_handled = false;
+       bool subdev_handled;
 
        pci_status = cx_read(PCI_INT_STAT);
        pci_mask = cx_read(PCI_INT_MSK);
@@ -1681,7 +1681,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
                          PCI_MSK_VID_C   | PCI_MSK_VID_B   | PCI_MSK_VID_A   |
                          PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT |
                          PCI_MSK_GPIO0   | PCI_MSK_GPIO1   |
-                         PCI_MSK_IR)) {
+                         PCI_MSK_AV_CORE | PCI_MSK_IR)) {
 
                if (pci_status & PCI_MSK_RISC_RD)
                        dprintk(7, " (PCI_MSK_RISC_RD   0x%08x)\n",
@@ -1731,6 +1731,10 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
                        dprintk(7, " (PCI_MSK_GPIO1     0x%08x)\n",
                                PCI_MSK_GPIO1);
 
+               if (pci_status & PCI_MSK_AV_CORE)
+                       dprintk(7, " (PCI_MSK_AV_CORE   0x%08x)\n",
+                               PCI_MSK_AV_CORE);
+
                if (pci_status & PCI_MSK_IR)
                        dprintk(7, " (PCI_MSK_IR        0x%08x)\n",
                                PCI_MSK_IR);
@@ -1765,9 +1769,19 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
                handled += cx23885_video_irq(dev, vida_status);
 
        if (pci_status & PCI_MSK_IR) {
+               subdev_handled = false;
                v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine,
-                                pci_status, &ir_handled);
-               if (ir_handled)
+                                pci_status, &subdev_handled);
+               if (subdev_handled)
+                       handled++;
+       }
+
+       if (pci_status & PCI_MSK_AV_CORE) {
+               subdev_handled = false;
+               v4l2_subdev_call(dev->sd_cx25840,
+                                core, interrupt_service_routine,
+                                pci_status, &subdev_handled);
+               if (subdev_handled)
                        handled++;
        }
 
index 496d751ffdc86f9f725eb1da3e2e2373c2d3be6f..3f924e21b9575f7d67d99d71c8585d41828aabfe 100644 (file)
@@ -99,8 +99,10 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
+       case CX23885_BOARD_TEVII_S470:
+       case CX23885_BOARD_HAUPPAUGE_HVR1250:
                /*
-                * The only board we handle right now.  However other boards
+                * The only boards we handle right now.  However other boards
                 * using the CX2388x integrated IR controller should be similar
                 */
                break;
@@ -148,6 +150,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
+       case CX23885_BOARD_HAUPPAUGE_HVR1250:
                /*
                 * The IR controller on this board only returns pulse widths.
                 * Any other mode setting will fail to set up the device.
@@ -172,6 +175,37 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
                 */
                params.invert_level = true;
                break;
+       case CX23885_BOARD_TEVII_S470:
+               /*
+                * The IR controller on this board only returns pulse widths.
+                * Any other mode setting will fail to set up the device.
+                */
+               params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+               params.enable = true;
+               params.interrupt_enable = true;
+               params.shutdown = false;
+
+               /* Setup for a standard NEC protocol */
+               params.carrier_freq = 37917; /* Hz, 455 kHz/12 for NEC */
+               params.carrier_range_lower = 33000; /* Hz */
+               params.carrier_range_upper = 43000; /* Hz */
+               params.duty_cycle = 33; /* percent, 33 percent for NEC */
+
+               /*
+                * NEC max pulse width: (64/3)/(455 kHz/12) * 16 nec_units
+                * (64/3)/(455 kHz/12) * 16 nec_units * 1.375 = 12378022 ns
+                */
+               params.max_pulse_width = 12378022; /* ns */
+
+               /*
+                * NEC noise filter min width: (64/3)/(455 kHz/12) * 1 nec_unit
+                * (64/3)/(455 kHz/12) * 1 nec_units * 0.625 = 351648 ns
+                */
+               params.noise_filter_min_width = 351648; /* ns */
+
+               params.modulation = false;
+               params.invert_level = true;
+               break;
        }
        v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
        return 0;
@@ -244,12 +278,20 @@ int cx23885_input_init(struct cx23885_dev *dev)
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
-               /* Integrated CX23888 IR controller */
+       case CX23885_BOARD_HAUPPAUGE_HVR1250:
+               /* Integrated CX2388[58] IR controller */
                driver_type = RC_DRIVER_IR_RAW;
                allowed_protos = IR_TYPE_ALL;
                /* The grey Hauppauge RC-5 remote */
                rc_map = RC_MAP_RC5_HAUPPAUGE_NEW;
                break;
+       case CX23885_BOARD_TEVII_S470:
+               /* Integrated CX23885 IR controller */
+               driver_type = RC_DRIVER_IR_RAW;
+               allowed_protos = IR_TYPE_ALL;
+               /* A guess at the remote */
+               rc_map = RC_MAP_TEVII_NEC;
+               break;
        default:
                return -ENODEV;
        }
index c0bc9a068954b91deb4e2c1f0c467693555b9ec5..a28772db11f0e0da220f85142febbf0d0b235ddb 100644 (file)
@@ -213,6 +213,7 @@ Channel manager Data Structure entry = 20 DWORD
 #define DEV_CNTRL2     0x00040000
 
 #define PCI_MSK_IR        (1 << 28)
+#define PCI_MSK_AV_CORE   (1 << 27)
 #define PCI_MSK_GPIO1     (1 << 24)
 #define PCI_MSK_GPIO0     (1 << 23)
 #define PCI_MSK_APB_DMA   (1 << 12)