aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/rc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/Kconfig2
-rw-r--r--drivers/media/rc/Makefile1
-rw-r--r--drivers/media/rc/img-ir/Kconfig1
-rw-r--r--drivers/media/rc/ir_toy.c1
-rw-r--r--drivers/media/rc/keymaps/Makefile1
-rw-r--r--drivers/media/rc/keymaps/rc-cec.c28
-rw-r--r--drivers/media/rc/mceusb.c11
-rw-r--r--drivers/media/rc/rc-main.c6
-rw-r--r--drivers/media/rc/sunxi-cir.c169
9 files changed, 126 insertions, 94 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 2c0ee2e5b446..8a4b4040be45 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -92,6 +92,7 @@ config IR_SONY_DECODER
config IR_SANYO_DECODER
tristate "Enable IR raw decoder for the Sanyo protocol"
depends on RC_CORE
+ select BITREVERSE
help
Enable this option if you have an infrared remote control which
@@ -101,6 +102,7 @@ config IR_SANYO_DECODER
config IR_SHARP_DECODER
tristate "Enable IR raw decoder for the Sharp protocol"
depends on RC_CORE
+ select BITREVERSE
help
Enable this option if you have an infrared remote control which
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 5bb2932ab119..ff6a8fc4c38e 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -5,6 +5,7 @@ obj-y += keymaps/
obj-$(CONFIG_RC_CORE) += rc-core.o
rc-core-y := rc-main.o rc-ir-raw.o
rc-core-$(CONFIG_LIRC) += lirc_dev.o
+rc-core-$(CONFIG_MEDIA_CEC_RC) += keymaps/rc-cec.o
rc-core-$(CONFIG_BPF_LIRC_MODE2) += bpf-lirc.o
obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig
index 5c0508f2719f..a80cfcd87a95 100644
--- a/drivers/media/rc/img-ir/Kconfig
+++ b/drivers/media/rc/img-ir/Kconfig
@@ -30,6 +30,7 @@ config IR_IMG_HW
config IR_IMG_NEC
bool "NEC protocol support"
depends on IR_IMG_HW
+ select BITREVERSE
help
Say Y here to enable support for the NEC, extended NEC, and 32-bit
NEC protocols in the ImgTec infrared decoder block.
diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c
index e0242c9b6aeb..3e729a17b35f 100644
--- a/drivers/media/rc/ir_toy.c
+++ b/drivers/media/rc/ir_toy.c
@@ -491,6 +491,7 @@ static void irtoy_disconnect(struct usb_interface *intf)
static const struct usb_device_id irtoy_table[] = {
{ USB_DEVICE_INTERFACE_CLASS(0x04d8, 0xfd08, USB_CLASS_CDC_DATA) },
+ { USB_DEVICE_INTERFACE_CLASS(0x04d8, 0xf58b, USB_CLASS_CDC_DATA) },
{ }
};
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index b252a1d2ebd6..cc6662e1903f 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-behold.o \
rc-behold-columbus.o \
rc-budget-ci-old.o \
- rc-cec.o \
rc-cinergy-1400.o \
rc-cinergy.o \
rc-d680-dmb.o \
diff --git a/drivers/media/rc/keymaps/rc-cec.c b/drivers/media/rc/keymaps/rc-cec.c
index 3e3bd11092b4..068e22aeac8c 100644
--- a/drivers/media/rc/keymaps/rc-cec.c
+++ b/drivers/media/rc/keymaps/rc-cec.c
@@ -1,6 +1,16 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* Keytable for the CEC remote control
*
+ * This keymap is unusual in that it can't be built as a module,
+ * instead it is registered directly in rc-main.c if CONFIG_MEDIA_CEC_RC
+ * is set. This is because it can be called from drm_dp_cec_set_edid() via
+ * cec_register_adapter() in an asynchronous context, and it is not
+ * allowed to use request_module() to load rc-cec.ko in that case.
+ *
+ * Since this keymap is only used if CONFIG_MEDIA_CEC_RC is set, we
+ * just compile this keymap into the rc-core module and never as a
+ * separate module.
+ *
* Copyright (c) 2015 by Kamil Debski
*/
@@ -152,7 +162,7 @@ static struct rc_map_table cec[] = {
/* 0x77-0xff: Reserved */
};
-static struct rc_map_list cec_map = {
+struct rc_map_list cec_map = {
.map = {
.scan = cec,
.size = ARRAY_SIZE(cec),
@@ -160,19 +170,3 @@ static struct rc_map_list cec_map = {
.name = RC_MAP_CEC,
}
};
-
-static int __init init_rc_map_cec(void)
-{
- return rc_map_register(&cec_map);
-}
-
-static void __exit exit_rc_map_cec(void)
-{
- rc_map_unregister(&cec_map);
-}
-
-module_init(init_rc_map_cec);
-module_exit(exit_rc_map_cec);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kamil Debski");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index f1dbd059ed08..5642595a057e 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -701,11 +701,18 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
data[0], data[1]);
break;
case MCE_RSP_EQIRCFS:
+ if (!data[0] && !data[1]) {
+ dev_dbg(dev, "%s: no carrier", inout);
+ break;
+ }
+ // prescaler should make sense
+ if (data[0] > 8)
+ break;
period = DIV_ROUND_CLOSEST((1U << data[0] * 2) *
(data[1] + 1), 10);
if (!period)
break;
- carrier = (1000 * 1000) / period;
+ carrier = USEC_PER_SEC / period;
dev_dbg(dev, "%s carrier of %u Hz (period %uus)",
inout, carrier, period);
break;
@@ -1169,7 +1176,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, u8 *buf_in)
switch (subcmd) {
/* the one and only 5-byte return value command */
case MCE_RSP_GETPORTSTATUS:
- if (buf_in[5] == 0)
+ if (buf_in[5] == 0 && *hi < 8)
ir->txports_cabled |= 1 << *hi;
break;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 1fd62c1dac76..8e88dc8ea6c5 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -2069,6 +2069,9 @@ static int __init rc_core_init(void)
led_trigger_register_simple("rc-feedback", &led_feedback);
rc_map_register(&empty_map);
+#ifdef CONFIG_MEDIA_CEC_RC
+ rc_map_register(&cec_map);
+#endif
return 0;
}
@@ -2078,6 +2081,9 @@ static void __exit rc_core_exit(void)
lirc_dev_exit();
class_unregister(&rc_class);
led_trigger_unregister_simple(led_feedback);
+#ifdef CONFIG_MEDIA_CEC_RC
+ rc_map_unregister(&cec_map);
+#endif
rc_map_unregister(&empty_map);
}
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index 8555c7798706..168e1d2c876a 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -86,7 +86,6 @@ struct sunxi_ir_quirks {
};
struct sunxi_ir {
- spinlock_t ir_lock;
struct rc_dev *rc;
void __iomem *base;
int irq;
@@ -105,8 +104,6 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id)
struct sunxi_ir *ir = dev_id;
struct ir_raw_event rawir = {};
- spin_lock(&ir->ir_lock);
-
status = readl(ir->base + SUNXI_IR_RXSTA_REG);
/* clean all pending statuses */
@@ -137,8 +134,6 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id)
ir_raw_event_handle(ir->rc);
}
- spin_unlock(&ir->ir_lock);
-
return IRQ_HANDLED;
}
@@ -160,27 +155,102 @@ static int sunxi_ir_set_timeout(struct rc_dev *rc_dev, unsigned int timeout)
{
struct sunxi_ir *ir = rc_dev->priv;
unsigned int base_clk = clk_get_rate(ir->clk);
- unsigned long flags;
unsigned int ithr = sunxi_usec_to_ithr(base_clk, timeout);
dev_dbg(rc_dev->dev.parent, "setting idle threshold to %u\n", ithr);
- spin_lock_irqsave(&ir->ir_lock, flags);
/* Set noise threshold and idle threshold */
writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE) | REG_CIR_ITHR(ithr),
ir->base + SUNXI_IR_CIR_REG);
- spin_unlock_irqrestore(&ir->ir_lock, flags);
rc_dev->timeout = sunxi_ithr_to_usec(base_clk, ithr);
return 0;
}
+static int sunxi_ir_hw_init(struct device *dev)
+{
+ struct sunxi_ir *ir = dev_get_drvdata(dev);
+ u32 tmp;
+ int ret;
+
+ ret = reset_control_deassert(ir->rst);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(ir->apb_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable apb clk\n");
+ goto exit_assert_reset;
+ }
+
+ ret = clk_prepare_enable(ir->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable ir clk\n");
+ goto exit_disable_apb_clk;
+ }
+
+ /* Enable CIR Mode */
+ writel(REG_CTL_MD, ir->base + SUNXI_IR_CTL_REG);
+
+ /* Set noise threshold and idle threshold */
+ sunxi_ir_set_timeout(ir->rc, ir->rc->timeout);
+
+ /* Invert Input Signal */
+ writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG);
+
+ /* Clear All Rx Interrupt Status */
+ writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
+
+ /*
+ * Enable IRQ on overflow, packet end, FIFO available with trigger
+ * level
+ */
+ writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN |
+ REG_RXINT_RAI_EN | REG_RXINT_RAL(ir->fifo_size / 2 - 1),
+ ir->base + SUNXI_IR_RXINT_REG);
+
+ /* Enable IR Module */
+ tmp = readl(ir->base + SUNXI_IR_CTL_REG);
+ writel(tmp | REG_CTL_GEN | REG_CTL_RXEN, ir->base + SUNXI_IR_CTL_REG);
+
+ return 0;
+
+exit_disable_apb_clk:
+ clk_disable_unprepare(ir->apb_clk);
+exit_assert_reset:
+ reset_control_assert(ir->rst);
+
+ return ret;
+}
+
+static void sunxi_ir_hw_exit(struct device *dev)
+{
+ struct sunxi_ir *ir = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(ir->clk);
+ clk_disable_unprepare(ir->apb_clk);
+ reset_control_assert(ir->rst);
+}
+
+static int __maybe_unused sunxi_ir_suspend(struct device *dev)
+{
+ sunxi_ir_hw_exit(dev);
+
+ return 0;
+}
+
+static int __maybe_unused sunxi_ir_resume(struct device *dev)
+{
+ return sunxi_ir_hw_init(dev);
+}
+
+static SIMPLE_DEV_PM_OPS(sunxi_ir_pm_ops, sunxi_ir_suspend, sunxi_ir_resume);
+
static int sunxi_ir_probe(struct platform_device *pdev)
{
int ret = 0;
- unsigned long tmp = 0;
struct device *dev = &pdev->dev;
struct device_node *dn = dev->of_node;
@@ -199,8 +269,6 @@ static int sunxi_ir_probe(struct platform_device *pdev)
return -ENODEV;
}
- spin_lock_init(&ir->ir_lock);
-
ir->fifo_size = quirks->fifo_size;
/* Clock */
@@ -223,43 +291,26 @@ static int sunxi_ir_probe(struct platform_device *pdev)
ir->rst = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(ir->rst))
return PTR_ERR(ir->rst);
- ret = reset_control_deassert(ir->rst);
- if (ret)
- return ret;
}
ret = clk_set_rate(ir->clk, b_clk_freq);
if (ret) {
dev_err(dev, "set ir base clock failed!\n");
- goto exit_reset_assert;
+ return ret;
}
dev_dbg(dev, "set base clock frequency to %d Hz.\n", b_clk_freq);
- if (clk_prepare_enable(ir->apb_clk)) {
- dev_err(dev, "try to enable apb_ir_clk failed\n");
- ret = -EINVAL;
- goto exit_reset_assert;
- }
-
- if (clk_prepare_enable(ir->clk)) {
- dev_err(dev, "try to enable ir_clk failed\n");
- ret = -EINVAL;
- goto exit_clkdisable_apb_clk;
- }
-
/* IO */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ir->base = devm_ioremap_resource(dev, res);
if (IS_ERR(ir->base)) {
- ret = PTR_ERR(ir->base);
- goto exit_clkdisable_clk;
+ return PTR_ERR(ir->base);
}
ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW);
if (!ir->rc) {
dev_err(dev, "failed to allocate device\n");
- ret = -ENOMEM;
- goto exit_clkdisable_clk;
+ return -ENOMEM;
}
ir->rc->priv = ir;
@@ -275,6 +326,7 @@ static int sunxi_ir_probe(struct platform_device *pdev)
ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
/* Frequency after IR internal divider with sample period in us */
ir->rc->rx_resolution = (USEC_PER_SEC / (b_clk_freq / 64));
+ ir->rc->timeout = IR_DEFAULT_TIMEOUT;
ir->rc->min_timeout = sunxi_ithr_to_usec(b_clk_freq, 0);
ir->rc->max_timeout = sunxi_ithr_to_usec(b_clk_freq, 255);
ir->rc->s_timeout = sunxi_ir_set_timeout;
@@ -301,67 +353,34 @@ static int sunxi_ir_probe(struct platform_device *pdev)
goto exit_free_dev;
}
- /* Enable CIR Mode */
- writel(REG_CTL_MD, ir->base+SUNXI_IR_CTL_REG);
-
- /* Set noise threshold and idle threshold */
- sunxi_ir_set_timeout(ir->rc, IR_DEFAULT_TIMEOUT);
-
- /* Invert Input Signal */
- writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG);
-
- /* Clear All Rx Interrupt Status */
- writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
-
- /*
- * Enable IRQ on overflow, packet end, FIFO available with trigger
- * level
- */
- writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN |
- REG_RXINT_RAI_EN | REG_RXINT_RAL(ir->fifo_size / 2 - 1),
- ir->base + SUNXI_IR_RXINT_REG);
-
- /* Enable IR Module */
- tmp = readl(ir->base + SUNXI_IR_CTL_REG);
- writel(tmp | REG_CTL_GEN | REG_CTL_RXEN, ir->base + SUNXI_IR_CTL_REG);
+ ret = sunxi_ir_hw_init(dev);
+ if (ret)
+ goto exit_free_dev;
dev_info(dev, "initialized sunXi IR driver\n");
return 0;
exit_free_dev:
rc_free_device(ir->rc);
-exit_clkdisable_clk:
- clk_disable_unprepare(ir->clk);
-exit_clkdisable_apb_clk:
- clk_disable_unprepare(ir->apb_clk);
-exit_reset_assert:
- reset_control_assert(ir->rst);
return ret;
}
static int sunxi_ir_remove(struct platform_device *pdev)
{
- unsigned long flags;
struct sunxi_ir *ir = platform_get_drvdata(pdev);
- clk_disable_unprepare(ir->clk);
- clk_disable_unprepare(ir->apb_clk);
- reset_control_assert(ir->rst);
-
- spin_lock_irqsave(&ir->ir_lock, flags);
- /* disable IR IRQ */
- writel(0, ir->base + SUNXI_IR_RXINT_REG);
- /* clear All Rx Interrupt Status */
- writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
- /* disable IR */
- writel(0, ir->base + SUNXI_IR_CTL_REG);
- spin_unlock_irqrestore(&ir->ir_lock, flags);
-
rc_unregister_device(ir->rc);
+ sunxi_ir_hw_exit(&pdev->dev);
+
return 0;
}
+static void sunxi_ir_shutdown(struct platform_device *pdev)
+{
+ sunxi_ir_hw_exit(&pdev->dev);
+}
+
static const struct sunxi_ir_quirks sun4i_a10_ir_quirks = {
.has_reset = false,
.fifo_size = 16,
@@ -397,9 +416,11 @@ MODULE_DEVICE_TABLE(of, sunxi_ir_match);
static struct platform_driver sunxi_ir_driver = {
.probe = sunxi_ir_probe,
.remove = sunxi_ir_remove,
+ .shutdown = sunxi_ir_shutdown,
.driver = {
.name = SUNXI_IR_DEV,
.of_match_table = sunxi_ir_match,
+ .pm = &sunxi_ir_pm_ops,
},
};