diff options
author | Antti Seppälä <a.seppala@gmail.com> | 2015-03-31 13:48:12 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-05-14 13:37:03 -0400 |
commit | da7ee60b03bd66bb10974d7444aa444de6391312 (patch) | |
tree | d123bf7671c6878f6724037c0464d87894ae2d07 /drivers/media/rc | |
parent | 2e4ebde269236da2a41183522127715b6d9d80ce (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.c | 127 | ||||
-rw-r--r-- | drivers/media/rc/nuvoton-cir.h | 1 |
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 | ||
529 | static 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 | |||
583 | static 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); | ||
640 | out_raw: | ||
641 | kfree(raw); | ||
642 | |||
643 | return ret; | ||
644 | } | ||
645 | |||
646 | /* Dummy implementation. nuvoton is agnostic to the protocol used */ | ||
647 | static 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 | ||
67 | struct nvt_dev { | 68 | struct nvt_dev { |
68 | struct pnp_dev *pdev; | 69 | struct pnp_dev *pdev; |