aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/rc
diff options
context:
space:
mode:
authorAntti Seppälä <a.seppala@gmail.com>2015-03-31 13:48:12 -0400
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-05-14 13:37:03 -0400
commitda7ee60b03bd66bb10974d7444aa444de6391312 (patch)
treed123bf7671c6878f6724037c0464d87894ae2d07 /drivers/media/rc
parent2e4ebde269236da2a41183522127715b6d9d80ce (diff)
[media] rc: nuvoton-cir: Add support for writing wakeup samples via sysfs filter callback
Nuvoton-cir utilizes the encoding capabilities of rc-core to convert scancodes from user space to pulse/space format understood by the underlying hardware. Converted samples are then written to the wakeup fifo along with other necessary configuration to enable wake up functionality. Signed-off-by: Antti Seppälä <a.seppala@gmail.com> Signed-off-by: James Hogan <james@albanarts.com> Cc: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/nuvoton-cir.c127
-rw-r--r--drivers/media/rc/nuvoton-cir.h1
2 files changed, 128 insertions, 0 deletions
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 85af7a869167..baeb5971fd52 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -526,6 +526,130 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
526 return 0; 526 return 0;
527} 527}
528 528
529static int nvt_write_wakeup_codes(struct rc_dev *dev,
530 const u8 *wakeup_sample_buf, int count)
531{
532 int i = 0;
533 u8 reg, reg_learn_mode;
534 unsigned long flags;
535 struct nvt_dev *nvt = dev->priv;
536
537 nvt_dbg_wake("writing wakeup samples");
538
539 reg = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
540 reg_learn_mode = reg & ~CIR_WAKE_IRCON_MODE0;
541 reg_learn_mode |= CIR_WAKE_IRCON_MODE1;
542
543 /* Lock the learn area to prevent racing with wake-isr */
544 spin_lock_irqsave(&nvt->nvt_lock, flags);
545
546 /* Enable fifo writes */
547 nvt_cir_wake_reg_write(nvt, reg_learn_mode, CIR_WAKE_IRCON);
548
549 /* Clear cir wake rx fifo */
550 nvt_clear_cir_wake_fifo(nvt);
551
552 if (count > WAKE_FIFO_LEN) {
553 nvt_dbg_wake("HW FIFO too small for all wake samples");
554 count = WAKE_FIFO_LEN;
555 }
556
557 if (count)
558 pr_info("Wake samples (%d) =", count);
559 else
560 pr_info("Wake sample fifo cleared");
561
562 /* Write wake samples to fifo */
563 for (i = 0; i < count; i++) {
564 pr_cont(" %02x", wakeup_sample_buf[i]);
565 nvt_cir_wake_reg_write(nvt, wakeup_sample_buf[i],
566 CIR_WAKE_WR_FIFO_DATA);
567 }
568 pr_cont("\n");
569
570 /* Switch cir to wakeup mode and disable fifo writing */
571 nvt_cir_wake_reg_write(nvt, reg, CIR_WAKE_IRCON);
572
573 /* Set number of bytes needed for wake */
574 nvt_cir_wake_reg_write(nvt, count ? count :
575 CIR_WAKE_FIFO_CMP_BYTES,
576 CIR_WAKE_FIFO_CMP_DEEP);
577
578 spin_unlock_irqrestore(&nvt->nvt_lock, flags);
579
580 return 0;
581}
582
583static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev,
584 struct rc_scancode_filter *sc_filter)
585{
586 u8 *reg_buf;
587 u8 buf_val;
588 int i, ret, count;
589 unsigned int val;
590 struct ir_raw_event *raw;
591 bool complete;
592
593 /* Require both mask and data to be set before actually committing */
594 if (!sc_filter->mask || !sc_filter->data)
595 return 0;
596
597 raw = kmalloc_array(WAKE_FIFO_LEN, sizeof(*raw), GFP_KERNEL);
598 if (!raw)
599 return -ENOMEM;
600
601 ret = ir_raw_encode_scancode(dev->enabled_wakeup_protocols, sc_filter,
602 raw, WAKE_FIFO_LEN);
603 complete = (ret != -ENOBUFS);
604 if (!complete)
605 ret = WAKE_FIFO_LEN;
606 else if (ret < 0)
607 goto out_raw;
608
609 reg_buf = kmalloc_array(WAKE_FIFO_LEN, sizeof(*reg_buf), GFP_KERNEL);
610 if (!reg_buf) {
611 ret = -ENOMEM;
612 goto out_raw;
613 }
614
615 /* Inspect the ir samples */
616 for (i = 0, count = 0; i < ret && count < WAKE_FIFO_LEN; ++i) {
617 val = NS_TO_US((raw[i]).duration) / SAMPLE_PERIOD;
618
619 /* Split too large values into several smaller ones */
620 while (val > 0 && count < WAKE_FIFO_LEN) {
621
622 /* Skip last value for better comparison tolerance */
623 if (complete && i == ret - 1 && val < BUF_LEN_MASK)
624 break;
625
626 /* Clamp values to BUF_LEN_MASK at most */
627 buf_val = (val > BUF_LEN_MASK) ? BUF_LEN_MASK : val;
628
629 reg_buf[count] = buf_val;
630 val -= buf_val;
631 if ((raw[i]).pulse)
632 reg_buf[count] |= BUF_PULSE_BIT;
633 count++;
634 }
635 }
636
637 ret = nvt_write_wakeup_codes(dev, reg_buf, count);
638
639 kfree(reg_buf);
640out_raw:
641 kfree(raw);
642
643 return ret;
644}
645
646/* Dummy implementation. nuvoton is agnostic to the protocol used */
647static int nvt_ir_raw_change_wakeup_protocol(struct rc_dev *dev,
648 u64 *rc_type)
649{
650 return 0;
651}
652
529/* 653/*
530 * nvt_tx_ir 654 * nvt_tx_ir
531 * 655 *
@@ -1043,11 +1167,14 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
1043 /* Set up the rc device */ 1167 /* Set up the rc device */
1044 rdev->priv = nvt; 1168 rdev->priv = nvt;
1045 rdev->driver_type = RC_DRIVER_IR_RAW; 1169 rdev->driver_type = RC_DRIVER_IR_RAW;
1170 rdev->encode_wakeup = true;
1046 rdev->allowed_protocols = RC_BIT_ALL; 1171 rdev->allowed_protocols = RC_BIT_ALL;
1047 rdev->open = nvt_open; 1172 rdev->open = nvt_open;
1048 rdev->close = nvt_close; 1173 rdev->close = nvt_close;
1049 rdev->tx_ir = nvt_tx_ir; 1174 rdev->tx_ir = nvt_tx_ir;
1050 rdev->s_tx_carrier = nvt_set_tx_carrier; 1175 rdev->s_tx_carrier = nvt_set_tx_carrier;
1176 rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter;
1177 rdev->change_wakeup_protocol = nvt_ir_raw_change_wakeup_protocol;
1051 rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; 1178 rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
1052 rdev->input_phys = "nuvoton/cir0"; 1179 rdev->input_phys = "nuvoton/cir0";
1053 rdev->input_id.bustype = BUS_HOST; 1180 rdev->input_id.bustype = BUS_HOST;
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index e1cf23c3875b..9d0e161c2a88 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -63,6 +63,7 @@ static int debug;
63 */ 63 */
64#define TX_BUF_LEN 256 64#define TX_BUF_LEN 256
65#define RX_BUF_LEN 32 65#define RX_BUF_LEN 32
66#define WAKE_FIFO_LEN 67
66 67
67struct nvt_dev { 68struct nvt_dev {
68 struct pnp_dev *pdev; 69 struct pnp_dev *pdev;