162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for the Conexant CX23885/7/8 PCIe bridge 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Infrared device support routines - non-input, non-vl42_subdev routines 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "cx23885.h" 1162306a36Sopenharmony_ci#include "cx23885-ir.h" 1262306a36Sopenharmony_ci#include "cx23885-input.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <media/v4l2-device.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define CX23885_IR_RX_FIFO_SERVICE_REQ 0 1762306a36Sopenharmony_ci#define CX23885_IR_RX_END_OF_RX_DETECTED 1 1862306a36Sopenharmony_ci#define CX23885_IR_RX_HW_FIFO_OVERRUN 2 1962306a36Sopenharmony_ci#define CX23885_IR_RX_SW_FIFO_OVERRUN 3 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define CX23885_IR_TX_FIFO_SERVICE_REQ 0 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_civoid cx23885_ir_rx_work_handler(struct work_struct *work) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct cx23885_dev *dev = 2762306a36Sopenharmony_ci container_of(work, struct cx23885_dev, ir_rx_work); 2862306a36Sopenharmony_ci u32 events = 0; 2962306a36Sopenharmony_ci unsigned long *notifications = &dev->ir_rx_notifications; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications)) 3262306a36Sopenharmony_ci events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; 3362306a36Sopenharmony_ci if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications)) 3462306a36Sopenharmony_ci events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; 3562306a36Sopenharmony_ci if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications)) 3662306a36Sopenharmony_ci events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; 3762306a36Sopenharmony_ci if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications)) 3862306a36Sopenharmony_ci events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (events == 0) 4162306a36Sopenharmony_ci return; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (dev->kernel_ir) 4462306a36Sopenharmony_ci cx23885_input_rx_work_handler(dev, events); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_civoid cx23885_ir_tx_work_handler(struct work_struct *work) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct cx23885_dev *dev = 5062306a36Sopenharmony_ci container_of(work, struct cx23885_dev, ir_tx_work); 5162306a36Sopenharmony_ci u32 events = 0; 5262306a36Sopenharmony_ci unsigned long *notifications = &dev->ir_tx_notifications; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications)) 5562306a36Sopenharmony_ci events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (events == 0) 5862306a36Sopenharmony_ci return; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Possibly called in an IRQ context */ 6362306a36Sopenharmony_civoid cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); 6662306a36Sopenharmony_ci unsigned long *notifications = &dev->ir_rx_notifications; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ) 6962306a36Sopenharmony_ci set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications); 7062306a36Sopenharmony_ci if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED) 7162306a36Sopenharmony_ci set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications); 7262306a36Sopenharmony_ci if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN) 7362306a36Sopenharmony_ci set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications); 7462306a36Sopenharmony_ci if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN) 7562306a36Sopenharmony_ci set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* 7862306a36Sopenharmony_ci * For the integrated AV core, we are already in a workqueue context. 7962306a36Sopenharmony_ci * For the CX23888 integrated IR, we are in an interrupt context. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci if (sd == dev->sd_cx25840) 8262306a36Sopenharmony_ci cx23885_ir_rx_work_handler(&dev->ir_rx_work); 8362306a36Sopenharmony_ci else 8462306a36Sopenharmony_ci schedule_work(&dev->ir_rx_work); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* Possibly called in an IRQ context */ 8862306a36Sopenharmony_civoid cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); 9162306a36Sopenharmony_ci unsigned long *notifications = &dev->ir_tx_notifications; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ) 9462306a36Sopenharmony_ci set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* 9762306a36Sopenharmony_ci * For the integrated AV core, we are already in a workqueue context. 9862306a36Sopenharmony_ci * For the CX23888 integrated IR, we are in an interrupt context. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci if (sd == dev->sd_cx25840) 10162306a36Sopenharmony_ci cx23885_ir_tx_work_handler(&dev->ir_tx_work); 10262306a36Sopenharmony_ci else 10362306a36Sopenharmony_ci schedule_work(&dev->ir_tx_work); 10462306a36Sopenharmony_ci} 105