1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
268de959fSMauro Carvalho Chehab /*
368de959fSMauro Carvalho Chehab *
468de959fSMauro Carvalho Chehab * Copyright (c) 2003 Gerd Knorr
568de959fSMauro Carvalho Chehab * Copyright (c) 2003 Pavel Machek
668de959fSMauro Carvalho Chehab */
768de959fSMauro Carvalho Chehab
868de959fSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
968de959fSMauro Carvalho Chehab
1068de959fSMauro Carvalho Chehab #include <linux/module.h>
1168de959fSMauro Carvalho Chehab #include <linux/init.h>
1268de959fSMauro Carvalho Chehab #include <linux/delay.h>
1368de959fSMauro Carvalho Chehab #include <linux/interrupt.h>
1468de959fSMauro Carvalho Chehab #include <linux/input.h>
1568de959fSMauro Carvalho Chehab #include <linux/slab.h>
1668de959fSMauro Carvalho Chehab
1768de959fSMauro Carvalho Chehab #include "bttv.h"
1868de959fSMauro Carvalho Chehab #include "bttvp.h"
1968de959fSMauro Carvalho Chehab
2068de959fSMauro Carvalho Chehab
2168de959fSMauro Carvalho Chehab static int ir_debug;
2268de959fSMauro Carvalho Chehab module_param(ir_debug, int, 0644);
2368de959fSMauro Carvalho Chehab
2468de959fSMauro Carvalho Chehab static int ir_rc5_remote_gap = 885;
2568de959fSMauro Carvalho Chehab module_param(ir_rc5_remote_gap, int, 0644);
2668de959fSMauro Carvalho Chehab
2768de959fSMauro Carvalho Chehab #undef dprintk
2868de959fSMauro Carvalho Chehab #define dprintk(fmt, ...) \
2968de959fSMauro Carvalho Chehab do { \
3068de959fSMauro Carvalho Chehab if (ir_debug >= 1) \
3168de959fSMauro Carvalho Chehab pr_info(fmt, ##__VA_ARGS__); \
3268de959fSMauro Carvalho Chehab } while (0)
3368de959fSMauro Carvalho Chehab
3468de959fSMauro Carvalho Chehab #define DEVNAME "bttv-input"
3568de959fSMauro Carvalho Chehab
3668de959fSMauro Carvalho Chehab #define MODULE_NAME "bttv"
3768de959fSMauro Carvalho Chehab
3868de959fSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
3968de959fSMauro Carvalho Chehab
ir_handle_key(struct bttv * btv)4068de959fSMauro Carvalho Chehab static void ir_handle_key(struct bttv *btv)
4168de959fSMauro Carvalho Chehab {
4268de959fSMauro Carvalho Chehab struct bttv_ir *ir = btv->remote;
4368de959fSMauro Carvalho Chehab u32 gpio,data;
4468de959fSMauro Carvalho Chehab
4568de959fSMauro Carvalho Chehab /* read gpio value */
4668de959fSMauro Carvalho Chehab gpio = bttv_gpio_read(&btv->c);
4768de959fSMauro Carvalho Chehab if (ir->polling) {
4868de959fSMauro Carvalho Chehab if (ir->last_gpio == gpio)
4968de959fSMauro Carvalho Chehab return;
5068de959fSMauro Carvalho Chehab ir->last_gpio = gpio;
5168de959fSMauro Carvalho Chehab }
5268de959fSMauro Carvalho Chehab
5368de959fSMauro Carvalho Chehab /* extract data */
5468de959fSMauro Carvalho Chehab data = ir_extract_bits(gpio, ir->mask_keycode);
5568de959fSMauro Carvalho Chehab dprintk("irq gpio=0x%x code=%d | %s%s%s\n",
5668de959fSMauro Carvalho Chehab gpio, data,
5768de959fSMauro Carvalho Chehab ir->polling ? "poll" : "irq",
5868de959fSMauro Carvalho Chehab (gpio & ir->mask_keydown) ? " down" : "",
5968de959fSMauro Carvalho Chehab (gpio & ir->mask_keyup) ? " up" : "");
6068de959fSMauro Carvalho Chehab
6168de959fSMauro Carvalho Chehab if ((ir->mask_keydown && (gpio & ir->mask_keydown)) ||
6268de959fSMauro Carvalho Chehab (ir->mask_keyup && !(gpio & ir->mask_keyup))) {
636d741bfeSSean Young rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0);
6468de959fSMauro Carvalho Chehab } else {
6568de959fSMauro Carvalho Chehab /* HACK: Probably, ir->mask_keydown is missing
6668de959fSMauro Carvalho Chehab for this board */
6768de959fSMauro Carvalho Chehab if (btv->c.type == BTTV_BOARD_WINFAST2000)
686d741bfeSSean Young rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data,
696d741bfeSSean Young 0);
7068de959fSMauro Carvalho Chehab
7168de959fSMauro Carvalho Chehab rc_keyup(ir->dev);
7268de959fSMauro Carvalho Chehab }
7368de959fSMauro Carvalho Chehab }
7468de959fSMauro Carvalho Chehab
ir_enltv_handle_key(struct bttv * btv)7568de959fSMauro Carvalho Chehab static void ir_enltv_handle_key(struct bttv *btv)
7668de959fSMauro Carvalho Chehab {
7768de959fSMauro Carvalho Chehab struct bttv_ir *ir = btv->remote;
7868de959fSMauro Carvalho Chehab u32 gpio, data, keyup;
7968de959fSMauro Carvalho Chehab
8068de959fSMauro Carvalho Chehab /* read gpio value */
8168de959fSMauro Carvalho Chehab gpio = bttv_gpio_read(&btv->c);
8268de959fSMauro Carvalho Chehab
8368de959fSMauro Carvalho Chehab /* extract data */
8468de959fSMauro Carvalho Chehab data = ir_extract_bits(gpio, ir->mask_keycode);
8568de959fSMauro Carvalho Chehab
8668de959fSMauro Carvalho Chehab /* Check if it is keyup */
8795c52069SMauro Carvalho Chehab keyup = (gpio & ir->mask_keyup) ? 1UL << 31 : 0;
8868de959fSMauro Carvalho Chehab
8968de959fSMauro Carvalho Chehab if ((ir->last_gpio & 0x7f) != data) {
9068de959fSMauro Carvalho Chehab dprintk("gpio=0x%x code=%d | %s\n",
9168de959fSMauro Carvalho Chehab gpio, data,
9268de959fSMauro Carvalho Chehab (gpio & ir->mask_keyup) ? " up" : "up/down");
9368de959fSMauro Carvalho Chehab
946d741bfeSSean Young rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0);
9568de959fSMauro Carvalho Chehab if (keyup)
9668de959fSMauro Carvalho Chehab rc_keyup(ir->dev);
9768de959fSMauro Carvalho Chehab } else {
9895c52069SMauro Carvalho Chehab if ((ir->last_gpio & 1UL << 31) == keyup)
9968de959fSMauro Carvalho Chehab return;
10068de959fSMauro Carvalho Chehab
10168de959fSMauro Carvalho Chehab dprintk("(cnt) gpio=0x%x code=%d | %s\n",
10268de959fSMauro Carvalho Chehab gpio, data,
10368de959fSMauro Carvalho Chehab (gpio & ir->mask_keyup) ? " up" : "down");
10468de959fSMauro Carvalho Chehab
10568de959fSMauro Carvalho Chehab if (keyup)
10668de959fSMauro Carvalho Chehab rc_keyup(ir->dev);
10768de959fSMauro Carvalho Chehab else
1086d741bfeSSean Young rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data,
1096d741bfeSSean Young 0);
11068de959fSMauro Carvalho Chehab }
11168de959fSMauro Carvalho Chehab
11268de959fSMauro Carvalho Chehab ir->last_gpio = data | keyup;
11368de959fSMauro Carvalho Chehab }
11468de959fSMauro Carvalho Chehab
11568de959fSMauro Carvalho Chehab static int bttv_rc5_irq(struct bttv *btv);
11668de959fSMauro Carvalho Chehab
bttv_input_irq(struct bttv * btv)11768de959fSMauro Carvalho Chehab void bttv_input_irq(struct bttv *btv)
11868de959fSMauro Carvalho Chehab {
11968de959fSMauro Carvalho Chehab struct bttv_ir *ir = btv->remote;
12068de959fSMauro Carvalho Chehab
12168de959fSMauro Carvalho Chehab if (ir->rc5_gpio)
12268de959fSMauro Carvalho Chehab bttv_rc5_irq(btv);
12368de959fSMauro Carvalho Chehab else if (!ir->polling)
12468de959fSMauro Carvalho Chehab ir_handle_key(btv);
12568de959fSMauro Carvalho Chehab }
12668de959fSMauro Carvalho Chehab
bttv_input_timer(struct timer_list * t)127162e6376SKees Cook static void bttv_input_timer(struct timer_list *t)
12868de959fSMauro Carvalho Chehab {
129162e6376SKees Cook struct bttv_ir *ir = from_timer(ir, t, timer);
130162e6376SKees Cook struct bttv *btv = ir->btv;
13168de959fSMauro Carvalho Chehab
13268de959fSMauro Carvalho Chehab if (btv->c.type == BTTV_BOARD_ENLTV_FM_2)
13368de959fSMauro Carvalho Chehab ir_enltv_handle_key(btv);
13468de959fSMauro Carvalho Chehab else
13568de959fSMauro Carvalho Chehab ir_handle_key(btv);
13668de959fSMauro Carvalho Chehab mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
13768de959fSMauro Carvalho Chehab }
13868de959fSMauro Carvalho Chehab
13968de959fSMauro Carvalho Chehab /*
14068de959fSMauro Carvalho Chehab * FIXME: Nebula digi uses the legacy way to decode RC5, instead of relying
14168de959fSMauro Carvalho Chehab * on the rc-core way. As we need to be sure that both IRQ transitions are
14268de959fSMauro Carvalho Chehab * properly triggered, Better to touch it only with this hardware for
14368de959fSMauro Carvalho Chehab * testing.
14468de959fSMauro Carvalho Chehab */
14568de959fSMauro Carvalho Chehab
1462886f013SDavid Härdeman #define RC5_START(x) (((x) >> 12) & 0x03)
1472886f013SDavid Härdeman #define RC5_TOGGLE(x) (((x) >> 11) & 0x01)
1482886f013SDavid Härdeman #define RC5_ADDR(x) (((x) >> 6) & 0x1f)
1492886f013SDavid Härdeman #define RC5_INSTR(x) (((x) >> 0) & 0x3f)
15068de959fSMauro Carvalho Chehab
15168de959fSMauro Carvalho Chehab /* decode raw bit pattern to RC5 code */
bttv_rc5_decode(unsigned int code)15268de959fSMauro Carvalho Chehab static u32 bttv_rc5_decode(unsigned int code)
15368de959fSMauro Carvalho Chehab {
15468de959fSMauro Carvalho Chehab unsigned int org_code = code;
15568de959fSMauro Carvalho Chehab unsigned int pair;
15668de959fSMauro Carvalho Chehab unsigned int rc5 = 0;
15768de959fSMauro Carvalho Chehab int i;
15868de959fSMauro Carvalho Chehab
15968de959fSMauro Carvalho Chehab for (i = 0; i < 14; ++i) {
16068de959fSMauro Carvalho Chehab pair = code & 0x3;
16168de959fSMauro Carvalho Chehab code >>= 2;
16268de959fSMauro Carvalho Chehab
16368de959fSMauro Carvalho Chehab rc5 <<= 1;
16468de959fSMauro Carvalho Chehab switch (pair) {
16568de959fSMauro Carvalho Chehab case 0:
16668de959fSMauro Carvalho Chehab case 2:
16768de959fSMauro Carvalho Chehab break;
16868de959fSMauro Carvalho Chehab case 1:
16968de959fSMauro Carvalho Chehab rc5 |= 1;
17068de959fSMauro Carvalho Chehab break;
17168de959fSMauro Carvalho Chehab case 3:
17268de959fSMauro Carvalho Chehab dprintk("rc5_decode(%x) bad code\n",
17368de959fSMauro Carvalho Chehab org_code);
17468de959fSMauro Carvalho Chehab return 0;
17568de959fSMauro Carvalho Chehab }
17668de959fSMauro Carvalho Chehab }
177652fd6eaSMauro Carvalho Chehab dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, instr=%x\n",
178652fd6eaSMauro Carvalho Chehab rc5, org_code, RC5_START(rc5),
17968de959fSMauro Carvalho Chehab RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
18068de959fSMauro Carvalho Chehab return rc5;
18168de959fSMauro Carvalho Chehab }
18268de959fSMauro Carvalho Chehab
bttv_rc5_timer_end(struct timer_list * t)183162e6376SKees Cook static void bttv_rc5_timer_end(struct timer_list *t)
18468de959fSMauro Carvalho Chehab {
185162e6376SKees Cook struct bttv_ir *ir = from_timer(ir, t, timer);
18682fde1a9SAbhilash Jindal ktime_t tv;
1872886f013SDavid Härdeman u32 gap, rc5, scancode;
1882886f013SDavid Härdeman u8 toggle, command, system;
18968de959fSMauro Carvalho Chehab
19068de959fSMauro Carvalho Chehab /* get time */
19182fde1a9SAbhilash Jindal tv = ktime_get();
19268de959fSMauro Carvalho Chehab
19382fde1a9SAbhilash Jindal gap = ktime_to_us(ktime_sub(tv, ir->base_time));
19468de959fSMauro Carvalho Chehab /* avoid overflow with gap >1s */
19582fde1a9SAbhilash Jindal if (gap > USEC_PER_SEC) {
19668de959fSMauro Carvalho Chehab gap = 200000;
19768de959fSMauro Carvalho Chehab }
19868de959fSMauro Carvalho Chehab /* signal we're ready to start a new code */
19968de959fSMauro Carvalho Chehab ir->active = false;
20068de959fSMauro Carvalho Chehab
20168de959fSMauro Carvalho Chehab /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
20268de959fSMauro Carvalho Chehab if (gap < 28000) {
20368de959fSMauro Carvalho Chehab dprintk("spurious timer_end\n");
20468de959fSMauro Carvalho Chehab return;
20568de959fSMauro Carvalho Chehab }
20668de959fSMauro Carvalho Chehab
20768de959fSMauro Carvalho Chehab if (ir->last_bit < 20) {
20868de959fSMauro Carvalho Chehab /* ignore spurious codes (caused by light/other remotes) */
20968de959fSMauro Carvalho Chehab dprintk("short code: %x\n", ir->code);
2102886f013SDavid Härdeman return;
2112886f013SDavid Härdeman }
2122886f013SDavid Härdeman
21368de959fSMauro Carvalho Chehab ir->code = (ir->code << ir->shift_by) | 1;
21468de959fSMauro Carvalho Chehab rc5 = bttv_rc5_decode(ir->code);
21568de959fSMauro Carvalho Chehab
2162886f013SDavid Härdeman toggle = RC5_TOGGLE(rc5);
2172886f013SDavid Härdeman system = RC5_ADDR(rc5);
2182886f013SDavid Härdeman command = RC5_INSTR(rc5);
21968de959fSMauro Carvalho Chehab
2202886f013SDavid Härdeman switch (RC5_START(rc5)) {
2212886f013SDavid Härdeman case 0x3:
2222886f013SDavid Härdeman break;
2232886f013SDavid Härdeman case 0x2:
2242886f013SDavid Härdeman command += 0x40;
2252886f013SDavid Härdeman break;
2262886f013SDavid Härdeman default:
2272886f013SDavid Härdeman return;
2282886f013SDavid Härdeman }
22968de959fSMauro Carvalho Chehab
230120703f9SDavid Härdeman scancode = RC_SCANCODE_RC5(system, command);
2316d741bfeSSean Young rc_keydown(ir->dev, RC_PROTO_RC5, scancode, toggle);
2322886f013SDavid Härdeman dprintk("scancode %x, toggle %x\n", scancode, toggle);
23368de959fSMauro Carvalho Chehab }
23468de959fSMauro Carvalho Chehab
bttv_rc5_irq(struct bttv * btv)23568de959fSMauro Carvalho Chehab static int bttv_rc5_irq(struct bttv *btv)
23668de959fSMauro Carvalho Chehab {
23768de959fSMauro Carvalho Chehab struct bttv_ir *ir = btv->remote;
23882fde1a9SAbhilash Jindal ktime_t tv;
23968de959fSMauro Carvalho Chehab u32 gpio;
24068de959fSMauro Carvalho Chehab u32 gap;
24168de959fSMauro Carvalho Chehab unsigned long current_jiffies;
24268de959fSMauro Carvalho Chehab
24368de959fSMauro Carvalho Chehab /* read gpio port */
24468de959fSMauro Carvalho Chehab gpio = bttv_gpio_read(&btv->c);
24568de959fSMauro Carvalho Chehab
24668de959fSMauro Carvalho Chehab /* get time of bit */
24768de959fSMauro Carvalho Chehab current_jiffies = jiffies;
24882fde1a9SAbhilash Jindal tv = ktime_get();
24968de959fSMauro Carvalho Chehab
25082fde1a9SAbhilash Jindal gap = ktime_to_us(ktime_sub(tv, ir->base_time));
25168de959fSMauro Carvalho Chehab /* avoid overflow with gap >1s */
25282fde1a9SAbhilash Jindal if (gap > USEC_PER_SEC) {
25368de959fSMauro Carvalho Chehab gap = 200000;
25468de959fSMauro Carvalho Chehab }
25568de959fSMauro Carvalho Chehab
25668de959fSMauro Carvalho Chehab dprintk("RC5 IRQ: gap %d us for %s\n",
25768de959fSMauro Carvalho Chehab gap, (gpio & 0x20) ? "mark" : "space");
25868de959fSMauro Carvalho Chehab
25968de959fSMauro Carvalho Chehab /* remote IRQ? */
26068de959fSMauro Carvalho Chehab if (!(gpio & 0x20))
26168de959fSMauro Carvalho Chehab return 0;
26268de959fSMauro Carvalho Chehab
26368de959fSMauro Carvalho Chehab /* active code => add bit */
26468de959fSMauro Carvalho Chehab if (ir->active) {
26568de959fSMauro Carvalho Chehab /* only if in the code (otherwise spurious IRQ or timer
26668de959fSMauro Carvalho Chehab late) */
26768de959fSMauro Carvalho Chehab if (ir->last_bit < 28) {
26868de959fSMauro Carvalho Chehab ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
26968de959fSMauro Carvalho Chehab ir_rc5_remote_gap;
27068de959fSMauro Carvalho Chehab ir->code |= 1 << ir->last_bit;
27168de959fSMauro Carvalho Chehab }
27268de959fSMauro Carvalho Chehab /* starting new code */
27368de959fSMauro Carvalho Chehab } else {
27468de959fSMauro Carvalho Chehab ir->active = true;
27568de959fSMauro Carvalho Chehab ir->code = 0;
27668de959fSMauro Carvalho Chehab ir->base_time = tv;
27768de959fSMauro Carvalho Chehab ir->last_bit = 0;
27868de959fSMauro Carvalho Chehab
27968de959fSMauro Carvalho Chehab mod_timer(&ir->timer, current_jiffies + msecs_to_jiffies(30));
28068de959fSMauro Carvalho Chehab }
28168de959fSMauro Carvalho Chehab
28268de959fSMauro Carvalho Chehab /* toggle GPIO pin 4 to reset the irq */
28368de959fSMauro Carvalho Chehab bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
28468de959fSMauro Carvalho Chehab bttv_gpio_write(&btv->c, gpio | (1 << 4));
28568de959fSMauro Carvalho Chehab return 1;
28668de959fSMauro Carvalho Chehab }
28768de959fSMauro Carvalho Chehab
28868de959fSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
28968de959fSMauro Carvalho Chehab
bttv_ir_start(struct bttv_ir * ir)290162e6376SKees Cook static void bttv_ir_start(struct bttv_ir *ir)
29168de959fSMauro Carvalho Chehab {
29268de959fSMauro Carvalho Chehab if (ir->polling) {
293162e6376SKees Cook timer_setup(&ir->timer, bttv_input_timer, 0);
29468de959fSMauro Carvalho Chehab ir->timer.expires = jiffies + msecs_to_jiffies(1000);
29568de959fSMauro Carvalho Chehab add_timer(&ir->timer);
29668de959fSMauro Carvalho Chehab } else if (ir->rc5_gpio) {
29768de959fSMauro Carvalho Chehab /* set timer_end for code completion */
298162e6376SKees Cook timer_setup(&ir->timer, bttv_rc5_timer_end, 0);
29968de959fSMauro Carvalho Chehab ir->shift_by = 1;
30068de959fSMauro Carvalho Chehab ir->rc5_remote_gap = ir_rc5_remote_gap;
30168de959fSMauro Carvalho Chehab }
30268de959fSMauro Carvalho Chehab }
30368de959fSMauro Carvalho Chehab
bttv_ir_stop(struct bttv * btv)30468de959fSMauro Carvalho Chehab static void bttv_ir_stop(struct bttv *btv)
30568de959fSMauro Carvalho Chehab {
30668de959fSMauro Carvalho Chehab if (btv->remote->polling)
30768de959fSMauro Carvalho Chehab del_timer_sync(&btv->remote->timer);
30868de959fSMauro Carvalho Chehab
30968de959fSMauro Carvalho Chehab if (btv->remote->rc5_gpio) {
31068de959fSMauro Carvalho Chehab u32 gpio;
31168de959fSMauro Carvalho Chehab
31268de959fSMauro Carvalho Chehab del_timer_sync(&btv->remote->timer);
31368de959fSMauro Carvalho Chehab
31468de959fSMauro Carvalho Chehab gpio = bttv_gpio_read(&btv->c);
31568de959fSMauro Carvalho Chehab bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
31668de959fSMauro Carvalho Chehab }
31768de959fSMauro Carvalho Chehab }
31868de959fSMauro Carvalho Chehab
31968de959fSMauro Carvalho Chehab /*
32068de959fSMauro Carvalho Chehab * Get_key functions used by I2C remotes
32168de959fSMauro Carvalho Chehab */
32268de959fSMauro Carvalho Chehab
get_key_pv951(struct IR_i2c * ir,enum rc_proto * protocol,u32 * scancode,u8 * toggle)3236d741bfeSSean Young static int get_key_pv951(struct IR_i2c *ir, enum rc_proto *protocol,
3244dd9bb91SDavid Härdeman u32 *scancode, u8 *toggle)
32568de959fSMauro Carvalho Chehab {
326d3c449e1SMauro Carvalho Chehab int rc;
32768de959fSMauro Carvalho Chehab unsigned char b;
32868de959fSMauro Carvalho Chehab
32968de959fSMauro Carvalho Chehab /* poll IR chip */
330d3c449e1SMauro Carvalho Chehab rc = i2c_master_recv(ir->c, &b, 1);
331d3c449e1SMauro Carvalho Chehab if (rc != 1) {
33268de959fSMauro Carvalho Chehab dprintk("read error\n");
333d3c449e1SMauro Carvalho Chehab if (rc < 0)
334d3c449e1SMauro Carvalho Chehab return rc;
33568de959fSMauro Carvalho Chehab return -EIO;
33668de959fSMauro Carvalho Chehab }
33768de959fSMauro Carvalho Chehab
33868de959fSMauro Carvalho Chehab /* ignore 0xaa */
33968de959fSMauro Carvalho Chehab if (b==0xaa)
34068de959fSMauro Carvalho Chehab return 0;
34168de959fSMauro Carvalho Chehab dprintk("key %02x\n", b);
34268de959fSMauro Carvalho Chehab
34368de959fSMauro Carvalho Chehab /*
34468de959fSMauro Carvalho Chehab * NOTE:
34568de959fSMauro Carvalho Chehab * lirc_i2c maps the pv951 code as:
34668de959fSMauro Carvalho Chehab * addr = 0x61D6
34768de959fSMauro Carvalho Chehab * cmd = bit_reverse (b)
34868de959fSMauro Carvalho Chehab * So, it seems that this device uses NEC extended
34968de959fSMauro Carvalho Chehab * I decided to not fix the table, due to two reasons:
35068de959fSMauro Carvalho Chehab * 1) Without the actual device, this is only a guess;
35168de959fSMauro Carvalho Chehab * 2) As the addr is not reported via I2C, nor can be changed,
35268de959fSMauro Carvalho Chehab * the device is bound to the vendor-provided RC.
35368de959fSMauro Carvalho Chehab */
35468de959fSMauro Carvalho Chehab
3556d741bfeSSean Young *protocol = RC_PROTO_UNKNOWN;
3564dd9bb91SDavid Härdeman *scancode = b;
3574dd9bb91SDavid Härdeman *toggle = 0;
35868de959fSMauro Carvalho Chehab return 1;
35968de959fSMauro Carvalho Chehab }
36068de959fSMauro Carvalho Chehab
36168de959fSMauro Carvalho Chehab /* Instantiate the I2C IR receiver device, if present */
init_bttv_i2c_ir(struct bttv * btv)3624c62e976SGreg Kroah-Hartman void init_bttv_i2c_ir(struct bttv *btv)
36368de959fSMauro Carvalho Chehab {
364c93d541dSColin Ian King static const unsigned short addr_list[] = {
36568de959fSMauro Carvalho Chehab 0x1a, 0x18, 0x64, 0x30, 0x71,
36668de959fSMauro Carvalho Chehab I2C_CLIENT_END
36768de959fSMauro Carvalho Chehab };
36868de959fSMauro Carvalho Chehab struct i2c_board_info info;
369fa563073SFrank Schaefer struct i2c_client *i2c_dev;
37068de959fSMauro Carvalho Chehab
37168de959fSMauro Carvalho Chehab if (0 != btv->i2c_rc)
37268de959fSMauro Carvalho Chehab return;
37368de959fSMauro Carvalho Chehab
37468de959fSMauro Carvalho Chehab memset(&info, 0, sizeof(struct i2c_board_info));
37568de959fSMauro Carvalho Chehab memset(&btv->init_data, 0, sizeof(btv->init_data));
376c0decac1SMauro Carvalho Chehab strscpy(info.type, "ir_video", I2C_NAME_SIZE);
37768de959fSMauro Carvalho Chehab
37868de959fSMauro Carvalho Chehab switch (btv->c.type) {
37968de959fSMauro Carvalho Chehab case BTTV_BOARD_PV951:
38068de959fSMauro Carvalho Chehab btv->init_data.name = "PV951";
38168de959fSMauro Carvalho Chehab btv->init_data.get_key = get_key_pv951;
38268de959fSMauro Carvalho Chehab btv->init_data.ir_codes = RC_MAP_PV951;
38368de959fSMauro Carvalho Chehab info.addr = 0x4b;
38468de959fSMauro Carvalho Chehab break;
385fa563073SFrank Schaefer }
386fa563073SFrank Schaefer
387fa563073SFrank Schaefer if (btv->init_data.name) {
388fa563073SFrank Schaefer info.platform_data = &btv->init_data;
389*832d76ecSWolfram Sang i2c_dev = i2c_new_client_device(&btv->c.i2c_adap, &info);
390fa563073SFrank Schaefer } else {
39168de959fSMauro Carvalho Chehab /*
39268de959fSMauro Carvalho Chehab * The external IR receiver is at i2c address 0x34 (0x35 for
39368de959fSMauro Carvalho Chehab * reads). Future Hauppauge cards will have an internal
39468de959fSMauro Carvalho Chehab * receiver at 0x30 (0x31 for reads). In theory, both can be
39568de959fSMauro Carvalho Chehab * fitted, and Hauppauge suggest an external overrides an
39668de959fSMauro Carvalho Chehab * internal.
39768de959fSMauro Carvalho Chehab * That's why we probe 0x1a (~0x34) first. CB
39868de959fSMauro Carvalho Chehab */
399*832d76ecSWolfram Sang i2c_dev = i2c_new_scanned_device(&btv->c.i2c_adap, &info, addr_list, NULL);
40068de959fSMauro Carvalho Chehab }
401*832d76ecSWolfram Sang if (IS_ERR(i2c_dev))
40268de959fSMauro Carvalho Chehab return;
403fa563073SFrank Schaefer
404fa563073SFrank Schaefer #if defined(CONFIG_MODULES) && defined(MODULE)
405fa563073SFrank Schaefer request_module("ir-kbd-i2c");
406fa563073SFrank Schaefer #endif
40768de959fSMauro Carvalho Chehab }
40868de959fSMauro Carvalho Chehab
bttv_input_init(struct bttv * btv)40968de959fSMauro Carvalho Chehab int bttv_input_init(struct bttv *btv)
41068de959fSMauro Carvalho Chehab {
41168de959fSMauro Carvalho Chehab struct bttv_ir *ir;
41268de959fSMauro Carvalho Chehab char *ir_codes = NULL;
41368de959fSMauro Carvalho Chehab struct rc_dev *rc;
41468de959fSMauro Carvalho Chehab int err = -ENOMEM;
41568de959fSMauro Carvalho Chehab
41668de959fSMauro Carvalho Chehab if (!btv->has_remote)
41768de959fSMauro Carvalho Chehab return -ENODEV;
41868de959fSMauro Carvalho Chehab
41968de959fSMauro Carvalho Chehab ir = kzalloc(sizeof(*ir),GFP_KERNEL);
4200f7499fdSAndi Shyti rc = rc_allocate_device(RC_DRIVER_SCANCODE);
42168de959fSMauro Carvalho Chehab if (!ir || !rc)
42268de959fSMauro Carvalho Chehab goto err_out_free;
42368de959fSMauro Carvalho Chehab
42468de959fSMauro Carvalho Chehab /* detect & configure */
42568de959fSMauro Carvalho Chehab switch (btv->c.type) {
42668de959fSMauro Carvalho Chehab case BTTV_BOARD_AVERMEDIA:
42768de959fSMauro Carvalho Chehab case BTTV_BOARD_AVPHONE98:
42868de959fSMauro Carvalho Chehab case BTTV_BOARD_AVERMEDIA98:
42968de959fSMauro Carvalho Chehab ir_codes = RC_MAP_AVERMEDIA;
43068de959fSMauro Carvalho Chehab ir->mask_keycode = 0xf88000;
43168de959fSMauro Carvalho Chehab ir->mask_keydown = 0x010000;
43268de959fSMauro Carvalho Chehab ir->polling = 50; // ms
43368de959fSMauro Carvalho Chehab break;
43468de959fSMauro Carvalho Chehab
43568de959fSMauro Carvalho Chehab case BTTV_BOARD_AVDVBT_761:
43668de959fSMauro Carvalho Chehab case BTTV_BOARD_AVDVBT_771:
43768de959fSMauro Carvalho Chehab ir_codes = RC_MAP_AVERMEDIA_DVBT;
43868de959fSMauro Carvalho Chehab ir->mask_keycode = 0x0f00c0;
43968de959fSMauro Carvalho Chehab ir->mask_keydown = 0x000020;
44068de959fSMauro Carvalho Chehab ir->polling = 50; // ms
44168de959fSMauro Carvalho Chehab break;
44268de959fSMauro Carvalho Chehab
44368de959fSMauro Carvalho Chehab case BTTV_BOARD_PXELVWPLTVPAK:
44468de959fSMauro Carvalho Chehab ir_codes = RC_MAP_PIXELVIEW;
44568de959fSMauro Carvalho Chehab ir->mask_keycode = 0x003e00;
44668de959fSMauro Carvalho Chehab ir->mask_keyup = 0x010000;
44768de959fSMauro Carvalho Chehab ir->polling = 50; // ms
44868de959fSMauro Carvalho Chehab break;
44968de959fSMauro Carvalho Chehab case BTTV_BOARD_PV_M4900:
45068de959fSMauro Carvalho Chehab case BTTV_BOARD_PV_BT878P_9B:
45168de959fSMauro Carvalho Chehab case BTTV_BOARD_PV_BT878P_PLUS:
45268de959fSMauro Carvalho Chehab ir_codes = RC_MAP_PIXELVIEW;
45368de959fSMauro Carvalho Chehab ir->mask_keycode = 0x001f00;
45468de959fSMauro Carvalho Chehab ir->mask_keyup = 0x008000;
45568de959fSMauro Carvalho Chehab ir->polling = 50; // ms
45668de959fSMauro Carvalho Chehab break;
45768de959fSMauro Carvalho Chehab
45868de959fSMauro Carvalho Chehab case BTTV_BOARD_WINFAST2000:
45968de959fSMauro Carvalho Chehab ir_codes = RC_MAP_WINFAST;
46068de959fSMauro Carvalho Chehab ir->mask_keycode = 0x1f8;
46168de959fSMauro Carvalho Chehab break;
46268de959fSMauro Carvalho Chehab case BTTV_BOARD_MAGICTVIEW061:
46368de959fSMauro Carvalho Chehab case BTTV_BOARD_MAGICTVIEW063:
46468de959fSMauro Carvalho Chehab ir_codes = RC_MAP_WINFAST;
46568de959fSMauro Carvalho Chehab ir->mask_keycode = 0x0008e000;
46668de959fSMauro Carvalho Chehab ir->mask_keydown = 0x00200000;
46768de959fSMauro Carvalho Chehab break;
46868de959fSMauro Carvalho Chehab case BTTV_BOARD_APAC_VIEWCOMP:
46968de959fSMauro Carvalho Chehab ir_codes = RC_MAP_APAC_VIEWCOMP;
47068de959fSMauro Carvalho Chehab ir->mask_keycode = 0x001f00;
47168de959fSMauro Carvalho Chehab ir->mask_keyup = 0x008000;
47268de959fSMauro Carvalho Chehab ir->polling = 50; // ms
47368de959fSMauro Carvalho Chehab break;
47468de959fSMauro Carvalho Chehab case BTTV_BOARD_ASKEY_CPH03X:
47568de959fSMauro Carvalho Chehab case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
47668de959fSMauro Carvalho Chehab case BTTV_BOARD_CONTVFMI:
477493a9cfdSPojar George case BTTV_BOARD_KWORLD_VSTREAM_XPERT:
47868de959fSMauro Carvalho Chehab ir_codes = RC_MAP_PIXELVIEW;
47968de959fSMauro Carvalho Chehab ir->mask_keycode = 0x001F00;
48068de959fSMauro Carvalho Chehab ir->mask_keyup = 0x006000;
48168de959fSMauro Carvalho Chehab ir->polling = 50; // ms
48268de959fSMauro Carvalho Chehab break;
48368de959fSMauro Carvalho Chehab case BTTV_BOARD_NEBULA_DIGITV:
48468de959fSMauro Carvalho Chehab ir_codes = RC_MAP_NEBULA;
48568de959fSMauro Carvalho Chehab ir->rc5_gpio = true;
48668de959fSMauro Carvalho Chehab break;
48768de959fSMauro Carvalho Chehab case BTTV_BOARD_MACHTV_MAGICTV:
48868de959fSMauro Carvalho Chehab ir_codes = RC_MAP_APAC_VIEWCOMP;
48968de959fSMauro Carvalho Chehab ir->mask_keycode = 0x001F00;
49068de959fSMauro Carvalho Chehab ir->mask_keyup = 0x004000;
49168de959fSMauro Carvalho Chehab ir->polling = 50; /* ms */
49268de959fSMauro Carvalho Chehab break;
49368de959fSMauro Carvalho Chehab case BTTV_BOARD_KOZUMI_KTV_01C:
49468de959fSMauro Carvalho Chehab ir_codes = RC_MAP_PCTV_SEDNA;
49568de959fSMauro Carvalho Chehab ir->mask_keycode = 0x001f00;
49668de959fSMauro Carvalho Chehab ir->mask_keyup = 0x006000;
49768de959fSMauro Carvalho Chehab ir->polling = 50; /* ms */
49868de959fSMauro Carvalho Chehab break;
49968de959fSMauro Carvalho Chehab case BTTV_BOARD_ENLTV_FM_2:
50068de959fSMauro Carvalho Chehab ir_codes = RC_MAP_ENCORE_ENLTV2;
50168de959fSMauro Carvalho Chehab ir->mask_keycode = 0x00fd00;
50268de959fSMauro Carvalho Chehab ir->mask_keyup = 0x000080;
50368de959fSMauro Carvalho Chehab ir->polling = 1; /* ms */
50468de959fSMauro Carvalho Chehab ir->last_gpio = ir_extract_bits(bttv_gpio_read(&btv->c),
50568de959fSMauro Carvalho Chehab ir->mask_keycode);
50668de959fSMauro Carvalho Chehab break;
50768de959fSMauro Carvalho Chehab }
5082886f013SDavid Härdeman
5092886f013SDavid Härdeman if (!ir_codes) {
51068de959fSMauro Carvalho Chehab dprintk("Ooops: IR config error [card=%d]\n", btv->c.type);
51168de959fSMauro Carvalho Chehab err = -ENODEV;
51268de959fSMauro Carvalho Chehab goto err_out_free;
51368de959fSMauro Carvalho Chehab }
51468de959fSMauro Carvalho Chehab
51568de959fSMauro Carvalho Chehab if (ir->rc5_gpio) {
51668de959fSMauro Carvalho Chehab u32 gpio;
51768de959fSMauro Carvalho Chehab /* enable remote irq */
51868de959fSMauro Carvalho Chehab bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
51968de959fSMauro Carvalho Chehab gpio = bttv_gpio_read(&btv->c);
52068de959fSMauro Carvalho Chehab bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
52168de959fSMauro Carvalho Chehab bttv_gpio_write(&btv->c, gpio | (1 << 4));
52268de959fSMauro Carvalho Chehab } else {
52368de959fSMauro Carvalho Chehab /* init hardware-specific stuff */
52468de959fSMauro Carvalho Chehab bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0);
52568de959fSMauro Carvalho Chehab }
52668de959fSMauro Carvalho Chehab
52768de959fSMauro Carvalho Chehab /* init input device */
52868de959fSMauro Carvalho Chehab ir->dev = rc;
529162e6376SKees Cook ir->btv = btv;
53068de959fSMauro Carvalho Chehab
53168de959fSMauro Carvalho Chehab snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
53268de959fSMauro Carvalho Chehab btv->c.type);
53368de959fSMauro Carvalho Chehab snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
53468de959fSMauro Carvalho Chehab pci_name(btv->c.pci));
53568de959fSMauro Carvalho Chehab
536518f4b26SSean Young rc->device_name = ir->name;
53768de959fSMauro Carvalho Chehab rc->input_phys = ir->phys;
53868de959fSMauro Carvalho Chehab rc->input_id.bustype = BUS_PCI;
53968de959fSMauro Carvalho Chehab rc->input_id.version = 1;
54068de959fSMauro Carvalho Chehab if (btv->c.pci->subsystem_vendor) {
54168de959fSMauro Carvalho Chehab rc->input_id.vendor = btv->c.pci->subsystem_vendor;
54268de959fSMauro Carvalho Chehab rc->input_id.product = btv->c.pci->subsystem_device;
54368de959fSMauro Carvalho Chehab } else {
54468de959fSMauro Carvalho Chehab rc->input_id.vendor = btv->c.pci->vendor;
54568de959fSMauro Carvalho Chehab rc->input_id.product = btv->c.pci->device;
54668de959fSMauro Carvalho Chehab }
54768de959fSMauro Carvalho Chehab rc->dev.parent = &btv->c.pci->dev;
54868de959fSMauro Carvalho Chehab rc->map_name = ir_codes;
54968de959fSMauro Carvalho Chehab rc->driver_name = MODULE_NAME;
55068de959fSMauro Carvalho Chehab
55168de959fSMauro Carvalho Chehab btv->remote = ir;
552162e6376SKees Cook bttv_ir_start(ir);
55368de959fSMauro Carvalho Chehab
55468de959fSMauro Carvalho Chehab /* all done */
55568de959fSMauro Carvalho Chehab err = rc_register_device(rc);
55668de959fSMauro Carvalho Chehab if (err)
55768de959fSMauro Carvalho Chehab goto err_out_stop;
55868de959fSMauro Carvalho Chehab
55968de959fSMauro Carvalho Chehab return 0;
56068de959fSMauro Carvalho Chehab
56168de959fSMauro Carvalho Chehab err_out_stop:
56268de959fSMauro Carvalho Chehab bttv_ir_stop(btv);
56368de959fSMauro Carvalho Chehab btv->remote = NULL;
56468de959fSMauro Carvalho Chehab err_out_free:
56568de959fSMauro Carvalho Chehab rc_free_device(rc);
56668de959fSMauro Carvalho Chehab kfree(ir);
56768de959fSMauro Carvalho Chehab return err;
56868de959fSMauro Carvalho Chehab }
56968de959fSMauro Carvalho Chehab
bttv_input_fini(struct bttv * btv)57068de959fSMauro Carvalho Chehab void bttv_input_fini(struct bttv *btv)
57168de959fSMauro Carvalho Chehab {
57268de959fSMauro Carvalho Chehab if (btv->remote == NULL)
57368de959fSMauro Carvalho Chehab return;
57468de959fSMauro Carvalho Chehab
57568de959fSMauro Carvalho Chehab bttv_ir_stop(btv);
57668de959fSMauro Carvalho Chehab rc_unregister_device(btv->remote->dev);
57768de959fSMauro Carvalho Chehab kfree(btv->remote);
57868de959fSMauro Carvalho Chehab btv->remote = NULL;
57968de959fSMauro Carvalho Chehab }
580