From afc7f24c01034b7820365d9fa64822504b4dc35d Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 18 Oct 2017 09:39:12 -0400 Subject: media: rc: i2c: set parent of rc device and improve name With the parent set for the rc device, the messages clearly state that it is attached via i2c. The additional printk is unnecessary. These are the old messages: rc rc1: i2c IR (Hauppauge WinTV PVR-150 as /devices/virtual/rc/rc1 ir-kbd-i2c: i2c IR (Hauppauge WinTV PVR-150 detected at i2c-10/10-0071/ir0 [ivtv i2c driver #0] Now we simply get: rc rc1: Hauppauge WinTV PVR-150 as /devices/pci0000:00/0000:00:1e.0/0000:02:00.0/i2c-10/10-0071/rc/rc1 Note that we no longer copy the name. I've checked all call sites to verfiy this is not a problem. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/media/i2c/ir-kbd-i2c.c') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 8b5f7d0435e4..27e36f45286c 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -439,12 +439,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_out_free; } - /* Sets name */ - snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name); ir->ir_codes = ir_codes; - snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", - dev_name(&adap->dev), + snprintf(ir->phys, sizeof(ir->phys), "%s/%s", dev_name(&adap->dev), dev_name(&client->dev)); /* @@ -453,7 +450,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) */ rc->input_id.bustype = BUS_I2C; rc->input_phys = ir->phys; - rc->device_name = ir->name; + rc->device_name = name; + rc->dev.parent = &client->dev; /* * Initialize the other fields of rc_dev @@ -467,9 +465,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) if (err) goto err_out_free; - printk(MODULE_NAME ": %s detected at %s [%s]\n", - ir->name, ir->phys, adap->name); - /* start polling via eventd */ INIT_DELAYED_WORK(&ir->work, ir_work); schedule_delayed_work(&ir->work, 0); -- cgit From 50a762b413ad7ed137e75b79b1aa50cf4b1e2b73 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 18 Oct 2017 10:00:50 -0400 Subject: media: rc: i2c: use dev_dbg rather hand-rolled debug Use the dev_dbg dynamic infrastructure instead of rolling our own custom debug logic. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 61 +++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 36 deletions(-) (limited to 'drivers/media/i2c/ir-kbd-i2c.c') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 27e36f45286c..1b8cd1b75bfb 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -46,18 +46,6 @@ #include #include -/* ----------------------------------------------------------------------- */ -/* insmod parameters */ - -static int debug; -module_param(debug, int, 0644); /* debug level (0,1,2) */ - - -#define MODULE_NAME "ir-kbd-i2c" -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG MODULE_NAME ": " fmt , ## arg) - -/* ----------------------------------------------------------------------- */ static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *ptoggle, int size) @@ -96,7 +84,8 @@ static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, if (!range) code += 64; - dprintk(1, "ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", + dev_dbg(&ir->rc->dev, + "ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", start, range, toggle, dev, code); *protocol = RC_PROTO_RC5; @@ -113,13 +102,15 @@ static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, *ptoggle = (dev & 0x80) != 0; *protocol = RC_PROTO_RC6_MCE; dev &= 0x7f; - dprintk(1, "ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n", - *ptoggle, vendor, dev, code); + dev_dbg(&ir->rc->dev, + "ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n", + *ptoggle, vendor, dev, code); } else { *ptoggle = 0; *protocol = RC_PROTO_RC6_6A_32; - dprintk(1, "ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n", - vendor, dev, code); + dev_dbg(&ir->rc->dev, + "ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n", + vendor, dev, code); } *scancode = RC_SCANCODE_RC6_6A(vendor, dev, code); @@ -162,7 +153,7 @@ static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol, /* poll IR chip */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - dprintk(1,"read error\n"); + dev_dbg(&ir->rc->dev, "read error\n"); return -EIO; } @@ -179,13 +170,12 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol, /* poll IR chip */ if (4 != i2c_master_recv(ir->c, buf, 4)) { - dprintk(1,"read error\n"); + dev_dbg(&ir->rc->dev, "read error\n"); return -EIO; } - if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) - dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__, - buf[0], buf[1], buf[2], buf[3]); + if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0 || buf[3] != 0) + dev_dbg(&ir->rc->dev, "%s: %*ph\n", __func__, 4, buf); /* no key pressed or signal from other ir remote */ if(buf[0] != 0x1 || buf[1] != 0xfe) @@ -204,7 +194,7 @@ static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol, /* poll IR chip */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - dprintk(1,"read error\n"); + dev_dbg(&ir->rc->dev, "read error\n"); return -EIO; } @@ -212,7 +202,7 @@ static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol, down, while 0xff indicates that no button is hold down. 0xfe sequences are sometimes interrupted by 0xFF */ - dprintk(2,"key %02x\n", b); + dev_dbg(&ir->rc->dev, "key %02x\n", b); if (b == 0xff) return 0; @@ -237,7 +227,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, .buf = &key, .len = 1} }; subaddr = 0x0d; if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { - dprintk(1, "read error\n"); + dev_dbg(&ir->rc->dev, "read error\n"); return -EIO; } @@ -247,18 +237,17 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, subaddr = 0x0b; msg[1].buf = &keygroup; if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { - dprintk(1, "read error\n"); + dev_dbg(&ir->rc->dev, "read error\n"); return -EIO; } if (keygroup == 0xff) return 0; - dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup); + dev_dbg(&ir->rc->dev, "read key 0x%02x/0x%02x\n", key, keygroup); if (keygroup < 2 || keygroup > 4) { - /* Only a warning */ - dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n", - keygroup, key); + dev_warn(&ir->rc->dev, "warning: invalid key group 0x%02x for key 0x%02x\n", + keygroup, key); } key |= (keygroup & 1) << 6; @@ -279,15 +268,15 @@ static int ir_key_poll(struct IR_i2c *ir) u8 toggle; int rc; - dprintk(3, "%s\n", __func__); + dev_dbg(&ir->rc->dev, "%s\n", __func__); rc = ir->get_key(ir, &protocol, &scancode, &toggle); if (rc < 0) { - dprintk(2,"error\n"); + dev_warn(&ir->rc->dev, "error %d\n", rc); return rc; } if (rc) { - dprintk(1, "%s: proto = 0x%04x, scancode = 0x%08x\n", + dev_dbg(&ir->rc->dev, "%s: proto = 0x%04x, scancode = 0x%08x\n", __func__, protocol, scancode); rc_keydown(ir->rc, protocol, scancode, toggle); } @@ -433,8 +422,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Make sure we are all setup before going on */ if (!name || !ir->get_key || !rc_proto || !ir_codes) { - dprintk(1, ": Unsupported device at address 0x%02x\n", - addr); + dev_warn(&client->dev, "Unsupported device at address 0x%02x\n", + addr); err = -ENODEV; goto err_out_free; } @@ -459,7 +448,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) rc->map_name = ir->ir_codes; rc->allowed_protocols = rc_proto; if (!rc->driver_name) - rc->driver_name = MODULE_NAME; + rc->driver_name = KBUILD_MODNAME; err = rc_register_device(rc); if (err) -- cgit From a6927d81c0073c89a468ff558212f230941a941f Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 17 Oct 2017 16:31:20 -0400 Subject: media: rc: i2c: only poll if the rc device is opened The lirc_zilog driver only polls the device if the lirc chardev is opened; do the same with the rc-core driver. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/media/i2c/ir-kbd-i2c.c') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 1b8cd1b75bfb..22f32717638a 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -298,6 +298,22 @@ static void ir_work(struct work_struct *work) schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); } +static int ir_open(struct rc_dev *dev) +{ + struct IR_i2c *ir = dev->priv; + + schedule_delayed_work(&ir->work, 0); + + return 0; +} + +static void ir_close(struct rc_dev *dev) +{ + struct IR_i2c *ir = dev->priv; + + cancel_delayed_work_sync(&ir->work); +} + /* ----------------------------------------------------------------------- */ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -441,6 +457,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) rc->input_phys = ir->phys; rc->device_name = name; rc->dev.parent = &client->dev; + rc->priv = ir; + rc->open = ir_open; + rc->close = ir_close; /* * Initialize the other fields of rc_dev @@ -450,14 +469,12 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) if (!rc->driver_name) rc->driver_name = KBUILD_MODNAME; + INIT_DELAYED_WORK(&ir->work, ir_work); + err = rc_register_device(rc); if (err) goto err_out_free; - /* start polling via eventd */ - INIT_DELAYED_WORK(&ir->work, ir_work); - schedule_delayed_work(&ir->work, 0); - return 0; err_out_free: -- cgit From ab5222ed1691b522b196624794a904c879033afb Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 12 Oct 2017 18:02:57 -0400 Subject: media: merge ir_tx_z8f0811_haup and ir_rx_z8f0811_haup i2c devices These two devices ids are really just one device with multiple addresses. Probing becomes much simpler if we simply fold this into one i2c device with two address. Note that this breaks the lirc_zilog driver, however we will teach ir-kbd-i2c to do what lirc_zilog does in a later commit. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/i2c/ir-kbd-i2c.c') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 22f32717638a..ec669ec4cfc5 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -501,8 +501,8 @@ static const struct i2c_device_id ir_kbd_id[] = { /* Generic entry for any IR receiver */ { "ir_video", 0 }, /* IR device specific entries should be added here */ - { "ir_rx_z8f0811_haup", 0 }, - { "ir_rx_z8f0811_hdpvr", 0 }, + { "ir_z8f0811_haup", 0 }, + { "ir_z8f0811_hdpvr", 0 }, { } }; -- cgit From acaa34bf06e963f0b9481a3c16bfd6867e2369a0 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 21 Oct 2017 08:16:47 -0400 Subject: media: rc: implement zilog transmitter This code implements the transmitter which is currently implemented in the staging lirc_zilog driver. The new code does not need a signal database, iow. the haup-ir-blaster.bin firmware file is no longer needed, and the driver does not know anything about the keycodes in that file. Instead, the new driver can send raw IR, but the hardware is limited to few different lengths of pulse and spaces, so it is best to use generated IR rather than recorded IR. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 436 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 428 insertions(+), 8 deletions(-) (limited to 'drivers/media/i2c/ir-kbd-i2c.c') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index ec669ec4cfc5..020ef0d7058e 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -18,6 +18,20 @@ * Brian Rogers * modified for AVerMedia Cardbus by * Oldrich Jedlicka + * Zilog Transmitter portions/ideas were derived from GPLv2+ sources: + * - drivers/char/pctv_zilogir.[ch] from Hauppauge Broadway product + * Copyright 2011 Hauppauge Computer works + * - drivers/staging/media/lirc/lirc_zilog.c + * Copyright (c) 2000 Gerd Knorr + * Michal Kochanowicz + * Christoph Bartelmus + * Ulrich Mueller + * Stefan Jahn + * Jerome Brock + * Thomas Reitmayr (treitmayr@yahoo.com) + * Mark Weaver + * Jarod Wilson + * Copyright (C) 2011 Andy Walls * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,6 +60,8 @@ #include #include +#define FLAG_TX 1 +#define FLAG_HDPVR 2 static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *ptoggle, int size) @@ -288,11 +304,18 @@ static void ir_work(struct work_struct *work) int rc; struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); - rc = ir_key_poll(ir); - if (rc == -ENODEV) { - rc_unregister_device(ir->rc); - ir->rc = NULL; - return; + /* + * If the transmit code is holding the lock, skip polling for + * IR, we'll get it to it next time round + */ + if (mutex_trylock(&ir->lock)) { + rc = ir_key_poll(ir); + mutex_unlock(&ir->lock); + if (rc == -ENODEV) { + rc_unregister_device(ir->rc); + ir->rc = NULL; + return; + } } schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); @@ -314,7 +337,383 @@ static void ir_close(struct rc_dev *dev) cancel_delayed_work_sync(&ir->work); } -/* ----------------------------------------------------------------------- */ +/* Zilog Transmit Interface */ +#define XTAL_FREQ 18432000 + +#define ZILOG_SEND 0x80 +#define ZILOG_UIR_END 0x40 +#define ZILOG_INIT_END 0x20 +#define ZILOG_LIR_END 0x10 + +#define ZILOG_STATUS_OK 0x80 +#define ZILOG_STATUS_TX 0x40 +#define ZILOG_STATUS_SET 0x20 + +/* + * As you can see here, very few different lengths of pulse and space + * can be encoded. This means that the hardware does not work well with + * recorded IR. It's best to work with generated IR, like from ir-ctl or + * the in-kernel encoders. + */ +struct code_block { + u8 length; + u16 pulse[7]; /* not aligned */ + u8 carrier_pulse; + u8 carrier_space; + u16 space[8]; /* not aligned */ + u8 codes[61]; + u8 csum[2]; +} __packed; + +static int send_data_block(struct IR_i2c *ir, int cmd, + struct code_block *code_block) +{ + int i, j, ret; + u8 buf[5], *p; + + p = &code_block->length; + for (i = 0; p < code_block->csum; i++) + code_block->csum[i & 1] ^= *p++; + + p = &code_block->length; + + for (i = 0; i < sizeof(*code_block);) { + int tosend = sizeof(*code_block) - i; + + if (tosend > 4) + tosend = 4; + buf[0] = i + 1; + for (j = 0; j < tosend; ++j) + buf[1 + j] = p[i + j]; + dev_dbg(&ir->rc->dev, "%*ph", tosend + 1, buf); + ret = i2c_master_send(ir->tx_c, buf, tosend + 1); + if (ret != tosend + 1) { + dev_dbg(&ir->rc->dev, + "i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EIO; + } + i += tosend; + } + + buf[0] = 0; + buf[1] = cmd; + ret = i2c_master_send(ir->tx_c, buf, 2); + if (ret != 2) { + dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EIO; + } + + usleep_range(2000, 5000); + + ret = i2c_master_send(ir->tx_c, buf, 1); + if (ret != 1) { + dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +static int zilog_init(struct IR_i2c *ir) +{ + struct code_block code_block = { .length = sizeof(code_block) }; + u8 buf[4]; + int ret; + + put_unaligned_be16(0x1000, &code_block.pulse[3]); + + ret = send_data_block(ir, ZILOG_INIT_END, &code_block); + if (ret) + return ret; + + ret = i2c_master_recv(ir->tx_c, buf, 4); + if (ret != 4) { + dev_err(&ir->c->dev, "failed to retrieve firmware version: %d\n", + ret); + return ret < 0 ? ret : -EIO; + } + + dev_info(&ir->c->dev, "Zilog/Hauppauge IR blaster firmware version %d.%d.%d\n", + buf[1], buf[2], buf[3]); + + return 0; +} + +/* + * If the last slot for pulse is the same as the current slot for pulse, + * then use slot no 7. + */ +static void copy_codes(u8 *dst, u8 *src, unsigned int count) +{ + u8 c, last = 0xff; + + while (count--) { + c = *src++; + if ((c & 0xf0) == last) { + *dst++ = 0x70 | (c & 0xf); + } else { + *dst++ = c; + last = c & 0xf0; + } + } +} + +/* + * When looking for repeats, we don't care about the trailing space. This + * is set to the shortest possible anyway. + */ +static int cmp_no_trail(u8 *a, u8 *b, unsigned int count) +{ + while (--count) { + if (*a++ != *b++) + return 1; + } + + return (*a & 0xf0) - (*b & 0xf0); +} + +static int find_slot(u16 *array, unsigned int size, u16 val) +{ + int i; + + for (i = 0; i < size; i++) { + if (get_unaligned_be16(&array[i]) == val) { + return i; + } else if (!array[i]) { + put_unaligned_be16(val, &array[i]); + return i; + } + } + + return -1; +} + +static int zilog_ir_format(struct rc_dev *rcdev, unsigned int *txbuf, + unsigned int count, struct code_block *code_block) +{ + struct IR_i2c *ir = rcdev->priv; + int rep, i, l, p = 0, s, c = 0; + bool repeating; + u8 codes[174]; + + code_block->carrier_pulse = DIV_ROUND_CLOSEST( + ir->duty_cycle * XTAL_FREQ / 1000, ir->carrier); + code_block->carrier_space = DIV_ROUND_CLOSEST( + (100 - ir->duty_cycle) * XTAL_FREQ / 1000, ir->carrier); + + for (i = 0; i < count; i++) { + if (c >= ARRAY_SIZE(codes) - 1) { + dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); + return -EINVAL; + } + + /* + * Lengths more than 142220us cannot be encoded; also + * this checks for multiply overflow + */ + if (txbuf[i] > 142220) + return -EINVAL; + + l = DIV_ROUND_CLOSEST((XTAL_FREQ / 1000) * txbuf[i], 40000); + + if (i & 1) { + s = find_slot(code_block->space, + ARRAY_SIZE(code_block->space), l); + if (s == -1) { + dev_warn(&rcdev->dev, "Too many different lengths spaces, cannot transmit"); + return -EINVAL; + } + + /* We have a pulse and space */ + codes[c++] = (p << 4) | s; + } else { + p = find_slot(code_block->pulse, + ARRAY_SIZE(code_block->pulse), l); + if (p == -1) { + dev_warn(&rcdev->dev, "Too many different lengths pulses, cannot transmit"); + return -EINVAL; + } + } + } + + /* We have to encode the trailing pulse. Find the shortest space */ + s = 0; + for (i = 1; i < ARRAY_SIZE(code_block->space); i++) { + u16 d = get_unaligned_be16(&code_block->space[i]); + + if (get_unaligned_be16(&code_block->space[s]) > d) + s = i; + } + + codes[c++] = (p << 4) | s; + + dev_dbg(&rcdev->dev, "generated %d codes\n", c); + + /* + * Are the last N codes (so pulse + space) repeating 3 times? + * if so we can shorten the codes list and use code 0xc0 to repeat + * them. + */ + repeating = false; + + for (rep = c / 3; rep >= 1; rep--) { + if (!memcmp(&codes[c - rep * 3], &codes[c - rep * 2], rep) && + !cmp_no_trail(&codes[c - rep], &codes[c - rep * 2], rep)) { + repeating = true; + break; + } + } + + if (repeating) { + /* first copy any leading non-repeating */ + int leading = c - rep * 3; + + if (leading + rep >= ARRAY_SIZE(code_block->codes) - 3) { + dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); + return -EINVAL; + } + + dev_dbg(&rcdev->dev, "found trailing %d repeat\n", rep); + copy_codes(code_block->codes, codes, leading); + code_block->codes[leading] = 0x82; + copy_codes(code_block->codes + leading + 1, codes + leading, + rep); + c = leading + 1 + rep; + code_block->codes[c++] = 0xc0; + } else { + if (c >= ARRAY_SIZE(code_block->codes) - 3) { + dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); + return -EINVAL; + } + + dev_dbg(&rcdev->dev, "found no trailing repeat\n"); + code_block->codes[0] = 0x82; + copy_codes(code_block->codes + 1, codes, c); + c++; + code_block->codes[c++] = 0xc4; + } + + while (c < ARRAY_SIZE(code_block->codes)) + code_block->codes[c++] = 0x83; + + return 0; +} + +static int zilog_tx(struct rc_dev *rcdev, unsigned int *txbuf, + unsigned int count) +{ + struct IR_i2c *ir = rcdev->priv; + struct code_block code_block = { .length = sizeof(code_block) }; + u8 buf[2]; + int ret, i; + + ret = zilog_ir_format(rcdev, txbuf, count, &code_block); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&ir->lock); + if (ret) + return ret; + + ret = send_data_block(ir, ZILOG_UIR_END, &code_block); + if (ret) + goto out_unlock; + + ret = i2c_master_recv(ir->tx_c, buf, 1); + if (ret != 1) { + dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret); + goto out_unlock; + } + + dev_dbg(&ir->rc->dev, "code set status: %02x\n", buf[0]); + + if (buf[0] != (ZILOG_STATUS_OK | ZILOG_STATUS_SET)) { + dev_err(&ir->rc->dev, "unexpected IR TX response %02x\n", + buf[0]); + ret = -EIO; + goto out_unlock; + } + + buf[0] = 0x00; + buf[1] = ZILOG_SEND; + + ret = i2c_master_send(ir->tx_c, buf, 2); + if (ret != 2) { + dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret); + if (ret >= 0) + ret = -EIO; + goto out_unlock; + } + + dev_dbg(&ir->rc->dev, "send command sent\n"); + + /* + * This bit NAKs until the device is ready, so we retry it + * sleeping a bit each time. This seems to be what the windows + * driver does, approximately. + * Try for up to 1s. + */ + for (i = 0; i < 20; ++i) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(50)); + ret = i2c_master_send(ir->tx_c, buf, 1); + if (ret == 1) + break; + dev_dbg(&ir->rc->dev, + "NAK expected: i2c_master_send failed with %d (try %d)\n", + ret, i + 1); + } + + if (ret != 1) { + dev_err(&ir->rc->dev, + "IR TX chip never got ready: last i2c_master_send failed with %d\n", + ret); + if (ret >= 0) + ret = -EIO; + goto out_unlock; + } + + i = i2c_master_recv(ir->tx_c, buf, 1); + if (i != 1) { + dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret); + ret = -EIO; + goto out_unlock; + } else if (buf[0] != ZILOG_STATUS_OK) { + dev_err(&ir->rc->dev, "unexpected IR TX response #2: %02x\n", + buf[0]); + ret = -EIO; + goto out_unlock; + } + dev_dbg(&ir->rc->dev, "transmit complete\n"); + + /* Oh good, it worked */ + ret = count; +out_unlock: + mutex_unlock(&ir->lock); + + return ret; +} + +static int zilog_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + struct IR_i2c *ir = dev->priv; + + if (carrier > 500000 || carrier < 20000) + return -EINVAL; + + ir->carrier = carrier; + + return 0; +} + +static int zilog_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle) +{ + struct IR_i2c *ir = dev->priv; + + ir->duty_cycle = duty_cycle; + + return 0; +} static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -469,8 +868,23 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) if (!rc->driver_name) rc->driver_name = KBUILD_MODNAME; + mutex_init(&ir->lock); + INIT_DELAYED_WORK(&ir->work, ir_work); + if (id->driver_data & FLAG_TX) { + ir->tx_c = i2c_new_dummy(client->adapter, 0x70); + if (!ir->tx_c) { + dev_err(&client->dev, "failed to setup tx i2c address"); + } else if (!zilog_init(ir)) { + ir->carrier = 38000; + ir->duty_cycle = 40; + rc->tx_ir = zilog_tx; + rc->s_tx_carrier = zilog_tx_carrier; + rc->s_tx_duty_cycle = zilog_tx_duty_cycle; + } + } + err = rc_register_device(rc); if (err) goto err_out_free; @@ -478,6 +892,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) return 0; err_out_free: + if (ir->tx_c) + i2c_unregister_device(ir->tx_c); + /* Only frees rc if it were allocated internally */ rc_free_device(rc); return err; @@ -490,6 +907,9 @@ static int ir_remove(struct i2c_client *client) /* kill outstanding polls */ cancel_delayed_work_sync(&ir->work); + if (ir->tx_c) + i2c_unregister_device(ir->tx_c); + /* unregister device */ rc_unregister_device(ir->rc); @@ -501,8 +921,8 @@ static const struct i2c_device_id ir_kbd_id[] = { /* Generic entry for any IR receiver */ { "ir_video", 0 }, /* IR device specific entries should be added here */ - { "ir_z8f0811_haup", 0 }, - { "ir_z8f0811_hdpvr", 0 }, + { "ir_z8f0811_haup", FLAG_TX }, + { "ir_z8f0811_hdpvr", FLAG_TX | FLAG_HDPVR }, { } }; -- cgit From 1cb26030f3494a8bb3c953d45cffba838ec4d454 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 24 Oct 2017 17:04:16 -0400 Subject: media: i2c: enable i2c IR for hardware which isn't HD-PVR This is a fix for commit 329d88da4df9 ("[media] media: i2c: Don't export ir-kbd-i2c module alias") that stopped the module from being loaded automagically. The problems described only affect the HD-PVR, so it should not affect other hardware; also if the module happens to be loaded, the i2c IR part of the HD-PVR will be enabled anyway. Fixes: 329d88da4df9 ("[media] media: i2c: Don't export ir-kbd-i2c module alias") Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/media/i2c/ir-kbd-i2c.c') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 020ef0d7058e..193020d64e51 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -63,6 +63,9 @@ #define FLAG_TX 1 #define FLAG_HDPVR 2 +static bool enable_hdpvr; +module_param(enable_hdpvr, bool, 0644); + static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *ptoggle, int size) { @@ -726,6 +729,11 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) unsigned short addr = client->addr; int err; + if ((id->driver_data & FLAG_HDPVR) && !enable_hdpvr) { + dev_err(&client->dev, "IR for HDPVR is known to cause problems during recording, use enable_hdpvr modparam to enable\n"); + return -ENODEV; + } + ir = devm_kzalloc(&client->dev, sizeof(*ir), GFP_KERNEL); if (!ir) return -ENOMEM; @@ -925,6 +933,7 @@ static const struct i2c_device_id ir_kbd_id[] = { { "ir_z8f0811_hdpvr", FLAG_TX | FLAG_HDPVR }, { } }; +MODULE_DEVICE_TABLE(i2c, ir_kbd_id); static struct i2c_driver ir_kbd_driver = { .driver = { -- cgit