23105057a9f92571a690b172c44cb573be560f44
[openwrt/openwrt.git] / target / linux / bcm27xx / patches-5.4 / 950-0538-clk-bcm-Add-BCM2711-DVP-driver.patch
1 From 0a2b9668e391b5fef4c54f992d7f8f99e5f50ef3 Mon Sep 17 00:00:00 2001
2 From: Maxime Ripard <maxime@cerno.tech>
3 Date: Tue, 28 Jan 2020 09:36:27 +0100
4 Subject: [PATCH] clk: bcm: Add BCM2711 DVP driver
5
6 The HDMI block has a block that controls clocks and reset signals to the
7 HDMI0 and HDMI1 controllers.
8
9 Let's expose that through a clock driver implementing a clock and reset
10 provider.
11
12 Cc: Michael Turquette <mturquette@baylibre.com>
13 Cc: Stephen Boyd <sboyd@kernel.org>
14 Cc: Rob Herring <robh+dt@kernel.org>
15 Cc: linux-clk@vger.kernel.org
16 Cc: devicetree@vger.kernel.org
17 Signed-off-by: Maxime Ripard <maxime@cerno.tech>
18 ---
19 drivers/clk/bcm/Kconfig | 1 +
20 drivers/clk/bcm/Makefile | 1 +
21 drivers/clk/bcm/clk-bcm2711-dvp.c | 125 ++++++++++++++++++++++++++++++
22 3 files changed, 127 insertions(+)
23 create mode 100644 drivers/clk/bcm/clk-bcm2711-dvp.c
24
25 --- a/drivers/clk/bcm/Kconfig
26 +++ b/drivers/clk/bcm/Kconfig
27 @@ -4,6 +4,7 @@ config CLK_BCM2835
28 depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
29 depends on COMMON_CLK
30 default ARCH_BCM2835 || ARCH_BRCMSTB
31 + select RESET_SIMPLE
32 help
33 Enable common clock framework support for Broadcom BCM2835
34 SoCs.
35 --- a/drivers/clk/bcm/Makefile
36 +++ b/drivers/clk/bcm/Makefile
37 @@ -6,6 +6,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-s
38 obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
39 obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
40 obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
41 +obj-$(CONFIG_CLK_BCM2835) += clk-bcm2711-dvp.o
42 obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835.o
43 obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835-aux.o
44 obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o
45 --- /dev/null
46 +++ b/drivers/clk/bcm/clk-bcm2711-dvp.c
47 @@ -0,0 +1,125 @@
48 +// SPDX-License-Identifier: GPL-2.0-or-later
49 +// Copyright 2020 Cerno
50 +
51 +#include <linux/clk-provider.h>
52 +#include <linux/module.h>
53 +#include <linux/platform_device.h>
54 +#include <linux/reset-controller.h>
55 +#include <linux/reset/reset-simple.h>
56 +
57 +#define DVP_HT_RPI_SW_INIT 0x04
58 +#define DVP_HT_RPI_MISC_CONFIG 0x08
59 +
60 +#define NR_CLOCKS 2
61 +#define NR_RESETS 6
62 +
63 +struct clk_dvp {
64 + struct clk_hw_onecell_data *data;
65 + struct reset_simple_data reset;
66 +};
67 +
68 +static int clk_dvp_probe(struct platform_device *pdev)
69 +{
70 + struct clk_hw_onecell_data *data;
71 + struct resource *res;
72 + struct clk_dvp *dvp;
73 + void __iomem *base;
74 + const char *parent;
75 + int ret;
76 +
77 + dvp = devm_kzalloc(&pdev->dev, sizeof(*dvp), GFP_KERNEL);
78 + if (!dvp)
79 + return -ENOMEM;
80 + platform_set_drvdata(pdev, dvp);
81 +
82 + dvp->data = devm_kzalloc(&pdev->dev,
83 + struct_size(dvp->data, hws, NR_CLOCKS),
84 + GFP_KERNEL);
85 + if (!dvp->data)
86 + return -ENOMEM;
87 + data = dvp->data;
88 +
89 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
90 + base = devm_ioremap_resource(&pdev->dev, res);
91 + if (IS_ERR(base))
92 + return PTR_ERR(base);
93 +
94 + dvp->reset.rcdev.owner = THIS_MODULE;
95 + dvp->reset.rcdev.nr_resets = NR_RESETS;
96 + dvp->reset.rcdev.ops = &reset_simple_ops;
97 + dvp->reset.rcdev.of_node = pdev->dev.of_node;
98 + dvp->reset.membase = base + DVP_HT_RPI_SW_INIT;
99 + spin_lock_init(&dvp->reset.lock);
100 +
101 + ret = reset_controller_register(&dvp->reset.rcdev);
102 + if (ret)
103 + return ret;
104 +
105 + parent = of_clk_get_parent_name(pdev->dev.of_node, 0);
106 + if (!parent)
107 + goto unregister_reset;
108 +
109 + data->hws[0] = clk_hw_register_gate(&pdev->dev, "hdmi0-108MHz",
110 + parent, 0,
111 + base + DVP_HT_RPI_MISC_CONFIG, 3,
112 + CLK_GATE_SET_TO_DISABLE, &dvp->reset.lock);
113 + if (IS_ERR(data->hws[0])) {
114 + ret = PTR_ERR(data->hws[0]);
115 + goto unregister_reset;
116 + }
117 +
118 + data->hws[1] = clk_hw_register_gate(&pdev->dev, "hdmi1-108MHz",
119 + parent, 0,
120 + base + DVP_HT_RPI_MISC_CONFIG, 4,
121 + CLK_GATE_SET_TO_DISABLE, &dvp->reset.lock);
122 + if (IS_ERR(data->hws[1])) {
123 + ret = PTR_ERR(data->hws[1]);
124 + goto unregister_clk0;
125 + }
126 +
127 + data->num = NR_CLOCKS;
128 + ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
129 + data);
130 + if (ret)
131 + goto unregister_clk1;
132 +
133 + return 0;
134 +
135 +
136 +unregister_clk1:
137 + clk_hw_unregister_gate(data->hws[1]);
138 +
139 +unregister_clk0:
140 + clk_hw_unregister_gate(data->hws[0]);
141 +
142 +unregister_reset:
143 + reset_controller_unregister(&dvp->reset.rcdev);
144 + return ret;
145 +};
146 +
147 +static int clk_dvp_remove(struct platform_device *pdev)
148 +{
149 + struct clk_dvp *dvp = platform_get_drvdata(pdev);
150 + struct clk_hw_onecell_data *data = dvp->data;
151 +
152 + clk_hw_unregister_gate(data->hws[1]);
153 + clk_hw_unregister_gate(data->hws[0]);
154 + reset_controller_unregister(&dvp->reset.rcdev);
155 +
156 + return 0;
157 +}
158 +
159 +static const struct of_device_id clk_dvp_dt_ids[] = {
160 + { .compatible = "brcm,brcm2711-dvp", },
161 + { /* sentinel */ }
162 +};
163 +
164 +static struct platform_driver clk_dvp_driver = {
165 + .probe = clk_dvp_probe,
166 + .remove = clk_dvp_remove,
167 + .driver = {
168 + .name = "brcm2711-dvp",
169 + .of_match_table = clk_dvp_dt_ids,
170 + },
171 +};
172 +module_platform_driver(clk_dvp_driver);