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} |
|