xref: /openbmc/linux/drivers/media/pci/bt8xx/bttv-input.c (revision 8dd06ef34b6e2f41b29fbf5fc1663780f2524285)
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