clk-scu.c (ead5d1f4d877e92c051e1a1ade623d0d30e71619) clk-scu.c (77d8f3068c63ee0983f0b5ba3207d3f7cce11be4)
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2018 NXP
4 * Dong Aisheng <aisheng.dong@nxp.com>
5 */
6
7#include <dt-bindings/firmware/imx/rsrc.h>
8#include <linux/arm-smccc.h>
9#include <linux/clk-provider.h>
10#include <linux/err.h>
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2018 NXP
4 * Dong Aisheng <aisheng.dong@nxp.com>
5 */
6
7#include <dt-bindings/firmware/imx/rsrc.h>
8#include <linux/arm-smccc.h>
9#include <linux/clk-provider.h>
10#include <linux/err.h>
11#include <linux/of_platform.h>
12#include <linux/platform_device.h>
13#include <linux/pm_domain.h>
11#include <linux/slab.h>
12
13#include "clk-scu.h"
14
15#define IMX_SIP_CPUFREQ 0xC2000001
16#define IMX_SIP_SET_CPUFREQ 0x00
17
18static struct imx_sc_ipc *ccm_ipc_handle;
14#include <linux/slab.h>
15
16#include "clk-scu.h"
17
18#define IMX_SIP_CPUFREQ 0xC2000001
19#define IMX_SIP_SET_CPUFREQ 0x00
20
21static struct imx_sc_ipc *ccm_ipc_handle;
22struct device_node *pd_np;
19
23
24struct imx_scu_clk_node {
25 const char *name;
26 u32 rsrc;
27 u8 clk_type;
28 const char * const *parents;
29 int num_parents;
30
31 struct clk_hw *hw;
32 struct list_head node;
33};
34
35struct list_head imx_scu_clks[IMX_SC_R_LAST];
36
20/*
21 * struct clk_scu - Description of one SCU clock
22 * @hw: the common clk_hw
23 * @rsrc_id: resource ID of this SCU clock
24 * @clk_type: type of this clock resource
25 */
26struct clk_scu {
27 struct clk_hw hw;

--- 95 unchanged lines hidden (view full) ---

123 u8 autog;
124} __packed __aligned(4);
125
126static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
127{
128 return container_of(hw, struct clk_scu, hw);
129}
130
37/*
38 * struct clk_scu - Description of one SCU clock
39 * @hw: the common clk_hw
40 * @rsrc_id: resource ID of this SCU clock
41 * @clk_type: type of this clock resource
42 */
43struct clk_scu {
44 struct clk_hw hw;

--- 95 unchanged lines hidden (view full) ---

140 u8 autog;
141} __packed __aligned(4);
142
143static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
144{
145 return container_of(hw, struct clk_scu, hw);
146}
147
131int imx_clk_scu_init(void)
148int imx_clk_scu_init(struct device_node *np)
132{
149{
133 return imx_scu_get_handle(&ccm_ipc_handle);
150 struct platform_device *pd_dev;
151 u32 clk_cells;
152 int ret, i;
153
154 ret = imx_scu_get_handle(&ccm_ipc_handle);
155 if (ret)
156 return ret;
157
158 of_property_read_u32(np, "#clock-cells", &clk_cells);
159
160 if (clk_cells == 2) {
161 for (i = 0; i < IMX_SC_R_LAST; i++)
162 INIT_LIST_HEAD(&imx_scu_clks[i]);
163 /*
164 * Note: SCU clock driver depends on SCU power domain to be ready
165 * first. As there're no power domains under scu clock node in dts,
166 * we can't use PROBE_DEFER automatically.
167 */
168 pd_np = of_find_compatible_node(NULL, NULL, "fsl,scu-pd");
169 pd_dev = of_find_device_by_node(pd_np);
170 if (!pd_dev || !device_is_bound(&pd_dev->dev)) {
171 of_node_put(pd_np);
172 return -EPROBE_DEFER;
173 }
174 }
175
176 return 0;
134}
135
136/*
137 * clk_scu_recalc_rate - Get clock rate for a SCU clock
138 * @hw: clock to get rate for
139 * @parent_rate: parent rate provided by common clock framework, not used
140 *
141 * Gets the current clock rate of a SCU clock. Returns the current

--- 240 unchanged lines hidden (view full) ---

382 ret = clk_hw_register(NULL, hw);
383 if (ret) {
384 kfree(clk);
385 hw = ERR_PTR(ret);
386 }
387
388 return hw;
389}
177}
178
179/*
180 * clk_scu_recalc_rate - Get clock rate for a SCU clock
181 * @hw: clock to get rate for
182 * @parent_rate: parent rate provided by common clock framework, not used
183 *
184 * Gets the current clock rate of a SCU clock. Returns the current

--- 240 unchanged lines hidden (view full) ---

425 ret = clk_hw_register(NULL, hw);
426 if (ret) {
427 kfree(clk);
428 hw = ERR_PTR(ret);
429 }
430
431 return hw;
432}
433
434struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
435 void *data)
436{
437 unsigned int rsrc = clkspec->args[0];
438 unsigned int idx = clkspec->args[1];
439 struct list_head *scu_clks = data;
440 struct imx_scu_clk_node *clk;
441
442 list_for_each_entry(clk, &scu_clks[rsrc], node) {
443 if (clk->clk_type == idx)
444 return clk->hw;
445 }
446
447 return ERR_PTR(-ENODEV);
448}
449
450static int imx_clk_scu_probe(struct platform_device *pdev)
451{
452 struct device *dev = &pdev->dev;
453 struct imx_scu_clk_node *clk = dev_get_platdata(dev);
454 struct clk_hw *hw;
455
456 hw = __imx_clk_scu(clk->name, clk->parents, clk->num_parents,
457 clk->rsrc, clk->clk_type);
458 if (IS_ERR(hw))
459 return PTR_ERR(hw);
460
461 clk->hw = hw;
462 list_add_tail(&clk->node, &imx_scu_clks[clk->rsrc]);
463
464 dev_dbg(dev, "register SCU clock rsrc:%d type:%d\n", clk->rsrc,
465 clk->clk_type);
466
467 return 0;
468}
469
470static struct platform_driver imx_clk_scu_driver = {
471 .driver = {
472 .name = "imx-scu-clk",
473 .suppress_bind_attrs = true,
474 },
475 .probe = imx_clk_scu_probe,
476};
477builtin_platform_driver(imx_clk_scu_driver);
478
479static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id)
480{
481 struct of_phandle_args genpdspec = {
482 .np = pd_np,
483 .args_count = 1,
484 .args[0] = rsrc_id,
485 };
486
487 return of_genpd_add_device(&genpdspec, dev);
488}
489
490struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
491 const char * const *parents,
492 int num_parents, u32 rsrc_id, u8 clk_type)
493{
494 struct imx_scu_clk_node clk = {
495 .name = name,
496 .rsrc = rsrc_id,
497 .clk_type = clk_type,
498 .parents = parents,
499 .num_parents = num_parents,
500 };
501 struct platform_device *pdev;
502 int ret;
503
504 pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE);
505 if (!pdev) {
506 pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n",
507 name, rsrc_id, clk_type);
508 return ERR_PTR(-ENOMEM);
509 }
510
511 ret = platform_device_add_data(pdev, &clk, sizeof(clk));
512 if (ret) {
513 platform_device_put(pdev);
514 return ERR_PTR(ret);
515 }
516
517 pdev->driver_override = "imx-scu-clk";
518
519 ret = imx_clk_scu_attach_pd(&pdev->dev, rsrc_id);
520 if (ret)
521 pr_warn("%s: failed to attached the power domain %d\n",
522 name, ret);
523
524 platform_device_add(pdev);
525
526 /* For API backwards compatiblilty, simply return NULL for success */
527 return NULL;
528}
529
530void imx_clk_scu_unregister(void)
531{
532 struct imx_scu_clk_node *clk;
533 int i;
534
535 for (i = 0; i < IMX_SC_R_LAST; i++) {
536 list_for_each_entry(clk, &imx_scu_clks[i], node) {
537 clk_hw_unregister(clk->hw);
538 kfree(clk);
539 }
540 }
541}