1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Driver for the Conexant CX23885/7/8 PCIe bridge 4 * 5 * Infrared device support routines - non-input, non-vl42_subdev routines 6 * 7 * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> 8 */ 9 10 #include "cx23885.h" 11 #include "cx23885-ir.h" 12 #include "cx23885-input.h" 13 14 #include <media/v4l2-device.h> 15 16 #define CX23885_IR_RX_FIFO_SERVICE_REQ 0 17 #define CX23885_IR_RX_END_OF_RX_DETECTED 1 18 #define CX23885_IR_RX_HW_FIFO_OVERRUN 2 19 #define CX23885_IR_RX_SW_FIFO_OVERRUN 3 20 21 #define CX23885_IR_TX_FIFO_SERVICE_REQ 0 22 23 24 void cx23885_ir_rx_work_handler(struct work_struct *work) 25 { 26 struct cx23885_dev *dev = 27 container_of(work, struct cx23885_dev, ir_rx_work); 28 u32 events = 0; 29 unsigned long *notifications = &dev->ir_rx_notifications; 30 31 if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications)) 32 events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; 33 if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications)) 34 events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; 35 if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications)) 36 events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; 37 if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications)) 38 events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; 39 40 if (events == 0) 41 return; 42 43 if (dev->kernel_ir) 44 cx23885_input_rx_work_handler(dev, events); 45 } 46 47 void cx23885_ir_tx_work_handler(struct work_struct *work) 48 { 49 struct cx23885_dev *dev = 50 container_of(work, struct cx23885_dev, ir_tx_work); 51 u32 events = 0; 52 unsigned long *notifications = &dev->ir_tx_notifications; 53 54 if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications)) 55 events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; 56 57 if (events == 0) 58 return; 59 60 } 61 62 /* Possibly called in an IRQ context */ 63 void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) 64 { 65 struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); 66 unsigned long *notifications = &dev->ir_rx_notifications; 67 68 if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ) 69 set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications); 70 if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED) 71 set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications); 72 if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN) 73 set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications); 74 if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN) 75 set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications); 76 77 /* 78 * For the integrated AV core, we are already in a workqueue context. 79 * For the CX23888 integrated IR, we are in an interrupt context. 80 */ 81 if (sd == dev->sd_cx25840) 82 cx23885_ir_rx_work_handler(&dev->ir_rx_work); 83 else 84 schedule_work(&dev->ir_rx_work); 85 } 86 87 /* Possibly called in an IRQ context */ 88 void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) 89 { 90 struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); 91 unsigned long *notifications = &dev->ir_tx_notifications; 92 93 if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ) 94 set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications); 95 96 /* 97 * For the integrated AV core, we are already in a workqueue context. 98 * For the CX23888 integrated IR, we are in an interrupt context. 99 */ 100 if (sd == dev->sd_cx25840) 101 cx23885_ir_tx_work_handler(&dev->ir_tx_work); 102 else 103 schedule_work(&dev->ir_tx_work); 104 } 105