1f22e9e71SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0+
2f22e9e71SMauro Carvalho Chehab //
3f22e9e71SMauro Carvalho Chehab // handle em28xx IR remotes via linux kernel input layer.
4f22e9e71SMauro Carvalho Chehab //
5f22e9e71SMauro Carvalho Chehab // Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
6f22e9e71SMauro Carvalho Chehab // Markus Rechberger <mrechberger@gmail.com>
732590819SMauro Carvalho Chehab // Mauro Carvalho Chehab <mchehab@kernel.org>
8f22e9e71SMauro Carvalho Chehab // Sascha Sommer <saschasommer@freenet.de>
90c0d06caSMauro Carvalho Chehab
108314d402SMauro Carvalho Chehab #include "em28xx.h"
118314d402SMauro Carvalho Chehab
120c0d06caSMauro Carvalho Chehab #include <linux/module.h>
130c0d06caSMauro Carvalho Chehab #include <linux/init.h>
140c0d06caSMauro Carvalho Chehab #include <linux/delay.h>
150c0d06caSMauro Carvalho Chehab #include <linux/interrupt.h>
160c0d06caSMauro Carvalho Chehab #include <linux/usb.h>
170547858bSSean Young #include <linux/usb/input.h>
180c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
19120703f9SDavid Härdeman #include <linux/bitrev.h>
200c0d06caSMauro Carvalho Chehab
210c0d06caSMauro Carvalho Chehab #define EM28XX_SNAPSHOT_KEY KEY_CAMERA
220ff950a7SFrank Schaefer #define EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL 500 /* [ms] */
230ff950a7SFrank Schaefer #define EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL 100 /* [ms] */
240c0d06caSMauro Carvalho Chehab
250c0d06caSMauro Carvalho Chehab static unsigned int ir_debug;
260c0d06caSMauro Carvalho Chehab module_param(ir_debug, int, 0644);
270c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
280c0d06caSMauro Carvalho Chehab
290c0d06caSMauro Carvalho Chehab #define MODULE_NAME "em28xx"
300c0d06caSMauro Carvalho Chehab
31ce8591ffSMauro Carvalho Chehab #define dprintk(fmt, arg...) do { \
32ce8591ffSMauro Carvalho Chehab if (ir_debug) \
3329b05e22SMauro Carvalho Chehab dev_printk(KERN_DEBUG, &ir->dev->intf->dev, \
34ce8591ffSMauro Carvalho Chehab "input: %s: " fmt, __func__, ## arg); \
35ce8591ffSMauro Carvalho Chehab } while (0)
360c0d06caSMauro Carvalho Chehab
3708cc05e4SMauro Carvalho Chehab /*
3808cc05e4SMauro Carvalho Chehab * Polling structure used by em28xx IR's
3908cc05e4SMauro Carvalho Chehab */
400c0d06caSMauro Carvalho Chehab
410c0d06caSMauro Carvalho Chehab struct em28xx_ir_poll_result {
420c0d06caSMauro Carvalho Chehab unsigned int toggle_bit:1;
430c0d06caSMauro Carvalho Chehab unsigned int read_count:7;
44105e3687SMauro Carvalho Chehab
456d741bfeSSean Young enum rc_proto protocol;
46105e3687SMauro Carvalho Chehab u32 scancode;
470c0d06caSMauro Carvalho Chehab };
480c0d06caSMauro Carvalho Chehab
490c0d06caSMauro Carvalho Chehab struct em28xx_IR {
500c0d06caSMauro Carvalho Chehab struct em28xx *dev;
510c0d06caSMauro Carvalho Chehab struct rc_dev *rc;
520c0d06caSMauro Carvalho Chehab char phys[32];
530c0d06caSMauro Carvalho Chehab
54768da3dbSFrank Schaefer /* poll decoder */
550c0d06caSMauro Carvalho Chehab int polling;
560c0d06caSMauro Carvalho Chehab struct delayed_work work;
570c0d06caSMauro Carvalho Chehab unsigned int full_code:1;
580c0d06caSMauro Carvalho Chehab unsigned int last_readcount;
596d741bfeSSean Young u64 rc_proto;
600c0d06caSMauro Carvalho Chehab
6178e719a5SFrank Schaefer struct i2c_client *i2c_client;
62768da3dbSFrank Schaefer
636d741bfeSSean Young int (*get_key_i2c)(struct i2c_client *ir, enum rc_proto *protocol,
646d741bfeSSean Young u32 *scancode);
6508cc05e4SMauro Carvalho Chehab int (*get_key)(struct em28xx_IR *ir, struct em28xx_ir_poll_result *r);
660c0d06caSMauro Carvalho Chehab };
670c0d06caSMauro Carvalho Chehab
6808cc05e4SMauro Carvalho Chehab /*
6908cc05e4SMauro Carvalho Chehab * I2C IR based get keycodes - should be used with ir-kbd-i2c
7008cc05e4SMauro Carvalho Chehab */
710c0d06caSMauro Carvalho Chehab
em28xx_get_key_terratec(struct i2c_client * i2c_dev,enum rc_proto * protocol,u32 * scancode)72120703f9SDavid Härdeman static int em28xx_get_key_terratec(struct i2c_client *i2c_dev,
736d741bfeSSean Young enum rc_proto *protocol, u32 *scancode)
740c0d06caSMauro Carvalho Chehab {
75728d9fd9SMauro Carvalho Chehab int rc;
760c0d06caSMauro Carvalho Chehab unsigned char b;
770c0d06caSMauro Carvalho Chehab
780c0d06caSMauro Carvalho Chehab /* poll IR chip */
79728d9fd9SMauro Carvalho Chehab rc = i2c_master_recv(i2c_dev, &b, 1);
80728d9fd9SMauro Carvalho Chehab if (rc != 1) {
81728d9fd9SMauro Carvalho Chehab if (rc < 0)
82728d9fd9SMauro Carvalho Chehab return rc;
830c0d06caSMauro Carvalho Chehab return -EIO;
84728d9fd9SMauro Carvalho Chehab }
850c0d06caSMauro Carvalho Chehab
8608cc05e4SMauro Carvalho Chehab /*
8708cc05e4SMauro Carvalho Chehab * it seems that 0xFE indicates that a button is still hold
8808cc05e4SMauro Carvalho Chehab * down, while 0xff indicates that no button is hold down.
8908cc05e4SMauro Carvalho Chehab */
900c0d06caSMauro Carvalho Chehab
910c0d06caSMauro Carvalho Chehab if (b == 0xff)
920c0d06caSMauro Carvalho Chehab return 0;
930c0d06caSMauro Carvalho Chehab
940c0d06caSMauro Carvalho Chehab if (b == 0xfe)
950c0d06caSMauro Carvalho Chehab /* keep old data */
960c0d06caSMauro Carvalho Chehab return 1;
970c0d06caSMauro Carvalho Chehab
986d741bfeSSean Young *protocol = RC_PROTO_UNKNOWN;
99120703f9SDavid Härdeman *scancode = b;
1000c0d06caSMauro Carvalho Chehab return 1;
1010c0d06caSMauro Carvalho Chehab }
1020c0d06caSMauro Carvalho Chehab
em28xx_get_key_em_haup(struct i2c_client * i2c_dev,enum rc_proto * protocol,u32 * scancode)103120703f9SDavid Härdeman static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev,
1046d741bfeSSean Young enum rc_proto *protocol, u32 *scancode)
1050c0d06caSMauro Carvalho Chehab {
1060c0d06caSMauro Carvalho Chehab unsigned char buf[2];
1070c0d06caSMauro Carvalho Chehab int size;
1080c0d06caSMauro Carvalho Chehab
1090c0d06caSMauro Carvalho Chehab /* poll IR chip */
110768da3dbSFrank Schaefer size = i2c_master_recv(i2c_dev, buf, sizeof(buf));
1110c0d06caSMauro Carvalho Chehab
1120c0d06caSMauro Carvalho Chehab if (size != 2)
1130c0d06caSMauro Carvalho Chehab return -EIO;
1140c0d06caSMauro Carvalho Chehab
1150c0d06caSMauro Carvalho Chehab /* Does eliminate repeated parity code */
1160c0d06caSMauro Carvalho Chehab if (buf[1] == 0xff)
1170c0d06caSMauro Carvalho Chehab return 0;
1180c0d06caSMauro Carvalho Chehab
1190c0d06caSMauro Carvalho Chehab /*
1200c0d06caSMauro Carvalho Chehab * Rearranges bits to the right order.
1210c0d06caSMauro Carvalho Chehab * The bit order were determined experimentally by using
1220c0d06caSMauro Carvalho Chehab * The original Hauppauge Grey IR and another RC5 that uses addr=0x08
1230c0d06caSMauro Carvalho Chehab * The RC5 code has 14 bits, but we've experimentally determined
1240c0d06caSMauro Carvalho Chehab * the meaning for only 11 bits.
1250c0d06caSMauro Carvalho Chehab * So, the code translation is not complete. Yet, it is enough to
1260c0d06caSMauro Carvalho Chehab * work with the provided RC5 IR.
1270c0d06caSMauro Carvalho Chehab */
1286d741bfeSSean Young *protocol = RC_PROTO_RC5;
129120703f9SDavid Härdeman *scancode = (bitrev8(buf[1]) & 0x1f) << 8 | bitrev8(buf[0]) >> 2;
1300c0d06caSMauro Carvalho Chehab return 1;
1310c0d06caSMauro Carvalho Chehab }
1320c0d06caSMauro Carvalho Chehab
em28xx_get_key_pinnacle_usb_grey(struct i2c_client * i2c_dev,enum rc_proto * protocol,u32 * scancode)133768da3dbSFrank Schaefer static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
1346d741bfeSSean Young enum rc_proto *protocol,
1356d741bfeSSean Young u32 *scancode)
1360c0d06caSMauro Carvalho Chehab {
1370c0d06caSMauro Carvalho Chehab unsigned char buf[3];
1380c0d06caSMauro Carvalho Chehab
1390c0d06caSMauro Carvalho Chehab /* poll IR chip */
1400c0d06caSMauro Carvalho Chehab
14108cc05e4SMauro Carvalho Chehab if (i2c_master_recv(i2c_dev, buf, 3) != 3)
1420c0d06caSMauro Carvalho Chehab return -EIO;
1430c0d06caSMauro Carvalho Chehab
1440c0d06caSMauro Carvalho Chehab if (buf[0] != 0x00)
1450c0d06caSMauro Carvalho Chehab return 0;
1460c0d06caSMauro Carvalho Chehab
1476d741bfeSSean Young *protocol = RC_PROTO_UNKNOWN;
148120703f9SDavid Härdeman *scancode = buf[2] & 0x3f;
1490c0d06caSMauro Carvalho Chehab return 1;
1500c0d06caSMauro Carvalho Chehab }
1510c0d06caSMauro Carvalho Chehab
em28xx_get_key_winfast_usbii_deluxe(struct i2c_client * i2c_dev,enum rc_proto * protocol,u32 * scancode)152768da3dbSFrank Schaefer static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
1536d741bfeSSean Young enum rc_proto *protocol,
1546d741bfeSSean Young u32 *scancode)
1550c0d06caSMauro Carvalho Chehab {
1560c0d06caSMauro Carvalho Chehab unsigned char subaddr, keydetect, key;
1570c0d06caSMauro Carvalho Chehab
15808cc05e4SMauro Carvalho Chehab struct i2c_msg msg[] = {
15908cc05e4SMauro Carvalho Chehab {
16008cc05e4SMauro Carvalho Chehab .addr = i2c_dev->addr,
16108cc05e4SMauro Carvalho Chehab .flags = 0,
16208cc05e4SMauro Carvalho Chehab .buf = &subaddr, .len = 1
16308cc05e4SMauro Carvalho Chehab }, {
16408cc05e4SMauro Carvalho Chehab .addr = i2c_dev->addr,
16508cc05e4SMauro Carvalho Chehab .flags = I2C_M_RD,
16608cc05e4SMauro Carvalho Chehab .buf = &keydetect,
16708cc05e4SMauro Carvalho Chehab .len = 1
16808cc05e4SMauro Carvalho Chehab }
16908cc05e4SMauro Carvalho Chehab };
1700c0d06caSMauro Carvalho Chehab
1710c0d06caSMauro Carvalho Chehab subaddr = 0x10;
17208cc05e4SMauro Carvalho Chehab if (i2c_transfer(i2c_dev->adapter, msg, 2) != 2)
1730c0d06caSMauro Carvalho Chehab return -EIO;
1740c0d06caSMauro Carvalho Chehab if (keydetect == 0x00)
1750c0d06caSMauro Carvalho Chehab return 0;
1760c0d06caSMauro Carvalho Chehab
1770c0d06caSMauro Carvalho Chehab subaddr = 0x00;
1780c0d06caSMauro Carvalho Chehab msg[1].buf = &key;
17908cc05e4SMauro Carvalho Chehab if (i2c_transfer(i2c_dev->adapter, msg, 2) != 2)
1800c0d06caSMauro Carvalho Chehab return -EIO;
1810c0d06caSMauro Carvalho Chehab if (key == 0x00)
1820c0d06caSMauro Carvalho Chehab return 0;
1830c0d06caSMauro Carvalho Chehab
1846d741bfeSSean Young *protocol = RC_PROTO_UNKNOWN;
185120703f9SDavid Härdeman *scancode = key;
1860c0d06caSMauro Carvalho Chehab return 1;
1870c0d06caSMauro Carvalho Chehab }
1880c0d06caSMauro Carvalho Chehab
18908cc05e4SMauro Carvalho Chehab /*
19008cc05e4SMauro Carvalho Chehab * Poll based get keycode functions
19108cc05e4SMauro Carvalho Chehab */
1920c0d06caSMauro Carvalho Chehab
1930c0d06caSMauro Carvalho Chehab /* This is for the em2860/em2880 */
default_polling_getkey(struct em28xx_IR * ir,struct em28xx_ir_poll_result * poll_result)1940c0d06caSMauro Carvalho Chehab static int default_polling_getkey(struct em28xx_IR *ir,
1950c0d06caSMauro Carvalho Chehab struct em28xx_ir_poll_result *poll_result)
1960c0d06caSMauro Carvalho Chehab {
1970c0d06caSMauro Carvalho Chehab struct em28xx *dev = ir->dev;
1980c0d06caSMauro Carvalho Chehab int rc;
1990c0d06caSMauro Carvalho Chehab u8 msg[3] = { 0, 0, 0 };
2000c0d06caSMauro Carvalho Chehab
20108cc05e4SMauro Carvalho Chehab /*
20208cc05e4SMauro Carvalho Chehab * Read key toggle, brand, and key code
20308cc05e4SMauro Carvalho Chehab * on registers 0x45, 0x46 and 0x47
2040c0d06caSMauro Carvalho Chehab */
2050c0d06caSMauro Carvalho Chehab rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
2060c0d06caSMauro Carvalho Chehab msg, sizeof(msg));
2070c0d06caSMauro Carvalho Chehab if (rc < 0)
2080c0d06caSMauro Carvalho Chehab return rc;
2090c0d06caSMauro Carvalho Chehab
2100c0d06caSMauro Carvalho Chehab /* Infrared toggle (Reg 0x45[7]) */
2110c0d06caSMauro Carvalho Chehab poll_result->toggle_bit = (msg[0] >> 7);
2120c0d06caSMauro Carvalho Chehab
2130c0d06caSMauro Carvalho Chehab /* Infrared read count (Reg 0x45[6:0] */
2140c0d06caSMauro Carvalho Chehab poll_result->read_count = (msg[0] & 0x7f);
2150c0d06caSMauro Carvalho Chehab
216105e3687SMauro Carvalho Chehab /* Remote Control Address/Data (Regs 0x46/0x47) */
2176d741bfeSSean Young switch (ir->rc_proto) {
2186d741bfeSSean Young case RC_PROTO_BIT_RC5:
2196d741bfeSSean Young poll_result->protocol = RC_PROTO_RC5;
220120703f9SDavid Härdeman poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]);
221120703f9SDavid Härdeman break;
222120703f9SDavid Härdeman
2236d741bfeSSean Young case RC_PROTO_BIT_NEC:
2246d741bfeSSean Young poll_result->protocol = RC_PROTO_NEC;
225120703f9SDavid Härdeman poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[2]);
226120703f9SDavid Härdeman break;
227120703f9SDavid Härdeman
228120703f9SDavid Härdeman default:
2296d741bfeSSean Young poll_result->protocol = RC_PROTO_UNKNOWN;
230105e3687SMauro Carvalho Chehab poll_result->scancode = msg[1] << 8 | msg[2];
231120703f9SDavid Härdeman break;
232120703f9SDavid Härdeman }
2330c0d06caSMauro Carvalho Chehab
2340c0d06caSMauro Carvalho Chehab return 0;
2350c0d06caSMauro Carvalho Chehab }
2360c0d06caSMauro Carvalho Chehab
em2874_polling_getkey(struct em28xx_IR * ir,struct em28xx_ir_poll_result * poll_result)2370c0d06caSMauro Carvalho Chehab static int em2874_polling_getkey(struct em28xx_IR *ir,
2380c0d06caSMauro Carvalho Chehab struct em28xx_ir_poll_result *poll_result)
2390c0d06caSMauro Carvalho Chehab {
2400c0d06caSMauro Carvalho Chehab struct em28xx *dev = ir->dev;
2410c0d06caSMauro Carvalho Chehab int rc;
2420c0d06caSMauro Carvalho Chehab u8 msg[5] = { 0, 0, 0, 0, 0 };
2430c0d06caSMauro Carvalho Chehab
24408cc05e4SMauro Carvalho Chehab /*
24508cc05e4SMauro Carvalho Chehab * Read key toggle, brand, and key code
24608cc05e4SMauro Carvalho Chehab * on registers 0x51-55
2470c0d06caSMauro Carvalho Chehab */
2480c0d06caSMauro Carvalho Chehab rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR,
2490c0d06caSMauro Carvalho Chehab msg, sizeof(msg));
2500c0d06caSMauro Carvalho Chehab if (rc < 0)
2510c0d06caSMauro Carvalho Chehab return rc;
2520c0d06caSMauro Carvalho Chehab
2530c0d06caSMauro Carvalho Chehab /* Infrared toggle (Reg 0x51[7]) */
2540c0d06caSMauro Carvalho Chehab poll_result->toggle_bit = (msg[0] >> 7);
2550c0d06caSMauro Carvalho Chehab
2560c0d06caSMauro Carvalho Chehab /* Infrared read count (Reg 0x51[6:0] */
2570c0d06caSMauro Carvalho Chehab poll_result->read_count = (msg[0] & 0x7f);
2580c0d06caSMauro Carvalho Chehab
259105e3687SMauro Carvalho Chehab /*
260105e3687SMauro Carvalho Chehab * Remote Control Address (Reg 0x52)
261105e3687SMauro Carvalho Chehab * Remote Control Data (Reg 0x53-0x55)
262105e3687SMauro Carvalho Chehab */
2636d741bfeSSean Young switch (ir->rc_proto) {
2646d741bfeSSean Young case RC_PROTO_BIT_RC5:
2656d741bfeSSean Young poll_result->protocol = RC_PROTO_RC5;
266120703f9SDavid Härdeman poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]);
267105e3687SMauro Carvalho Chehab break;
268120703f9SDavid Härdeman
2696d741bfeSSean Young case RC_PROTO_BIT_NEC:
2706bd914bcSSean Young poll_result->scancode = ir_nec_bytes_to_scancode(msg[1], msg[2], msg[3], msg[4],
2716bd914bcSSean Young &poll_result->protocol);
272105e3687SMauro Carvalho Chehab break;
273120703f9SDavid Härdeman
2746d741bfeSSean Young case RC_PROTO_BIT_RC6_0:
2756d741bfeSSean Young poll_result->protocol = RC_PROTO_RC6_0;
276120703f9SDavid Härdeman poll_result->scancode = RC_SCANCODE_RC6_0(msg[1], msg[2]);
2770dae8839SMauro Carvalho Chehab break;
278120703f9SDavid Härdeman
279105e3687SMauro Carvalho Chehab default:
2806d741bfeSSean Young poll_result->protocol = RC_PROTO_UNKNOWN;
281105e3687SMauro Carvalho Chehab poll_result->scancode = (msg[1] << 24) | (msg[2] << 16) |
282105e3687SMauro Carvalho Chehab (msg[3] << 8) | msg[4];
283105e3687SMauro Carvalho Chehab break;
284105e3687SMauro Carvalho Chehab }
2850c0d06caSMauro Carvalho Chehab
2860c0d06caSMauro Carvalho Chehab return 0;
2870c0d06caSMauro Carvalho Chehab }
2880c0d06caSMauro Carvalho Chehab
28908cc05e4SMauro Carvalho Chehab /*
29008cc05e4SMauro Carvalho Chehab * Polling code for em28xx
29108cc05e4SMauro Carvalho Chehab */
2920c0d06caSMauro Carvalho Chehab
em28xx_i2c_ir_handle_key(struct em28xx_IR * ir)293768da3dbSFrank Schaefer static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
294768da3dbSFrank Schaefer {
295120703f9SDavid Härdeman static u32 scancode;
2966d741bfeSSean Young enum rc_proto protocol;
297768da3dbSFrank Schaefer int rc;
298768da3dbSFrank Schaefer
29978e719a5SFrank Schaefer rc = ir->get_key_i2c(ir->i2c_client, &protocol, &scancode);
300768da3dbSFrank Schaefer if (rc < 0) {
301768da3dbSFrank Schaefer dprintk("ir->get_key_i2c() failed: %d\n", rc);
302768da3dbSFrank Schaefer return rc;
303768da3dbSFrank Schaefer }
304768da3dbSFrank Schaefer
305768da3dbSFrank Schaefer if (rc) {
306120703f9SDavid Härdeman dprintk("%s: proto = 0x%04x, scancode = 0x%04x\n",
307120703f9SDavid Härdeman __func__, protocol, scancode);
308120703f9SDavid Härdeman rc_keydown(ir->rc, protocol, scancode, 0);
309768da3dbSFrank Schaefer }
310768da3dbSFrank Schaefer return 0;
311768da3dbSFrank Schaefer }
312768da3dbSFrank Schaefer
em28xx_ir_handle_key(struct em28xx_IR * ir)3130c0d06caSMauro Carvalho Chehab static void em28xx_ir_handle_key(struct em28xx_IR *ir)
3140c0d06caSMauro Carvalho Chehab {
3150c0d06caSMauro Carvalho Chehab int result;
3160c0d06caSMauro Carvalho Chehab struct em28xx_ir_poll_result poll_result;
3170c0d06caSMauro Carvalho Chehab
3180c0d06caSMauro Carvalho Chehab /* read the registers containing the IR status */
3190c0d06caSMauro Carvalho Chehab result = ir->get_key(ir, &poll_result);
3200c0d06caSMauro Carvalho Chehab if (unlikely(result < 0)) {
321768da3dbSFrank Schaefer dprintk("ir->get_key() failed: %d\n", result);
3220c0d06caSMauro Carvalho Chehab return;
3230c0d06caSMauro Carvalho Chehab }
3240c0d06caSMauro Carvalho Chehab
3250c0d06caSMauro Carvalho Chehab if (unlikely(poll_result.read_count != ir->last_readcount)) {
326105e3687SMauro Carvalho Chehab dprintk("%s: toggle: %d, count: %d, key 0x%04x\n", __func__,
3270c0d06caSMauro Carvalho Chehab poll_result.toggle_bit, poll_result.read_count,
328105e3687SMauro Carvalho Chehab poll_result.scancode);
3290c0d06caSMauro Carvalho Chehab if (ir->full_code)
3300c0d06caSMauro Carvalho Chehab rc_keydown(ir->rc,
331120703f9SDavid Härdeman poll_result.protocol,
332105e3687SMauro Carvalho Chehab poll_result.scancode,
3330c0d06caSMauro Carvalho Chehab poll_result.toggle_bit);
3340c0d06caSMauro Carvalho Chehab else
3350c0d06caSMauro Carvalho Chehab rc_keydown(ir->rc,
3366d741bfeSSean Young RC_PROTO_UNKNOWN,
337105e3687SMauro Carvalho Chehab poll_result.scancode & 0xff,
3380c0d06caSMauro Carvalho Chehab poll_result.toggle_bit);
3390c0d06caSMauro Carvalho Chehab
3400c0d06caSMauro Carvalho Chehab if (ir->dev->chip_id == CHIP_ID_EM2874 ||
3410c0d06caSMauro Carvalho Chehab ir->dev->chip_id == CHIP_ID_EM2884)
34208cc05e4SMauro Carvalho Chehab /*
34308cc05e4SMauro Carvalho Chehab * The em2874 clears the readcount field every time the
34408cc05e4SMauro Carvalho Chehab * register is read. The em2860/2880 datasheet says
34508cc05e4SMauro Carvalho Chehab * that it is supposed to clear the readcount, but it
34608cc05e4SMauro Carvalho Chehab * doesn't. So with the em2874, we are looking for a
34708cc05e4SMauro Carvalho Chehab * non-zero read count as opposed to a readcount
34808cc05e4SMauro Carvalho Chehab * that is incrementing
34908cc05e4SMauro Carvalho Chehab */
3500c0d06caSMauro Carvalho Chehab ir->last_readcount = 0;
3510c0d06caSMauro Carvalho Chehab else
3520c0d06caSMauro Carvalho Chehab ir->last_readcount = poll_result.read_count;
3530c0d06caSMauro Carvalho Chehab }
3540c0d06caSMauro Carvalho Chehab }
3550c0d06caSMauro Carvalho Chehab
em28xx_ir_work(struct work_struct * work)3560c0d06caSMauro Carvalho Chehab static void em28xx_ir_work(struct work_struct *work)
3570c0d06caSMauro Carvalho Chehab {
3580c0d06caSMauro Carvalho Chehab struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
3590c0d06caSMauro Carvalho Chehab
36078e719a5SFrank Schaefer if (ir->i2c_client) /* external i2c device */
3619b4539beSFrank Schaefer em28xx_i2c_ir_handle_key(ir);
3629b4539beSFrank Schaefer else /* internal device */
3630c0d06caSMauro Carvalho Chehab em28xx_ir_handle_key(ir);
3640c0d06caSMauro Carvalho Chehab schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
3650c0d06caSMauro Carvalho Chehab }
3660c0d06caSMauro Carvalho Chehab
em28xx_ir_start(struct rc_dev * rc)3670c0d06caSMauro Carvalho Chehab static int em28xx_ir_start(struct rc_dev *rc)
3680c0d06caSMauro Carvalho Chehab {
3690c0d06caSMauro Carvalho Chehab struct em28xx_IR *ir = rc->priv;
3700c0d06caSMauro Carvalho Chehab
3710c0d06caSMauro Carvalho Chehab INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
3720c0d06caSMauro Carvalho Chehab schedule_delayed_work(&ir->work, 0);
3730c0d06caSMauro Carvalho Chehab
3740c0d06caSMauro Carvalho Chehab return 0;
3750c0d06caSMauro Carvalho Chehab }
3760c0d06caSMauro Carvalho Chehab
em28xx_ir_stop(struct rc_dev * rc)3770c0d06caSMauro Carvalho Chehab static void em28xx_ir_stop(struct rc_dev *rc)
3780c0d06caSMauro Carvalho Chehab {
3790c0d06caSMauro Carvalho Chehab struct em28xx_IR *ir = rc->priv;
3800c0d06caSMauro Carvalho Chehab
3810c0d06caSMauro Carvalho Chehab cancel_delayed_work_sync(&ir->work);
3820c0d06caSMauro Carvalho Chehab }
3830c0d06caSMauro Carvalho Chehab
em2860_ir_change_protocol(struct rc_dev * rc_dev,u64 * rc_proto)3846d741bfeSSean Young static int em2860_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_proto)
3850c0d06caSMauro Carvalho Chehab {
3860dae8839SMauro Carvalho Chehab struct em28xx_IR *ir = rc_dev->priv;
3870dae8839SMauro Carvalho Chehab struct em28xx *dev = ir->dev;
3880dae8839SMauro Carvalho Chehab
3890dae8839SMauro Carvalho Chehab /* Adjust xclk based on IR table for RC5/NEC tables */
3906d741bfeSSean Young if (*rc_proto & RC_PROTO_BIT_RC5) {
3910dae8839SMauro Carvalho Chehab dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
3920dae8839SMauro Carvalho Chehab ir->full_code = 1;
3936d741bfeSSean Young *rc_proto = RC_PROTO_BIT_RC5;
3946d741bfeSSean Young } else if (*rc_proto & RC_PROTO_BIT_NEC) {
3950dae8839SMauro Carvalho Chehab dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
3960dae8839SMauro Carvalho Chehab ir->full_code = 1;
3976d741bfeSSean Young *rc_proto = RC_PROTO_BIT_NEC;
3986d741bfeSSean Young } else if (*rc_proto & RC_PROTO_BIT_UNKNOWN) {
3996d741bfeSSean Young *rc_proto = RC_PROTO_BIT_UNKNOWN;
4000dae8839SMauro Carvalho Chehab } else {
4016d741bfeSSean Young *rc_proto = ir->rc_proto;
4020dae8839SMauro Carvalho Chehab return -EINVAL;
4030dae8839SMauro Carvalho Chehab }
4040dae8839SMauro Carvalho Chehab em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
4050dae8839SMauro Carvalho Chehab EM28XX_XCLK_IR_RC5_MODE);
4060dae8839SMauro Carvalho Chehab
4076d741bfeSSean Young ir->rc_proto = *rc_proto;
4080dae8839SMauro Carvalho Chehab
4090dae8839SMauro Carvalho Chehab return 0;
4100dae8839SMauro Carvalho Chehab }
4110dae8839SMauro Carvalho Chehab
em2874_ir_change_protocol(struct rc_dev * rc_dev,u64 * rc_proto)4126d741bfeSSean Young static int em2874_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_proto)
4130dae8839SMauro Carvalho Chehab {
4140c0d06caSMauro Carvalho Chehab struct em28xx_IR *ir = rc_dev->priv;
4150c0d06caSMauro Carvalho Chehab struct em28xx *dev = ir->dev;
4160c0d06caSMauro Carvalho Chehab u8 ir_config = EM2874_IR_RC5;
4170c0d06caSMauro Carvalho Chehab
4180dae8839SMauro Carvalho Chehab /* Adjust xclk and set type based on IR table for RC5/NEC/RC6 tables */
4196d741bfeSSean Young if (*rc_proto & RC_PROTO_BIT_RC5) {
4200c0d06caSMauro Carvalho Chehab dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
4210c0d06caSMauro Carvalho Chehab ir->full_code = 1;
4226d741bfeSSean Young *rc_proto = RC_PROTO_BIT_RC5;
4236d741bfeSSean Young } else if (*rc_proto & RC_PROTO_BIT_NEC) {
4240c0d06caSMauro Carvalho Chehab dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
425105e3687SMauro Carvalho Chehab ir_config = EM2874_IR_NEC | EM2874_IR_NEC_NO_PARITY;
4260c0d06caSMauro Carvalho Chehab ir->full_code = 1;
4276d741bfeSSean Young *rc_proto = RC_PROTO_BIT_NEC;
4286d741bfeSSean Young } else if (*rc_proto & RC_PROTO_BIT_RC6_0) {
4290dae8839SMauro Carvalho Chehab dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
4300dae8839SMauro Carvalho Chehab ir_config = EM2874_IR_RC6_MODE_0;
4310dae8839SMauro Carvalho Chehab ir->full_code = 1;
4326d741bfeSSean Young *rc_proto = RC_PROTO_BIT_RC6_0;
4336d741bfeSSean Young } else if (*rc_proto & RC_PROTO_BIT_UNKNOWN) {
4346d741bfeSSean Young *rc_proto = RC_PROTO_BIT_UNKNOWN;
4350dae8839SMauro Carvalho Chehab } else {
4366d741bfeSSean Young *rc_proto = ir->rc_proto;
4370dae8839SMauro Carvalho Chehab return -EINVAL;
4380dae8839SMauro Carvalho Chehab }
4390dae8839SMauro Carvalho Chehab em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
4400c0d06caSMauro Carvalho Chehab em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
4410c0d06caSMauro Carvalho Chehab EM28XX_XCLK_IR_RC5_MODE);
4420c0d06caSMauro Carvalho Chehab
4436d741bfeSSean Young ir->rc_proto = *rc_proto;
4440dae8839SMauro Carvalho Chehab
4450dae8839SMauro Carvalho Chehab return 0;
4460dae8839SMauro Carvalho Chehab }
4476d741bfeSSean Young
em28xx_ir_change_protocol(struct rc_dev * rc_dev,u64 * rc_proto)4486d741bfeSSean Young static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_proto)
4490dae8839SMauro Carvalho Chehab {
4500dae8839SMauro Carvalho Chehab struct em28xx_IR *ir = rc_dev->priv;
4510dae8839SMauro Carvalho Chehab struct em28xx *dev = ir->dev;
4520dae8839SMauro Carvalho Chehab
4530c0d06caSMauro Carvalho Chehab /* Setup the proper handler based on the chip */
4540c0d06caSMauro Carvalho Chehab switch (dev->chip_id) {
4550c0d06caSMauro Carvalho Chehab case CHIP_ID_EM2860:
4560c0d06caSMauro Carvalho Chehab case CHIP_ID_EM2883:
4576d741bfeSSean Young return em2860_ir_change_protocol(rc_dev, rc_proto);
4580c0d06caSMauro Carvalho Chehab case CHIP_ID_EM2884:
4590c0d06caSMauro Carvalho Chehab case CHIP_ID_EM2874:
4600c0d06caSMauro Carvalho Chehab case CHIP_ID_EM28174:
4619f1d0bdaSAntti Palosaari case CHIP_ID_EM28178:
4626d741bfeSSean Young return em2874_ir_change_protocol(rc_dev, rc_proto);
4630c0d06caSMauro Carvalho Chehab default:
46429b05e22SMauro Carvalho Chehab dev_err(&ir->dev->intf->dev,
465ce8591ffSMauro Carvalho Chehab "Unrecognized em28xx chip id 0x%02x: IR not supported\n",
4660c0d06caSMauro Carvalho Chehab dev->chip_id);
4670dae8839SMauro Carvalho Chehab return -EINVAL;
4680c0d06caSMauro Carvalho Chehab }
4690c0d06caSMauro Carvalho Chehab }
4700c0d06caSMauro Carvalho Chehab
em28xx_probe_i2c_ir(struct em28xx * dev)4711d968cdaSFrank Schaefer static int em28xx_probe_i2c_ir(struct em28xx *dev)
4720c0d06caSMauro Carvalho Chehab {
473768da3dbSFrank Schaefer int i = 0;
47408cc05e4SMauro Carvalho Chehab /*
47508cc05e4SMauro Carvalho Chehab * Leadtek winfast tv USBII deluxe can find a non working IR-device
47608cc05e4SMauro Carvalho Chehab * at address 0x18, so if that address is needed for another board in
47708cc05e4SMauro Carvalho Chehab * the future, please put it after 0x1f.
47808cc05e4SMauro Carvalho Chehab */
4796fe59b7eSColin Ian King static const unsigned short addr_list[] = {
4800c0d06caSMauro Carvalho Chehab 0x1f, 0x30, 0x47, I2C_CLIENT_END
4810c0d06caSMauro Carvalho Chehab };
4820c0d06caSMauro Carvalho Chehab
483768da3dbSFrank Schaefer while (addr_list[i] != I2C_CLIENT_END) {
48408cc05e4SMauro Carvalho Chehab if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus],
48508cc05e4SMauro Carvalho Chehab addr_list[i]) == 1)
4861d968cdaSFrank Schaefer return addr_list[i];
487768da3dbSFrank Schaefer i++;
488768da3dbSFrank Schaefer }
4890c0d06caSMauro Carvalho Chehab
4901d968cdaSFrank Schaefer return -ENODEV;
4910c0d06caSMauro Carvalho Chehab }
4920c0d06caSMauro Carvalho Chehab
49308cc05e4SMauro Carvalho Chehab /*
49408cc05e4SMauro Carvalho Chehab * Handle buttons
49508cc05e4SMauro Carvalho Chehab */
4960c0d06caSMauro Carvalho Chehab
em28xx_query_buttons(struct work_struct * work)497f5222609SFrank Schaefer static void em28xx_query_buttons(struct work_struct *work)
4980c0d06caSMauro Carvalho Chehab {
4990c0d06caSMauro Carvalho Chehab struct em28xx *dev =
500f5222609SFrank Schaefer container_of(work, struct em28xx, buttons_query_work.work);
501f5222609SFrank Schaefer u8 i, j;
502f5222609SFrank Schaefer int regval;
5037763481aSFrank Schaefer bool is_pressed, was_pressed;
5046063d077SFrank Schaefer const struct em28xx_led *led;
5050c0d06caSMauro Carvalho Chehab
506f5222609SFrank Schaefer /* Poll and evaluate all addresses */
507f5222609SFrank Schaefer for (i = 0; i < dev->num_button_polling_addresses; i++) {
508f5222609SFrank Schaefer /* Read value from register */
509f5222609SFrank Schaefer regval = em28xx_read_reg(dev, dev->button_polling_addresses[i]);
510f5222609SFrank Schaefer if (regval < 0)
511f5222609SFrank Schaefer continue;
512f5222609SFrank Schaefer /* Check states of the buttons and act */
513f5222609SFrank Schaefer j = 0;
514f5222609SFrank Schaefer while (dev->board.buttons[j].role >= 0 &&
515f5222609SFrank Schaefer dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) {
51608cc05e4SMauro Carvalho Chehab const struct em28xx_button *button;
51708cc05e4SMauro Carvalho Chehab
51808cc05e4SMauro Carvalho Chehab button = &dev->board.buttons[j];
5190108ae7fSMauro Carvalho Chehab
520f5222609SFrank Schaefer /* Check if button uses the current address */
521f5222609SFrank Schaefer if (button->reg_r != dev->button_polling_addresses[i]) {
522f5222609SFrank Schaefer j++;
523f5222609SFrank Schaefer continue;
5240c0d06caSMauro Carvalho Chehab }
5257763481aSFrank Schaefer /* Determine if button is and was pressed last time */
5267763481aSFrank Schaefer is_pressed = regval & button->mask;
5277763481aSFrank Schaefer was_pressed = dev->button_polling_last_values[i]
5287763481aSFrank Schaefer & button->mask;
5297763481aSFrank Schaefer if (button->inverted) {
5307763481aSFrank Schaefer is_pressed = !is_pressed;
5317763481aSFrank Schaefer was_pressed = !was_pressed;
5327763481aSFrank Schaefer }
5337763481aSFrank Schaefer /* Clear button state (if needed) */
5347763481aSFrank Schaefer if (is_pressed && button->reg_clearing)
5357763481aSFrank Schaefer em28xx_write_reg(dev, button->reg_clearing,
5367763481aSFrank Schaefer (~regval & button->mask)
5377763481aSFrank Schaefer | (regval & ~button->mask));
538f5222609SFrank Schaefer /* Handle button state */
5397763481aSFrank Schaefer if (!is_pressed || was_pressed) {
540f5222609SFrank Schaefer j++;
541f5222609SFrank Schaefer continue;
542f5222609SFrank Schaefer }
543f5222609SFrank Schaefer switch (button->role) {
544f5222609SFrank Schaefer case EM28XX_BUTTON_SNAPSHOT:
545f5222609SFrank Schaefer /* Emulate the keypress */
546f5222609SFrank Schaefer input_report_key(dev->sbutton_input_dev,
547f5222609SFrank Schaefer EM28XX_SNAPSHOT_KEY, 1);
548f5222609SFrank Schaefer /* Unpress the key */
549f5222609SFrank Schaefer input_report_key(dev->sbutton_input_dev,
550f5222609SFrank Schaefer EM28XX_SNAPSHOT_KEY, 0);
551f5222609SFrank Schaefer break;
5526063d077SFrank Schaefer case EM28XX_BUTTON_ILLUMINATION:
5536063d077SFrank Schaefer led = em28xx_find_led(dev,
5546063d077SFrank Schaefer EM28XX_LED_ILLUMINATION);
5556063d077SFrank Schaefer /* Switch illumination LED on/off */
5566063d077SFrank Schaefer if (led)
5576063d077SFrank Schaefer em28xx_toggle_reg_bits(dev,
5586063d077SFrank Schaefer led->gpio_reg,
5596063d077SFrank Schaefer led->gpio_mask);
5606063d077SFrank Schaefer break;
561f5222609SFrank Schaefer default:
562f5222609SFrank Schaefer WARN_ONCE(1, "BUG: unhandled button role.");
563f5222609SFrank Schaefer }
564f5222609SFrank Schaefer /* Next button */
565f5222609SFrank Schaefer j++;
566f5222609SFrank Schaefer }
5677763481aSFrank Schaefer /* Save current value for comparison during the next polling */
5687763481aSFrank Schaefer dev->button_polling_last_values[i] = regval;
569f5222609SFrank Schaefer }
5700c0d06caSMauro Carvalho Chehab /* Schedule next poll */
571f5222609SFrank Schaefer schedule_delayed_work(&dev->buttons_query_work,
5720ff950a7SFrank Schaefer msecs_to_jiffies(dev->button_polling_interval));
5730c0d06caSMauro Carvalho Chehab }
5740c0d06caSMauro Carvalho Chehab
em28xx_register_snapshot_button(struct em28xx * dev)575f5222609SFrank Schaefer static int em28xx_register_snapshot_button(struct em28xx *dev)
5760c0d06caSMauro Carvalho Chehab {
577c6d48134SMauro Carvalho Chehab struct usb_device *udev = interface_to_usbdev(dev->intf);
5780c0d06caSMauro Carvalho Chehab struct input_dev *input_dev;
5790c0d06caSMauro Carvalho Chehab int err;
5800c0d06caSMauro Carvalho Chehab
58129b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Registering snapshot button...\n");
5820c0d06caSMauro Carvalho Chehab input_dev = input_allocate_device();
583da4a7339SJoe Perches if (!input_dev)
584f5222609SFrank Schaefer return -ENOMEM;
5850c0d06caSMauro Carvalho Chehab
586c6d48134SMauro Carvalho Chehab usb_make_path(udev, dev->snapshot_button_path,
5870c0d06caSMauro Carvalho Chehab sizeof(dev->snapshot_button_path));
5880c0d06caSMauro Carvalho Chehab strlcat(dev->snapshot_button_path, "/sbutton",
5890c0d06caSMauro Carvalho Chehab sizeof(dev->snapshot_button_path));
5900c0d06caSMauro Carvalho Chehab
5910c0d06caSMauro Carvalho Chehab input_dev->name = "em28xx snapshot button";
5920c0d06caSMauro Carvalho Chehab input_dev->phys = dev->snapshot_button_path;
5930c0d06caSMauro Carvalho Chehab input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
5940c0d06caSMauro Carvalho Chehab set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit);
5950c0d06caSMauro Carvalho Chehab input_dev->keycodesize = 0;
5960c0d06caSMauro Carvalho Chehab input_dev->keycodemax = 0;
5970547858bSSean Young usb_to_input_id(udev, &input_dev->id);
59829b05e22SMauro Carvalho Chehab input_dev->dev.parent = &dev->intf->dev;
5990c0d06caSMauro Carvalho Chehab
6000c0d06caSMauro Carvalho Chehab err = input_register_device(input_dev);
6010c0d06caSMauro Carvalho Chehab if (err) {
60229b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev, "input_register_device failed\n");
6030c0d06caSMauro Carvalho Chehab input_free_device(input_dev);
604f5222609SFrank Schaefer return err;
6050c0d06caSMauro Carvalho Chehab }
6060c0d06caSMauro Carvalho Chehab
6070c0d06caSMauro Carvalho Chehab dev->sbutton_input_dev = input_dev;
608f5222609SFrank Schaefer return 0;
6090c0d06caSMauro Carvalho Chehab }
6100c0d06caSMauro Carvalho Chehab
em28xx_init_buttons(struct em28xx * dev)611f5222609SFrank Schaefer static void em28xx_init_buttons(struct em28xx *dev)
6120c0d06caSMauro Carvalho Chehab {
613f5222609SFrank Schaefer u8 i = 0, j = 0;
6147e6c8c19SMauro Carvalho Chehab bool addr_new = false;
615f5222609SFrank Schaefer
6160ff950a7SFrank Schaefer dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL;
617f5222609SFrank Schaefer while (dev->board.buttons[i].role >= 0 &&
618f5222609SFrank Schaefer dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) {
6190108ae7fSMauro Carvalho Chehab const struct em28xx_button *button = &dev->board.buttons[i];
6200108ae7fSMauro Carvalho Chehab
621f5222609SFrank Schaefer /* Check if polling address is already on the list */
6227e6c8c19SMauro Carvalho Chehab addr_new = true;
623f5222609SFrank Schaefer for (j = 0; j < dev->num_button_polling_addresses; j++) {
624f5222609SFrank Schaefer if (button->reg_r == dev->button_polling_addresses[j]) {
6257e6c8c19SMauro Carvalho Chehab addr_new = false;
626f5222609SFrank Schaefer break;
627f5222609SFrank Schaefer }
628f5222609SFrank Schaefer }
629f5222609SFrank Schaefer /* Check if max. number of polling addresses is exceeded */
630f5222609SFrank Schaefer if (addr_new && dev->num_button_polling_addresses
631f5222609SFrank Schaefer >= EM28XX_NUM_BUTTON_ADDRESSES_MAX) {
632f5222609SFrank Schaefer WARN_ONCE(1, "BUG: maximum number of button polling addresses exceeded.");
6330ff950a7SFrank Schaefer goto next_button;
634f5222609SFrank Schaefer }
6356063d077SFrank Schaefer /* Button role specific checks and actions */
636f5222609SFrank Schaefer if (button->role == EM28XX_BUTTON_SNAPSHOT) {
6376063d077SFrank Schaefer /* Register input device */
638f5222609SFrank Schaefer if (em28xx_register_snapshot_button(dev) < 0)
6390ff950a7SFrank Schaefer goto next_button;
6406063d077SFrank Schaefer } else if (button->role == EM28XX_BUTTON_ILLUMINATION) {
6416063d077SFrank Schaefer /* Check sanity */
6426063d077SFrank Schaefer if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) {
64329b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
644ce8591ffSMauro Carvalho Chehab "BUG: illumination button defined, but no illumination LED.\n");
6450ff950a7SFrank Schaefer goto next_button;
6466063d077SFrank Schaefer }
647f5222609SFrank Schaefer }
648f5222609SFrank Schaefer /* Add read address to list of polling addresses */
649f5222609SFrank Schaefer if (addr_new) {
650f5222609SFrank Schaefer unsigned int index = dev->num_button_polling_addresses;
65108cc05e4SMauro Carvalho Chehab
652f5222609SFrank Schaefer dev->button_polling_addresses[index] = button->reg_r;
653f5222609SFrank Schaefer dev->num_button_polling_addresses++;
654f5222609SFrank Schaefer }
6550ff950a7SFrank Schaefer /* Reduce polling interval if necessary */
6560ff950a7SFrank Schaefer if (!button->reg_clearing)
6570ff950a7SFrank Schaefer dev->button_polling_interval =
6580ff950a7SFrank Schaefer EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL;
6590ff950a7SFrank Schaefer next_button:
660f5222609SFrank Schaefer /* Next button */
661f5222609SFrank Schaefer i++;
662f5222609SFrank Schaefer }
663f5222609SFrank Schaefer
664f5222609SFrank Schaefer /* Start polling */
665f5222609SFrank Schaefer if (dev->num_button_polling_addresses) {
6667763481aSFrank Schaefer memset(dev->button_polling_last_values, 0,
6677763481aSFrank Schaefer EM28XX_NUM_BUTTON_ADDRESSES_MAX);
668f5222609SFrank Schaefer schedule_delayed_work(&dev->buttons_query_work,
6690ff950a7SFrank Schaefer msecs_to_jiffies(dev->button_polling_interval));
670f5222609SFrank Schaefer }
671f5222609SFrank Schaefer }
672f5222609SFrank Schaefer
em28xx_shutdown_buttons(struct em28xx * dev)673f5222609SFrank Schaefer static void em28xx_shutdown_buttons(struct em28xx *dev)
674f5222609SFrank Schaefer {
675f5222609SFrank Schaefer /* Cancel polling */
676f5222609SFrank Schaefer cancel_delayed_work_sync(&dev->buttons_query_work);
677f5222609SFrank Schaefer /* Clear polling addresses list */
678f5222609SFrank Schaefer dev->num_button_polling_addresses = 0;
679f5222609SFrank Schaefer /* Deregister input devices */
68008cc05e4SMauro Carvalho Chehab if (dev->sbutton_input_dev) {
68129b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Deregistering snapshot button\n");
6820c0d06caSMauro Carvalho Chehab input_unregister_device(dev->sbutton_input_dev);
6830c0d06caSMauro Carvalho Chehab dev->sbutton_input_dev = NULL;
6840c0d06caSMauro Carvalho Chehab }
6850c0d06caSMauro Carvalho Chehab }
6860c0d06caSMauro Carvalho Chehab
em28xx_ir_init(struct em28xx * dev)6870c0d06caSMauro Carvalho Chehab static int em28xx_ir_init(struct em28xx *dev)
6880c0d06caSMauro Carvalho Chehab {
689c6d48134SMauro Carvalho Chehab struct usb_device *udev = interface_to_usbdev(dev->intf);
6900c0d06caSMauro Carvalho Chehab struct em28xx_IR *ir;
6910c0d06caSMauro Carvalho Chehab struct rc_dev *rc;
6920c0d06caSMauro Carvalho Chehab int err = -ENOMEM;
6936d741bfeSSean Young u64 rc_proto;
6941d968cdaSFrank Schaefer u16 i2c_rc_dev_addr = 0;
6950c0d06caSMauro Carvalho Chehab
696822b8deaSMauro Carvalho Chehab if (dev->is_audio_only) {
697822b8deaSMauro Carvalho Chehab /* Shouldn't initialize IR for this interface */
698822b8deaSMauro Carvalho Chehab return 0;
699822b8deaSMauro Carvalho Chehab }
700822b8deaSMauro Carvalho Chehab
70147677e51SMauro Carvalho Chehab kref_get(&dev->ref);
702bbfebeeaSRussell King INIT_DELAYED_WORK(&dev->buttons_query_work, em28xx_query_buttons);
70347677e51SMauro Carvalho Chehab
704f5222609SFrank Schaefer if (dev->board.buttons)
705f5222609SFrank Schaefer em28xx_init_buttons(dev);
7068303dc99SMauro Carvalho Chehab
7078303dc99SMauro Carvalho Chehab if (dev->board.has_ir_i2c) {
7081d968cdaSFrank Schaefer i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev);
7091d968cdaSFrank Schaefer if (!i2c_rc_dev_addr) {
710768da3dbSFrank Schaefer dev->board.has_ir_i2c = 0;
71129b05e22SMauro Carvalho Chehab dev_warn(&dev->intf->dev,
712ce8591ffSMauro Carvalho Chehab "No i2c IR remote control device found.\n");
713*ac568863SIgor Matheus Andrade Torrente err = -ENODEV;
714*ac568863SIgor Matheus Andrade Torrente goto ref_put;
715768da3dbSFrank Schaefer }
7168303dc99SMauro Carvalho Chehab }
7178303dc99SMauro Carvalho Chehab
71808cc05e4SMauro Carvalho Chehab if (!dev->board.ir_codes && !dev->board.has_ir_i2c) {
7190c0d06caSMauro Carvalho Chehab /* No remote control support */
72029b05e22SMauro Carvalho Chehab dev_warn(&dev->intf->dev,
721ce8591ffSMauro Carvalho Chehab "Remote control support is not available for this card.\n");
7220c0d06caSMauro Carvalho Chehab return 0;
7230c0d06caSMauro Carvalho Chehab }
7240c0d06caSMauro Carvalho Chehab
72529b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Registering input extension\n");
7269634614fSMauro Carvalho Chehab
7270c0d06caSMauro Carvalho Chehab ir = kzalloc(sizeof(*ir), GFP_KERNEL);
72834d7c248SDan Carpenter if (!ir)
729*ac568863SIgor Matheus Andrade Torrente goto ref_put;
7300f7499fdSAndi Shyti rc = rc_allocate_device(RC_DRIVER_SCANCODE);
73134d7c248SDan Carpenter if (!rc)
7322f5741aaSFrank Schaefer goto error;
7330c0d06caSMauro Carvalho Chehab
7340c0d06caSMauro Carvalho Chehab /* record handles to ourself */
7350c0d06caSMauro Carvalho Chehab ir->dev = dev;
7360c0d06caSMauro Carvalho Chehab dev->ir = ir;
7370c0d06caSMauro Carvalho Chehab ir->rc = rc;
7380c0d06caSMauro Carvalho Chehab
7390c0d06caSMauro Carvalho Chehab rc->priv = ir;
7400c0d06caSMauro Carvalho Chehab rc->open = em28xx_ir_start;
7410c0d06caSMauro Carvalho Chehab rc->close = em28xx_ir_stop;
7420c0d06caSMauro Carvalho Chehab
743768da3dbSFrank Schaefer if (dev->board.has_ir_i2c) { /* external i2c device */
744768da3dbSFrank Schaefer switch (dev->model) {
745768da3dbSFrank Schaefer case EM2800_BOARD_TERRATEC_CINERGY_200:
746768da3dbSFrank Schaefer case EM2820_BOARD_TERRATEC_CINERGY_250:
747768da3dbSFrank Schaefer rc->map_name = RC_MAP_EM_TERRATEC;
748768da3dbSFrank Schaefer ir->get_key_i2c = em28xx_get_key_terratec;
749768da3dbSFrank Schaefer break;
750768da3dbSFrank Schaefer case EM2820_BOARD_PINNACLE_USB_2:
751768da3dbSFrank Schaefer rc->map_name = RC_MAP_PINNACLE_GREY;
752768da3dbSFrank Schaefer ir->get_key_i2c = em28xx_get_key_pinnacle_usb_grey;
753768da3dbSFrank Schaefer break;
754768da3dbSFrank Schaefer case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
755768da3dbSFrank Schaefer rc->map_name = RC_MAP_HAUPPAUGE;
756768da3dbSFrank Schaefer ir->get_key_i2c = em28xx_get_key_em_haup;
7576d741bfeSSean Young rc->allowed_protocols = RC_PROTO_BIT_RC5;
758768da3dbSFrank Schaefer break;
759768da3dbSFrank Schaefer case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
760768da3dbSFrank Schaefer rc->map_name = RC_MAP_WINFAST_USBII_DELUXE;
761768da3dbSFrank Schaefer ir->get_key_i2c = em28xx_get_key_winfast_usbii_deluxe;
762768da3dbSFrank Schaefer break;
763768da3dbSFrank Schaefer default:
764768da3dbSFrank Schaefer err = -ENODEV;
765768da3dbSFrank Schaefer goto error;
766768da3dbSFrank Schaefer }
767768da3dbSFrank Schaefer
76808cc05e4SMauro Carvalho Chehab ir->i2c_client = kzalloc(sizeof(*ir->i2c_client), GFP_KERNEL);
76978e719a5SFrank Schaefer if (!ir->i2c_client)
77078e719a5SFrank Schaefer goto error;
77178e719a5SFrank Schaefer ir->i2c_client->adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
77278e719a5SFrank Schaefer ir->i2c_client->addr = i2c_rc_dev_addr;
77378e719a5SFrank Schaefer ir->i2c_client->flags = 0;
77478e719a5SFrank Schaefer /* NOTE: all other fields of i2c_client are unused */
775768da3dbSFrank Schaefer } else { /* internal device */
7760dae8839SMauro Carvalho Chehab switch (dev->chip_id) {
7770dae8839SMauro Carvalho Chehab case CHIP_ID_EM2860:
7780dae8839SMauro Carvalho Chehab case CHIP_ID_EM2883:
7796d741bfeSSean Young rc->allowed_protocols = RC_PROTO_BIT_RC5 |
7806d741bfeSSean Young RC_PROTO_BIT_NEC;
7816ea887efSFrank Schaefer ir->get_key = default_polling_getkey;
7820dae8839SMauro Carvalho Chehab break;
7830dae8839SMauro Carvalho Chehab case CHIP_ID_EM2884:
7840dae8839SMauro Carvalho Chehab case CHIP_ID_EM2874:
7850dae8839SMauro Carvalho Chehab case CHIP_ID_EM28174:
7869f1d0bdaSAntti Palosaari case CHIP_ID_EM28178:
7876ea887efSFrank Schaefer ir->get_key = em2874_polling_getkey;
7886d741bfeSSean Young rc->allowed_protocols = RC_PROTO_BIT_RC5 |
7896d741bfeSSean Young RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX |
7906d741bfeSSean Young RC_PROTO_BIT_NEC32 | RC_PROTO_BIT_RC6_0;
7910dae8839SMauro Carvalho Chehab break;
7920dae8839SMauro Carvalho Chehab default:
7930dae8839SMauro Carvalho Chehab err = -ENODEV;
7942f5741aaSFrank Schaefer goto error;
7950dae8839SMauro Carvalho Chehab }
7960dae8839SMauro Carvalho Chehab
797768da3dbSFrank Schaefer rc->change_protocol = em28xx_ir_change_protocol;
798768da3dbSFrank Schaefer rc->map_name = dev->board.ir_codes;
799768da3dbSFrank Schaefer
8000c0d06caSMauro Carvalho Chehab /* By default, keep protocol field untouched */
8016d741bfeSSean Young rc_proto = RC_PROTO_BIT_UNKNOWN;
8026d741bfeSSean Young err = em28xx_ir_change_protocol(rc, &rc_proto);
8030c0d06caSMauro Carvalho Chehab if (err)
8042f5741aaSFrank Schaefer goto error;
805768da3dbSFrank Schaefer }
8060c0d06caSMauro Carvalho Chehab
8070c0d06caSMauro Carvalho Chehab /* This is how often we ask the chip for IR information */
8080c0d06caSMauro Carvalho Chehab ir->polling = 100; /* ms */
8090c0d06caSMauro Carvalho Chehab
810c6d48134SMauro Carvalho Chehab usb_make_path(udev, ir->phys, sizeof(ir->phys));
8110c0d06caSMauro Carvalho Chehab strlcat(ir->phys, "/input0", sizeof(ir->phys));
8120c0d06caSMauro Carvalho Chehab
8135c1c6953SSean Young rc->device_name = em28xx_boards[dev->model].name;
8140c0d06caSMauro Carvalho Chehab rc->input_phys = ir->phys;
8150547858bSSean Young usb_to_input_id(udev, &rc->input_id);
81629b05e22SMauro Carvalho Chehab rc->dev.parent = &dev->intf->dev;
8170c0d06caSMauro Carvalho Chehab rc->driver_name = MODULE_NAME;
8180c0d06caSMauro Carvalho Chehab
8190c0d06caSMauro Carvalho Chehab /* all done */
8200c0d06caSMauro Carvalho Chehab err = rc_register_device(rc);
8210c0d06caSMauro Carvalho Chehab if (err)
8222f5741aaSFrank Schaefer goto error;
8230c0d06caSMauro Carvalho Chehab
8241250a85bSMauro Carvalho Chehab dev_info(&dev->intf->dev, "Input extension successfully initialized\n");
8259634614fSMauro Carvalho Chehab
8260c0d06caSMauro Carvalho Chehab return 0;
8270c0d06caSMauro Carvalho Chehab
8282f5741aaSFrank Schaefer error:
82978e719a5SFrank Schaefer kfree(ir->i2c_client);
8300c0d06caSMauro Carvalho Chehab dev->ir = NULL;
8310c0d06caSMauro Carvalho Chehab rc_free_device(rc);
8320c0d06caSMauro Carvalho Chehab kfree(ir);
833*ac568863SIgor Matheus Andrade Torrente ref_put:
834*ac568863SIgor Matheus Andrade Torrente em28xx_shutdown_buttons(dev);
8350c0d06caSMauro Carvalho Chehab return err;
8360c0d06caSMauro Carvalho Chehab }
8370c0d06caSMauro Carvalho Chehab
em28xx_ir_fini(struct em28xx * dev)8380c0d06caSMauro Carvalho Chehab static int em28xx_ir_fini(struct em28xx *dev)
8390c0d06caSMauro Carvalho Chehab {
8400c0d06caSMauro Carvalho Chehab struct em28xx_IR *ir = dev->ir;
8410c0d06caSMauro Carvalho Chehab
842822b8deaSMauro Carvalho Chehab if (dev->is_audio_only) {
843822b8deaSMauro Carvalho Chehab /* Shouldn't initialize IR for this interface */
844822b8deaSMauro Carvalho Chehab return 0;
845822b8deaSMauro Carvalho Chehab }
846822b8deaSMauro Carvalho Chehab
84729b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Closing input extension\n");
848aa929ad7SMauro Carvalho Chehab
849f5222609SFrank Schaefer em28xx_shutdown_buttons(dev);
8500c0d06caSMauro Carvalho Chehab
8510c0d06caSMauro Carvalho Chehab /* skip detach on non attached boards */
8520c0d06caSMauro Carvalho Chehab if (!ir)
85347677e51SMauro Carvalho Chehab goto ref_put;
8540c0d06caSMauro Carvalho Chehab
8550c0d06caSMauro Carvalho Chehab rc_unregister_device(ir->rc);
8560c0d06caSMauro Carvalho Chehab
85778e719a5SFrank Schaefer kfree(ir->i2c_client);
85878e719a5SFrank Schaefer
8590c0d06caSMauro Carvalho Chehab /* done */
8600c0d06caSMauro Carvalho Chehab kfree(ir);
8610c0d06caSMauro Carvalho Chehab dev->ir = NULL;
86247677e51SMauro Carvalho Chehab
86347677e51SMauro Carvalho Chehab ref_put:
86447677e51SMauro Carvalho Chehab kref_put(&dev->ref, em28xx_free_device);
86547677e51SMauro Carvalho Chehab
8660c0d06caSMauro Carvalho Chehab return 0;
8670c0d06caSMauro Carvalho Chehab }
8680c0d06caSMauro Carvalho Chehab
em28xx_ir_suspend(struct em28xx * dev)8695025076aSShuah Khan static int em28xx_ir_suspend(struct em28xx *dev)
8705025076aSShuah Khan {
8715025076aSShuah Khan struct em28xx_IR *ir = dev->ir;
8725025076aSShuah Khan
8735025076aSShuah Khan if (dev->is_audio_only)
8745025076aSShuah Khan return 0;
8755025076aSShuah Khan
87629b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Suspending input extension\n");
8775025076aSShuah Khan if (ir)
8785025076aSShuah Khan cancel_delayed_work_sync(&ir->work);
8795025076aSShuah Khan cancel_delayed_work_sync(&dev->buttons_query_work);
88008cc05e4SMauro Carvalho Chehab /*
88108cc05e4SMauro Carvalho Chehab * is canceling delayed work sufficient or does the rc event
88208cc05e4SMauro Carvalho Chehab * kthread needs stopping? kthread is stopped in
88308cc05e4SMauro Carvalho Chehab * ir_raw_event_unregister()
88408cc05e4SMauro Carvalho Chehab */
8855025076aSShuah Khan return 0;
8865025076aSShuah Khan }
8875025076aSShuah Khan
em28xx_ir_resume(struct em28xx * dev)8885025076aSShuah Khan static int em28xx_ir_resume(struct em28xx *dev)
8895025076aSShuah Khan {
8905025076aSShuah Khan struct em28xx_IR *ir = dev->ir;
8915025076aSShuah Khan
8925025076aSShuah Khan if (dev->is_audio_only)
8935025076aSShuah Khan return 0;
8945025076aSShuah Khan
89529b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Resuming input extension\n");
89608cc05e4SMauro Carvalho Chehab /*
89708cc05e4SMauro Carvalho Chehab * if suspend calls ir_raw_event_unregister(), the should call
89808cc05e4SMauro Carvalho Chehab * ir_raw_event_register()
89908cc05e4SMauro Carvalho Chehab */
9005025076aSShuah Khan if (ir)
9015025076aSShuah Khan schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
9025025076aSShuah Khan if (dev->num_button_polling_addresses)
9035025076aSShuah Khan schedule_delayed_work(&dev->buttons_query_work,
9045025076aSShuah Khan msecs_to_jiffies(dev->button_polling_interval));
9055025076aSShuah Khan return 0;
9065025076aSShuah Khan }
9075025076aSShuah Khan
9080c0d06caSMauro Carvalho Chehab static struct em28xx_ops rc_ops = {
9090c0d06caSMauro Carvalho Chehab .id = EM28XX_RC,
9100c0d06caSMauro Carvalho Chehab .name = "Em28xx Input Extension",
9110c0d06caSMauro Carvalho Chehab .init = em28xx_ir_init,
9120c0d06caSMauro Carvalho Chehab .fini = em28xx_ir_fini,
9135025076aSShuah Khan .suspend = em28xx_ir_suspend,
9145025076aSShuah Khan .resume = em28xx_ir_resume,
9150c0d06caSMauro Carvalho Chehab };
9160c0d06caSMauro Carvalho Chehab
em28xx_rc_register(void)9170c0d06caSMauro Carvalho Chehab static int __init em28xx_rc_register(void)
9180c0d06caSMauro Carvalho Chehab {
9190c0d06caSMauro Carvalho Chehab return em28xx_register_extension(&rc_ops);
9200c0d06caSMauro Carvalho Chehab }
9210c0d06caSMauro Carvalho Chehab
em28xx_rc_unregister(void)9220c0d06caSMauro Carvalho Chehab static void __exit em28xx_rc_unregister(void)
9230c0d06caSMauro Carvalho Chehab {
9240c0d06caSMauro Carvalho Chehab em28xx_unregister_extension(&rc_ops);
9250c0d06caSMauro Carvalho Chehab }
9260c0d06caSMauro Carvalho Chehab
927f22e9e71SMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
92837e59f87SMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab");
929d8992b09SMauro Carvalho Chehab MODULE_DESCRIPTION(DRIVER_DESC " - input interface");
930d8992b09SMauro Carvalho Chehab MODULE_VERSION(EM28XX_VERSION);
9310c0d06caSMauro Carvalho Chehab
9320c0d06caSMauro Carvalho Chehab module_init(em28xx_rc_register);
9330c0d06caSMauro Carvalho Chehab module_exit(em28xx_rc_unregister);
934