162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2003 Gerd Knorr 562306a36Sopenharmony_ci * Copyright (c) 2003 Pavel Machek 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/input.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "bttv.h" 1862306a36Sopenharmony_ci#include "bttvp.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int ir_debug; 2262306a36Sopenharmony_cimodule_param(ir_debug, int, 0644); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic int ir_rc5_remote_gap = 885; 2562306a36Sopenharmony_cimodule_param(ir_rc5_remote_gap, int, 0644); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#undef dprintk 2862306a36Sopenharmony_ci#define dprintk(fmt, ...) \ 2962306a36Sopenharmony_cido { \ 3062306a36Sopenharmony_ci if (ir_debug >= 1) \ 3162306a36Sopenharmony_ci pr_info(fmt, ##__VA_ARGS__); \ 3262306a36Sopenharmony_ci} while (0) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define DEVNAME "bttv-input" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define MODULE_NAME "bttv" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* ---------------------------------------------------------------------- */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void ir_handle_key(struct bttv *btv) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct bttv_ir *ir = btv->remote; 4362306a36Sopenharmony_ci u32 gpio,data; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* read gpio value */ 4662306a36Sopenharmony_ci gpio = bttv_gpio_read(&btv->c); 4762306a36Sopenharmony_ci if (ir->polling) { 4862306a36Sopenharmony_ci if (ir->last_gpio == gpio) 4962306a36Sopenharmony_ci return; 5062306a36Sopenharmony_ci ir->last_gpio = gpio; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* extract data */ 5462306a36Sopenharmony_ci data = ir_extract_bits(gpio, ir->mask_keycode); 5562306a36Sopenharmony_ci dprintk("irq gpio=0x%x code=%d | %s%s%s\n", 5662306a36Sopenharmony_ci gpio, data, 5762306a36Sopenharmony_ci ir->polling ? "poll" : "irq", 5862306a36Sopenharmony_ci (gpio & ir->mask_keydown) ? " down" : "", 5962306a36Sopenharmony_ci (gpio & ir->mask_keyup) ? " up" : ""); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if ((ir->mask_keydown && (gpio & ir->mask_keydown)) || 6262306a36Sopenharmony_ci (ir->mask_keyup && !(gpio & ir->mask_keyup))) { 6362306a36Sopenharmony_ci rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0); 6462306a36Sopenharmony_ci } else { 6562306a36Sopenharmony_ci /* HACK: Probably, ir->mask_keydown is missing 6662306a36Sopenharmony_ci for this board */ 6762306a36Sopenharmony_ci if (btv->c.type == BTTV_BOARD_WINFAST2000) 6862306a36Sopenharmony_ci rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 6962306a36Sopenharmony_ci 0); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci rc_keyup(ir->dev); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void ir_enltv_handle_key(struct bttv *btv) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct bttv_ir *ir = btv->remote; 7862306a36Sopenharmony_ci u32 gpio, data, keyup; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* read gpio value */ 8162306a36Sopenharmony_ci gpio = bttv_gpio_read(&btv->c); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* extract data */ 8462306a36Sopenharmony_ci data = ir_extract_bits(gpio, ir->mask_keycode); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* Check if it is keyup */ 8762306a36Sopenharmony_ci keyup = (gpio & ir->mask_keyup) ? 1UL << 31 : 0; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if ((ir->last_gpio & 0x7f) != data) { 9062306a36Sopenharmony_ci dprintk("gpio=0x%x code=%d | %s\n", 9162306a36Sopenharmony_ci gpio, data, 9262306a36Sopenharmony_ci (gpio & ir->mask_keyup) ? " up" : "up/down"); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0); 9562306a36Sopenharmony_ci if (keyup) 9662306a36Sopenharmony_ci rc_keyup(ir->dev); 9762306a36Sopenharmony_ci } else { 9862306a36Sopenharmony_ci if ((ir->last_gpio & 1UL << 31) == keyup) 9962306a36Sopenharmony_ci return; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci dprintk("(cnt) gpio=0x%x code=%d | %s\n", 10262306a36Sopenharmony_ci gpio, data, 10362306a36Sopenharmony_ci (gpio & ir->mask_keyup) ? " up" : "down"); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (keyup) 10662306a36Sopenharmony_ci rc_keyup(ir->dev); 10762306a36Sopenharmony_ci else 10862306a36Sopenharmony_ci rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 10962306a36Sopenharmony_ci 0); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci ir->last_gpio = data | keyup; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int bttv_rc5_irq(struct bttv *btv); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_civoid bttv_input_irq(struct bttv *btv) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct bttv_ir *ir = btv->remote; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (ir->rc5_gpio) 12262306a36Sopenharmony_ci bttv_rc5_irq(btv); 12362306a36Sopenharmony_ci else if (!ir->polling) 12462306a36Sopenharmony_ci ir_handle_key(btv); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic void bttv_input_timer(struct timer_list *t) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct bttv_ir *ir = from_timer(ir, t, timer); 13062306a36Sopenharmony_ci struct bttv *btv = ir->btv; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (btv->c.type == BTTV_BOARD_ENLTV_FM_2) 13362306a36Sopenharmony_ci ir_enltv_handle_key(btv); 13462306a36Sopenharmony_ci else 13562306a36Sopenharmony_ci ir_handle_key(btv); 13662306a36Sopenharmony_ci mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * FIXME: Nebula digi uses the legacy way to decode RC5, instead of relying 14162306a36Sopenharmony_ci * on the rc-core way. As we need to be sure that both IRQ transitions are 14262306a36Sopenharmony_ci * properly triggered, Better to touch it only with this hardware for 14362306a36Sopenharmony_ci * testing. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci#define RC5_START(x) (((x) >> 12) & 0x03) 14762306a36Sopenharmony_ci#define RC5_TOGGLE(x) (((x) >> 11) & 0x01) 14862306a36Sopenharmony_ci#define RC5_ADDR(x) (((x) >> 6) & 0x1f) 14962306a36Sopenharmony_ci#define RC5_INSTR(x) (((x) >> 0) & 0x3f) 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* decode raw bit pattern to RC5 code */ 15262306a36Sopenharmony_cistatic u32 bttv_rc5_decode(unsigned int code) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci unsigned int org_code = code; 15562306a36Sopenharmony_ci unsigned int pair; 15662306a36Sopenharmony_ci unsigned int rc5 = 0; 15762306a36Sopenharmony_ci int i; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci for (i = 0; i < 14; ++i) { 16062306a36Sopenharmony_ci pair = code & 0x3; 16162306a36Sopenharmony_ci code >>= 2; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci rc5 <<= 1; 16462306a36Sopenharmony_ci switch (pair) { 16562306a36Sopenharmony_ci case 0: 16662306a36Sopenharmony_ci case 2: 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci case 1: 16962306a36Sopenharmony_ci rc5 |= 1; 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci case 3: 17262306a36Sopenharmony_ci dprintk("rc5_decode(%x) bad code\n", 17362306a36Sopenharmony_ci org_code); 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, instr=%x\n", 17862306a36Sopenharmony_ci rc5, org_code, RC5_START(rc5), 17962306a36Sopenharmony_ci RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); 18062306a36Sopenharmony_ci return rc5; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic void bttv_rc5_timer_end(struct timer_list *t) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct bttv_ir *ir = from_timer(ir, t, timer); 18662306a36Sopenharmony_ci ktime_t tv; 18762306a36Sopenharmony_ci u32 gap, rc5, scancode; 18862306a36Sopenharmony_ci u8 toggle, command, system; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* get time */ 19162306a36Sopenharmony_ci tv = ktime_get(); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci gap = ktime_to_us(ktime_sub(tv, ir->base_time)); 19462306a36Sopenharmony_ci /* avoid overflow with gap >1s */ 19562306a36Sopenharmony_ci if (gap > USEC_PER_SEC) { 19662306a36Sopenharmony_ci gap = 200000; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci /* signal we're ready to start a new code */ 19962306a36Sopenharmony_ci ir->active = false; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */ 20262306a36Sopenharmony_ci if (gap < 28000) { 20362306a36Sopenharmony_ci dprintk("spurious timer_end\n"); 20462306a36Sopenharmony_ci return; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (ir->last_bit < 20) { 20862306a36Sopenharmony_ci /* ignore spurious codes (caused by light/other remotes) */ 20962306a36Sopenharmony_ci dprintk("short code: %x\n", ir->code); 21062306a36Sopenharmony_ci return; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci ir->code = (ir->code << ir->shift_by) | 1; 21462306a36Sopenharmony_ci rc5 = bttv_rc5_decode(ir->code); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci toggle = RC5_TOGGLE(rc5); 21762306a36Sopenharmony_ci system = RC5_ADDR(rc5); 21862306a36Sopenharmony_ci command = RC5_INSTR(rc5); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci switch (RC5_START(rc5)) { 22162306a36Sopenharmony_ci case 0x3: 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci case 0x2: 22462306a36Sopenharmony_ci command += 0x40; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci default: 22762306a36Sopenharmony_ci return; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci scancode = RC_SCANCODE_RC5(system, command); 23162306a36Sopenharmony_ci rc_keydown(ir->dev, RC_PROTO_RC5, scancode, toggle); 23262306a36Sopenharmony_ci dprintk("scancode %x, toggle %x\n", scancode, toggle); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int bttv_rc5_irq(struct bttv *btv) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct bttv_ir *ir = btv->remote; 23862306a36Sopenharmony_ci ktime_t tv; 23962306a36Sopenharmony_ci u32 gpio; 24062306a36Sopenharmony_ci u32 gap; 24162306a36Sopenharmony_ci unsigned long current_jiffies; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* read gpio port */ 24462306a36Sopenharmony_ci gpio = bttv_gpio_read(&btv->c); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* get time of bit */ 24762306a36Sopenharmony_ci current_jiffies = jiffies; 24862306a36Sopenharmony_ci tv = ktime_get(); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci gap = ktime_to_us(ktime_sub(tv, ir->base_time)); 25162306a36Sopenharmony_ci /* avoid overflow with gap >1s */ 25262306a36Sopenharmony_ci if (gap > USEC_PER_SEC) { 25362306a36Sopenharmony_ci gap = 200000; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci dprintk("RC5 IRQ: gap %d us for %s\n", 25762306a36Sopenharmony_ci gap, (gpio & 0x20) ? "mark" : "space"); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* remote IRQ? */ 26062306a36Sopenharmony_ci if (!(gpio & 0x20)) 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* active code => add bit */ 26462306a36Sopenharmony_ci if (ir->active) { 26562306a36Sopenharmony_ci /* only if in the code (otherwise spurious IRQ or timer 26662306a36Sopenharmony_ci late) */ 26762306a36Sopenharmony_ci if (ir->last_bit < 28) { 26862306a36Sopenharmony_ci ir->last_bit = (gap - ir_rc5_remote_gap / 2) / 26962306a36Sopenharmony_ci ir_rc5_remote_gap; 27062306a36Sopenharmony_ci ir->code |= 1 << ir->last_bit; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci /* starting new code */ 27362306a36Sopenharmony_ci } else { 27462306a36Sopenharmony_ci ir->active = true; 27562306a36Sopenharmony_ci ir->code = 0; 27662306a36Sopenharmony_ci ir->base_time = tv; 27762306a36Sopenharmony_ci ir->last_bit = 0; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci mod_timer(&ir->timer, current_jiffies + msecs_to_jiffies(30)); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* toggle GPIO pin 4 to reset the irq */ 28362306a36Sopenharmony_ci bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); 28462306a36Sopenharmony_ci bttv_gpio_write(&btv->c, gpio | (1 << 4)); 28562306a36Sopenharmony_ci return 1; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci/* ---------------------------------------------------------------------- */ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void bttv_ir_start(struct bttv_ir *ir) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci if (ir->polling) { 29362306a36Sopenharmony_ci timer_setup(&ir->timer, bttv_input_timer, 0); 29462306a36Sopenharmony_ci ir->timer.expires = jiffies + msecs_to_jiffies(1000); 29562306a36Sopenharmony_ci add_timer(&ir->timer); 29662306a36Sopenharmony_ci } else if (ir->rc5_gpio) { 29762306a36Sopenharmony_ci /* set timer_end for code completion */ 29862306a36Sopenharmony_ci timer_setup(&ir->timer, bttv_rc5_timer_end, 0); 29962306a36Sopenharmony_ci ir->shift_by = 1; 30062306a36Sopenharmony_ci ir->rc5_remote_gap = ir_rc5_remote_gap; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void bttv_ir_stop(struct bttv *btv) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci if (btv->remote->polling) 30762306a36Sopenharmony_ci del_timer_sync(&btv->remote->timer); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (btv->remote->rc5_gpio) { 31062306a36Sopenharmony_ci u32 gpio; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci del_timer_sync(&btv->remote->timer); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci gpio = bttv_gpio_read(&btv->c); 31562306a36Sopenharmony_ci bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/* 32062306a36Sopenharmony_ci * Get_key functions used by I2C remotes 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int get_key_pv951(struct IR_i2c *ir, enum rc_proto *protocol, 32462306a36Sopenharmony_ci u32 *scancode, u8 *toggle) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci int rc; 32762306a36Sopenharmony_ci unsigned char b; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* poll IR chip */ 33062306a36Sopenharmony_ci rc = i2c_master_recv(ir->c, &b, 1); 33162306a36Sopenharmony_ci if (rc != 1) { 33262306a36Sopenharmony_ci dprintk("read error\n"); 33362306a36Sopenharmony_ci if (rc < 0) 33462306a36Sopenharmony_ci return rc; 33562306a36Sopenharmony_ci return -EIO; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* ignore 0xaa */ 33962306a36Sopenharmony_ci if (b==0xaa) 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci dprintk("key %02x\n", b); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* 34462306a36Sopenharmony_ci * NOTE: 34562306a36Sopenharmony_ci * lirc_i2c maps the pv951 code as: 34662306a36Sopenharmony_ci * addr = 0x61D6 34762306a36Sopenharmony_ci * cmd = bit_reverse (b) 34862306a36Sopenharmony_ci * So, it seems that this device uses NEC extended 34962306a36Sopenharmony_ci * I decided to not fix the table, due to two reasons: 35062306a36Sopenharmony_ci * 1) Without the actual device, this is only a guess; 35162306a36Sopenharmony_ci * 2) As the addr is not reported via I2C, nor can be changed, 35262306a36Sopenharmony_ci * the device is bound to the vendor-provided RC. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci *protocol = RC_PROTO_UNKNOWN; 35662306a36Sopenharmony_ci *scancode = b; 35762306a36Sopenharmony_ci *toggle = 0; 35862306a36Sopenharmony_ci return 1; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/* Instantiate the I2C IR receiver device, if present */ 36262306a36Sopenharmony_civoid init_bttv_i2c_ir(struct bttv *btv) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci static const unsigned short addr_list[] = { 36562306a36Sopenharmony_ci 0x1a, 0x18, 0x64, 0x30, 0x71, 36662306a36Sopenharmony_ci I2C_CLIENT_END 36762306a36Sopenharmony_ci }; 36862306a36Sopenharmony_ci struct i2c_board_info info; 36962306a36Sopenharmony_ci struct i2c_client *i2c_dev; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (0 != btv->i2c_rc) 37262306a36Sopenharmony_ci return; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 37562306a36Sopenharmony_ci memset(&btv->init_data, 0, sizeof(btv->init_data)); 37662306a36Sopenharmony_ci strscpy(info.type, "ir_video", I2C_NAME_SIZE); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci switch (btv->c.type) { 37962306a36Sopenharmony_ci case BTTV_BOARD_PV951: 38062306a36Sopenharmony_ci btv->init_data.name = "PV951"; 38162306a36Sopenharmony_ci btv->init_data.get_key = get_key_pv951; 38262306a36Sopenharmony_ci btv->init_data.ir_codes = RC_MAP_PV951; 38362306a36Sopenharmony_ci info.addr = 0x4b; 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (btv->init_data.name) { 38862306a36Sopenharmony_ci info.platform_data = &btv->init_data; 38962306a36Sopenharmony_ci i2c_dev = i2c_new_client_device(&btv->c.i2c_adap, &info); 39062306a36Sopenharmony_ci } else { 39162306a36Sopenharmony_ci /* 39262306a36Sopenharmony_ci * The external IR receiver is at i2c address 0x34 (0x35 for 39362306a36Sopenharmony_ci * reads). Future Hauppauge cards will have an internal 39462306a36Sopenharmony_ci * receiver at 0x30 (0x31 for reads). In theory, both can be 39562306a36Sopenharmony_ci * fitted, and Hauppauge suggest an external overrides an 39662306a36Sopenharmony_ci * internal. 39762306a36Sopenharmony_ci * That's why we probe 0x1a (~0x34) first. CB 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_ci i2c_dev = i2c_new_scanned_device(&btv->c.i2c_adap, &info, addr_list, NULL); 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci if (IS_ERR(i2c_dev)) 40262306a36Sopenharmony_ci return; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci#if defined(CONFIG_MODULES) && defined(MODULE) 40562306a36Sopenharmony_ci request_module("ir-kbd-i2c"); 40662306a36Sopenharmony_ci#endif 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ciint bttv_input_init(struct bttv *btv) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct bttv_ir *ir; 41262306a36Sopenharmony_ci char *ir_codes = NULL; 41362306a36Sopenharmony_ci struct rc_dev *rc; 41462306a36Sopenharmony_ci int err = -ENOMEM; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (!btv->has_remote) 41762306a36Sopenharmony_ci return -ENODEV; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci ir = kzalloc(sizeof(*ir),GFP_KERNEL); 42062306a36Sopenharmony_ci rc = rc_allocate_device(RC_DRIVER_SCANCODE); 42162306a36Sopenharmony_ci if (!ir || !rc) 42262306a36Sopenharmony_ci goto err_out_free; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* detect & configure */ 42562306a36Sopenharmony_ci switch (btv->c.type) { 42662306a36Sopenharmony_ci case BTTV_BOARD_AVERMEDIA: 42762306a36Sopenharmony_ci case BTTV_BOARD_AVPHONE98: 42862306a36Sopenharmony_ci case BTTV_BOARD_AVERMEDIA98: 42962306a36Sopenharmony_ci ir_codes = RC_MAP_AVERMEDIA; 43062306a36Sopenharmony_ci ir->mask_keycode = 0xf88000; 43162306a36Sopenharmony_ci ir->mask_keydown = 0x010000; 43262306a36Sopenharmony_ci ir->polling = 50; // ms 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci case BTTV_BOARD_AVDVBT_761: 43662306a36Sopenharmony_ci case BTTV_BOARD_AVDVBT_771: 43762306a36Sopenharmony_ci ir_codes = RC_MAP_AVERMEDIA_DVBT; 43862306a36Sopenharmony_ci ir->mask_keycode = 0x0f00c0; 43962306a36Sopenharmony_ci ir->mask_keydown = 0x000020; 44062306a36Sopenharmony_ci ir->polling = 50; // ms 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci case BTTV_BOARD_PXELVWPLTVPAK: 44462306a36Sopenharmony_ci ir_codes = RC_MAP_PIXELVIEW; 44562306a36Sopenharmony_ci ir->mask_keycode = 0x003e00; 44662306a36Sopenharmony_ci ir->mask_keyup = 0x010000; 44762306a36Sopenharmony_ci ir->polling = 50; // ms 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci case BTTV_BOARD_PV_M4900: 45062306a36Sopenharmony_ci case BTTV_BOARD_PV_BT878P_9B: 45162306a36Sopenharmony_ci case BTTV_BOARD_PV_BT878P_PLUS: 45262306a36Sopenharmony_ci ir_codes = RC_MAP_PIXELVIEW; 45362306a36Sopenharmony_ci ir->mask_keycode = 0x001f00; 45462306a36Sopenharmony_ci ir->mask_keyup = 0x008000; 45562306a36Sopenharmony_ci ir->polling = 50; // ms 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci case BTTV_BOARD_WINFAST2000: 45962306a36Sopenharmony_ci ir_codes = RC_MAP_WINFAST; 46062306a36Sopenharmony_ci ir->mask_keycode = 0x1f8; 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci case BTTV_BOARD_MAGICTVIEW061: 46362306a36Sopenharmony_ci case BTTV_BOARD_MAGICTVIEW063: 46462306a36Sopenharmony_ci ir_codes = RC_MAP_WINFAST; 46562306a36Sopenharmony_ci ir->mask_keycode = 0x0008e000; 46662306a36Sopenharmony_ci ir->mask_keydown = 0x00200000; 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci case BTTV_BOARD_APAC_VIEWCOMP: 46962306a36Sopenharmony_ci ir_codes = RC_MAP_APAC_VIEWCOMP; 47062306a36Sopenharmony_ci ir->mask_keycode = 0x001f00; 47162306a36Sopenharmony_ci ir->mask_keyup = 0x008000; 47262306a36Sopenharmony_ci ir->polling = 50; // ms 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci case BTTV_BOARD_ASKEY_CPH03X: 47562306a36Sopenharmony_ci case BTTV_BOARD_CONCEPTRONIC_CTVFMI2: 47662306a36Sopenharmony_ci case BTTV_BOARD_CONTVFMI: 47762306a36Sopenharmony_ci case BTTV_BOARD_KWORLD_VSTREAM_XPERT: 47862306a36Sopenharmony_ci ir_codes = RC_MAP_PIXELVIEW; 47962306a36Sopenharmony_ci ir->mask_keycode = 0x001F00; 48062306a36Sopenharmony_ci ir->mask_keyup = 0x006000; 48162306a36Sopenharmony_ci ir->polling = 50; // ms 48262306a36Sopenharmony_ci break; 48362306a36Sopenharmony_ci case BTTV_BOARD_NEBULA_DIGITV: 48462306a36Sopenharmony_ci ir_codes = RC_MAP_NEBULA; 48562306a36Sopenharmony_ci ir->rc5_gpio = true; 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci case BTTV_BOARD_MACHTV_MAGICTV: 48862306a36Sopenharmony_ci ir_codes = RC_MAP_APAC_VIEWCOMP; 48962306a36Sopenharmony_ci ir->mask_keycode = 0x001F00; 49062306a36Sopenharmony_ci ir->mask_keyup = 0x004000; 49162306a36Sopenharmony_ci ir->polling = 50; /* ms */ 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case BTTV_BOARD_KOZUMI_KTV_01C: 49462306a36Sopenharmony_ci ir_codes = RC_MAP_PCTV_SEDNA; 49562306a36Sopenharmony_ci ir->mask_keycode = 0x001f00; 49662306a36Sopenharmony_ci ir->mask_keyup = 0x006000; 49762306a36Sopenharmony_ci ir->polling = 50; /* ms */ 49862306a36Sopenharmony_ci break; 49962306a36Sopenharmony_ci case BTTV_BOARD_ENLTV_FM_2: 50062306a36Sopenharmony_ci ir_codes = RC_MAP_ENCORE_ENLTV2; 50162306a36Sopenharmony_ci ir->mask_keycode = 0x00fd00; 50262306a36Sopenharmony_ci ir->mask_keyup = 0x000080; 50362306a36Sopenharmony_ci ir->polling = 1; /* ms */ 50462306a36Sopenharmony_ci ir->last_gpio = ir_extract_bits(bttv_gpio_read(&btv->c), 50562306a36Sopenharmony_ci ir->mask_keycode); 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (!ir_codes) { 51062306a36Sopenharmony_ci dprintk("Ooops: IR config error [card=%d]\n", btv->c.type); 51162306a36Sopenharmony_ci err = -ENODEV; 51262306a36Sopenharmony_ci goto err_out_free; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (ir->rc5_gpio) { 51662306a36Sopenharmony_ci u32 gpio; 51762306a36Sopenharmony_ci /* enable remote irq */ 51862306a36Sopenharmony_ci bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4); 51962306a36Sopenharmony_ci gpio = bttv_gpio_read(&btv->c); 52062306a36Sopenharmony_ci bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); 52162306a36Sopenharmony_ci bttv_gpio_write(&btv->c, gpio | (1 << 4)); 52262306a36Sopenharmony_ci } else { 52362306a36Sopenharmony_ci /* init hardware-specific stuff */ 52462306a36Sopenharmony_ci bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0); 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* init input device */ 52862306a36Sopenharmony_ci ir->dev = rc; 52962306a36Sopenharmony_ci ir->btv = btv; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", 53262306a36Sopenharmony_ci btv->c.type); 53362306a36Sopenharmony_ci snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", 53462306a36Sopenharmony_ci pci_name(btv->c.pci)); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci rc->device_name = ir->name; 53762306a36Sopenharmony_ci rc->input_phys = ir->phys; 53862306a36Sopenharmony_ci rc->input_id.bustype = BUS_PCI; 53962306a36Sopenharmony_ci rc->input_id.version = 1; 54062306a36Sopenharmony_ci if (btv->c.pci->subsystem_vendor) { 54162306a36Sopenharmony_ci rc->input_id.vendor = btv->c.pci->subsystem_vendor; 54262306a36Sopenharmony_ci rc->input_id.product = btv->c.pci->subsystem_device; 54362306a36Sopenharmony_ci } else { 54462306a36Sopenharmony_ci rc->input_id.vendor = btv->c.pci->vendor; 54562306a36Sopenharmony_ci rc->input_id.product = btv->c.pci->device; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci rc->dev.parent = &btv->c.pci->dev; 54862306a36Sopenharmony_ci rc->map_name = ir_codes; 54962306a36Sopenharmony_ci rc->driver_name = MODULE_NAME; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci btv->remote = ir; 55262306a36Sopenharmony_ci bttv_ir_start(ir); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* all done */ 55562306a36Sopenharmony_ci err = rc_register_device(rc); 55662306a36Sopenharmony_ci if (err) 55762306a36Sopenharmony_ci goto err_out_stop; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return 0; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci err_out_stop: 56262306a36Sopenharmony_ci bttv_ir_stop(btv); 56362306a36Sopenharmony_ci btv->remote = NULL; 56462306a36Sopenharmony_ci err_out_free: 56562306a36Sopenharmony_ci rc_free_device(rc); 56662306a36Sopenharmony_ci kfree(ir); 56762306a36Sopenharmony_ci return err; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_civoid bttv_input_fini(struct bttv *btv) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci if (btv->remote == NULL) 57362306a36Sopenharmony_ci return; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci bttv_ir_stop(btv); 57662306a36Sopenharmony_ci rc_unregister_device(btv->remote->dev); 57762306a36Sopenharmony_ci kfree(btv->remote); 57862306a36Sopenharmony_ci btv->remote = NULL; 57962306a36Sopenharmony_ci} 580