aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/rc/winbond-cir.c
diff options
context:
space:
mode:
authorSean Young <sean@mess.org>2012-10-24 16:22:42 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-11-21 14:06:17 -0500
commit37b0b4e90d799cddfdd5d0a90ed470933f7e9859 (patch)
tree4c0ed67b3347459203511887f1ba2c83809b9e70 /drivers/media/rc/winbond-cir.c
parentc496e716e0a7e3c486b99edbab5a6db7649824b1 (diff)
[media] winbond-cir: add carrier detection
The winbond hardware has a counter for leading edges, which increases as they are received. As we read raw IR from a fifo in an interrupt handler, we cannot correlate them to specific IR pulses so we simply count all pulses and edges until we go idle and disable the receiver. Signed-off-by: Sean Young <sean@mess.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/rc/winbond-cir.c')
-rw-r--r--drivers/media/rc/winbond-cir.c80
1 files changed, 75 insertions, 5 deletions
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index f040bbfd2100..7f3c476dde05 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -7,6 +7,7 @@
7 * with minor modifications. 7 * with minor modifications.
8 * 8 *
9 * Original Author: David Härdeman <david@hardeman.nu> 9 * Original Author: David Härdeman <david@hardeman.nu>
10 * Copyright (C) 2012 Sean Young <sean@mess.org>
10 * Copyright (C) 2009 - 2011 David Härdeman <david@hardeman.nu> 11 * Copyright (C) 2009 - 2011 David Härdeman <david@hardeman.nu>
11 * 12 *
12 * Dedicated to my daughter Matilda, without whose loving attention this 13 * Dedicated to my daughter Matilda, without whose loving attention this
@@ -22,9 +23,7 @@
22 * o IR Receive 23 * o IR Receive
23 * o IR Transmit 24 * o IR Transmit
24 * o Wake-On-CIR functionality 25 * o Wake-On-CIR functionality
25 * 26 * o Carrier detection
26 * To do:
27 * o Learning
28 * 27 *
29 * This program is free software; you can redistribute it and/or modify 28 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by 29 * it under the terms of the GNU General Public License as published by
@@ -149,6 +148,12 @@
149#define WBCIR_REGSEL_MASK 0x20 148#define WBCIR_REGSEL_MASK 0x20
150/* Starting address of selected register in WBCIR_REG_WCEIR_INDEX */ 149/* Starting address of selected register in WBCIR_REG_WCEIR_INDEX */
151#define WBCIR_REG_ADDR0 0x00 150#define WBCIR_REG_ADDR0 0x00
151/* Enable carrier counter */
152#define WBCIR_CNTR_EN 0x01
153/* Reset carrier counter */
154#define WBCIR_CNTR_R 0x02
155/* Invert TX */
156#define WBCIR_IRTX_INV 0x04
152 157
153/* Valid banks for the SP3 UART */ 158/* Valid banks for the SP3 UART */
154enum wbcir_bank { 159enum wbcir_bank {
@@ -207,6 +212,8 @@ struct wbcir_data {
207 /* RX state */ 212 /* RX state */
208 enum wbcir_rxstate rxstate; 213 enum wbcir_rxstate rxstate;
209 struct led_trigger *rxtrigger; 214 struct led_trigger *rxtrigger;
215 int carrier_report_enabled;
216 u32 pulse_duration;
210 217
211 /* TX state */ 218 /* TX state */
212 enum wbcir_txstate txstate; 219 enum wbcir_txstate txstate;
@@ -329,6 +336,30 @@ wbcir_to_rc6cells(u8 val)
329 *****************************************************************************/ 336 *****************************************************************************/
330 337
331static void 338static void
339wbcir_carrier_report(struct wbcir_data *data)
340{
341 unsigned counter = inb(data->ebase + WBCIR_REG_ECEIR_CNT_LO) |
342 inb(data->ebase + WBCIR_REG_ECEIR_CNT_HI) << 8;
343
344 if (counter > 0 && counter < 0xffff) {
345 DEFINE_IR_RAW_EVENT(ev);
346
347 ev.carrier_report = 1;
348 ev.carrier = DIV_ROUND_CLOSEST(counter * 1000000u,
349 data->pulse_duration);
350
351 ir_raw_event_store(data->dev, &ev);
352 }
353
354 /* reset and restart the counter */
355 data->pulse_duration = 0;
356 wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_R,
357 WBCIR_CNTR_EN | WBCIR_CNTR_R);
358 wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_EN,
359 WBCIR_CNTR_EN | WBCIR_CNTR_R);
360}
361
362static void
332wbcir_idle_rx(struct rc_dev *dev, bool idle) 363wbcir_idle_rx(struct rc_dev *dev, bool idle)
333{ 364{
334 struct wbcir_data *data = dev->priv; 365 struct wbcir_data *data = dev->priv;
@@ -341,6 +372,10 @@ wbcir_idle_rx(struct rc_dev *dev, bool idle)
341 if (idle && data->rxstate != WBCIR_RXSTATE_INACTIVE) { 372 if (idle && data->rxstate != WBCIR_RXSTATE_INACTIVE) {
342 data->rxstate = WBCIR_RXSTATE_INACTIVE; 373 data->rxstate = WBCIR_RXSTATE_INACTIVE;
343 led_trigger_event(data->rxtrigger, LED_OFF); 374 led_trigger_event(data->rxtrigger, LED_OFF);
375
376 if (data->carrier_report_enabled)
377 wbcir_carrier_report(data);
378
344 /* Tell hardware to go idle by setting RXINACTIVE */ 379 /* Tell hardware to go idle by setting RXINACTIVE */
345 outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR); 380 outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR);
346 } 381 }
@@ -351,14 +386,21 @@ wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
351{ 386{
352 u8 irdata; 387 u8 irdata;
353 DEFINE_IR_RAW_EVENT(rawir); 388 DEFINE_IR_RAW_EVENT(rawir);
389 unsigned duration;
354 390
355 /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */ 391 /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
356 while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL) { 392 while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL) {
357 irdata = inb(data->sbase + WBCIR_REG_SP3_RXDATA); 393 irdata = inb(data->sbase + WBCIR_REG_SP3_RXDATA);
358 if (data->rxstate == WBCIR_RXSTATE_ERROR) 394 if (data->rxstate == WBCIR_RXSTATE_ERROR)
359 continue; 395 continue;
396
397 duration = ((irdata & 0x7F) + 1) * 2;
360 rawir.pulse = irdata & 0x80 ? false : true; 398 rawir.pulse = irdata & 0x80 ? false : true;
361 rawir.duration = US_TO_NS(((irdata & 0x7F) + 1) * 2); 399 rawir.duration = US_TO_NS(duration);
400
401 if (rawir.pulse)
402 data->pulse_duration += duration;
403
362 ir_raw_event_store_with_filter(data->dev, &rawir); 404 ir_raw_event_store_with_filter(data->dev, &rawir);
363 } 405 }
364 406
@@ -488,6 +530,33 @@ wbcir_irq_handler(int irqno, void *cookie)
488 *****************************************************************************/ 530 *****************************************************************************/
489 531
490static int 532static int
533wbcir_set_carrier_report(struct rc_dev *dev, int enable)
534{
535 struct wbcir_data *data = dev->priv;
536 unsigned long flags;
537
538 spin_lock_irqsave(&data->spinlock, flags);
539
540 if (data->carrier_report_enabled == enable) {
541 spin_unlock_irqrestore(&data->spinlock, flags);
542 return 0;
543 }
544
545 data->pulse_duration = 0;
546 wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_R,
547 WBCIR_CNTR_EN | WBCIR_CNTR_R);
548
549 if (enable && data->dev->idle)
550 wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL,
551 WBCIR_CNTR_EN, WBCIR_CNTR_EN | WBCIR_CNTR_R);
552
553 data->carrier_report_enabled = enable;
554 spin_unlock_irqrestore(&data->spinlock, flags);
555
556 return 0;
557}
558
559static int
491wbcir_txcarrier(struct rc_dev *dev, u32 carrier) 560wbcir_txcarrier(struct rc_dev *dev, u32 carrier)
492{ 561{
493 struct wbcir_data *data = dev->priv; 562 struct wbcir_data *data = dev->priv;
@@ -833,7 +902,7 @@ wbcir_init_hw(struct wbcir_data *data)
833 902
834 /* Set IRTX_INV */ 903 /* Set IRTX_INV */
835 if (invert) 904 if (invert)
836 outb(0x04, data->ebase + WBCIR_REG_ECEIR_CCTL); 905 outb(WBCIR_IRTX_INV, data->ebase + WBCIR_REG_ECEIR_CCTL);
837 else 906 else
838 outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL); 907 outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL);
839 908
@@ -1014,6 +1083,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
1014 data->dev->input_id.version = WBCIR_ID_CHIP; 1083 data->dev->input_id.version = WBCIR_ID_CHIP;
1015 data->dev->map_name = RC_MAP_RC6_MCE; 1084 data->dev->map_name = RC_MAP_RC6_MCE;
1016 data->dev->s_idle = wbcir_idle_rx; 1085 data->dev->s_idle = wbcir_idle_rx;
1086 data->dev->s_carrier_report = wbcir_set_carrier_report;
1017 data->dev->s_tx_mask = wbcir_txmask; 1087 data->dev->s_tx_mask = wbcir_txmask;
1018 data->dev->s_tx_carrier = wbcir_txcarrier; 1088 data->dev->s_tx_carrier = wbcir_txcarrier;
1019 data->dev->tx_ir = wbcir_tx; 1089 data->dev->tx_ir = wbcir_tx;