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