224 lines
6.0 KiB
Diff
224 lines
6.0 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Holland <samuel@sholland.org>
|
|
Date: Sun, 10 Jan 2021 00:50:32 -0600
|
|
Subject: [PATCH] media: sunxi-cir: Factor out hardware initialization
|
|
|
|
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
|
---
|
|
drivers/media/rc/sunxi-cir.c | 142 ++++++++++++++++++++---------------
|
|
1 file changed, 82 insertions(+), 60 deletions(-)
|
|
|
|
--- a/drivers/media/rc/sunxi-cir.c
|
|
+++ b/drivers/media/rc/sunxi-cir.c
|
|
@@ -90,6 +90,7 @@ struct sunxi_ir {
|
|
void __iomem *base;
|
|
int irq;
|
|
int fifo_size;
|
|
+ u32 base_clk_freq;
|
|
struct clk *clk;
|
|
struct clk *apb_clk;
|
|
struct reset_control *rst;
|
|
@@ -169,10 +170,81 @@ static int sunxi_ir_set_timeout(struct r
|
|
return 0;
|
|
}
|
|
|
|
+static int sunxi_ir_hw_init(struct device *dev)
|
|
+{
|
|
+ struct sunxi_ir *ir = dev_get_drvdata(dev);
|
|
+ unsigned long tmp;
|
|
+ int ret;
|
|
+
|
|
+ ret = reset_control_deassert(ir->rst);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = clk_set_rate(ir->clk, ir->base_clk_freq);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "set ir base clock failed!\n");
|
|
+ goto exit_reset_assert;
|
|
+ }
|
|
+ dev_dbg(dev, "set base clock frequency to %d Hz.\n", ir->base_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_apb_clk_disable;
|
|
+ }
|
|
+
|
|
+ /* 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_apb_clk_disable:
|
|
+ clk_disable_unprepare(ir->apb_clk);
|
|
+exit_reset_assert:
|
|
+ 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 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;
|
|
@@ -207,49 +279,26 @@ static int sunxi_ir_probe(struct platfor
|
|
|
|
/* Base clock frequency (optional) */
|
|
of_property_read_u32(dn, "clock-frequency", &b_clk_freq);
|
|
+ ir->base_clk_freq = b_clk_freq;
|
|
|
|
/* Reset */
|
|
if (quirks->has_reset) {
|
|
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;
|
|
- }
|
|
- 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;
|
|
@@ -265,6 +314,7 @@ static int sunxi_ir_probe(struct platfor
|
|
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;
|
|
@@ -291,41 +341,15 @@ static int sunxi_ir_probe(struct platfor
|
|
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;
|
|
}
|
|
@@ -334,11 +358,9 @@ static int sunxi_ir_remove(struct platfo
|
|
{
|
|
struct sunxi_ir *ir = platform_get_drvdata(pdev);
|
|
|
|
- clk_disable_unprepare(ir->clk);
|
|
- clk_disable_unprepare(ir->apb_clk);
|
|
- reset_control_assert(ir->rst);
|
|
-
|
|
+ sunxi_ir_hw_exit(&pdev->dev);
|
|
rc_unregister_device(ir->rc);
|
|
+
|
|
return 0;
|
|
}
|
|
|