Lines Matching +full:gpio +full:- +full:ir +full:- +full:receiver

1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Device driver for GPIO attached remote control interfaces
20 #include <media/rc-core.h>
24 /* ---------------------------------------------------------------------- */
35 /* sample from gpio pin 16 */
50 MODULE_PARM_DESC(ir_samplerate, "IR samplerate in kHz, 1 - 20, default 4");
53 module_param(ir_debug, int, 0644); /* debug level [IR] */
54 MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
58 printk(KERN_DEBUG "%s IR: " fmt, ir->core->name, ##arg);\
63 printk(KERN_DEBUG "cx88 IR: " fmt, ##arg); \
66 /* ---------------------------------------------------------------------- */
68 static void cx88_ir_handle_key(struct cx88_IR *ir) in cx88_ir_handle_key() argument
70 struct cx88_core *core = ir->core; in cx88_ir_handle_key()
71 u32 gpio, data, auxgpio; in cx88_ir_handle_key() local
73 /* read gpio value */ in cx88_ir_handle_key()
74 gpio = cx_read(ir->gpio_addr); in cx88_ir_handle_key()
75 switch (core->boardnr) { in cx88_ir_handle_key()
78 * This board apparently uses a combination of 2 GPIO in cx88_ir_handle_key()
79 * to represent the keys. Additionally, the second GPIO in cx88_ir_handle_key()
85 * gpio = 0x758, auxgpio = 0xe5 or 0xf5 in cx88_ir_handle_key()
87 * gpio = 0x758, auxgpio = 0xed or 0xfd in cx88_ir_handle_key()
92 gpio = (gpio & 0x7fd) + (auxgpio & 0xef); in cx88_ir_handle_key()
101 gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900); in cx88_ir_handle_key()
102 auxgpio = gpio; in cx88_ir_handle_key()
105 auxgpio = gpio; in cx88_ir_handle_key()
107 if (ir->polling) { in cx88_ir_handle_key()
108 if (ir->last_gpio == auxgpio) in cx88_ir_handle_key()
110 ir->last_gpio = auxgpio; in cx88_ir_handle_key()
114 data = ir_extract_bits(gpio, ir->mask_keycode); in cx88_ir_handle_key()
115 ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n", in cx88_ir_handle_key()
116 gpio, data, in cx88_ir_handle_key()
117 ir->polling ? "poll" : "irq", in cx88_ir_handle_key()
118 (gpio & ir->mask_keydown) ? " down" : "", in cx88_ir_handle_key()
119 (gpio & ir->mask_keyup) ? " up" : ""); in cx88_ir_handle_key()
121 if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) { in cx88_ir_handle_key()
126 rc_keydown(ir->dev, RC_PROTO_UNKNOWN, data, 0); in cx88_ir_handle_key()
128 } else if (ir->core->boardnr == CX88_BOARD_PROLINK_PLAYTVPVR || in cx88_ir_handle_key()
129 ir->core->boardnr == CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO) { in cx88_ir_handle_key()
139 if (0 == (gpio & ir->mask_keyup)) in cx88_ir_handle_key()
140 rc_keydown_notimeout(ir->dev, RC_PROTO_NECX, scancode, in cx88_ir_handle_key()
143 rc_keyup(ir->dev); in cx88_ir_handle_key()
145 } else if (ir->mask_keydown) { in cx88_ir_handle_key()
147 if (gpio & ir->mask_keydown) in cx88_ir_handle_key()
148 rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, in cx88_ir_handle_key()
151 rc_keyup(ir->dev); in cx88_ir_handle_key()
153 } else if (ir->mask_keyup) { in cx88_ir_handle_key()
155 if (0 == (gpio & ir->mask_keyup)) in cx88_ir_handle_key()
156 rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, in cx88_ir_handle_key()
159 rc_keyup(ir->dev); in cx88_ir_handle_key()
162 /* can't distinguish keydown/up :-/ */ in cx88_ir_handle_key()
163 rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0); in cx88_ir_handle_key()
164 rc_keyup(ir->dev); in cx88_ir_handle_key()
171 struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer); in cx88_ir_work() local
173 cx88_ir_handle_key(ir); in cx88_ir_work()
174 missed = hrtimer_forward_now(&ir->timer, in cx88_ir_work()
175 ktime_set(0, ir->polling * 1000000)); in cx88_ir_work()
177 ir_dprintk("Missed ticks %llu\n", missed - 1); in cx88_ir_work()
185 struct cx88_IR *ir; in __cx88_ir_start() local
187 if (!core || !core->ir) in __cx88_ir_start()
188 return -EINVAL; in __cx88_ir_start()
190 ir = core->ir; in __cx88_ir_start()
192 if (ir->polling) { in __cx88_ir_start()
193 hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); in __cx88_ir_start()
194 ir->timer.function = cx88_ir_work; in __cx88_ir_start()
195 hrtimer_start(&ir->timer, in __cx88_ir_start()
196 ktime_set(0, ir->polling * 1000000), in __cx88_ir_start()
199 if (ir->sampling) { in __cx88_ir_start()
200 core->pci_irqmask |= PCI_INT_IR_SMPINT; in __cx88_ir_start()
210 struct cx88_IR *ir; in __cx88_ir_stop() local
212 if (!core || !core->ir) in __cx88_ir_stop()
215 ir = core->ir; in __cx88_ir_stop()
216 if (ir->sampling) { in __cx88_ir_stop()
218 core->pci_irqmask &= ~PCI_INT_IR_SMPINT; in __cx88_ir_stop()
221 if (ir->polling) in __cx88_ir_stop()
222 hrtimer_cancel(&ir->timer); in __cx88_ir_stop()
227 if (core->ir->users) in cx88_ir_start()
236 if (core->ir->users) in cx88_ir_stop()
243 struct cx88_core *core = rc->priv; in cx88_ir_open()
245 core->ir->users++; in cx88_ir_open()
251 struct cx88_core *core = rc->priv; in cx88_ir_close()
253 core->ir->users--; in cx88_ir_close()
254 if (!core->ir->users) in cx88_ir_close()
258 /* ---------------------------------------------------------------------- */
262 struct cx88_IR *ir; in cx88_ir_init() local
266 int err = -ENOMEM; in cx88_ir_init()
268 * used with a full-code IR table in cx88_ir_init()
271 ir = kzalloc(sizeof(*ir), GFP_KERNEL); in cx88_ir_init()
273 if (!ir || !dev) in cx88_ir_init()
276 ir->dev = dev; in cx88_ir_init()
279 switch (core->boardnr) { in cx88_ir_init()
284 ir->gpio_addr = MO_GP1_IO; in cx88_ir_init()
285 ir->mask_keycode = 0x1f; in cx88_ir_init()
286 ir->mask_keyup = 0x60; in cx88_ir_init()
287 ir->polling = 50; /* ms */ in cx88_ir_init()
291 ir->sampling = 0xeb04; /* address */ in cx88_ir_init()
305 ir->sampling = 1; in cx88_ir_init()
313 ir->gpio_addr = MO_GP0_IO; in cx88_ir_init()
314 ir->mask_keycode = 0x8f8; in cx88_ir_init()
315 ir->mask_keyup = 0x100; in cx88_ir_init()
316 ir->polling = 50; /* ms */ in cx88_ir_init()
324 ir->gpio_addr = MO_GP0_IO; in cx88_ir_init()
325 ir->mask_keycode = 0x8f8; in cx88_ir_init()
326 ir->mask_keyup = 0x100; in cx88_ir_init()
327 ir->polling = 1; /* ms */ in cx88_ir_init()
331 ir->gpio_addr = MO_GP0_IO; in cx88_ir_init()
332 ir->mask_keycode = 0xfd; in cx88_ir_init()
333 ir->mask_keydown = 0x02; in cx88_ir_init()
334 ir->polling = 5; /* ms */ in cx88_ir_init()
341 * IR's with different address won't work. Still, there are in cx88_ir_init()
342 * other IR's from the same manufacturer that works, like the in cx88_ir_init()
343 * 002-T mini RC, provided with newer PV hardware in cx88_ir_init()
347 ir->gpio_addr = MO_GP1_IO; in cx88_ir_init()
348 ir->mask_keyup = 0x80; in cx88_ir_init()
349 ir->polling = 10; /* ms */ in cx88_ir_init()
355 ir->gpio_addr = MO_GP1_IO; in cx88_ir_init()
356 ir->mask_keycode = 0x3f; in cx88_ir_init()
357 ir->mask_keyup = 0x80; in cx88_ir_init()
358 ir->polling = 1; /* ms */ in cx88_ir_init()
362 ir->gpio_addr = MO_GP1_IO; in cx88_ir_init()
363 ir->mask_keycode = 0x1f; in cx88_ir_init()
364 ir->mask_keyup = 0x60; in cx88_ir_init()
365 ir->polling = 1; /* ms */ in cx88_ir_init()
369 ir->gpio_addr = MO_GP1_IO; in cx88_ir_init()
370 ir->mask_keycode = 0xbf; in cx88_ir_init()
371 ir->mask_keyup = 0x40; in cx88_ir_init()
372 ir->polling = 50; /* ms */ in cx88_ir_init()
376 ir->gpio_addr = MO_GP1_IO; in cx88_ir_init()
377 ir->mask_keycode = 0x1f; in cx88_ir_init()
378 ir->mask_keyup = 0x40; in cx88_ir_init()
379 ir->polling = 1; /* ms */ in cx88_ir_init()
384 ir->gpio_addr = MO_GP2_IO; in cx88_ir_init()
385 ir->mask_keycode = 0xfb; in cx88_ir_init()
386 ir->mask_keydown = 0x02; in cx88_ir_init()
387 ir->polling = 50; /* ms */ in cx88_ir_init()
397 ir->sampling = 0xff00; /* address */ in cx88_ir_init()
403 ir->sampling = 0xff00; /* address */ in cx88_ir_init()
407 ir->sampling = 0xff00; /* address */ in cx88_ir_init()
411 ir->gpio_addr = MO_GP1_IO; in cx88_ir_init()
412 ir->mask_keycode = 0x0e; in cx88_ir_init()
413 ir->mask_keyup = 0x80; in cx88_ir_init()
414 ir->polling = 50; /* ms */ in cx88_ir_init()
418 ir->gpio_addr = MO_GP0_IO; in cx88_ir_init()
419 ir->mask_keycode = 0xfa; in cx88_ir_init()
420 ir->polling = 50; /* ms */ in cx88_ir_init()
424 ir->sampling = 1; in cx88_ir_init()
428 ir->gpio_addr = MO_GP2_IO; in cx88_ir_init()
429 ir->mask_keycode = 0x7e; in cx88_ir_init()
430 ir->polling = 100; /* ms */ in cx88_ir_init()
434 ir->sampling = 0xff00; /* address */ in cx88_ir_init()
439 err = -ENODEV; in cx88_ir_init()
448 * the full scancodes, since it allows replacing the IR remote by in cx88_ir_init()
451 * GPIO. So, there's no way to get the full scancode. Due to that, in cx88_ir_init()
455 if (hardware_mask && !ir->mask_keycode) in cx88_ir_init()
456 ir->mask_keycode = hardware_mask; in cx88_ir_init()
459 snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); in cx88_ir_init()
460 snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); in cx88_ir_init()
462 dev->device_name = ir->name; in cx88_ir_init()
463 dev->input_phys = ir->phys; in cx88_ir_init()
464 dev->input_id.bustype = BUS_PCI; in cx88_ir_init()
465 dev->input_id.version = 1; in cx88_ir_init()
466 if (pci->subsystem_vendor) { in cx88_ir_init()
467 dev->input_id.vendor = pci->subsystem_vendor; in cx88_ir_init()
468 dev->input_id.product = pci->subsystem_device; in cx88_ir_init()
470 dev->input_id.vendor = pci->vendor; in cx88_ir_init()
471 dev->input_id.product = pci->device; in cx88_ir_init()
473 dev->dev.parent = &pci->dev; in cx88_ir_init()
474 dev->map_name = ir_codes; in cx88_ir_init()
475 dev->driver_name = MODULE_NAME; in cx88_ir_init()
476 dev->priv = core; in cx88_ir_init()
477 dev->open = cx88_ir_open; in cx88_ir_init()
478 dev->close = cx88_ir_close; in cx88_ir_init()
479 dev->scancode_mask = hardware_mask; in cx88_ir_init()
481 if (ir->sampling) { in cx88_ir_init()
482 dev->timeout = MS_TO_US(10); /* 10 ms */ in cx88_ir_init()
484 dev->driver_type = RC_DRIVER_SCANCODE; in cx88_ir_init()
485 dev->allowed_protocols = rc_proto; in cx88_ir_init()
488 ir->core = core; in cx88_ir_init()
489 core->ir = ir; in cx88_ir_init()
500 core->ir = NULL; in cx88_ir_init()
501 kfree(ir); in cx88_ir_init()
507 struct cx88_IR *ir = core->ir; in cx88_ir_fini() local
510 if (!ir) in cx88_ir_fini()
514 rc_unregister_device(ir->dev); in cx88_ir_fini()
515 kfree(ir); in cx88_ir_fini()
518 core->ir = NULL; in cx88_ir_fini()
522 /* ---------------------------------------------------------------------- */
526 struct cx88_IR *ir = core->ir; in cx88_ir_irq() local
531 if (!ir || !ir->sampling) in cx88_ir_irq()
541 if (samples == 0xff && ir->dev->idle) in cx88_ir_irq()
544 for (todo = 32; todo > 0; todo -= bits) { in cx88_ir_irq()
546 bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples)); in cx88_ir_irq()
548 ir_raw_event_store_with_filter(ir->dev, &ev); in cx88_ir_irq()
551 ir_raw_event_handle(ir->dev); in cx88_ir_irq()
554 static int get_key_pvr2000(struct IR_i2c *ir, enum rc_proto *protocol, in get_key_pvr2000() argument
559 /* poll IR chip */ in get_key_pvr2000()
560 flags = i2c_smbus_read_byte_data(ir->c, 0x10); in get_key_pvr2000()
570 code = i2c_smbus_read_byte_data(ir->c, 0x00); in get_key_pvr2000()
576 dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", in get_key_pvr2000()
598 /* Instantiate the IR receiver device, if present */ in cx88_i2c_init_ir()
599 if (core->i2c_rc != 0) in cx88_i2c_init_ir()
605 switch (core->boardnr) { in cx88_i2c_init_ir()
608 core->init_data.name = "cx88 Leadtek PVR 2000 remote"; in cx88_i2c_init_ir()
609 core->init_data.type = RC_PROTO_BIT_UNKNOWN; in cx88_i2c_init_ir()
610 core->init_data.get_key = get_key_pvr2000; in cx88_i2c_init_ir()
611 core->init_data.ir_codes = RC_MAP_EMPTY; in cx88_i2c_init_ir()
617 * quick writes for probing and at least some RC receiver in cx88_i2c_init_ir()
624 memset(&core->init_data, 0, sizeof(core->init_data)); in cx88_i2c_init_ir()
629 core->init_data.name = core->board.name; in cx88_i2c_init_ir()
630 core->init_data.ir_codes = RC_MAP_HAUPPAUGE; in cx88_i2c_init_ir()
631 core->init_data.type = RC_PROTO_BIT_RC5 | in cx88_i2c_init_ir()
633 core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; in cx88_i2c_init_ir()
635 info.platform_data = &core->init_data; in cx88_i2c_init_ir()
637 if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0, in cx88_i2c_init_ir()
641 i2c_new_client_device(&core->i2c_adap, &info); in cx88_i2c_init_ir()
647 /* ---------------------------------------------------------------------- */
650 MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls");