18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for the Conexant CX23885/7/8 PCIe bridge 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Infrared device support routines - non-input, non-vl42_subdev routines 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "cx23885.h" 118c2ecf20Sopenharmony_ci#include "cx23885-ir.h" 128c2ecf20Sopenharmony_ci#include "cx23885-input.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define CX23885_IR_RX_FIFO_SERVICE_REQ 0 178c2ecf20Sopenharmony_ci#define CX23885_IR_RX_END_OF_RX_DETECTED 1 188c2ecf20Sopenharmony_ci#define CX23885_IR_RX_HW_FIFO_OVERRUN 2 198c2ecf20Sopenharmony_ci#define CX23885_IR_RX_SW_FIFO_OVERRUN 3 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define CX23885_IR_TX_FIFO_SERVICE_REQ 0 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_civoid cx23885_ir_rx_work_handler(struct work_struct *work) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct cx23885_dev *dev = 278c2ecf20Sopenharmony_ci container_of(work, struct cx23885_dev, ir_rx_work); 288c2ecf20Sopenharmony_ci u32 events = 0; 298c2ecf20Sopenharmony_ci unsigned long *notifications = &dev->ir_rx_notifications; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications)) 328c2ecf20Sopenharmony_ci events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; 338c2ecf20Sopenharmony_ci if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications)) 348c2ecf20Sopenharmony_ci events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; 358c2ecf20Sopenharmony_ci if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications)) 368c2ecf20Sopenharmony_ci events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; 378c2ecf20Sopenharmony_ci if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications)) 388c2ecf20Sopenharmony_ci events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (events == 0) 418c2ecf20Sopenharmony_ci return; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (dev->kernel_ir) 448c2ecf20Sopenharmony_ci cx23885_input_rx_work_handler(dev, events); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_civoid cx23885_ir_tx_work_handler(struct work_struct *work) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct cx23885_dev *dev = 508c2ecf20Sopenharmony_ci container_of(work, struct cx23885_dev, ir_tx_work); 518c2ecf20Sopenharmony_ci u32 events = 0; 528c2ecf20Sopenharmony_ci unsigned long *notifications = &dev->ir_tx_notifications; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications)) 558c2ecf20Sopenharmony_ci events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (events == 0) 588c2ecf20Sopenharmony_ci return; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* Possibly called in an IRQ context */ 638c2ecf20Sopenharmony_civoid cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); 668c2ecf20Sopenharmony_ci unsigned long *notifications = &dev->ir_rx_notifications; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ) 698c2ecf20Sopenharmony_ci set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications); 708c2ecf20Sopenharmony_ci if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED) 718c2ecf20Sopenharmony_ci set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications); 728c2ecf20Sopenharmony_ci if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN) 738c2ecf20Sopenharmony_ci set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications); 748c2ecf20Sopenharmony_ci if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN) 758c2ecf20Sopenharmony_ci set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * For the integrated AV core, we are already in a workqueue context. 798c2ecf20Sopenharmony_ci * For the CX23888 integrated IR, we are in an interrupt context. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci if (sd == dev->sd_cx25840) 828c2ecf20Sopenharmony_ci cx23885_ir_rx_work_handler(&dev->ir_rx_work); 838c2ecf20Sopenharmony_ci else 848c2ecf20Sopenharmony_ci schedule_work(&dev->ir_rx_work); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* Possibly called in an IRQ context */ 888c2ecf20Sopenharmony_civoid cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); 918c2ecf20Sopenharmony_ci unsigned long *notifications = &dev->ir_tx_notifications; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ) 948c2ecf20Sopenharmony_ci set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* 978c2ecf20Sopenharmony_ci * For the integrated AV core, we are already in a workqueue context. 988c2ecf20Sopenharmony_ci * For the CX23888 integrated IR, we are in an interrupt context. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci if (sd == dev->sd_cx25840) 1018c2ecf20Sopenharmony_ci cx23885_ir_tx_work_handler(&dev->ir_tx_work); 1028c2ecf20Sopenharmony_ci else 1038c2ecf20Sopenharmony_ci schedule_work(&dev->ir_tx_work); 1048c2ecf20Sopenharmony_ci} 105