clk:starfive:isp:Add runtime and system pm control
[platform/kernel/linux-starfive.git] / drivers / clk / starfive / clk-starfive-jh7110-isp.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * StarFive JH7110 Isp Clock Driver
4  *
5  * Copyright (C) 2022 Xingyu Wu <xingyu.wu@starfivetech.com>
6  */
7
8 #include <linux/bits.h>
9 #include <linux/clk.h>
10 #include <linux/clk-provider.h>
11 #include <linux/debugfs.h>
12 #include <linux/device.h>
13 #include <linux/init.h>
14 #include <linux/io.h>
15 #include <linux/kernel.h>
16 #include <linux/mod_devicetable.h>
17 #include <linux/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/of_device.h>
20 #include <linux/reset.h>
21 #include <linux/reset-controller.h>
22 #include <dt-bindings/clock/starfive-jh7110-isp.h>
23 #include <linux/pm_runtime.h>
24
25 #include "clk-starfive-jh7110.h"
26
27 /* external clocks */
28 #define JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN    (JH7110_CLK_ISP_END + 0)
29 #define JH7110_ISP_TOP_CLK_ISP_AXI_CLKGEN       (JH7110_CLK_ISP_END + 1)
30 #define JH7110_ISP_TOP_CLK_BIST_APB_CLKGEN      (JH7110_CLK_ISP_END + 2)
31 #define JH7110_ISP_TOP_CLK_DVP_CLKGEN           (JH7110_CLK_ISP_END + 3)
32
33 struct isp_init_crg {
34         int num_clks;
35         struct clk_bulk_data *clks;
36         struct reset_control *rsts;
37 };
38
39 static const struct jh7110_clk_data jh7110_clk_isp_data[] __initconst = {
40         //syscon
41         JH7110__DIV(JH7110_DOM4_APB_FUNC, "dom4_apb_func",
42                         15, JH7110_ISP_TOP_CLK_ISP_AXI_CLKGEN),
43         //crg
44         JH7110__DIV(JH7110_MIPI_RX0_PXL, "mipi_rx0_pxl",
45                         8, JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN),
46         JH7110__INV(JH7110_DVP_INV, "dvp_inv", JH7110_ISP_TOP_CLK_DVP_CLKGEN),
47         //vin
48         JH7110__DIV(JH7110_U0_M31DPHY_CFGCLK_IN, "u0_m31dphy_cfgclk_in",
49                         16, JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN),
50         JH7110__DIV(JH7110_U0_M31DPHY_REFCLK_IN, "u0_m31dphy_refclk_in",
51                         16, JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN),
52         JH7110__DIV(JH7110_U0_M31DPHY_TXCLKESC_LAN0, "u0_m31dphy_txclkesc_lan0",
53                         60, JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN),
54         JH7110_GATE(JH7110_U0_VIN_PCLK, "u0_vin_pclk",
55                         CLK_IGNORE_UNUSED, JH7110_DOM4_APB),
56         JH7110__DIV(JH7110_U0_VIN_SYS_CLK, "u0_vin_sys_clk",
57                         8, JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN),
58         JH7110_GATE(JH7110_U0_VIN_PIXEL_CLK_IF0, "u0_vin_pixel_clk_if0",
59                         CLK_IGNORE_UNUSED, JH7110_MIPI_RX0_PXL),
60         JH7110_GATE(JH7110_U0_VIN_PIXEL_CLK_IF1, "u0_vin_pixel_clk_if1",
61                         CLK_IGNORE_UNUSED, JH7110_MIPI_RX0_PXL),
62         JH7110_GATE(JH7110_U0_VIN_PIXEL_CLK_IF2, "u0_vin_pixel_clk_if2",
63                         CLK_IGNORE_UNUSED, JH7110_MIPI_RX0_PXL),
64         JH7110_GATE(JH7110_U0_VIN_PIXEL_CLK_IF3, "u0_vin_pixel_clk_if3",
65                         CLK_IGNORE_UNUSED, JH7110_MIPI_RX0_PXL),
66         JH7110__MUX(JH7110_U0_VIN_CLK_P_AXIWR, "u0_vin_clk_p_axiwr",
67                         PARENT_NUMS_2,
68                         JH7110_MIPI_RX0_PXL,
69                         JH7110_DVP_INV),
70         //ispv2_top_wrapper
71         JH7110_GMUX(JH7110_U0_ISPV2_TOP_WRAPPER_CLK_C,
72                         "u0_ispv2_top_wrapper_clk_c",
73                         CLK_IGNORE_UNUSED, PARENT_NUMS_2,
74                         JH7110_MIPI_RX0_PXL,
75                         JH7110_DVP_INV),
76 };
77
78 static struct clk_bulk_data isp_top_clks[] = {
79         { .id = "u0_dom_isp_top_clk_dom_isp_top_clk_ispcore_2x" },
80         { .id = "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi" },
81 };
82
83 static int jh7110_isp_crg_get(struct device *dev, struct isp_init_crg *crg)
84 {
85         int ret;
86
87         crg->rsts = devm_reset_control_array_get_shared(dev);
88         if (IS_ERR(crg->rsts)) {
89                 dev_err(dev, "rst get failed\n");
90                 return PTR_ERR(crg->rsts);
91         }
92
93         crg->clks = isp_top_clks;
94         crg->num_clks = ARRAY_SIZE(isp_top_clks);
95         ret = clk_bulk_get(dev, crg->num_clks, crg->clks);
96         if (ret) {
97                 dev_err(dev, "clks get failed: %d\n", ret);
98                 goto clks_get_failed;
99         }
100
101         return 0;
102
103 clks_get_failed:
104         reset_control_assert(crg->rsts);
105         reset_control_put(crg->rsts);
106
107         return ret;
108 }
109
110 static int jh7110_isp_crg_enable(struct device *dev, struct isp_init_crg *crg, bool enable)
111 {
112         int ret;
113
114         dev_dbg(dev, "starfive jh7110 isp clk&rst %sable\n", enable ? "en":"dis");
115         if (enable) {
116                 ret = reset_control_deassert(crg->rsts);
117                 if (ret) {
118                         dev_err(dev, "rst deassert failed: %d\n", ret);
119                         goto crg_failed;
120                 }
121
122                 ret = clk_bulk_prepare_enable(crg->num_clks, crg->clks);
123                 if (ret) {
124                         dev_err(dev, "clks enable failed: %d\n", ret);
125                         goto crg_failed;
126                 }
127         } else {
128                 clk_bulk_disable_unprepare(crg->num_clks, crg->clks);
129         }
130
131         return 0;
132 crg_failed:
133         return ret;
134 }
135
136 #ifdef CONFIG_PM_SLEEP
137 static int clk_isp_system_suspend(struct device *dev)
138 {
139         return pm_runtime_force_suspend(dev);
140 }
141
142 static int clk_isp_system_resume(struct device *dev)
143 {
144         return pm_runtime_force_resume(dev);
145 }
146 #endif
147
148 #ifdef CONFIG_PM
149 static int clk_isp_runtime_suspend(struct device *dev)
150 {
151         struct isp_init_crg *crg = dev_get_drvdata(dev);
152
153         return jh7110_isp_crg_enable(dev, crg, false);
154 }
155
156 static int clk_isp_runtime_resume(struct device *dev)
157 {
158         struct isp_init_crg *crg = dev_get_drvdata(dev);
159
160         return jh7110_isp_crg_enable(dev, crg, true);
161 }
162 #endif
163
164 static const struct dev_pm_ops clk_isp_pm_ops = {
165         SET_RUNTIME_PM_OPS(clk_isp_runtime_suspend, clk_isp_runtime_resume, NULL)
166         SET_LATE_SYSTEM_SLEEP_PM_OPS(clk_isp_system_suspend, clk_isp_system_resume)
167 };
168
169 static struct clk_hw *jh7110_isp_clk_get(struct of_phandle_args *clkspec,
170                                         void *data)
171 {
172         struct jh7110_clk_priv *priv = data;
173         unsigned int idx = clkspec->args[0];
174
175         if (idx < JH7110_CLK_ISP_REG_END)
176                 return &priv->reg[idx].hw;
177
178         if (idx < JH7110_CLK_ISP_END)
179                 return priv->pll[PLL_OFI(idx)];
180
181         return ERR_PTR(-EINVAL);
182 }
183
184 static int __init clk_starfive_jh7110_isp_probe(struct platform_device *pdev)
185 {
186         struct jh7110_clk_priv *priv;
187         struct isp_init_crg *crg;
188         unsigned int idx;
189         int ret = 0;
190
191         priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg,
192                                 JH7110_CLK_ISP_END), GFP_KERNEL);
193         if (!priv)
194                 return -ENOMEM;
195
196         spin_lock_init(&priv->rmw_lock);
197         priv->dev = &pdev->dev;
198         priv->isp_base = devm_platform_ioremap_resource(pdev, 0);
199         if (IS_ERR(priv->isp_base))
200                 return PTR_ERR(priv->isp_base);
201
202         crg = devm_kzalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
203         if (!crg)
204                 return -ENOMEM;
205         dev_set_drvdata(&pdev->dev, crg);
206
207         ret = jh7110_isp_crg_get(&pdev->dev, crg);
208         if (ret)
209                 goto init_failed;
210
211         pm_runtime_use_autosuspend(&pdev->dev);
212         pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
213         pm_runtime_enable(&pdev->dev);
214         ret = pm_runtime_get_sync(&pdev->dev);
215         if (ret < 0) {
216                 dev_err(&pdev->dev, "failed to get pm runtime: %d\n", ret);
217                 goto init_failed;
218         }
219
220         priv->pll[PLL_OFI(JH7110_U3_PCLK_MUX_FUNC_PCLK)] =
221                         devm_clk_hw_register_fixed_factor(
222                         priv->dev, "u3_pclk_mux_func_pclk",
223                         "dom4_apb_func", 0, 1, 1);
224         priv->pll[PLL_OFI(JH7110_U3_PCLK_MUX_BIST_PCLK)] =
225                         devm_clk_hw_register_fixed_factor(
226                         priv->dev, "u3_pclk_mux_bist_pclk",
227                         "u0_dom_isp_top_clk_dom_isp_top_clk_bist_apb", 0, 1, 1);
228         priv->pll[PLL_OFI(JH7110_DOM4_APB)] =
229                         devm_clk_hw_register_fixed_factor(priv->dev, "dom4_apb",
230                         "u3_pclk_mux_pclk", 0, 1, 1);
231         //vin
232         priv->pll[PLL_OFI(JH7110_U0_VIN_PCLK_FREE)] =
233                         devm_clk_hw_register_fixed_factor(
234                         priv->dev, "u0_vin_pclk_free",
235                         "dom4_apb", 0, 1, 1);
236         priv->pll[PLL_OFI(JH7110_U0_VIN_CLK_P_AXIRD)] =
237                         devm_clk_hw_register_fixed_factor(
238                         priv->dev, "u0_vin_clk_p_axird",
239                         "mipi_rx0_pxl", 0, 1, 1);
240         priv->pll[PLL_OFI(JH7110_U0_VIN_ACLK)] =
241                         devm_clk_hw_register_fixed_factor(
242                         priv->dev, "u0_vin_ACLK",
243                         "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi", 0, 1, 1);
244         priv->pll[PLL_OFI(JH7110_U0_ISPV2_TOP_WRAPPER_CLK_ISP_AXI_IN)] =
245                         devm_clk_hw_register_fixed_factor(priv->dev,
246                         "u0_ispv2_top_wrapper_clk_isp_axi_in",
247                         "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi", 0, 1, 1);
248         priv->pll[PLL_OFI(JH7110_U0_ISPV2_TOP_WRAPPER_CLK_ISP_X2)] =
249                         devm_clk_hw_register_fixed_factor(priv->dev,
250                         "u0_ispv2_top_wrapper_clk_isp_x2",
251                         "u0_dom_isp_top_clk_dom_isp_top_clk_ispcore_2x",
252                         0, 1, 1);
253         //wrapper
254         priv->pll[PLL_OFI(JH7110_U0_ISPV2_TOP_WRAPPER_CLK_ISP)] =
255                         devm_clk_hw_register_fixed_factor(priv->dev,
256                         "u0_ispv2_top_wrapper_clk_isp",
257                         "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi", 0, 1, 1);
258         priv->pll[PLL_OFI(JH7110_U0_ISPV2_TOP_WRAPPER_CLK_P)] =
259                         devm_clk_hw_register_fixed_factor(priv->dev,
260                         "u0_ispv2_top_wrapper_clk_p",
261                         "mipi_rx0_pxl", 0, 1, 1);
262         priv->pll[PLL_OFI(JH7110_U0_CRG_PCLK)] =
263                         devm_clk_hw_register_fixed_factor(priv->dev,
264                         "u0_crg_pclk", "dom4_apb", 0, 1, 1);
265         priv->pll[PLL_OFI(JH7110_U0_SYSCON_PCLK)] =
266                         devm_clk_hw_register_fixed_factor(priv->dev,
267                         "u0_syscon_pclk", "dom4_apb", 0, 1, 1);
268         priv->pll[PLL_OFI(JH7110_U0_M31DPHY_APBCFG_PCLK)] =
269                         devm_clk_hw_register_fixed_factor(priv->dev,
270                         "u0_m31dphy_apbcfg_pclk", "dom4_apb", 0, 1, 1);
271         priv->pll[PLL_OFI(JH7110_U0_AXI2APB_BRIDGE_CLK_DOM4_APB)] =
272                         devm_clk_hw_register_fixed_factor(priv->dev,
273                         "u0_axi2apb_bridge_clk_dom4_apb", "dom4_apb", 0, 1, 1);
274         priv->pll[PLL_OFI(JH7110_U0_AXI2APB_BRIDGE_ISP_AXI4SLV_CLK)] =
275                         devm_clk_hw_register_fixed_factor(priv->dev,
276                         "u0_axi2apb_bridge_isp_axi4slv_clk",
277                         "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi", 0, 1, 1);
278         priv->pll[PLL_OFI(JH7110_U3_PCLK_MUX_PCLK)] =
279                         devm_clk_hw_register_fixed_factor(priv->dev,
280                         "u3_pclk_mux_pclk", "u3_pclk_mux_func_pclk", 0, 1, 1);
281
282         for (idx = 0; idx < JH7110_CLK_ISP_REG_END; idx++) {
283                 u32 max = jh7110_clk_isp_data[idx].max;
284                 struct clk_parent_data parents[2] = {};
285                 struct clk_init_data init = {
286                         .name = jh7110_clk_isp_data[idx].name,
287                         .ops = starfive_jh7110_clk_ops(max),
288                         .parent_data = parents,
289                         .num_parents = ((max & JH7110_CLK_MUX_MASK) >>
290                                         JH7110_CLK_MUX_SHIFT) + 1,
291                         .flags = jh7110_clk_isp_data[idx].flags,
292                 };
293                 struct jh7110_clk *clk = &priv->reg[idx];
294                 unsigned int i;
295                 char *fw_name[4] = {
296                         "u0_dom_isp_top_clk_dom_isp_top_clk_ispcore_2x",
297                         "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi",
298                         "u0_dom_isp_top_clk_dom_isp_top_clk_bist_apb",
299                         "u0_dom_isp_top_clk_dom_isp_top_clk_dvp"
300                 };
301
302                 for (i = 0; i < init.num_parents; i++) {
303                         unsigned int pidx = jh7110_clk_isp_data[idx].parents[i];
304
305                         if (pidx < JH7110_CLK_ISP_REG_END)
306                                 parents[i].hw = &priv->reg[pidx].hw;
307                         else if (pidx < JH7110_CLK_ISP_END)
308                                 parents[i].hw = priv->pll[PLL_OFI(pidx)];
309                         else if (pidx == JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN)
310                                 parents[i].fw_name = fw_name[0];
311                         else if (pidx == JH7110_ISP_TOP_CLK_ISP_AXI_CLKGEN)
312                                 parents[i].fw_name = fw_name[1];
313                         else if (pidx == JH7110_ISP_TOP_CLK_BIST_APB_CLKGEN)
314                                 parents[i].fw_name = fw_name[2];
315                         else if (pidx == JH7110_ISP_TOP_CLK_DVP_CLKGEN)
316                                 parents[i].fw_name = fw_name[3];
317                 }
318
319                 clk->hw.init = &init;
320                 clk->idx = idx;
321                 clk->max_div = max & JH7110_CLK_DIV_MASK;
322                 clk->reg_flags = JH7110_CLK_ISP_FLAG;
323
324                 ret = devm_clk_hw_register(priv->dev, &clk->hw);
325                 if (ret)
326                         goto init_failed;
327         }
328
329         ret = devm_of_clk_add_hw_provider(priv->dev, jh7110_isp_clk_get, priv);
330         if (ret)
331                 goto init_failed;
332
333         pm_runtime_put_sync(&pdev->dev);
334
335         dev_info(&pdev->dev, "starfive JH7110 clk_isp init successfully.");
336         return 0;
337
338 init_failed:
339         return ret;
340 }
341
342 static const struct of_device_id clk_starfive_jh7110_isp_match[] = {
343                 {.compatible = "starfive,jh7110-clk-isp" },
344                 { /* sentinel */ }
345 };
346
347 static struct platform_driver clk_starfive_jh7110_isp_driver = {
348         .probe = clk_starfive_jh7110_isp_probe,
349                 .driver = {
350                 .name = "clk-starfive-jh7110-isp",
351                 .of_match_table = clk_starfive_jh7110_isp_match,
352                 .pm     = &clk_isp_pm_ops,
353         },
354 };
355 module_platform_driver(clk_starfive_jh7110_isp_driver);
356
357 MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
358 MODULE_DESCRIPTION("StarFive JH7110 isp clock driver");
359 MODULE_LICENSE("GPL");