xref: /linux/drivers/media/usb/au0828/au0828-input.c (revision cbecf716ca618fd44feda6bd9a64a8179d031fc5)
175d1e3efSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0+
275d1e3efSMauro Carvalho Chehab // handle au0828 IR remotes via linux kernel input layer.
375d1e3efSMauro Carvalho Chehab //
475d1e3efSMauro Carvalho Chehab // Copyright (c) 2014 Mauro Carvalho Chehab <mchehab@samsung.com>
575d1e3efSMauro Carvalho Chehab // Copyright (c) 2014 Samsung Electronics Co., Ltd.
675d1e3efSMauro Carvalho Chehab //
775d1e3efSMauro Carvalho Chehab // Based on em28xx-input.c.
82fcfd317SMauro Carvalho Chehab 
983afb32aSMauro Carvalho Chehab #include "au0828.h"
1083afb32aSMauro Carvalho Chehab 
112fcfd317SMauro Carvalho Chehab #include <linux/module.h>
122fcfd317SMauro Carvalho Chehab #include <linux/init.h>
132fcfd317SMauro Carvalho Chehab #include <linux/delay.h>
142fcfd317SMauro Carvalho Chehab #include <linux/interrupt.h>
152fcfd317SMauro Carvalho Chehab #include <linux/usb.h>
162fcfd317SMauro Carvalho Chehab #include <linux/slab.h>
172fcfd317SMauro Carvalho Chehab #include <media/rc-core.h>
182fcfd317SMauro Carvalho Chehab 
19ff346b0fSMauro Carvalho Chehab static int disable_ir;
20ff346b0fSMauro Carvalho Chehab module_param(disable_ir,        int, 0444);
21ff346b0fSMauro Carvalho Chehab MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
22ff346b0fSMauro Carvalho Chehab 
232fcfd317SMauro Carvalho Chehab struct au0828_rc {
242fcfd317SMauro Carvalho Chehab 	struct au0828_dev *dev;
252fcfd317SMauro Carvalho Chehab 	struct rc_dev *rc;
262fcfd317SMauro Carvalho Chehab 	char name[32];
272fcfd317SMauro Carvalho Chehab 	char phys[32];
282fcfd317SMauro Carvalho Chehab 
292fcfd317SMauro Carvalho Chehab 	/* poll decoder */
302fcfd317SMauro Carvalho Chehab 	int polling;
312fcfd317SMauro Carvalho Chehab 	struct delayed_work work;
322fcfd317SMauro Carvalho Chehab 
332fcfd317SMauro Carvalho Chehab 	/* i2c slave address of external device (if used) */
342fcfd317SMauro Carvalho Chehab 	u16 i2c_dev_addr;
352fcfd317SMauro Carvalho Chehab 
362fcfd317SMauro Carvalho Chehab 	int  (*get_key_i2c)(struct au0828_rc *ir);
372fcfd317SMauro Carvalho Chehab };
382fcfd317SMauro Carvalho Chehab 
392fcfd317SMauro Carvalho Chehab /*
402fcfd317SMauro Carvalho Chehab  * AU8522 has a builtin IR receiver. Add functions to get IR from it
412fcfd317SMauro Carvalho Chehab  */
422fcfd317SMauro Carvalho Chehab 
au8522_rc_write(struct au0828_rc * ir,u16 reg,u8 data)432fcfd317SMauro Carvalho Chehab static int au8522_rc_write(struct au0828_rc *ir, u16 reg, u8 data)
442fcfd317SMauro Carvalho Chehab {
452fcfd317SMauro Carvalho Chehab 	int rc;
462fcfd317SMauro Carvalho Chehab 	char buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
472fcfd317SMauro Carvalho Chehab 	struct i2c_msg msg = { .addr = ir->i2c_dev_addr, .flags = 0,
482fcfd317SMauro Carvalho Chehab 			       .buf = buf, .len = sizeof(buf) };
492fcfd317SMauro Carvalho Chehab 
502fcfd317SMauro Carvalho Chehab 	rc = i2c_transfer(ir->dev->i2c_client.adapter, &msg, 1);
512fcfd317SMauro Carvalho Chehab 
522fcfd317SMauro Carvalho Chehab 	if (rc < 0)
532fcfd317SMauro Carvalho Chehab 		return rc;
542fcfd317SMauro Carvalho Chehab 
552fcfd317SMauro Carvalho Chehab 	return (rc == 1) ? 0 : -EIO;
562fcfd317SMauro Carvalho Chehab }
572fcfd317SMauro Carvalho Chehab 
au8522_rc_read(struct au0828_rc * ir,u16 reg,int val,char * buf,int size)582fcfd317SMauro Carvalho Chehab static int au8522_rc_read(struct au0828_rc *ir, u16 reg, int val,
592fcfd317SMauro Carvalho Chehab 				 char *buf, int size)
602fcfd317SMauro Carvalho Chehab {
612fcfd317SMauro Carvalho Chehab 	int rc;
622fcfd317SMauro Carvalho Chehab 	char obuf[3];
632fcfd317SMauro Carvalho Chehab 	struct i2c_msg msg[2] = { { .addr = ir->i2c_dev_addr, .flags = 0,
642fcfd317SMauro Carvalho Chehab 				    .buf = obuf, .len = 2 },
652fcfd317SMauro Carvalho Chehab 				  { .addr = ir->i2c_dev_addr, .flags = I2C_M_RD,
662fcfd317SMauro Carvalho Chehab 				    .buf = buf, .len = size } };
672fcfd317SMauro Carvalho Chehab 
682fcfd317SMauro Carvalho Chehab 	obuf[0] = 0x40 | reg >> 8;
692fcfd317SMauro Carvalho Chehab 	obuf[1] = reg & 0xff;
702fcfd317SMauro Carvalho Chehab 	if (val >= 0) {
712fcfd317SMauro Carvalho Chehab 		obuf[2] = val;
722fcfd317SMauro Carvalho Chehab 		msg[0].len++;
732fcfd317SMauro Carvalho Chehab 	}
742fcfd317SMauro Carvalho Chehab 
752fcfd317SMauro Carvalho Chehab 	rc = i2c_transfer(ir->dev->i2c_client.adapter, msg, 2);
762fcfd317SMauro Carvalho Chehab 
772fcfd317SMauro Carvalho Chehab 	if (rc < 0)
782fcfd317SMauro Carvalho Chehab 		return rc;
792fcfd317SMauro Carvalho Chehab 
802fcfd317SMauro Carvalho Chehab 	return (rc == 2) ? 0 : -EIO;
812fcfd317SMauro Carvalho Chehab }
822fcfd317SMauro Carvalho Chehab 
au8522_rc_andor(struct au0828_rc * ir,u16 reg,u8 mask,u8 value)832fcfd317SMauro Carvalho Chehab static int au8522_rc_andor(struct au0828_rc *ir, u16 reg, u8 mask, u8 value)
842fcfd317SMauro Carvalho Chehab {
852fcfd317SMauro Carvalho Chehab 	int rc;
862e0cc7eeSMauro Carvalho Chehab 	char buf, oldbuf;
872fcfd317SMauro Carvalho Chehab 
882fcfd317SMauro Carvalho Chehab 	rc = au8522_rc_read(ir, reg, -1, &buf, 1);
892fcfd317SMauro Carvalho Chehab 	if (rc < 0)
902fcfd317SMauro Carvalho Chehab 		return rc;
912fcfd317SMauro Carvalho Chehab 
922e0cc7eeSMauro Carvalho Chehab 	oldbuf = buf;
932fcfd317SMauro Carvalho Chehab 	buf = (buf & ~mask) | (value & mask);
942fcfd317SMauro Carvalho Chehab 
952e0cc7eeSMauro Carvalho Chehab 	/* Nothing to do, just return */
962e0cc7eeSMauro Carvalho Chehab 	if (buf == oldbuf)
972e0cc7eeSMauro Carvalho Chehab 		return 0;
982e0cc7eeSMauro Carvalho Chehab 
992fcfd317SMauro Carvalho Chehab 	return au8522_rc_write(ir, reg, buf);
1002fcfd317SMauro Carvalho Chehab }
1012fcfd317SMauro Carvalho Chehab 
1022fcfd317SMauro Carvalho Chehab #define au8522_rc_set(ir, reg, bit) au8522_rc_andor(ir, (reg), (bit), (bit))
1032fcfd317SMauro Carvalho Chehab #define au8522_rc_clear(ir, reg, bit) au8522_rc_andor(ir, (reg), (bit), 0)
1042fcfd317SMauro Carvalho Chehab 
1052fcfd317SMauro Carvalho Chehab /* Remote Controller time units */
1062fcfd317SMauro Carvalho Chehab 
107*528222d8SSean Young #define AU8522_UNIT		200 /* us */
108*528222d8SSean Young #define NEC_START_SPACE		(4500 / AU8522_UNIT)
109*528222d8SSean Young #define NEC_START_PULSE		(563 * 16)
1102fcfd317SMauro Carvalho Chehab #define RC5_START_SPACE		(4 * AU8522_UNIT)
111*528222d8SSean Young #define RC5_START_PULSE		889
1122fcfd317SMauro Carvalho Chehab 
au0828_get_key_au8522(struct au0828_rc * ir)1132fcfd317SMauro Carvalho Chehab static int au0828_get_key_au8522(struct au0828_rc *ir)
1142fcfd317SMauro Carvalho Chehab {
1152fcfd317SMauro Carvalho Chehab 	unsigned char buf[40];
116183e19f5SSean Young 	struct ir_raw_event rawir = {};
1172fcfd317SMauro Carvalho Chehab 	int i, j, rc;
1182fcfd317SMauro Carvalho Chehab 	int prv_bit, bit, width;
1192fcfd317SMauro Carvalho Chehab 	bool first = true;
1202fcfd317SMauro Carvalho Chehab 
121eb336eabSShuah Khan 	/* do nothing if device is disconnected */
122e8e3039fSMauro Carvalho Chehab 	if (test_bit(DEV_DISCONNECTED, &ir->dev->dev_state))
123eb336eabSShuah Khan 		return 0;
124eb336eabSShuah Khan 
1252fcfd317SMauro Carvalho Chehab 	/* Check IR int */
1262fcfd317SMauro Carvalho Chehab 	rc = au8522_rc_read(ir, 0xe1, -1, buf, 1);
1272e0cc7eeSMauro Carvalho Chehab 	if (rc < 0 || !(buf[0] & (1 << 4))) {
1282e0cc7eeSMauro Carvalho Chehab 		/* Be sure that IR is enabled */
1292e0cc7eeSMauro Carvalho Chehab 		au8522_rc_set(ir, 0xe0, 1 << 4);
1302fcfd317SMauro Carvalho Chehab 		return 0;
1312e0cc7eeSMauro Carvalho Chehab 	}
1322fcfd317SMauro Carvalho Chehab 
1332fcfd317SMauro Carvalho Chehab 	/* Something arrived. Get the data */
1342fcfd317SMauro Carvalho Chehab 	rc = au8522_rc_read(ir, 0xe3, 0x11, buf, sizeof(buf));
1352fcfd317SMauro Carvalho Chehab 
1362fcfd317SMauro Carvalho Chehab 
1372fcfd317SMauro Carvalho Chehab 	if (rc < 0)
1382fcfd317SMauro Carvalho Chehab 		return rc;
1392fcfd317SMauro Carvalho Chehab 
1402fcfd317SMauro Carvalho Chehab 	/* Disable IR */
1412fcfd317SMauro Carvalho Chehab 	au8522_rc_clear(ir, 0xe0, 1 << 4);
1422fcfd317SMauro Carvalho Chehab 
1432fcfd317SMauro Carvalho Chehab 	/* Enable IR */
1442fcfd317SMauro Carvalho Chehab 	au8522_rc_set(ir, 0xe0, 1 << 4);
1452fcfd317SMauro Carvalho Chehab 
1462fcfd317SMauro Carvalho Chehab 	dprintk(16, "RC data received: %*ph\n", 40, buf);
1472fcfd317SMauro Carvalho Chehab 
1482fcfd317SMauro Carvalho Chehab 	prv_bit = (buf[0] >> 7) & 0x01;
1492fcfd317SMauro Carvalho Chehab 	width = 0;
1502fcfd317SMauro Carvalho Chehab 	for (i = 0; i < sizeof(buf); i++) {
1512fcfd317SMauro Carvalho Chehab 		for (j = 7; j >= 0; j--) {
1522fcfd317SMauro Carvalho Chehab 			bit = (buf[i] >> j) & 0x01;
1532fcfd317SMauro Carvalho Chehab 			if (bit == prv_bit) {
1542fcfd317SMauro Carvalho Chehab 				width++;
1552fcfd317SMauro Carvalho Chehab 				continue;
1562fcfd317SMauro Carvalho Chehab 			}
1572fcfd317SMauro Carvalho Chehab 
1582fcfd317SMauro Carvalho Chehab 			/*
1592fcfd317SMauro Carvalho Chehab 			 * Fix an au8522 bug: the first pulse event
1602fcfd317SMauro Carvalho Chehab 			 * is lost. So, we need to fake it, based on the
1612fcfd317SMauro Carvalho Chehab 			 * protocol. That means that not all raw decoders
1622fcfd317SMauro Carvalho Chehab 			 * will work, as we need to add a hack for each
1632fcfd317SMauro Carvalho Chehab 			 * protocol, based on the first space.
1642fcfd317SMauro Carvalho Chehab 			 * So, we only support RC5 and NEC.
1652fcfd317SMauro Carvalho Chehab 			 */
1662fcfd317SMauro Carvalho Chehab 
1672fcfd317SMauro Carvalho Chehab 			if (first) {
1682fcfd317SMauro Carvalho Chehab 				first = false;
1692fcfd317SMauro Carvalho Chehab 
1702fcfd317SMauro Carvalho Chehab 				rawir.pulse = true;
1712fcfd317SMauro Carvalho Chehab 				if (width > NEC_START_SPACE - 2 &&
1722fcfd317SMauro Carvalho Chehab 				    width < NEC_START_SPACE + 2) {
1732fcfd317SMauro Carvalho Chehab 					/* NEC protocol */
1742fcfd317SMauro Carvalho Chehab 					rawir.duration = NEC_START_PULSE;
1752fcfd317SMauro Carvalho Chehab 					dprintk(16, "Storing NEC start %s with duration %d",
1762fcfd317SMauro Carvalho Chehab 						rawir.pulse ? "pulse" : "space",
1772fcfd317SMauro Carvalho Chehab 						rawir.duration);
1782fcfd317SMauro Carvalho Chehab 				} else {
1792fcfd317SMauro Carvalho Chehab 					/* RC5 protocol */
1802fcfd317SMauro Carvalho Chehab 					rawir.duration = RC5_START_PULSE;
1812fcfd317SMauro Carvalho Chehab 					dprintk(16, "Storing RC5 start %s with duration %d",
1822fcfd317SMauro Carvalho Chehab 						rawir.pulse ? "pulse" : "space",
1832fcfd317SMauro Carvalho Chehab 						rawir.duration);
1842fcfd317SMauro Carvalho Chehab 				}
1852fcfd317SMauro Carvalho Chehab 				ir_raw_event_store(ir->rc, &rawir);
1862fcfd317SMauro Carvalho Chehab 			}
1872fcfd317SMauro Carvalho Chehab 
1882fcfd317SMauro Carvalho Chehab 			rawir.pulse = prv_bit ? false : true;
1892fcfd317SMauro Carvalho Chehab 			rawir.duration = AU8522_UNIT * width;
1902fcfd317SMauro Carvalho Chehab 			dprintk(16, "Storing %s with duration %d",
1912fcfd317SMauro Carvalho Chehab 				rawir.pulse ? "pulse" : "space",
1922fcfd317SMauro Carvalho Chehab 				rawir.duration);
1932fcfd317SMauro Carvalho Chehab 			ir_raw_event_store(ir->rc, &rawir);
1942fcfd317SMauro Carvalho Chehab 
1952fcfd317SMauro Carvalho Chehab 			width = 1;
1962fcfd317SMauro Carvalho Chehab 			prv_bit = bit;
1972fcfd317SMauro Carvalho Chehab 		}
1982fcfd317SMauro Carvalho Chehab 	}
1992fcfd317SMauro Carvalho Chehab 
2002fcfd317SMauro Carvalho Chehab 	rawir.pulse = prv_bit ? false : true;
2012fcfd317SMauro Carvalho Chehab 	rawir.duration = AU8522_UNIT * width;
2022fcfd317SMauro Carvalho Chehab 	dprintk(16, "Storing end %s with duration %d",
2032fcfd317SMauro Carvalho Chehab 		rawir.pulse ? "pulse" : "space",
2042fcfd317SMauro Carvalho Chehab 		rawir.duration);
2052fcfd317SMauro Carvalho Chehab 	ir_raw_event_store(ir->rc, &rawir);
2062fcfd317SMauro Carvalho Chehab 
2072fcfd317SMauro Carvalho Chehab 	ir_raw_event_handle(ir->rc);
2082fcfd317SMauro Carvalho Chehab 
2092fcfd317SMauro Carvalho Chehab 	return 1;
2102fcfd317SMauro Carvalho Chehab }
2112fcfd317SMauro Carvalho Chehab 
2122fcfd317SMauro Carvalho Chehab /*
2132fcfd317SMauro Carvalho Chehab  * Generic IR code
2142fcfd317SMauro Carvalho Chehab  */
2152fcfd317SMauro Carvalho Chehab 
au0828_rc_work(struct work_struct * work)2162fcfd317SMauro Carvalho Chehab static void au0828_rc_work(struct work_struct *work)
2172fcfd317SMauro Carvalho Chehab {
2182fcfd317SMauro Carvalho Chehab 	struct au0828_rc *ir = container_of(work, struct au0828_rc, work.work);
2192fcfd317SMauro Carvalho Chehab 	int rc;
2202fcfd317SMauro Carvalho Chehab 
2212fcfd317SMauro Carvalho Chehab 	rc = ir->get_key_i2c(ir);
2222fcfd317SMauro Carvalho Chehab 	if (rc < 0)
2232fcfd317SMauro Carvalho Chehab 		pr_info("Error while getting RC scancode\n");
2242fcfd317SMauro Carvalho Chehab 
2252fcfd317SMauro Carvalho Chehab 	schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
2262fcfd317SMauro Carvalho Chehab }
2272fcfd317SMauro Carvalho Chehab 
au0828_rc_start(struct rc_dev * rc)2282fcfd317SMauro Carvalho Chehab static int au0828_rc_start(struct rc_dev *rc)
2292fcfd317SMauro Carvalho Chehab {
2302fcfd317SMauro Carvalho Chehab 	struct au0828_rc *ir = rc->priv;
2312fcfd317SMauro Carvalho Chehab 
2322fcfd317SMauro Carvalho Chehab 	INIT_DELAYED_WORK(&ir->work, au0828_rc_work);
2332fcfd317SMauro Carvalho Chehab 
2342fcfd317SMauro Carvalho Chehab 	/* Enable IR */
2352fcfd317SMauro Carvalho Chehab 	au8522_rc_set(ir, 0xe0, 1 << 4);
2362fcfd317SMauro Carvalho Chehab 
2372fcfd317SMauro Carvalho Chehab 	schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
2382fcfd317SMauro Carvalho Chehab 
2392fcfd317SMauro Carvalho Chehab 	return 0;
2402fcfd317SMauro Carvalho Chehab }
2412fcfd317SMauro Carvalho Chehab 
au0828_rc_stop(struct rc_dev * rc)2422fcfd317SMauro Carvalho Chehab static void au0828_rc_stop(struct rc_dev *rc)
2432fcfd317SMauro Carvalho Chehab {
2442fcfd317SMauro Carvalho Chehab 	struct au0828_rc *ir = rc->priv;
2452fcfd317SMauro Carvalho Chehab 
246e9018af0SMauro Carvalho Chehab 	cancel_delayed_work_sync(&ir->work);
247e9018af0SMauro Carvalho Chehab 
248eb336eabSShuah Khan 	/* do nothing if device is disconnected */
249e8e3039fSMauro Carvalho Chehab 	if (!test_bit(DEV_DISCONNECTED, &ir->dev->dev_state)) {
2502fcfd317SMauro Carvalho Chehab 		/* Disable IR */
2512fcfd317SMauro Carvalho Chehab 		au8522_rc_clear(ir, 0xe0, 1 << 4);
2522fcfd317SMauro Carvalho Chehab 	}
253eb336eabSShuah Khan }
2542fcfd317SMauro Carvalho Chehab 
au0828_probe_i2c_ir(struct au0828_dev * dev)2552fcfd317SMauro Carvalho Chehab static int au0828_probe_i2c_ir(struct au0828_dev *dev)
2562fcfd317SMauro Carvalho Chehab {
2572fcfd317SMauro Carvalho Chehab 	int i = 0;
258213bc75aSColin Ian King 	static const unsigned short addr_list[] = {
2592fcfd317SMauro Carvalho Chehab 		 0x47, I2C_CLIENT_END
2602fcfd317SMauro Carvalho Chehab 	};
2612fcfd317SMauro Carvalho Chehab 
2622fcfd317SMauro Carvalho Chehab 	while (addr_list[i] != I2C_CLIENT_END) {
2632fcfd317SMauro Carvalho Chehab 		if (i2c_probe_func_quick_read(dev->i2c_client.adapter,
2642fcfd317SMauro Carvalho Chehab 					      addr_list[i]) == 1)
2652fcfd317SMauro Carvalho Chehab 			return addr_list[i];
2662fcfd317SMauro Carvalho Chehab 		i++;
2672fcfd317SMauro Carvalho Chehab 	}
2682fcfd317SMauro Carvalho Chehab 
2692fcfd317SMauro Carvalho Chehab 	return -ENODEV;
2702fcfd317SMauro Carvalho Chehab }
2712fcfd317SMauro Carvalho Chehab 
au0828_rc_register(struct au0828_dev * dev)2722fcfd317SMauro Carvalho Chehab int au0828_rc_register(struct au0828_dev *dev)
2732fcfd317SMauro Carvalho Chehab {
2742fcfd317SMauro Carvalho Chehab 	struct au0828_rc *ir;
2752fcfd317SMauro Carvalho Chehab 	struct rc_dev *rc;
2762fcfd317SMauro Carvalho Chehab 	int err = -ENOMEM;
2772fcfd317SMauro Carvalho Chehab 	u16 i2c_rc_dev_addr = 0;
2782fcfd317SMauro Carvalho Chehab 
279ff346b0fSMauro Carvalho Chehab 	if (!dev->board.has_ir_i2c || disable_ir)
2802fcfd317SMauro Carvalho Chehab 		return 0;
2812fcfd317SMauro Carvalho Chehab 
2822fcfd317SMauro Carvalho Chehab 	i2c_rc_dev_addr = au0828_probe_i2c_ir(dev);
2832fcfd317SMauro Carvalho Chehab 	if (!i2c_rc_dev_addr)
2842fcfd317SMauro Carvalho Chehab 		return -ENODEV;
2852fcfd317SMauro Carvalho Chehab 
2862fcfd317SMauro Carvalho Chehab 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
2870f7499fdSAndi Shyti 	rc = rc_allocate_device(RC_DRIVER_IR_RAW);
2882fcfd317SMauro Carvalho Chehab 	if (!ir || !rc)
2892fcfd317SMauro Carvalho Chehab 		goto error;
2902fcfd317SMauro Carvalho Chehab 
2912fcfd317SMauro Carvalho Chehab 	/* record handles to ourself */
2922fcfd317SMauro Carvalho Chehab 	ir->dev = dev;
2932fcfd317SMauro Carvalho Chehab 	dev->ir = ir;
2942fcfd317SMauro Carvalho Chehab 	ir->rc = rc;
2952fcfd317SMauro Carvalho Chehab 
2962fcfd317SMauro Carvalho Chehab 	rc->priv = ir;
2972fcfd317SMauro Carvalho Chehab 	rc->open = au0828_rc_start;
2982fcfd317SMauro Carvalho Chehab 	rc->close = au0828_rc_stop;
2992fcfd317SMauro Carvalho Chehab 
3002fcfd317SMauro Carvalho Chehab 	if (dev->board.has_ir_i2c) {	/* external i2c device */
3012fcfd317SMauro Carvalho Chehab 		switch (dev->boardnr) {
3022fcfd317SMauro Carvalho Chehab 		case AU0828_BOARD_HAUPPAUGE_HVR950Q:
3032fcfd317SMauro Carvalho Chehab 			rc->map_name = RC_MAP_HAUPPAUGE;
3042fcfd317SMauro Carvalho Chehab 			ir->get_key_i2c = au0828_get_key_au8522;
3052fcfd317SMauro Carvalho Chehab 			break;
3062fcfd317SMauro Carvalho Chehab 		default:
3072fcfd317SMauro Carvalho Chehab 			err = -ENODEV;
3082fcfd317SMauro Carvalho Chehab 			goto error;
3092fcfd317SMauro Carvalho Chehab 		}
3102fcfd317SMauro Carvalho Chehab 
3112fcfd317SMauro Carvalho Chehab 		ir->i2c_dev_addr = i2c_rc_dev_addr;
3122fcfd317SMauro Carvalho Chehab 	}
3132fcfd317SMauro Carvalho Chehab 
3142fcfd317SMauro Carvalho Chehab 	/* This is how often we ask the chip for IR information */
3152fcfd317SMauro Carvalho Chehab 	ir->polling = 100; /* ms */
3162fcfd317SMauro Carvalho Chehab 
3172fcfd317SMauro Carvalho Chehab 	/* init input device */
3182fcfd317SMauro Carvalho Chehab 	snprintf(ir->name, sizeof(ir->name), "au0828 IR (%s)",
3192fcfd317SMauro Carvalho Chehab 		 dev->board.name);
3202fcfd317SMauro Carvalho Chehab 
3212fcfd317SMauro Carvalho Chehab 	usb_make_path(dev->usbdev, ir->phys, sizeof(ir->phys));
3222fcfd317SMauro Carvalho Chehab 	strlcat(ir->phys, "/input0", sizeof(ir->phys));
3232fcfd317SMauro Carvalho Chehab 
324518f4b26SSean Young 	rc->device_name = ir->name;
3252fcfd317SMauro Carvalho Chehab 	rc->input_phys = ir->phys;
3262fcfd317SMauro Carvalho Chehab 	rc->input_id.bustype = BUS_USB;
3272fcfd317SMauro Carvalho Chehab 	rc->input_id.version = 1;
3282fcfd317SMauro Carvalho Chehab 	rc->input_id.vendor = le16_to_cpu(dev->usbdev->descriptor.idVendor);
3292fcfd317SMauro Carvalho Chehab 	rc->input_id.product = le16_to_cpu(dev->usbdev->descriptor.idProduct);
3302fcfd317SMauro Carvalho Chehab 	rc->dev.parent = &dev->usbdev->dev;
3312fcfd317SMauro Carvalho Chehab 	rc->driver_name = "au0828-input";
3326d741bfeSSean Young 	rc->allowed_protocols = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX |
3336d741bfeSSean Young 				RC_PROTO_BIT_NEC32 | RC_PROTO_BIT_RC5;
3342fcfd317SMauro Carvalho Chehab 
3352fcfd317SMauro Carvalho Chehab 	/* all done */
3362fcfd317SMauro Carvalho Chehab 	err = rc_register_device(rc);
3372fcfd317SMauro Carvalho Chehab 	if (err)
3382fcfd317SMauro Carvalho Chehab 		goto error;
3392fcfd317SMauro Carvalho Chehab 
3401250a85bSMauro Carvalho Chehab 	pr_info("Remote controller %s initialized\n", ir->name);
3412fcfd317SMauro Carvalho Chehab 
3422fcfd317SMauro Carvalho Chehab 	return 0;
3432fcfd317SMauro Carvalho Chehab 
3442fcfd317SMauro Carvalho Chehab error:
3452fcfd317SMauro Carvalho Chehab 	dev->ir = NULL;
3462fcfd317SMauro Carvalho Chehab 	rc_free_device(rc);
3472fcfd317SMauro Carvalho Chehab 	kfree(ir);
3482fcfd317SMauro Carvalho Chehab 	return err;
3492fcfd317SMauro Carvalho Chehab }
3502fcfd317SMauro Carvalho Chehab 
au0828_rc_unregister(struct au0828_dev * dev)3512fcfd317SMauro Carvalho Chehab void au0828_rc_unregister(struct au0828_dev *dev)
3522fcfd317SMauro Carvalho Chehab {
3532fcfd317SMauro Carvalho Chehab 	struct au0828_rc *ir = dev->ir;
3542fcfd317SMauro Carvalho Chehab 
3552fcfd317SMauro Carvalho Chehab 	/* skip detach on non attached boards */
3562fcfd317SMauro Carvalho Chehab 	if (!ir)
3572fcfd317SMauro Carvalho Chehab 		return;
3582fcfd317SMauro Carvalho Chehab 
3592fcfd317SMauro Carvalho Chehab 	rc_unregister_device(ir->rc);
3602fcfd317SMauro Carvalho Chehab 
3612fcfd317SMauro Carvalho Chehab 	/* done */
3622fcfd317SMauro Carvalho Chehab 	kfree(ir);
3632fcfd317SMauro Carvalho Chehab 	dev->ir = NULL;
3642fcfd317SMauro Carvalho Chehab }
3652fcfd317SMauro Carvalho Chehab 
au0828_rc_suspend(struct au0828_dev * dev)3662fcfd317SMauro Carvalho Chehab int au0828_rc_suspend(struct au0828_dev *dev)
3672fcfd317SMauro Carvalho Chehab {
3682fcfd317SMauro Carvalho Chehab 	struct au0828_rc *ir = dev->ir;
3692fcfd317SMauro Carvalho Chehab 
3702fcfd317SMauro Carvalho Chehab 	if (!ir)
3712fcfd317SMauro Carvalho Chehab 		return 0;
3722fcfd317SMauro Carvalho Chehab 
37381187240SMauro Carvalho Chehab 	pr_info("Stopping RC\n");
37481187240SMauro Carvalho Chehab 
3752fcfd317SMauro Carvalho Chehab 	cancel_delayed_work_sync(&ir->work);
3762fcfd317SMauro Carvalho Chehab 
377345e3bfdSMauro Carvalho Chehab 	/* Disable IR */
378345e3bfdSMauro Carvalho Chehab 	au8522_rc_clear(ir, 0xe0, 1 << 4);
379345e3bfdSMauro Carvalho Chehab 
3802fcfd317SMauro Carvalho Chehab 	return 0;
3812fcfd317SMauro Carvalho Chehab }
3822fcfd317SMauro Carvalho Chehab 
au0828_rc_resume(struct au0828_dev * dev)3832fcfd317SMauro Carvalho Chehab int au0828_rc_resume(struct au0828_dev *dev)
3842fcfd317SMauro Carvalho Chehab {
3852fcfd317SMauro Carvalho Chehab 	struct au0828_rc *ir = dev->ir;
3862fcfd317SMauro Carvalho Chehab 
3872fcfd317SMauro Carvalho Chehab 	if (!ir)
3882fcfd317SMauro Carvalho Chehab 		return 0;
3892fcfd317SMauro Carvalho Chehab 
39081187240SMauro Carvalho Chehab 	pr_info("Restarting RC\n");
39181187240SMauro Carvalho Chehab 
392345e3bfdSMauro Carvalho Chehab 	/* Enable IR */
393345e3bfdSMauro Carvalho Chehab 	au8522_rc_set(ir, 0xe0, 1 << 4);
394345e3bfdSMauro Carvalho Chehab 
3952fcfd317SMauro Carvalho Chehab 	schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
3962fcfd317SMauro Carvalho Chehab 
3972fcfd317SMauro Carvalho Chehab 	return 0;
3982fcfd317SMauro Carvalho Chehab }
399