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