1 /*
2  *  Driver for the Conexant CX23885/7/8 PCIe bridge
3  *
4  *  Infrared device support routines - non-input, non-vl42_subdev routines
5  *
6  *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.net>
7  *
8  *  This program is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU General Public License
10  *  as published by the Free Software Foundation; either version 2
11  *  of the License, or (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  *  02110-1301, USA.
22  */
23 
24 #include <media/v4l2-device.h>
25 
26 #include "cx23885.h"
27 #include "cx23885-ir.h"
28 #include "cx23885-input.h"
29 
30 #define CX23885_IR_RX_FIFO_SERVICE_REQ		0
31 #define CX23885_IR_RX_END_OF_RX_DETECTED	1
32 #define CX23885_IR_RX_HW_FIFO_OVERRUN		2
33 #define CX23885_IR_RX_SW_FIFO_OVERRUN		3
34 
35 #define CX23885_IR_TX_FIFO_SERVICE_REQ		0
36 
37 
38 void cx23885_ir_rx_work_handler(struct work_struct *work)
39 {
40 	struct cx23885_dev *dev =
41 			     container_of(work, struct cx23885_dev, ir_rx_work);
42 	u32 events = 0;
43 	unsigned long *notifications = &dev->ir_rx_notifications;
44 
45 	if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications))
46 		events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
47 	if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications))
48 		events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
49 	if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications))
50 		events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
51 	if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications))
52 		events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
53 
54 	if (events == 0)
55 		return;
56 
57 	if (dev->kernel_ir)
58 		cx23885_input_rx_work_handler(dev, events);
59 }
60 
61 void cx23885_ir_tx_work_handler(struct work_struct *work)
62 {
63 	struct cx23885_dev *dev =
64 			     container_of(work, struct cx23885_dev, ir_tx_work);
65 	u32 events = 0;
66 	unsigned long *notifications = &dev->ir_tx_notifications;
67 
68 	if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications))
69 		events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
70 
71 	if (events == 0)
72 		return;
73 
74 }
75 
76 /* Possibly called in an IRQ context */
77 void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
78 {
79 	struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
80 	unsigned long *notifications = &dev->ir_rx_notifications;
81 
82 	if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ)
83 		set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications);
84 	if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED)
85 		set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications);
86 	if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN)
87 		set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications);
88 	if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN)
89 		set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications);
90 
91 	/*
92 	 * For the integrated AV core, we are already in a workqueue context.
93 	 * For the CX23888 integrated IR, we are in an interrupt context.
94 	 */
95 	if (sd == dev->sd_cx25840)
96 		cx23885_ir_rx_work_handler(&dev->ir_rx_work);
97 	else
98 		schedule_work(&dev->ir_rx_work);
99 }
100 
101 /* Possibly called in an IRQ context */
102 void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
103 {
104 	struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
105 	unsigned long *notifications = &dev->ir_tx_notifications;
106 
107 	if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ)
108 		set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications);
109 
110 	/*
111 	 * For the integrated AV core, we are already in a workqueue context.
112 	 * For the CX23888 integrated IR, we are in an interrupt context.
113 	 */
114 	if (sd == dev->sd_cx25840)
115 		cx23885_ir_tx_work_handler(&dev->ir_tx_work);
116 	else
117 		schedule_work(&dev->ir_tx_work);
118 }
119