1cb7a01acSMauro Carvalho Chehab /* 2cb7a01acSMauro Carvalho Chehab * 3cb7a01acSMauro Carvalho Chehab * keyboard input driver for i2c IR remote controls 4cb7a01acSMauro Carvalho Chehab * 5cb7a01acSMauro Carvalho Chehab * Copyright (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org> 6cb7a01acSMauro Carvalho Chehab * modified for PixelView (BT878P+W/FM) by 7cb7a01acSMauro Carvalho Chehab * Michal Kochanowicz <mkochano@pld.org.pl> 8cb7a01acSMauro Carvalho Chehab * Christoph Bartelmus <lirc@bartelmus.de> 9cb7a01acSMauro Carvalho Chehab * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by 10cb7a01acSMauro Carvalho Chehab * Ulrich Mueller <ulrich.mueller42@web.de> 11cb7a01acSMauro Carvalho Chehab * modified for em2820 based USB TV tuners by 12cb7a01acSMauro Carvalho Chehab * Markus Rechberger <mrechberger@gmail.com> 13cb7a01acSMauro Carvalho Chehab * modified for DViCO Fusion HDTV 5 RT GOLD by 14cb7a01acSMauro Carvalho Chehab * Chaogui Zhang <czhang1974@gmail.com> 15cb7a01acSMauro Carvalho Chehab * modified for MSI TV@nywhere Plus by 16cb7a01acSMauro Carvalho Chehab * Henry Wong <henry@stuffedcow.net> 17cb7a01acSMauro Carvalho Chehab * Mark Schultz <n9xmj@yahoo.com> 18cb7a01acSMauro Carvalho Chehab * Brian Rogers <brian_rogers@comcast.net> 19cb7a01acSMauro Carvalho Chehab * modified for AVerMedia Cardbus by 20cb7a01acSMauro Carvalho Chehab * Oldrich Jedlicka <oldium.pro@seznam.cz> 21cb7a01acSMauro Carvalho Chehab * 22cb7a01acSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 23cb7a01acSMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 24cb7a01acSMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 25cb7a01acSMauro Carvalho Chehab * (at your option) any later version. 26cb7a01acSMauro Carvalho Chehab * 27cb7a01acSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 28cb7a01acSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 29cb7a01acSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30cb7a01acSMauro Carvalho Chehab * GNU General Public License for more details. 31cb7a01acSMauro Carvalho Chehab * 32cb7a01acSMauro Carvalho Chehab */ 33cb7a01acSMauro Carvalho Chehab 3400bb8207SSean Young #include <asm/unaligned.h> 35cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 36cb7a01acSMauro Carvalho Chehab #include <linux/init.h> 37cb7a01acSMauro Carvalho Chehab #include <linux/kernel.h> 38cb7a01acSMauro Carvalho Chehab #include <linux/string.h> 39cb7a01acSMauro Carvalho Chehab #include <linux/timer.h> 40cb7a01acSMauro Carvalho Chehab #include <linux/delay.h> 41cb7a01acSMauro Carvalho Chehab #include <linux/errno.h> 42cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 43cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 44cb7a01acSMauro Carvalho Chehab #include <linux/workqueue.h> 45cb7a01acSMauro Carvalho Chehab 46cb7a01acSMauro Carvalho Chehab #include <media/rc-core.h> 47b5dcee22SMauro Carvalho Chehab #include <media/i2c/ir-kbd-i2c.h> 48cb7a01acSMauro Carvalho Chehab 49cb7a01acSMauro Carvalho Chehab 506d741bfeSSean Young static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, 5100bb8207SSean Young u32 *scancode, u8 *ptoggle, int size) 52cb7a01acSMauro Carvalho Chehab { 53cb7a01acSMauro Carvalho Chehab unsigned char buf[6]; 5400bb8207SSean Young int start, range, toggle, dev, code, ircode, vendor; 55cb7a01acSMauro Carvalho Chehab 56cb7a01acSMauro Carvalho Chehab /* poll IR chip */ 57cb7a01acSMauro Carvalho Chehab if (size != i2c_master_recv(ir->c, buf, size)) 58cb7a01acSMauro Carvalho Chehab return -EIO; 59cb7a01acSMauro Carvalho Chehab 6000bb8207SSean Young if (buf[0] & 0x80) { 6100bb8207SSean Young int offset = (size == 6) ? 3 : 0; 6200bb8207SSean Young 63cb7a01acSMauro Carvalho Chehab /* split rc5 data block ... */ 64cb7a01acSMauro Carvalho Chehab start = (buf[offset] >> 7) & 1; 65cb7a01acSMauro Carvalho Chehab range = (buf[offset] >> 6) & 1; 66cb7a01acSMauro Carvalho Chehab toggle = (buf[offset] >> 5) & 1; 67cb7a01acSMauro Carvalho Chehab dev = buf[offset] & 0x1f; 68cb7a01acSMauro Carvalho Chehab code = (buf[offset+1] >> 2) & 0x3f; 69cb7a01acSMauro Carvalho Chehab 70cb7a01acSMauro Carvalho Chehab /* rc5 has two start bits 71cb7a01acSMauro Carvalho Chehab * the first bit must be one 7200bb8207SSean Young * the second bit defines the command range: 7300bb8207SSean Young * 1 = 0-63, 0 = 64 - 127 74cb7a01acSMauro Carvalho Chehab */ 75cb7a01acSMauro Carvalho Chehab if (!start) 76cb7a01acSMauro Carvalho Chehab /* no key pressed */ 77cb7a01acSMauro Carvalho Chehab return 0; 784dd9bb91SDavid Härdeman 794dd9bb91SDavid Härdeman /* filter out invalid key presses */ 80cb7a01acSMauro Carvalho Chehab ircode = (start << 12) | (toggle << 11) | (dev << 6) | code; 81cb7a01acSMauro Carvalho Chehab if ((ircode & 0x1fff) == 0x1fff) 82cb7a01acSMauro Carvalho Chehab return 0; 83cb7a01acSMauro Carvalho Chehab 84cb7a01acSMauro Carvalho Chehab if (!range) 85cb7a01acSMauro Carvalho Chehab code += 64; 86cb7a01acSMauro Carvalho Chehab 8750a762b4SSean Young dev_dbg(&ir->rc->dev, 8850a762b4SSean Young "ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", 89cb7a01acSMauro Carvalho Chehab start, range, toggle, dev, code); 90cb7a01acSMauro Carvalho Chehab 916d741bfeSSean Young *protocol = RC_PROTO_RC5; 924dd9bb91SDavid Härdeman *scancode = RC_SCANCODE_RC5(dev, code); 934dd9bb91SDavid Härdeman *ptoggle = toggle; 9400bb8207SSean Young 95cb7a01acSMauro Carvalho Chehab return 1; 9600bb8207SSean Young } else if (size == 6 && (buf[0] & 0x40)) { 9700bb8207SSean Young code = buf[4]; 9800bb8207SSean Young dev = buf[3]; 9900bb8207SSean Young vendor = get_unaligned_be16(buf + 1); 10000bb8207SSean Young 10100bb8207SSean Young if (vendor == 0x800f) { 10200bb8207SSean Young *ptoggle = (dev & 0x80) != 0; 1036d741bfeSSean Young *protocol = RC_PROTO_RC6_MCE; 10400bb8207SSean Young dev &= 0x7f; 10550a762b4SSean Young dev_dbg(&ir->rc->dev, 10650a762b4SSean Young "ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n", 1079cdbe14fSArnd Bergmann *ptoggle, vendor, dev, code); 10800bb8207SSean Young } else { 10900bb8207SSean Young *ptoggle = 0; 1106d741bfeSSean Young *protocol = RC_PROTO_RC6_6A_32; 11150a762b4SSean Young dev_dbg(&ir->rc->dev, 11250a762b4SSean Young "ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n", 11300bb8207SSean Young vendor, dev, code); 11400bb8207SSean Young } 11500bb8207SSean Young 11600bb8207SSean Young *scancode = RC_SCANCODE_RC6_6A(vendor, dev, code); 11700bb8207SSean Young 11800bb8207SSean Young return 1; 11900bb8207SSean Young } 12000bb8207SSean Young 12100bb8207SSean Young return 0; 122cb7a01acSMauro Carvalho Chehab } 123cb7a01acSMauro Carvalho Chehab 1246d741bfeSSean Young static int get_key_haup(struct IR_i2c *ir, enum rc_proto *protocol, 1254dd9bb91SDavid Härdeman u32 *scancode, u8 *toggle) 126cb7a01acSMauro Carvalho Chehab { 12700bb8207SSean Young return get_key_haup_common(ir, protocol, scancode, toggle, 3); 128cb7a01acSMauro Carvalho Chehab } 129cb7a01acSMauro Carvalho Chehab 1306d741bfeSSean Young static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_proto *protocol, 1314dd9bb91SDavid Härdeman u32 *scancode, u8 *toggle) 132cb7a01acSMauro Carvalho Chehab { 133cb7a01acSMauro Carvalho Chehab int ret; 134cb7a01acSMauro Carvalho Chehab unsigned char buf[1] = { 0 }; 135cb7a01acSMauro Carvalho Chehab 136cb7a01acSMauro Carvalho Chehab /* 137cb7a01acSMauro Carvalho Chehab * This is the same apparent "are you ready?" poll command observed 138cb7a01acSMauro Carvalho Chehab * watching Windows driver traffic and implemented in lirc_zilog. With 139cb7a01acSMauro Carvalho Chehab * this added, we get far saner remote behavior with z8 chips on usb 140cb7a01acSMauro Carvalho Chehab * connected devices, even with the default polling interval of 100ms. 141cb7a01acSMauro Carvalho Chehab */ 142cb7a01acSMauro Carvalho Chehab ret = i2c_master_send(ir->c, buf, 1); 143cb7a01acSMauro Carvalho Chehab if (ret != 1) 144cb7a01acSMauro Carvalho Chehab return (ret < 0) ? ret : -EINVAL; 145cb7a01acSMauro Carvalho Chehab 14600bb8207SSean Young return get_key_haup_common(ir, protocol, scancode, toggle, 6); 147cb7a01acSMauro Carvalho Chehab } 148cb7a01acSMauro Carvalho Chehab 1496d741bfeSSean Young static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol, 1504dd9bb91SDavid Härdeman u32 *scancode, u8 *toggle) 151cb7a01acSMauro Carvalho Chehab { 152cb7a01acSMauro Carvalho Chehab unsigned char b; 153cb7a01acSMauro Carvalho Chehab 154cb7a01acSMauro Carvalho Chehab /* poll IR chip */ 155cb7a01acSMauro Carvalho Chehab if (1 != i2c_master_recv(ir->c, &b, 1)) { 15650a762b4SSean Young dev_dbg(&ir->rc->dev, "read error\n"); 157cb7a01acSMauro Carvalho Chehab return -EIO; 158cb7a01acSMauro Carvalho Chehab } 1594dd9bb91SDavid Härdeman 1606d741bfeSSean Young *protocol = RC_PROTO_OTHER; 1614dd9bb91SDavid Härdeman *scancode = b; 1624dd9bb91SDavid Härdeman *toggle = 0; 163cb7a01acSMauro Carvalho Chehab return 1; 164cb7a01acSMauro Carvalho Chehab } 165cb7a01acSMauro Carvalho Chehab 1666d741bfeSSean Young static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol, 1674dd9bb91SDavid Härdeman u32 *scancode, u8 *toggle) 168cb7a01acSMauro Carvalho Chehab { 169cb7a01acSMauro Carvalho Chehab unsigned char buf[4]; 170cb7a01acSMauro Carvalho Chehab 171cb7a01acSMauro Carvalho Chehab /* poll IR chip */ 172cb7a01acSMauro Carvalho Chehab if (4 != i2c_master_recv(ir->c, buf, 4)) { 17350a762b4SSean Young dev_dbg(&ir->rc->dev, "read error\n"); 174cb7a01acSMauro Carvalho Chehab return -EIO; 175cb7a01acSMauro Carvalho Chehab } 176cb7a01acSMauro Carvalho Chehab 177cb7a01acSMauro Carvalho Chehab if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0 || buf[3] != 0) 17850a762b4SSean Young dev_dbg(&ir->rc->dev, "%s: %*ph\n", __func__, 4, buf); 179cb7a01acSMauro Carvalho Chehab 180cb7a01acSMauro Carvalho Chehab /* no key pressed or signal from other ir remote */ 181cb7a01acSMauro Carvalho Chehab if(buf[0] != 0x1 || buf[1] != 0xfe) 182cb7a01acSMauro Carvalho Chehab return 0; 183cb7a01acSMauro Carvalho Chehab 1846d741bfeSSean Young *protocol = RC_PROTO_UNKNOWN; 1854dd9bb91SDavid Härdeman *scancode = buf[2]; 1864dd9bb91SDavid Härdeman *toggle = 0; 187cb7a01acSMauro Carvalho Chehab return 1; 188cb7a01acSMauro Carvalho Chehab } 189cb7a01acSMauro Carvalho Chehab 1906d741bfeSSean Young static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol, 1914dd9bb91SDavid Härdeman u32 *scancode, u8 *toggle) 192cb7a01acSMauro Carvalho Chehab { 193cb7a01acSMauro Carvalho Chehab unsigned char b; 194cb7a01acSMauro Carvalho Chehab 195cb7a01acSMauro Carvalho Chehab /* poll IR chip */ 196cb7a01acSMauro Carvalho Chehab if (1 != i2c_master_recv(ir->c, &b, 1)) { 19750a762b4SSean Young dev_dbg(&ir->rc->dev, "read error\n"); 198cb7a01acSMauro Carvalho Chehab return -EIO; 199cb7a01acSMauro Carvalho Chehab } 200cb7a01acSMauro Carvalho Chehab 201cb7a01acSMauro Carvalho Chehab /* it seems that 0xFE indicates that a button is still hold 202cb7a01acSMauro Carvalho Chehab down, while 0xff indicates that no button is hold 203cb7a01acSMauro Carvalho Chehab down. 0xfe sequences are sometimes interrupted by 0xFF */ 204cb7a01acSMauro Carvalho Chehab 20550a762b4SSean Young dev_dbg(&ir->rc->dev, "key %02x\n", b); 206cb7a01acSMauro Carvalho Chehab 207cb7a01acSMauro Carvalho Chehab if (b == 0xff) 208cb7a01acSMauro Carvalho Chehab return 0; 209cb7a01acSMauro Carvalho Chehab 210cb7a01acSMauro Carvalho Chehab if (b == 0xfe) 211cb7a01acSMauro Carvalho Chehab /* keep old data */ 212cb7a01acSMauro Carvalho Chehab return 1; 213cb7a01acSMauro Carvalho Chehab 2146d741bfeSSean Young *protocol = RC_PROTO_UNKNOWN; 2154dd9bb91SDavid Härdeman *scancode = b; 2164dd9bb91SDavid Härdeman *toggle = 0; 217cb7a01acSMauro Carvalho Chehab return 1; 218cb7a01acSMauro Carvalho Chehab } 219cb7a01acSMauro Carvalho Chehab 2206d741bfeSSean Young static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, 2214dd9bb91SDavid Härdeman u32 *scancode, u8 *toggle) 222cb7a01acSMauro Carvalho Chehab { 223cb7a01acSMauro Carvalho Chehab unsigned char subaddr, key, keygroup; 224cb7a01acSMauro Carvalho Chehab struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, 225cb7a01acSMauro Carvalho Chehab .buf = &subaddr, .len = 1}, 226cb7a01acSMauro Carvalho Chehab { .addr = ir->c->addr, .flags = I2C_M_RD, 227cb7a01acSMauro Carvalho Chehab .buf = &key, .len = 1} }; 228cb7a01acSMauro Carvalho Chehab subaddr = 0x0d; 229cb7a01acSMauro Carvalho Chehab if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { 23050a762b4SSean Young dev_dbg(&ir->rc->dev, "read error\n"); 231cb7a01acSMauro Carvalho Chehab return -EIO; 232cb7a01acSMauro Carvalho Chehab } 233cb7a01acSMauro Carvalho Chehab 234cb7a01acSMauro Carvalho Chehab if (key == 0xff) 235cb7a01acSMauro Carvalho Chehab return 0; 236cb7a01acSMauro Carvalho Chehab 237cb7a01acSMauro Carvalho Chehab subaddr = 0x0b; 238cb7a01acSMauro Carvalho Chehab msg[1].buf = &keygroup; 239cb7a01acSMauro Carvalho Chehab if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { 24050a762b4SSean Young dev_dbg(&ir->rc->dev, "read error\n"); 241cb7a01acSMauro Carvalho Chehab return -EIO; 242cb7a01acSMauro Carvalho Chehab } 243cb7a01acSMauro Carvalho Chehab 244cb7a01acSMauro Carvalho Chehab if (keygroup == 0xff) 245cb7a01acSMauro Carvalho Chehab return 0; 246cb7a01acSMauro Carvalho Chehab 24750a762b4SSean Young dev_dbg(&ir->rc->dev, "read key 0x%02x/0x%02x\n", key, keygroup); 24834fe2784SOndrej Zary if (keygroup < 2 || keygroup > 4) { 24950a762b4SSean Young dev_warn(&ir->rc->dev, "warning: invalid key group 0x%02x for key 0x%02x\n", 250cb7a01acSMauro Carvalho Chehab keygroup, key); 251cb7a01acSMauro Carvalho Chehab } 252cb7a01acSMauro Carvalho Chehab key |= (keygroup & 1) << 6; 253cb7a01acSMauro Carvalho Chehab 2546d741bfeSSean Young *protocol = RC_PROTO_UNKNOWN; 2554dd9bb91SDavid Härdeman *scancode = key; 2564dd9bb91SDavid Härdeman if (ir->c->addr == 0x41) /* AVerMedia EM78P153 */ 2574dd9bb91SDavid Härdeman *scancode |= keygroup << 8; 2584dd9bb91SDavid Härdeman *toggle = 0; 259cb7a01acSMauro Carvalho Chehab return 1; 260cb7a01acSMauro Carvalho Chehab } 261cb7a01acSMauro Carvalho Chehab 262cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 263cb7a01acSMauro Carvalho Chehab 264cb7a01acSMauro Carvalho Chehab static int ir_key_poll(struct IR_i2c *ir) 265cb7a01acSMauro Carvalho Chehab { 2666d741bfeSSean Young enum rc_proto protocol; 2674dd9bb91SDavid Härdeman u32 scancode; 2684dd9bb91SDavid Härdeman u8 toggle; 269cb7a01acSMauro Carvalho Chehab int rc; 270cb7a01acSMauro Carvalho Chehab 27150a762b4SSean Young dev_dbg(&ir->rc->dev, "%s\n", __func__); 2724dd9bb91SDavid Härdeman rc = ir->get_key(ir, &protocol, &scancode, &toggle); 273cb7a01acSMauro Carvalho Chehab if (rc < 0) { 27450a762b4SSean Young dev_warn(&ir->rc->dev, "error %d\n", rc); 275cb7a01acSMauro Carvalho Chehab return rc; 276cb7a01acSMauro Carvalho Chehab } 277cb7a01acSMauro Carvalho Chehab 278cb7a01acSMauro Carvalho Chehab if (rc) { 27950a762b4SSean Young dev_dbg(&ir->rc->dev, "%s: proto = 0x%04x, scancode = 0x%08x\n", 280120703f9SDavid Härdeman __func__, protocol, scancode); 281120703f9SDavid Härdeman rc_keydown(ir->rc, protocol, scancode, toggle); 282cb7a01acSMauro Carvalho Chehab } 283cb7a01acSMauro Carvalho Chehab return 0; 284cb7a01acSMauro Carvalho Chehab } 285cb7a01acSMauro Carvalho Chehab 286cb7a01acSMauro Carvalho Chehab static void ir_work(struct work_struct *work) 287cb7a01acSMauro Carvalho Chehab { 288cb7a01acSMauro Carvalho Chehab int rc; 289cb7a01acSMauro Carvalho Chehab struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); 290cb7a01acSMauro Carvalho Chehab 291cb7a01acSMauro Carvalho Chehab rc = ir_key_poll(ir); 292cb7a01acSMauro Carvalho Chehab if (rc == -ENODEV) { 293cb7a01acSMauro Carvalho Chehab rc_unregister_device(ir->rc); 294cb7a01acSMauro Carvalho Chehab ir->rc = NULL; 295cb7a01acSMauro Carvalho Chehab return; 296cb7a01acSMauro Carvalho Chehab } 297cb7a01acSMauro Carvalho Chehab 298cb7a01acSMauro Carvalho Chehab schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); 299cb7a01acSMauro Carvalho Chehab } 300cb7a01acSMauro Carvalho Chehab 301*a6927d81SSean Young static int ir_open(struct rc_dev *dev) 302*a6927d81SSean Young { 303*a6927d81SSean Young struct IR_i2c *ir = dev->priv; 304*a6927d81SSean Young 305*a6927d81SSean Young schedule_delayed_work(&ir->work, 0); 306*a6927d81SSean Young 307*a6927d81SSean Young return 0; 308*a6927d81SSean Young } 309*a6927d81SSean Young 310*a6927d81SSean Young static void ir_close(struct rc_dev *dev) 311*a6927d81SSean Young { 312*a6927d81SSean Young struct IR_i2c *ir = dev->priv; 313*a6927d81SSean Young 314*a6927d81SSean Young cancel_delayed_work_sync(&ir->work); 315*a6927d81SSean Young } 316*a6927d81SSean Young 317cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 318cb7a01acSMauro Carvalho Chehab 319cb7a01acSMauro Carvalho Chehab static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) 320cb7a01acSMauro Carvalho Chehab { 321cb7a01acSMauro Carvalho Chehab char *ir_codes = NULL; 322cb7a01acSMauro Carvalho Chehab const char *name = NULL; 3236d741bfeSSean Young u64 rc_proto = RC_PROTO_BIT_UNKNOWN; 324cb7a01acSMauro Carvalho Chehab struct IR_i2c *ir; 325cb7a01acSMauro Carvalho Chehab struct rc_dev *rc = NULL; 326cb7a01acSMauro Carvalho Chehab struct i2c_adapter *adap = client->adapter; 327cb7a01acSMauro Carvalho Chehab unsigned short addr = client->addr; 328cb7a01acSMauro Carvalho Chehab int err; 329cb7a01acSMauro Carvalho Chehab 330c02b211dSLaurent Pinchart ir = devm_kzalloc(&client->dev, sizeof(*ir), GFP_KERNEL); 331cb7a01acSMauro Carvalho Chehab if (!ir) 332cb7a01acSMauro Carvalho Chehab return -ENOMEM; 333cb7a01acSMauro Carvalho Chehab 334cb7a01acSMauro Carvalho Chehab ir->c = client; 335cb7a01acSMauro Carvalho Chehab ir->polling_interval = DEFAULT_POLLING_INTERVAL; 336cb7a01acSMauro Carvalho Chehab i2c_set_clientdata(client, ir); 337cb7a01acSMauro Carvalho Chehab 338cb7a01acSMauro Carvalho Chehab switch(addr) { 339cb7a01acSMauro Carvalho Chehab case 0x64: 340cb7a01acSMauro Carvalho Chehab name = "Pixelview"; 341cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_pixelview; 3426d741bfeSSean Young rc_proto = RC_PROTO_BIT_OTHER; 343cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_EMPTY; 344cb7a01acSMauro Carvalho Chehab break; 345cb7a01acSMauro Carvalho Chehab case 0x18: 346cb7a01acSMauro Carvalho Chehab case 0x1f: 347cb7a01acSMauro Carvalho Chehab case 0x1a: 348cb7a01acSMauro Carvalho Chehab name = "Hauppauge"; 349cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_haup; 3506d741bfeSSean Young rc_proto = RC_PROTO_BIT_RC5; 351cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_HAUPPAUGE; 352cb7a01acSMauro Carvalho Chehab break; 353cb7a01acSMauro Carvalho Chehab case 0x30: 354cb7a01acSMauro Carvalho Chehab name = "KNC One"; 355cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_knc1; 3566d741bfeSSean Young rc_proto = RC_PROTO_BIT_OTHER; 357cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_EMPTY; 358cb7a01acSMauro Carvalho Chehab break; 359cb7a01acSMauro Carvalho Chehab case 0x6b: 360cb7a01acSMauro Carvalho Chehab name = "FusionHDTV"; 361cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_fusionhdtv; 3626d741bfeSSean Young rc_proto = RC_PROTO_BIT_UNKNOWN; 363cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_FUSIONHDTV_MCE; 364cb7a01acSMauro Carvalho Chehab break; 365cb7a01acSMauro Carvalho Chehab case 0x40: 366cb7a01acSMauro Carvalho Chehab name = "AVerMedia Cardbus remote"; 367cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_avermedia_cardbus; 3686d741bfeSSean Young rc_proto = RC_PROTO_BIT_OTHER; 369cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_AVERMEDIA_CARDBUS; 370cb7a01acSMauro Carvalho Chehab break; 37134fe2784SOndrej Zary case 0x41: 37234fe2784SOndrej Zary name = "AVerMedia EM78P153"; 37334fe2784SOndrej Zary ir->get_key = get_key_avermedia_cardbus; 3746d741bfeSSean Young rc_proto = RC_PROTO_BIT_OTHER; 37534fe2784SOndrej Zary /* RM-KV remote, seems to be same as RM-K6 */ 37634fe2784SOndrej Zary ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6; 37734fe2784SOndrej Zary break; 378cb7a01acSMauro Carvalho Chehab case 0x71: 379cb7a01acSMauro Carvalho Chehab name = "Hauppauge/Zilog Z8"; 380cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_haup_xvr; 3816d741bfeSSean Young rc_proto = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | 3826d741bfeSSean Young RC_PROTO_BIT_RC6_6A_32; 383cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_HAUPPAUGE; 384cb7a01acSMauro Carvalho Chehab break; 385cb7a01acSMauro Carvalho Chehab } 386cb7a01acSMauro Carvalho Chehab 387cb7a01acSMauro Carvalho Chehab /* Let the caller override settings */ 388cb7a01acSMauro Carvalho Chehab if (client->dev.platform_data) { 389cb7a01acSMauro Carvalho Chehab const struct IR_i2c_init_data *init_data = 390cb7a01acSMauro Carvalho Chehab client->dev.platform_data; 391cb7a01acSMauro Carvalho Chehab 392cb7a01acSMauro Carvalho Chehab ir_codes = init_data->ir_codes; 393cb7a01acSMauro Carvalho Chehab rc = init_data->rc_dev; 394cb7a01acSMauro Carvalho Chehab 395cb7a01acSMauro Carvalho Chehab name = init_data->name; 396cb7a01acSMauro Carvalho Chehab if (init_data->type) 3976d741bfeSSean Young rc_proto = init_data->type; 398cb7a01acSMauro Carvalho Chehab 399cb7a01acSMauro Carvalho Chehab if (init_data->polling_interval) 400cb7a01acSMauro Carvalho Chehab ir->polling_interval = init_data->polling_interval; 401cb7a01acSMauro Carvalho Chehab 402cb7a01acSMauro Carvalho Chehab switch (init_data->internal_get_key_func) { 403cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_CUSTOM: 404cb7a01acSMauro Carvalho Chehab /* The bridge driver provided us its own function */ 405cb7a01acSMauro Carvalho Chehab ir->get_key = init_data->get_key; 406cb7a01acSMauro Carvalho Chehab break; 407cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_PIXELVIEW: 408cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_pixelview; 409cb7a01acSMauro Carvalho Chehab break; 410cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_HAUP: 411cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_haup; 412cb7a01acSMauro Carvalho Chehab break; 413cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_KNC1: 414cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_knc1; 415cb7a01acSMauro Carvalho Chehab break; 416cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_FUSIONHDTV: 417cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_fusionhdtv; 418cb7a01acSMauro Carvalho Chehab break; 419cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_HAUP_XVR: 420cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_haup_xvr; 421cb7a01acSMauro Carvalho Chehab break; 422cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS: 423cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_avermedia_cardbus; 424cb7a01acSMauro Carvalho Chehab break; 425cb7a01acSMauro Carvalho Chehab } 426cb7a01acSMauro Carvalho Chehab } 427cb7a01acSMauro Carvalho Chehab 428cb7a01acSMauro Carvalho Chehab if (!rc) { 429cb7a01acSMauro Carvalho Chehab /* 43039c1cb2bSJonathan McCrohan * If platform_data doesn't specify rc_dev, initialize it 431cb7a01acSMauro Carvalho Chehab * internally 432cb7a01acSMauro Carvalho Chehab */ 4330f7499fdSAndi Shyti rc = rc_allocate_device(RC_DRIVER_SCANCODE); 434c02b211dSLaurent Pinchart if (!rc) 435c02b211dSLaurent Pinchart return -ENOMEM; 436cb7a01acSMauro Carvalho Chehab } 437cb7a01acSMauro Carvalho Chehab ir->rc = rc; 438cb7a01acSMauro Carvalho Chehab 439cb7a01acSMauro Carvalho Chehab /* Make sure we are all setup before going on */ 4406d741bfeSSean Young if (!name || !ir->get_key || !rc_proto || !ir_codes) { 44150a762b4SSean Young dev_warn(&client->dev, "Unsupported device at address 0x%02x\n", 442cb7a01acSMauro Carvalho Chehab addr); 443cb7a01acSMauro Carvalho Chehab err = -ENODEV; 444cb7a01acSMauro Carvalho Chehab goto err_out_free; 445cb7a01acSMauro Carvalho Chehab } 446cb7a01acSMauro Carvalho Chehab 447cb7a01acSMauro Carvalho Chehab ir->ir_codes = ir_codes; 448cb7a01acSMauro Carvalho Chehab 449afc7f24cSSean Young snprintf(ir->phys, sizeof(ir->phys), "%s/%s", dev_name(&adap->dev), 450cb7a01acSMauro Carvalho Chehab dev_name(&client->dev)); 451cb7a01acSMauro Carvalho Chehab 452cb7a01acSMauro Carvalho Chehab /* 453cb7a01acSMauro Carvalho Chehab * Initialize input_dev fields 454cb7a01acSMauro Carvalho Chehab * It doesn't make sense to allow overriding them via platform_data 455cb7a01acSMauro Carvalho Chehab */ 456cb7a01acSMauro Carvalho Chehab rc->input_id.bustype = BUS_I2C; 457cb7a01acSMauro Carvalho Chehab rc->input_phys = ir->phys; 458afc7f24cSSean Young rc->device_name = name; 459afc7f24cSSean Young rc->dev.parent = &client->dev; 460*a6927d81SSean Young rc->priv = ir; 461*a6927d81SSean Young rc->open = ir_open; 462*a6927d81SSean Young rc->close = ir_close; 463cb7a01acSMauro Carvalho Chehab 464cb7a01acSMauro Carvalho Chehab /* 465cb7a01acSMauro Carvalho Chehab * Initialize the other fields of rc_dev 466cb7a01acSMauro Carvalho Chehab */ 467cb7a01acSMauro Carvalho Chehab rc->map_name = ir->ir_codes; 4686d741bfeSSean Young rc->allowed_protocols = rc_proto; 469cb7a01acSMauro Carvalho Chehab if (!rc->driver_name) 47050a762b4SSean Young rc->driver_name = KBUILD_MODNAME; 471cb7a01acSMauro Carvalho Chehab 472*a6927d81SSean Young INIT_DELAYED_WORK(&ir->work, ir_work); 473*a6927d81SSean Young 474cb7a01acSMauro Carvalho Chehab err = rc_register_device(rc); 475cb7a01acSMauro Carvalho Chehab if (err) 476cb7a01acSMauro Carvalho Chehab goto err_out_free; 477cb7a01acSMauro Carvalho Chehab 478cb7a01acSMauro Carvalho Chehab return 0; 479cb7a01acSMauro Carvalho Chehab 480cb7a01acSMauro Carvalho Chehab err_out_free: 481cb7a01acSMauro Carvalho Chehab /* Only frees rc if it were allocated internally */ 482cb7a01acSMauro Carvalho Chehab rc_free_device(rc); 483cb7a01acSMauro Carvalho Chehab return err; 484cb7a01acSMauro Carvalho Chehab } 485cb7a01acSMauro Carvalho Chehab 486cb7a01acSMauro Carvalho Chehab static int ir_remove(struct i2c_client *client) 487cb7a01acSMauro Carvalho Chehab { 488cb7a01acSMauro Carvalho Chehab struct IR_i2c *ir = i2c_get_clientdata(client); 489cb7a01acSMauro Carvalho Chehab 490cb7a01acSMauro Carvalho Chehab /* kill outstanding polls */ 491cb7a01acSMauro Carvalho Chehab cancel_delayed_work_sync(&ir->work); 492cb7a01acSMauro Carvalho Chehab 493cb7a01acSMauro Carvalho Chehab /* unregister device */ 494cb7a01acSMauro Carvalho Chehab rc_unregister_device(ir->rc); 495cb7a01acSMauro Carvalho Chehab 496cb7a01acSMauro Carvalho Chehab /* free memory */ 497cb7a01acSMauro Carvalho Chehab return 0; 498cb7a01acSMauro Carvalho Chehab } 499cb7a01acSMauro Carvalho Chehab 500cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id ir_kbd_id[] = { 501cb7a01acSMauro Carvalho Chehab /* Generic entry for any IR receiver */ 502cb7a01acSMauro Carvalho Chehab { "ir_video", 0 }, 503cb7a01acSMauro Carvalho Chehab /* IR device specific entries should be added here */ 504cb7a01acSMauro Carvalho Chehab { "ir_rx_z8f0811_haup", 0 }, 505cb7a01acSMauro Carvalho Chehab { "ir_rx_z8f0811_hdpvr", 0 }, 506cb7a01acSMauro Carvalho Chehab { } 507cb7a01acSMauro Carvalho Chehab }; 508cb7a01acSMauro Carvalho Chehab 509cb7a01acSMauro Carvalho Chehab static struct i2c_driver ir_kbd_driver = { 510cb7a01acSMauro Carvalho Chehab .driver = { 511cb7a01acSMauro Carvalho Chehab .name = "ir-kbd-i2c", 512cb7a01acSMauro Carvalho Chehab }, 513cb7a01acSMauro Carvalho Chehab .probe = ir_probe, 514cb7a01acSMauro Carvalho Chehab .remove = ir_remove, 515cb7a01acSMauro Carvalho Chehab .id_table = ir_kbd_id, 516cb7a01acSMauro Carvalho Chehab }; 517cb7a01acSMauro Carvalho Chehab 518cb7a01acSMauro Carvalho Chehab module_i2c_driver(ir_kbd_driver); 519cb7a01acSMauro Carvalho Chehab 520cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 521cb7a01acSMauro Carvalho Chehab 522cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); 523cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("input driver for i2c IR remote controls"); 524cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 525