1 // SPDX-License-Identifier: GPL-2.0
3 * StarFive JH7110 Isp Clock Driver
5 * Copyright (C) 2022 Xingyu Wu <xingyu.wu@starfivetech.com>
8 #include <linux/bits.h>
10 #include <linux/clk-provider.h>
11 #include <linux/debugfs.h>
12 #include <linux/device.h>
13 #include <linux/init.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 <soc/starfive/jh7110_pmu.h>
25 #include "clk-starfive-jh7110.h"
27 static const struct jh7110_clk_data jh7110_clk_isp_data[] __initconst = {
29 JH7110__DIV(JH7110_DOM4_APB_FUNC, "dom4_apb_func",
30 15, JH7110_ISP_TOP_CLK_ISP_AXI_CLKGEN),
32 JH7110__DIV(JH7110_MIPI_RX0_PXL, "mipi_rx0_pxl",
33 8, JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN),
34 JH7110__INV(JH7110_DVP_INV, "dvp_inv", JH7110_ISP_TOP_CLK_DVP_CLKGEN),
36 JH7110__DIV(JH7110_U0_M31DPHY_CFGCLK_IN, "u0_m31dphy_cfgclk_in",
37 16, JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN),
38 JH7110__DIV(JH7110_U0_M31DPHY_REFCLK_IN, "u0_m31dphy_refclk_in",
39 16, JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN),
40 JH7110__DIV(JH7110_U0_M31DPHY_TXCLKESC_LAN0, "u0_m31dphy_txclkesc_lan0",
41 60, JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN),
42 JH7110_GATE(JH7110_U0_VIN_PCLK, "u0_vin_pclk", 0, JH7110_DOM4_APB),
43 JH7110__DIV(JH7110_U0_VIN_SYS_CLK, "u0_vin_sys_clk",
44 8, JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN),
45 JH7110_GATE(JH7110_U0_VIN_PIXEL_CLK_IF0, "u0_vin_pixel_clk_if0",
46 0, JH7110_MIPI_RX0_PXL),
47 JH7110_GATE(JH7110_U0_VIN_PIXEL_CLK_IF1, "u0_vin_pixel_clk_if1",
48 0, JH7110_MIPI_RX0_PXL),
49 JH7110_GATE(JH7110_U0_VIN_PIXEL_CLK_IF2, "u0_vin_pixel_clk_if2",
50 0, JH7110_MIPI_RX0_PXL),
51 JH7110_GATE(JH7110_U0_VIN_PIXEL_CLK_IF3, "u0_vin_pixel_clk_if3",
52 0, JH7110_MIPI_RX0_PXL),
53 JH7110__MUX(JH7110_U0_VIN_CLK_P_AXIWR, "u0_vin_clk_p_axiwr", 2,
57 JH7110_GMUX(JH7110_U0_ISPV2_TOP_WRAPPER_CLK_C,
58 "u0_ispv2_top_wrapper_clk_c", 0, 2,
63 static struct clk_hw *jh7110_isp_clk_get(struct of_phandle_args *clkspec,
66 struct jh7110_clk_priv *priv = data;
67 unsigned int idx = clkspec->args[0];
69 if (idx < JH7110_CLK_ISP_REG_END)
70 return &priv->reg[idx].hw;
72 if (idx < JH7110_CLK_ISP_END)
73 return priv->pll[PLL_OFI(idx)];
75 return ERR_PTR(-EINVAL);
78 static int __init clk_starfive_jh7110_isp_probe(struct platform_device *pdev)
80 struct jh7110_clk_priv *priv;
82 struct clk *clk_isp_2x;
83 struct clk *clk_isp_axi;
84 struct reset_control *rst_isp_n;
85 struct reset_control *rst_isp_axi;
88 priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg,
89 JH7110_CLK_ISP_END), GFP_KERNEL);
93 spin_lock_init(&priv->rmw_lock);
94 priv->dev = &pdev->dev;
95 priv->isp_base = devm_platform_ioremap_resource(pdev, 0);
96 if (IS_ERR(priv->isp_base))
97 return PTR_ERR(priv->isp_base);
99 starfive_power_domain_set(POWER_DOMAIN_ISP, 1);
101 clk_isp_2x = devm_clk_get(priv->dev,
102 "u0_dom_isp_top_clk_dom_isp_top_clk_ispcore_2x");
103 if (!IS_ERR(clk_isp_2x)){
104 ret = clk_prepare_enable(clk_isp_2x);
106 dev_err(priv->dev, "clk_isp_2x enable failed\n");
110 dev_err(priv->dev, "clk_isp_2x get failed\n");
111 return PTR_ERR(clk_isp_2x);
114 clk_isp_axi = devm_clk_get(priv->dev,
115 "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi");
116 if (!IS_ERR(clk_isp_axi)){
117 ret = clk_prepare_enable(clk_isp_axi);
119 dev_err(priv->dev, "clk_isp_axi enable failed\n");
123 dev_err(priv->dev, "clk_isp_axi get failed\n");
124 return PTR_ERR(clk_isp_axi);
127 rst_isp_n = devm_reset_control_get_exclusive(
128 priv->dev, "rst_isp_top_n");
129 if (!IS_ERR(rst_isp_n)) {
130 ret = reset_control_deassert(rst_isp_n);
132 dev_err(priv->dev, "rst_isp_n deassert failed.\n");
136 dev_err(priv->dev, "rst_isp_n get failed.\n");
137 return PTR_ERR(rst_isp_n);
140 rst_isp_axi = devm_reset_control_get_exclusive(
141 priv->dev, "rst_isp_top_axi");
142 if (!IS_ERR(rst_isp_axi)) {
143 ret = reset_control_deassert(rst_isp_axi);
145 dev_err(priv->dev, "rst_isp_axi deassert failed.\n");
149 dev_err(priv->dev, "rst_isp_axi get failed.\n");
150 return PTR_ERR(rst_isp_axi);
153 priv->pll[PLL_OFI(JH7110_U3_PCLK_MUX_FUNC_PCLK)] =
154 devm_clk_hw_register_fixed_factor(
155 priv->dev, "u3_pclk_mux_func_pclk",
156 "dom4_apb_func", 0, 1, 1);
157 priv->pll[PLL_OFI(JH7110_U3_PCLK_MUX_BIST_PCLK)] =
158 devm_clk_hw_register_fixed_factor(
159 priv->dev, "u3_pclk_mux_bist_pclk",
160 "u0_dom_isp_top_clk_dom_isp_top_clk_bist_apb", 0, 1, 1);
161 priv->pll[PLL_OFI(JH7110_DOM4_APB)] =
162 devm_clk_hw_register_fixed_factor(priv->dev, "dom4_apb",
163 "u3_pclk_mux_pclk", 0, 1, 1);
165 priv->pll[PLL_OFI(JH7110_U0_VIN_PCLK_FREE)] =
166 devm_clk_hw_register_fixed_factor(
167 priv->dev, "u0_vin_pclk_free",
168 "dom4_apb", 0, 1, 1);
169 priv->pll[PLL_OFI(JH7110_U0_VIN_CLK_P_AXIRD)] =
170 devm_clk_hw_register_fixed_factor(
171 priv->dev, "u0_vin_clk_p_axird",
172 "mipi_rx0_pxl", 0, 1, 1);
173 priv->pll[PLL_OFI(JH7110_U0_VIN_ACLK)] =
174 devm_clk_hw_register_fixed_factor(
175 priv->dev, "u0_vin_ACLK",
176 "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi", 0, 1, 1);
177 priv->pll[PLL_OFI(JH7110_U0_ISPV2_TOP_WRAPPER_CLK_ISP_AXI_IN)] =
178 devm_clk_hw_register_fixed_factor(priv->dev,
179 "u0_ispv2_top_wrapper_clk_isp_axi_in",
180 "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi", 0, 1, 1);
181 priv->pll[PLL_OFI(JH7110_U0_ISPV2_TOP_WRAPPER_CLK_ISP_X2)] =
182 devm_clk_hw_register_fixed_factor(priv->dev,
183 "u0_ispv2_top_wrapper_clk_isp_x2",
184 "u0_dom_isp_top_clk_dom_isp_top_clk_ispcore_2x",
187 priv->pll[PLL_OFI(JH7110_U0_ISPV2_TOP_WRAPPER_CLK_ISP)] =
188 devm_clk_hw_register_fixed_factor(priv->dev,
189 "u0_ispv2_top_wrapper_clk_isp",
190 "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi", 0, 1, 1);
191 priv->pll[PLL_OFI(JH7110_U0_ISPV2_TOP_WRAPPER_CLK_P)] =
192 devm_clk_hw_register_fixed_factor(priv->dev,
193 "u0_ispv2_top_wrapper_clk_p",
194 "mipi_rx0_pxl", 0, 1, 1);
195 priv->pll[PLL_OFI(JH7110_U0_CRG_PCLK)] =
196 devm_clk_hw_register_fixed_factor(priv->dev,
197 "u0_crg_pclk", "dom4_apb", 0, 1, 1);
198 priv->pll[PLL_OFI(JH7110_U0_SYSCON_PCLK)] =
199 devm_clk_hw_register_fixed_factor(priv->dev,
200 "u0_syscon_pclk", "dom4_apb", 0, 1, 1);
201 priv->pll[PLL_OFI(JH7110_U0_M31DPHY_APBCFG_PCLK)] =
202 devm_clk_hw_register_fixed_factor(priv->dev,
203 "u0_m31dphy_apbcfg_pclk", "dom4_apb", 0, 1, 1);
204 priv->pll[PLL_OFI(JH7110_U0_AXI2APB_BRIDGE_CLK_DOM4_APB)] =
205 devm_clk_hw_register_fixed_factor(priv->dev,
206 "u0_axi2apb_bridge_clk_dom4_apb", "dom4_apb", 0, 1, 1);
207 priv->pll[PLL_OFI(JH7110_U0_AXI2APB_BRIDGE_ISP_AXI4SLV_CLK)] =
208 devm_clk_hw_register_fixed_factor(priv->dev,
209 "u0_axi2apb_bridge_isp_axi4slv_clk",
210 "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi", 0, 1, 1);
211 priv->pll[PLL_OFI(JH7110_U3_PCLK_MUX_PCLK)] =
212 devm_clk_hw_register_fixed_factor(priv->dev,
213 "u3_pclk_mux_pclk", "u3_pclk_mux_func_pclk", 0, 1, 1);
215 for (idx = 0; idx < JH7110_CLK_ISP_REG_END; idx++) {
216 u32 max = jh7110_clk_isp_data[idx].max;
217 struct clk_parent_data parents[2] = {};
218 struct clk_init_data init = {
219 .name = jh7110_clk_isp_data[idx].name,
220 .ops = starfive_jh7110_clk_ops(max),
221 .parent_data = parents,
222 .num_parents = ((max & JH7110_CLK_MUX_MASK) \
223 >> JH7110_CLK_MUX_SHIFT) + 1,
224 .flags = jh7110_clk_isp_data[idx].flags,
226 struct jh7110_clk *clk = &priv->reg[idx];
229 for (i = 0; i < init.num_parents; i++) {
230 unsigned int pidx = jh7110_clk_isp_data[idx].parents[i];
232 if (pidx < JH7110_CLK_ISP_REG_END)
233 parents[i].hw = &priv->reg[pidx].hw;
234 else if (pidx < JH7110_CLK_ISP_END)
235 parents[i].hw = priv->pll[PLL_OFI(pidx)];
236 else if (pidx == JH7110_ISP_TOP_CLK_ISPCORE_2X_CLKGEN)
237 parents[i].fw_name = \
238 "u0_dom_isp_top_clk_dom_isp_top_clk_ispcore_2x";
239 else if (pidx == JH7110_ISP_TOP_CLK_ISP_AXI_CLKGEN)
240 parents[i].fw_name = \
241 "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi";
242 else if (pidx == JH7110_ISP_TOP_CLK_BIST_APB_CLKGEN)
243 parents[i].fw_name = \
244 "u0_dom_isp_top_clk_dom_isp_top_clk_bist_apb";
245 else if (pidx == JH7110_ISP_TOP_CLK_DVP_CLKGEN)
246 parents[i].fw_name = \
247 "u0_dom_isp_top_clk_dom_isp_top_clk_dvp";
250 clk->hw.init = &init;
252 clk->max_div = max & JH7110_CLK_DIV_MASK;
253 clk->reg_flags = JH7110_CLK_ISP_FLAG;
255 ret = devm_clk_hw_register(priv->dev, &clk->hw);
260 ret = devm_of_clk_add_hw_provider(priv->dev, jh7110_isp_clk_get, priv);
264 dev_info(&pdev->dev,"starfive JH7110 clk_isp init successfully.");
268 static const struct of_device_id clk_starfive_jh7110_isp_match[] = {
269 {.compatible = "starfive,jh7110-clk-isp" },
273 static struct platform_driver clk_starfive_jh7110_isp_driver = {
274 .probe = clk_starfive_jh7110_isp_probe,
276 .name = "clk-starfive-jh7110-isp",
277 .of_match_table = clk_starfive_jh7110_isp_match,
280 module_platform_driver(clk_starfive_jh7110_isp_driver);
282 MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
283 MODULE_DESCRIPTION("StarFive JH7110 isp clock driver");
284 MODULE_LICENSE("GPL");