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: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Родитель
d6b1850d3c
Коммит
98d109f90f
|
@ -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, ¶ms);
|
||||
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);
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
||||
|
|
|
@ -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, ¶ms);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче