blob: f81c2f9f0e9235477539ff117b857e10d8b785a8 [file] [log] [blame]
Andy Wallsdbda8f72009-09-27 20:55:41 -03001/*
2 * Driver for the Conexant CX23885/7/8 PCIe bridge
3 *
4 * Infrared remote control input device
5 *
6 * Most of this file is
7 *
Andy Walls6afdeaf2010-05-23 18:53:35 -03008 * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
Andy Wallsdbda8f72009-09-27 20:55:41 -03009 *
10 * However, the cx23885_input_{init,fini} functions contained herein are
11 * derived from Linux kernel files linux/media/video/.../...-input.c marked as:
12 *
13 * Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
14 * Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
15 * Markus Rechberger <mrechberger@gmail.com>
16 * Mauro Carvalho Chehab <mchehab@infradead.org>
17 * Sascha Sommer <saschasommer@freenet.de>
18 * Copyright (C) 2004, 2005 Chris Pascoe
19 * Copyright (C) 2003, 2004 Gerd Knorr
20 * Copyright (C) 2003 Pavel Machek
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version 2
25 * of the License, or (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
Andy Wallsdbda8f72009-09-27 20:55:41 -030031 */
32
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Mauro Carvalho Chehab6bda9642010-11-17 13:28:38 -030034#include <media/rc-core.h>
Andy Wallsdbda8f72009-09-27 20:55:41 -030035#include <media/v4l2-subdev.h>
36
37#include "cx23885.h"
Mauro Carvalho Chehabada73ee2012-10-27 11:29:23 -030038#include "cx23885-input.h"
Andy Wallsdbda8f72009-09-27 20:55:41 -030039
Mauro Carvalho Chehab727e6252010-03-12 21:18:14 -030040#define MODULE_NAME "cx23885"
41
Andy Walls43c24072010-06-27 23:15:35 -030042static void cx23885_input_process_measurements(struct cx23885_dev *dev,
43 bool overrun)
Andy Wallsdbda8f72009-09-27 20:55:41 -030044{
Andy Walls43c24072010-06-27 23:15:35 -030045 struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir;
Andy Wallsdbda8f72009-09-27 20:55:41 -030046
Andy Walls43c24072010-06-27 23:15:35 -030047 ssize_t num;
Andy Wallsdbda8f72009-09-27 20:55:41 -030048 int count, i;
Andy Walls43c24072010-06-27 23:15:35 -030049 bool handle = false;
Andy Wallsc02e0d12010-08-01 02:18:13 -030050 struct ir_raw_event ir_core_event[64];
Andy Wallsdbda8f72009-09-27 20:55:41 -030051
52 do {
Andy Walls43c24072010-06-27 23:15:35 -030053 num = 0;
Andy Wallsc02e0d12010-08-01 02:18:13 -030054 v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event,
55 sizeof(ir_core_event), &num);
Andy Wallsdbda8f72009-09-27 20:55:41 -030056
Andy Wallsc02e0d12010-08-01 02:18:13 -030057 count = num / sizeof(struct ir_raw_event);
Andy Wallsdbda8f72009-09-27 20:55:41 -030058
Andy Walls43c24072010-06-27 23:15:35 -030059 for (i = 0; i < count; i++) {
David Härdemand8b4b582010-10-29 16:08:23 -030060 ir_raw_event_store(kernel_ir->rc,
Andy Wallsc02e0d12010-08-01 02:18:13 -030061 &ir_core_event[i]);
Andy Walls43c24072010-06-27 23:15:35 -030062 handle = true;
Andy Wallsdbda8f72009-09-27 20:55:41 -030063 }
Andy Wallsdbda8f72009-09-27 20:55:41 -030064 } while (num != 0);
Andy Walls43c24072010-06-27 23:15:35 -030065
66 if (overrun)
David Härdemand8b4b582010-10-29 16:08:23 -030067 ir_raw_event_reset(kernel_ir->rc);
Andy Walls43c24072010-06-27 23:15:35 -030068 else if (handle)
David Härdemand8b4b582010-10-29 16:08:23 -030069 ir_raw_event_handle(kernel_ir->rc);
Andy Wallsdbda8f72009-09-27 20:55:41 -030070}
71
72void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
73{
74 struct v4l2_subdev_ir_parameters params;
75 int overrun, data_available;
76
77 if (dev->sd_ir == NULL || events == 0)
78 return;
79
80 switch (dev->board) {
Andy Walls9b3d8ec2011-06-08 21:24:25 -030081 case CX23885_BOARD_HAUPPAUGE_HVR1270:
Andy Wallsdbda8f72009-09-27 20:55:41 -030082 case CX23885_BOARD_HAUPPAUGE_HVR1850:
Michael Krufky7fec6fe2009-11-11 15:46:09 -030083 case CX23885_BOARD_HAUPPAUGE_HVR1290:
Djuri Baars076f0e32012-07-28 09:01:38 -030084 case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
Andy Walls98d109f2010-07-19 00:41:41 -030085 case CX23885_BOARD_TEVII_S470:
86 case CX23885_BOARD_HAUPPAUGE_HVR1250:
Alfredo Jesús Delaitie5f670b2012-11-08 15:50:25 -030087 case CX23885_BOARD_MYGICA_X8507:
Luis Alvese6001482013-10-01 22:11:35 -030088 case CX23885_BOARD_TBS_6980:
89 case CX23885_BOARD_TBS_6981:
nibble.maxd11a3832014-09-29 11:17:36 -030090 case CX23885_BOARD_DVBSKY_T9580:
Andy Wallsdbda8f72009-09-27 20:55:41 -030091 /*
Andy Walls98d109f2010-07-19 00:41:41 -030092 * The only boards we handle right now. However other boards
Andy Wallsdbda8f72009-09-27 20:55:41 -030093 * using the CX2388x integrated IR controller should be similar
94 */
95 break;
96 default:
97 return;
98 }
99
100 overrun = events & (V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN |
101 V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN);
102
103 data_available = events & (V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED |
104 V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ);
105
106 if (overrun) {
107 /* If there was a FIFO overrun, stop the device */
108 v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
109 params.enable = false;
110 /* Mitigate race with cx23885_input_ir_stop() */
111 params.shutdown = atomic_read(&dev->ir_input_stopping);
112 v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
113 }
114
115 if (data_available)
Andy Walls43c24072010-06-27 23:15:35 -0300116 cx23885_input_process_measurements(dev, overrun);
Andy Wallsdbda8f72009-09-27 20:55:41 -0300117
118 if (overrun) {
119 /* If there was a FIFO overrun, clear & restart the device */
120 params.enable = true;
121 /* Mitigate race with cx23885_input_ir_stop() */
122 params.shutdown = atomic_read(&dev->ir_input_stopping);
123 v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
124 }
125}
126
Andy Walls43c24072010-06-27 23:15:35 -0300127static int cx23885_input_ir_start(struct cx23885_dev *dev)
Andy Wallsdbda8f72009-09-27 20:55:41 -0300128{
Andy Wallsdbda8f72009-09-27 20:55:41 -0300129 struct v4l2_subdev_ir_parameters params;
130
131 if (dev->sd_ir == NULL)
Andy Walls43c24072010-06-27 23:15:35 -0300132 return -ENODEV;
Andy Wallsdbda8f72009-09-27 20:55:41 -0300133
134 atomic_set(&dev->ir_input_stopping, 0);
135
Andy Wallsdbda8f72009-09-27 20:55:41 -0300136 v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
137 switch (dev->board) {
Andy Walls9b3d8ec2011-06-08 21:24:25 -0300138 case CX23885_BOARD_HAUPPAUGE_HVR1270:
Andy Wallsdbda8f72009-09-27 20:55:41 -0300139 case CX23885_BOARD_HAUPPAUGE_HVR1850:
Michael Krufky7fec6fe2009-11-11 15:46:09 -0300140 case CX23885_BOARD_HAUPPAUGE_HVR1290:
Andy Walls98d109f2010-07-19 00:41:41 -0300141 case CX23885_BOARD_HAUPPAUGE_HVR1250:
Alfredo Jesús Delaitie5f670b2012-11-08 15:50:25 -0300142 case CX23885_BOARD_MYGICA_X8507:
nibble.maxd11a3832014-09-29 11:17:36 -0300143 case CX23885_BOARD_DVBSKY_T9580:
Andy Wallsdbda8f72009-09-27 20:55:41 -0300144 /*
145 * The IR controller on this board only returns pulse widths.
146 * Any other mode setting will fail to set up the device.
147 */
148 params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
149 params.enable = true;
150 params.interrupt_enable = true;
151 params.shutdown = false;
152
153 /* Setup for baseband compatible with both RC-5 and RC-6A */
154 params.modulation = false;
155 /* RC-5: 2,222,222 ns = 1/36 kHz * 32 cycles * 2 marks * 1.25*/
156 /* RC-6A: 3,333,333 ns = 1/36 kHz * 16 cycles * 6 marks * 1.25*/
157 params.max_pulse_width = 3333333; /* ns */
158 /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
159 /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
160 params.noise_filter_min_width = 333333; /* ns */
161 /*
162 * This board has inverted receive sense:
163 * mark is received as low logic level;
164 * falling edges are detected as rising edges; etc.
165 */
Andy Walls5a28d9a2010-07-18 19:57:25 -0300166 params.invert_level = true;
Andy Wallsdbda8f72009-09-27 20:55:41 -0300167 break;
Djuri Baars076f0e32012-07-28 09:01:38 -0300168 case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
Andy Walls98d109f2010-07-19 00:41:41 -0300169 case CX23885_BOARD_TEVII_S470:
Luis Alvese6001482013-10-01 22:11:35 -0300170 case CX23885_BOARD_TBS_6980:
171 case CX23885_BOARD_TBS_6981:
Andy Walls98d109f2010-07-19 00:41:41 -0300172 /*
173 * The IR controller on this board only returns pulse widths.
174 * Any other mode setting will fail to set up the device.
175 */
176 params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
177 params.enable = true;
178 params.interrupt_enable = true;
179 params.shutdown = false;
180
181 /* Setup for a standard NEC protocol */
182 params.carrier_freq = 37917; /* Hz, 455 kHz/12 for NEC */
183 params.carrier_range_lower = 33000; /* Hz */
184 params.carrier_range_upper = 43000; /* Hz */
185 params.duty_cycle = 33; /* percent, 33 percent for NEC */
186
187 /*
188 * NEC max pulse width: (64/3)/(455 kHz/12) * 16 nec_units
189 * (64/3)/(455 kHz/12) * 16 nec_units * 1.375 = 12378022 ns
190 */
191 params.max_pulse_width = 12378022; /* ns */
192
193 /*
194 * NEC noise filter min width: (64/3)/(455 kHz/12) * 1 nec_unit
195 * (64/3)/(455 kHz/12) * 1 nec_units * 0.625 = 351648 ns
196 */
197 params.noise_filter_min_width = 351648; /* ns */
198
199 params.modulation = false;
200 params.invert_level = true;
201 break;
Andy Wallsdbda8f72009-09-27 20:55:41 -0300202 }
203 v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
Andy Walls43c24072010-06-27 23:15:35 -0300204 return 0;
205}
206
David Härdemand8b4b582010-10-29 16:08:23 -0300207static int cx23885_input_ir_open(struct rc_dev *rc)
Andy Walls43c24072010-06-27 23:15:35 -0300208{
David Härdemand8b4b582010-10-29 16:08:23 -0300209 struct cx23885_kernel_ir *kernel_ir = rc->priv;
Andy Walls43c24072010-06-27 23:15:35 -0300210
211 if (kernel_ir->cx == NULL)
212 return -ENODEV;
213
214 return cx23885_input_ir_start(kernel_ir->cx);
Andy Wallsdbda8f72009-09-27 20:55:41 -0300215}
216
217static void cx23885_input_ir_stop(struct cx23885_dev *dev)
218{
Andy Wallsdbda8f72009-09-27 20:55:41 -0300219 struct v4l2_subdev_ir_parameters params;
220
221 if (dev->sd_ir == NULL)
222 return;
223
224 /*
225 * Stop the sd_ir subdevice from generating notifications and
226 * scheduling work.
227 * It is shutdown this way in order to mitigate a race with
228 * cx23885_input_rx_work_handler() in the overrun case, which could
229 * re-enable the subdevice.
230 */
231 atomic_set(&dev->ir_input_stopping, 1);
232 v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
233 while (params.shutdown == false) {
234 params.enable = false;
235 params.interrupt_enable = false;
236 params.shutdown = true;
237 v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
238 v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
239 }
Linus Torvalds0b8e74c2012-10-07 17:49:05 +0900240 flush_work(&dev->cx25840_work);
241 flush_work(&dev->ir_rx_work);
242 flush_work(&dev->ir_tx_work);
Andy Walls43c24072010-06-27 23:15:35 -0300243}
Andy Wallsdbda8f72009-09-27 20:55:41 -0300244
David Härdemand8b4b582010-10-29 16:08:23 -0300245static void cx23885_input_ir_close(struct rc_dev *rc)
Andy Walls43c24072010-06-27 23:15:35 -0300246{
David Härdemand8b4b582010-10-29 16:08:23 -0300247 struct cx23885_kernel_ir *kernel_ir = rc->priv;
Andy Walls43c24072010-06-27 23:15:35 -0300248
249 if (kernel_ir->cx != NULL)
250 cx23885_input_ir_stop(kernel_ir->cx);
Andy Wallsdbda8f72009-09-27 20:55:41 -0300251}
252
253int cx23885_input_init(struct cx23885_dev *dev)
254{
Andy Walls43c24072010-06-27 23:15:35 -0300255 struct cx23885_kernel_ir *kernel_ir;
David Härdemand8b4b582010-10-29 16:08:23 -0300256 struct rc_dev *rc;
Andy Walls43c24072010-06-27 23:15:35 -0300257 char *rc_map;
258 enum rc_driver_type driver_type;
259 unsigned long allowed_protos;
260
Andy Wallsdbda8f72009-09-27 20:55:41 -0300261 int ret;
262
263 /*
264 * If the IR device (hardware registers, chip, GPIO lines, etc.) isn't
265 * encapsulated in a v4l2_subdev, then I'm not going to deal with it.
266 */
267 if (dev->sd_ir == NULL)
268 return -ENODEV;
269
270 switch (dev->board) {
Andy Walls9b3d8ec2011-06-08 21:24:25 -0300271 case CX23885_BOARD_HAUPPAUGE_HVR1270:
Andy Wallsdbda8f72009-09-27 20:55:41 -0300272 case CX23885_BOARD_HAUPPAUGE_HVR1850:
Michael Krufky7fec6fe2009-11-11 15:46:09 -0300273 case CX23885_BOARD_HAUPPAUGE_HVR1290:
Andy Walls98d109f2010-07-19 00:41:41 -0300274 case CX23885_BOARD_HAUPPAUGE_HVR1250:
275 /* Integrated CX2388[58] IR controller */
Andy Walls43c24072010-06-27 23:15:35 -0300276 driver_type = RC_DRIVER_IR_RAW;
David Härdemanc003ab12012-10-11 19:11:54 -0300277 allowed_protos = RC_BIT_ALL;
Andy Walls43c24072010-06-27 23:15:35 -0300278 /* The grey Hauppauge RC-5 remote */
Mauro Carvalho Chehab15195d32011-01-24 12:18:47 -0300279 rc_map = RC_MAP_HAUPPAUGE;
Andy Wallsdbda8f72009-09-27 20:55:41 -0300280 break;
Djuri Baars076f0e32012-07-28 09:01:38 -0300281 case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
282 /* Integrated CX23885 IR controller */
283 driver_type = RC_DRIVER_IR_RAW;
David Härdemanc003ab12012-10-11 19:11:54 -0300284 allowed_protos = RC_BIT_NEC;
Djuri Baars076f0e32012-07-28 09:01:38 -0300285 /* The grey Terratec remote with orange buttons */
286 rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS;
287 break;
Andy Walls98d109f2010-07-19 00:41:41 -0300288 case CX23885_BOARD_TEVII_S470:
289 /* Integrated CX23885 IR controller */
290 driver_type = RC_DRIVER_IR_RAW;
David Härdemanc003ab12012-10-11 19:11:54 -0300291 allowed_protos = RC_BIT_ALL;
Andy Walls98d109f2010-07-19 00:41:41 -0300292 /* A guess at the remote */
293 rc_map = RC_MAP_TEVII_NEC;
294 break;
Alfredo Jesús Delaitie5f670b2012-11-08 15:50:25 -0300295 case CX23885_BOARD_MYGICA_X8507:
296 /* Integrated CX23885 IR controller */
297 driver_type = RC_DRIVER_IR_RAW;
298 allowed_protos = RC_BIT_ALL;
299 /* A guess at the remote */
300 rc_map = RC_MAP_TOTAL_MEDIA_IN_HAND_02;
301 break;
Luis Alvese6001482013-10-01 22:11:35 -0300302 case CX23885_BOARD_TBS_6980:
303 case CX23885_BOARD_TBS_6981:
304 /* Integrated CX23885 IR controller */
305 driver_type = RC_DRIVER_IR_RAW;
306 allowed_protos = RC_BIT_ALL;
307 /* A guess at the remote */
308 rc_map = RC_MAP_TBS_NEC;
309 break;
nibble.maxd11a3832014-09-29 11:17:36 -0300310 case CX23885_BOARD_DVBSKY_T9580:
311 /* Integrated CX23885 IR controller */
312 driver_type = RC_DRIVER_IR_RAW;
313 allowed_protos = RC_BIT_ALL;
314 rc_map = RC_MAP_DVBSKY;
315 break;
Andy Walls43c24072010-06-27 23:15:35 -0300316 default:
Andy Wallsdbda8f72009-09-27 20:55:41 -0300317 return -ENODEV;
Andy Walls43c24072010-06-27 23:15:35 -0300318 }
Andy Wallsdbda8f72009-09-27 20:55:41 -0300319
Andy Walls43c24072010-06-27 23:15:35 -0300320 /* cx23885 board instance kernel IR state */
321 kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL);
322 if (kernel_ir == NULL)
323 return -ENOMEM;
324
325 kernel_ir->cx = dev;
326 kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)",
327 cx23885_boards[dev->board].name);
328 kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0",
329 pci_name(dev->pci));
330
331 /* input device */
David Härdemand8b4b582010-10-29 16:08:23 -0300332 rc = rc_allocate_device();
333 if (!rc) {
Andy Wallsdbda8f72009-09-27 20:55:41 -0300334 ret = -ENOMEM;
335 goto err_out_free;
336 }
337
David Härdemand8b4b582010-10-29 16:08:23 -0300338 kernel_ir->rc = rc;
339 rc->input_name = kernel_ir->name;
340 rc->input_phys = kernel_ir->phys;
341 rc->input_id.bustype = BUS_PCI;
342 rc->input_id.version = 1;
Andy Wallsdbda8f72009-09-27 20:55:41 -0300343 if (dev->pci->subsystem_vendor) {
David Härdemand8b4b582010-10-29 16:08:23 -0300344 rc->input_id.vendor = dev->pci->subsystem_vendor;
345 rc->input_id.product = dev->pci->subsystem_device;
Andy Wallsdbda8f72009-09-27 20:55:41 -0300346 } else {
David Härdemand8b4b582010-10-29 16:08:23 -0300347 rc->input_id.vendor = dev->pci->vendor;
348 rc->input_id.product = dev->pci->device;
Andy Wallsdbda8f72009-09-27 20:55:41 -0300349 }
David Härdemand8b4b582010-10-29 16:08:23 -0300350 rc->dev.parent = &dev->pci->dev;
351 rc->driver_type = driver_type;
David Härdemanc5540fb2014-04-03 20:32:21 -0300352 rc->allowed_protocols = allowed_protos;
David Härdemand8b4b582010-10-29 16:08:23 -0300353 rc->priv = kernel_ir;
354 rc->open = cx23885_input_ir_open;
355 rc->close = cx23885_input_ir_close;
356 rc->map_name = rc_map;
357 rc->driver_name = MODULE_NAME;
Andy Wallsdbda8f72009-09-27 20:55:41 -0300358
Andy Walls43c24072010-06-27 23:15:35 -0300359 /* Go */
360 dev->kernel_ir = kernel_ir;
David Härdemand8b4b582010-10-29 16:08:23 -0300361 ret = rc_register_device(rc);
Andy Wallsdbda8f72009-09-27 20:55:41 -0300362 if (ret)
363 goto err_out_stop;
364
365 return 0;
366
367err_out_stop:
368 cx23885_input_ir_stop(dev);
Andy Walls43c24072010-06-27 23:15:35 -0300369 dev->kernel_ir = NULL;
David Härdemand8b4b582010-10-29 16:08:23 -0300370 rc_free_device(rc);
Andy Wallsdbda8f72009-09-27 20:55:41 -0300371err_out_free:
Andy Walls43c24072010-06-27 23:15:35 -0300372 kfree(kernel_ir->phys);
373 kfree(kernel_ir->name);
374 kfree(kernel_ir);
Andy Wallsdbda8f72009-09-27 20:55:41 -0300375 return ret;
376}
377
378void cx23885_input_fini(struct cx23885_dev *dev)
379{
380 /* Always stop the IR hardware from generating interrupts */
381 cx23885_input_ir_stop(dev);
382
Andy Walls43c24072010-06-27 23:15:35 -0300383 if (dev->kernel_ir == NULL)
Andy Wallsdbda8f72009-09-27 20:55:41 -0300384 return;
David Härdemand8b4b582010-10-29 16:08:23 -0300385 rc_unregister_device(dev->kernel_ir->rc);
Andy Walls43c24072010-06-27 23:15:35 -0300386 kfree(dev->kernel_ir->phys);
387 kfree(dev->kernel_ir->name);
388 kfree(dev->kernel_ir);
389 dev->kernel_ir = NULL;
Andy Wallsdbda8f72009-09-27 20:55:41 -0300390}