[media] rc: sunxi-cir: Add support for an optional reset controller
authorHans de Goede <hdegoede@redhat.com>
Thu, 20 Nov 2014 14:59:04 +0000 (11:59 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Thu, 29 Jan 2015 20:26:08 +0000 (18:26 -0200)
On sun6i the cir block is attached to the reset controller, add support
for de-asserting the reset if a reset controller is specified in dt.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Documentation/devicetree/bindings/media/sunxi-ir.txt
drivers/media/rc/sunxi-cir.c

index 23dd5ad..6b70b9b 100644 (file)
@@ -10,6 +10,7 @@ Required properties:
 
 Optional properties:
 - linux,rc-map-name : Remote control map name.
+- resets : phandle + reset specifier pair
 
 Example:
 
@@ -17,6 +18,7 @@ ir0: ir@01c21800 {
        compatible = "allwinner,sun4i-a10-ir";
        clocks = <&apb0_gates 6>, <&ir0_clk>;
        clock-names = "apb", "ir";
+       resets = <&apb0_rst 1>;
        interrupts = <0 5 1>;
        reg = <0x01C21800 0x40>;
        linux,rc-map-name = "rc-rc6-mce";
index 340f7f5..06170e0 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of_platform.h>
+#include <linux/reset.h>
 #include <media/rc-core.h>
 
 #define SUNXI_IR_DEV "sunxi-ir"
@@ -95,6 +96,7 @@ struct sunxi_ir {
        int             irq;
        struct clk      *clk;
        struct clk      *apb_clk;
+       struct reset_control *rst;
        const char      *map_name;
 };
 
@@ -166,15 +168,29 @@ static int sunxi_ir_probe(struct platform_device *pdev)
                return PTR_ERR(ir->clk);
        }
 
+       /* Reset (optional) */
+       ir->rst = devm_reset_control_get_optional(dev, NULL);
+       if (IS_ERR(ir->rst)) {
+               ret = PTR_ERR(ir->rst);
+               if (ret == -EPROBE_DEFER)
+                       return ret;
+               ir->rst = NULL;
+       } else {
+               ret = reset_control_deassert(ir->rst);
+               if (ret)
+                       return ret;
+       }
+
        ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK);
        if (ret) {
                dev_err(dev, "set ir base clock failed!\n");
-               return ret;
+               goto exit_reset_assert;
        }
 
        if (clk_prepare_enable(ir->apb_clk)) {
                dev_err(dev, "try to enable apb_ir_clk failed\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto exit_reset_assert;
        }
 
        if (clk_prepare_enable(ir->clk)) {
@@ -271,6 +287,9 @@ exit_clkdisable_clk:
        clk_disable_unprepare(ir->clk);
 exit_clkdisable_apb_clk:
        clk_disable_unprepare(ir->apb_clk);
+exit_reset_assert:
+       if (ir->rst)
+               reset_control_assert(ir->rst);
 
        return ret;
 }
@@ -282,6 +301,8 @@ static int sunxi_ir_remove(struct platform_device *pdev)
 
        clk_disable_unprepare(ir->clk);
        clk_disable_unprepare(ir->apb_clk);
+       if (ir->rst)
+               reset_control_assert(ir->rst);
 
        spin_lock_irqsave(&ir->ir_lock, flags);
        /* disable IR IRQ */