提交 98d109f9 编写于 作者: A Andy Walls 提交者: Mauro Carvalho Chehab

V4L/DVB: cx23885: Add preliminary IR Rx support for the HVR-1250 and TeVii S470

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: NAndy Walls <awalls@md.metrocast.net>
Signed-off-by: NMauro Carvalho Chehab <mchehab@redhat.com>
上级 d6b1850d
...@@ -962,7 +962,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) ...@@ -962,7 +962,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
int cx23885_ir_init(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, .flags = V4L2_SUBDEV_IO_PIN_INPUT,
.pin = CX23885_PIN_IR_RX_GPIO19, .pin = CX23885_PIN_IR_RX_GPIO19,
...@@ -977,12 +977,22 @@ int cx23885_ir_init(struct cx23885_dev *dev) ...@@ -977,12 +977,22 @@ int cx23885_ir_init(struct cx23885_dev *dev)
.strength = CX25840_PIN_DRIVE_MEDIUM, .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; struct v4l2_subdev_ir_parameters params;
int ret = 0; int ret = 0;
switch (dev->board) { switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800:
...@@ -1001,7 +1011,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) ...@@ -1001,7 +1011,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
break; break;
dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, 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; dev->pci_irqmask |= PCI_MSK_IR;
/* /*
* For these boards we need to invert the Tx output via the * For these boards we need to invert the Tx output via the
...@@ -1015,6 +1025,26 @@ int cx23885_ir_init(struct cx23885_dev *dev) ...@@ -1015,6 +1025,26 @@ int cx23885_ir_init(struct cx23885_dev *dev)
params.shutdown = true; params.shutdown = true;
v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params); v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
break; 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: case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
request_module("ir-kbd-i2c"); request_module("ir-kbd-i2c");
break; break;
...@@ -1033,6 +1063,13 @@ void cx23885_ir_fini(struct cx23885_dev *dev) ...@@ -1033,6 +1063,13 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
cx23888_ir_remove(dev); cx23888_ir_remove(dev);
dev->sd_ir = NULL; dev->sd_ir = NULL;
break; 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) ...@@ -1044,6 +1081,11 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_IR)) if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_IR))
cx_set(PCI_INT_MSK, PCI_MSK_IR); cx_set(PCI_INT_MSK, PCI_MSK_IR);
break; 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) ...@@ -1189,6 +1231,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_MAGICPRO_PROHDTVE2: case CX23885_BOARD_MAGICPRO_PROHDTVE2:
case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR1290:
case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: 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->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap, &dev->i2c_bus[2].i2c_adap,
"cx25840", "cx25840", 0x88 >> 1, NULL); "cx25840", "cx25840", 0x88 >> 1, NULL);
......
...@@ -1650,7 +1650,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) ...@@ -1650,7 +1650,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
u32 ts1_status, ts1_mask; u32 ts1_status, ts1_mask;
u32 ts2_status, ts2_mask; u32 ts2_status, ts2_mask;
int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; 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_status = cx_read(PCI_INT_STAT);
pci_mask = cx_read(PCI_INT_MSK); pci_mask = cx_read(PCI_INT_MSK);
...@@ -1681,7 +1681,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) ...@@ -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_VID_C | PCI_MSK_VID_B | PCI_MSK_VID_A |
PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT | PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT |
PCI_MSK_GPIO0 | PCI_MSK_GPIO1 | PCI_MSK_GPIO0 | PCI_MSK_GPIO1 |
PCI_MSK_IR)) { PCI_MSK_AV_CORE | PCI_MSK_IR)) {
if (pci_status & PCI_MSK_RISC_RD) if (pci_status & PCI_MSK_RISC_RD)
dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n",
...@@ -1731,6 +1731,10 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) ...@@ -1731,6 +1731,10 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n", dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n",
PCI_MSK_GPIO1); 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) if (pci_status & PCI_MSK_IR)
dprintk(7, " (PCI_MSK_IR 0x%08x)\n", dprintk(7, " (PCI_MSK_IR 0x%08x)\n",
PCI_MSK_IR); PCI_MSK_IR);
...@@ -1765,9 +1769,19 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) ...@@ -1765,9 +1769,19 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
handled += cx23885_video_irq(dev, vida_status); handled += cx23885_video_irq(dev, vida_status);
if (pci_status & PCI_MSK_IR) { if (pci_status & PCI_MSK_IR) {
subdev_handled = false;
v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine, v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine,
pci_status, &ir_handled); pci_status, &subdev_handled);
if (ir_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++; handled++;
} }
......
...@@ -99,8 +99,10 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) ...@@ -99,8 +99,10 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
switch (dev->board) { switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290: 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 * using the CX2388x integrated IR controller should be similar
*/ */
break; break;
...@@ -148,6 +150,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev) ...@@ -148,6 +150,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
switch (dev->board) { switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR1290:
case CX23885_BOARD_HAUPPAUGE_HVR1250:
/* /*
* The IR controller on this board only returns pulse widths. * The IR controller on this board only returns pulse widths.
* Any other mode setting will fail to set up the device. * 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) ...@@ -172,6 +175,37 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
*/ */
params.invert_level = true; params.invert_level = true;
break; 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); v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
return 0; return 0;
...@@ -244,12 +278,20 @@ int cx23885_input_init(struct cx23885_dev *dev) ...@@ -244,12 +278,20 @@ int cx23885_input_init(struct cx23885_dev *dev)
switch (dev->board) { switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290: 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; driver_type = RC_DRIVER_IR_RAW;
allowed_protos = IR_TYPE_ALL; allowed_protos = IR_TYPE_ALL;
/* The grey Hauppauge RC-5 remote */ /* The grey Hauppauge RC-5 remote */
rc_map = RC_MAP_RC5_HAUPPAUGE_NEW; rc_map = RC_MAP_RC5_HAUPPAUGE_NEW;
break; 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: default:
return -ENODEV; return -ENODEV;
} }
......
...@@ -213,6 +213,7 @@ Channel manager Data Structure entry = 20 DWORD ...@@ -213,6 +213,7 @@ Channel manager Data Structure entry = 20 DWORD
#define DEV_CNTRL2 0x00040000 #define DEV_CNTRL2 0x00040000
#define PCI_MSK_IR (1 << 28) #define PCI_MSK_IR (1 << 28)
#define PCI_MSK_AV_CORE (1 << 27)
#define PCI_MSK_GPIO1 (1 << 24) #define PCI_MSK_GPIO1 (1 << 24)
#define PCI_MSK_GPIO0 (1 << 23) #define PCI_MSK_GPIO0 (1 << 23)
#define PCI_MSK_APB_DMA (1 << 12) #define PCI_MSK_APB_DMA (1 << 12)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册