162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Hisilicon clock driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2012-2013 Hisilicon Limited. 662306a36Sopenharmony_ci * Copyright (c) 2012-2013 Linaro Limited. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author: Haojian Zhuang <haojian.zhuang@linaro.org> 962306a36Sopenharmony_ci * Xin Li <li.xin@linaro.org> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/clkdev.h> 1462306a36Sopenharmony_ci#include <linux/clk-provider.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/of_address.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "clk.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(hisi_clk_lock); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev, 2762306a36Sopenharmony_ci int nr_clks) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct hisi_clock_data *clk_data; 3062306a36Sopenharmony_ci struct resource *res; 3162306a36Sopenharmony_ci struct clk **clk_table; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci clk_data = devm_kmalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); 3462306a36Sopenharmony_ci if (!clk_data) 3562306a36Sopenharmony_ci return NULL; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3862306a36Sopenharmony_ci if (!res) 3962306a36Sopenharmony_ci return NULL; 4062306a36Sopenharmony_ci clk_data->base = devm_ioremap(&pdev->dev, 4162306a36Sopenharmony_ci res->start, resource_size(res)); 4262306a36Sopenharmony_ci if (!clk_data->base) 4362306a36Sopenharmony_ci return NULL; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci clk_table = devm_kmalloc_array(&pdev->dev, nr_clks, 4662306a36Sopenharmony_ci sizeof(*clk_table), 4762306a36Sopenharmony_ci GFP_KERNEL); 4862306a36Sopenharmony_ci if (!clk_table) 4962306a36Sopenharmony_ci return NULL; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci clk_data->clk_data.clks = clk_table; 5262306a36Sopenharmony_ci clk_data->clk_data.clk_num = nr_clks; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return clk_data; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_clk_alloc); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistruct hisi_clock_data *hisi_clk_init(struct device_node *np, 5962306a36Sopenharmony_ci int nr_clks) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct hisi_clock_data *clk_data; 6262306a36Sopenharmony_ci struct clk **clk_table; 6362306a36Sopenharmony_ci void __iomem *base; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci base = of_iomap(np, 0); 6662306a36Sopenharmony_ci if (!base) { 6762306a36Sopenharmony_ci pr_err("%s: failed to map clock registers\n", __func__); 6862306a36Sopenharmony_ci goto err; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 7262306a36Sopenharmony_ci if (!clk_data) 7362306a36Sopenharmony_ci goto err; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci clk_data->base = base; 7662306a36Sopenharmony_ci clk_table = kcalloc(nr_clks, sizeof(*clk_table), GFP_KERNEL); 7762306a36Sopenharmony_ci if (!clk_table) 7862306a36Sopenharmony_ci goto err_data; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci clk_data->clk_data.clks = clk_table; 8162306a36Sopenharmony_ci clk_data->clk_data.clk_num = nr_clks; 8262306a36Sopenharmony_ci of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data); 8362306a36Sopenharmony_ci return clk_data; 8462306a36Sopenharmony_cierr_data: 8562306a36Sopenharmony_ci kfree(clk_data); 8662306a36Sopenharmony_cierr: 8762306a36Sopenharmony_ci return NULL; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_clk_init); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciint hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks, 9262306a36Sopenharmony_ci int nums, struct hisi_clock_data *data) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct clk *clk; 9562306a36Sopenharmony_ci int i; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci for (i = 0; i < nums; i++) { 9862306a36Sopenharmony_ci clk = clk_register_fixed_rate(NULL, clks[i].name, 9962306a36Sopenharmony_ci clks[i].parent_name, 10062306a36Sopenharmony_ci clks[i].flags, 10162306a36Sopenharmony_ci clks[i].fixed_rate); 10262306a36Sopenharmony_ci if (IS_ERR(clk)) { 10362306a36Sopenharmony_ci pr_err("%s: failed to register clock %s\n", 10462306a36Sopenharmony_ci __func__, clks[i].name); 10562306a36Sopenharmony_ci goto err; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci data->clk_data.clks[clks[i].id] = clk; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cierr: 11362306a36Sopenharmony_ci while (i--) 11462306a36Sopenharmony_ci clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return PTR_ERR(clk); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ciint hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks, 12162306a36Sopenharmony_ci int nums, 12262306a36Sopenharmony_ci struct hisi_clock_data *data) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct clk *clk; 12562306a36Sopenharmony_ci int i; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci for (i = 0; i < nums; i++) { 12862306a36Sopenharmony_ci clk = clk_register_fixed_factor(NULL, clks[i].name, 12962306a36Sopenharmony_ci clks[i].parent_name, 13062306a36Sopenharmony_ci clks[i].flags, clks[i].mult, 13162306a36Sopenharmony_ci clks[i].div); 13262306a36Sopenharmony_ci if (IS_ERR(clk)) { 13362306a36Sopenharmony_ci pr_err("%s: failed to register clock %s\n", 13462306a36Sopenharmony_ci __func__, clks[i].name); 13562306a36Sopenharmony_ci goto err; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci data->clk_data.clks[clks[i].id] = clk; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cierr: 14362306a36Sopenharmony_ci while (i--) 14462306a36Sopenharmony_ci clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return PTR_ERR(clk); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciint hisi_clk_register_mux(const struct hisi_mux_clock *clks, 15162306a36Sopenharmony_ci int nums, struct hisi_clock_data *data) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct clk *clk; 15462306a36Sopenharmony_ci void __iomem *base = data->base; 15562306a36Sopenharmony_ci int i; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci for (i = 0; i < nums; i++) { 15862306a36Sopenharmony_ci u32 mask = BIT(clks[i].width) - 1; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci clk = clk_register_mux_table(NULL, clks[i].name, 16162306a36Sopenharmony_ci clks[i].parent_names, 16262306a36Sopenharmony_ci clks[i].num_parents, clks[i].flags, 16362306a36Sopenharmony_ci base + clks[i].offset, clks[i].shift, 16462306a36Sopenharmony_ci mask, clks[i].mux_flags, 16562306a36Sopenharmony_ci clks[i].table, &hisi_clk_lock); 16662306a36Sopenharmony_ci if (IS_ERR(clk)) { 16762306a36Sopenharmony_ci pr_err("%s: failed to register clock %s\n", 16862306a36Sopenharmony_ci __func__, clks[i].name); 16962306a36Sopenharmony_ci goto err; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (clks[i].alias) 17362306a36Sopenharmony_ci clk_register_clkdev(clk, clks[i].alias, NULL); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci data->clk_data.clks[clks[i].id] = clk; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return 0; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cierr: 18162306a36Sopenharmony_ci while (i--) 18262306a36Sopenharmony_ci clk_unregister_mux(data->clk_data.clks[clks[i].id]); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return PTR_ERR(clk); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_clk_register_mux); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ciint hisi_clk_register_phase(struct device *dev, 18962306a36Sopenharmony_ci const struct hisi_phase_clock *clks, 19062306a36Sopenharmony_ci int nums, struct hisi_clock_data *data) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci void __iomem *base = data->base; 19362306a36Sopenharmony_ci struct clk *clk; 19462306a36Sopenharmony_ci int i; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci for (i = 0; i < nums; i++) { 19762306a36Sopenharmony_ci clk = clk_register_hisi_phase(dev, &clks[i], base, 19862306a36Sopenharmony_ci &hisi_clk_lock); 19962306a36Sopenharmony_ci if (IS_ERR(clk)) { 20062306a36Sopenharmony_ci pr_err("%s: failed to register clock %s\n", __func__, 20162306a36Sopenharmony_ci clks[i].name); 20262306a36Sopenharmony_ci return PTR_ERR(clk); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci data->clk_data.clks[clks[i].id] = clk; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_clk_register_phase); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ciint hisi_clk_register_divider(const struct hisi_divider_clock *clks, 21362306a36Sopenharmony_ci int nums, struct hisi_clock_data *data) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct clk *clk; 21662306a36Sopenharmony_ci void __iomem *base = data->base; 21762306a36Sopenharmony_ci int i; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci for (i = 0; i < nums; i++) { 22062306a36Sopenharmony_ci clk = clk_register_divider_table(NULL, clks[i].name, 22162306a36Sopenharmony_ci clks[i].parent_name, 22262306a36Sopenharmony_ci clks[i].flags, 22362306a36Sopenharmony_ci base + clks[i].offset, 22462306a36Sopenharmony_ci clks[i].shift, clks[i].width, 22562306a36Sopenharmony_ci clks[i].div_flags, 22662306a36Sopenharmony_ci clks[i].table, 22762306a36Sopenharmony_ci &hisi_clk_lock); 22862306a36Sopenharmony_ci if (IS_ERR(clk)) { 22962306a36Sopenharmony_ci pr_err("%s: failed to register clock %s\n", 23062306a36Sopenharmony_ci __func__, clks[i].name); 23162306a36Sopenharmony_ci goto err; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (clks[i].alias) 23562306a36Sopenharmony_ci clk_register_clkdev(clk, clks[i].alias, NULL); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci data->clk_data.clks[clks[i].id] = clk; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci return 0; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cierr: 24362306a36Sopenharmony_ci while (i--) 24462306a36Sopenharmony_ci clk_unregister_divider(data->clk_data.clks[clks[i].id]); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return PTR_ERR(clk); 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_clk_register_divider); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciint hisi_clk_register_gate(const struct hisi_gate_clock *clks, 25162306a36Sopenharmony_ci int nums, struct hisi_clock_data *data) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct clk *clk; 25462306a36Sopenharmony_ci void __iomem *base = data->base; 25562306a36Sopenharmony_ci int i; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for (i = 0; i < nums; i++) { 25862306a36Sopenharmony_ci clk = clk_register_gate(NULL, clks[i].name, 25962306a36Sopenharmony_ci clks[i].parent_name, 26062306a36Sopenharmony_ci clks[i].flags, 26162306a36Sopenharmony_ci base + clks[i].offset, 26262306a36Sopenharmony_ci clks[i].bit_idx, 26362306a36Sopenharmony_ci clks[i].gate_flags, 26462306a36Sopenharmony_ci &hisi_clk_lock); 26562306a36Sopenharmony_ci if (IS_ERR(clk)) { 26662306a36Sopenharmony_ci pr_err("%s: failed to register clock %s\n", 26762306a36Sopenharmony_ci __func__, clks[i].name); 26862306a36Sopenharmony_ci goto err; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (clks[i].alias) 27262306a36Sopenharmony_ci clk_register_clkdev(clk, clks[i].alias, NULL); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci data->clk_data.clks[clks[i].id] = clk; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cierr: 28062306a36Sopenharmony_ci while (i--) 28162306a36Sopenharmony_ci clk_unregister_gate(data->clk_data.clks[clks[i].id]); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return PTR_ERR(clk); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_clk_register_gate); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_civoid hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks, 28862306a36Sopenharmony_ci int nums, struct hisi_clock_data *data) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct clk *clk; 29162306a36Sopenharmony_ci void __iomem *base = data->base; 29262306a36Sopenharmony_ci int i; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci for (i = 0; i < nums; i++) { 29562306a36Sopenharmony_ci clk = hisi_register_clkgate_sep(NULL, clks[i].name, 29662306a36Sopenharmony_ci clks[i].parent_name, 29762306a36Sopenharmony_ci clks[i].flags, 29862306a36Sopenharmony_ci base + clks[i].offset, 29962306a36Sopenharmony_ci clks[i].bit_idx, 30062306a36Sopenharmony_ci clks[i].gate_flags, 30162306a36Sopenharmony_ci &hisi_clk_lock); 30262306a36Sopenharmony_ci if (IS_ERR(clk)) { 30362306a36Sopenharmony_ci pr_err("%s: failed to register clock %s\n", 30462306a36Sopenharmony_ci __func__, clks[i].name); 30562306a36Sopenharmony_ci continue; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (clks[i].alias) 30962306a36Sopenharmony_ci clk_register_clkdev(clk, clks[i].alias, NULL); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci data->clk_data.clks[clks[i].id] = clk; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_civoid __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks, 31762306a36Sopenharmony_ci int nums, struct hisi_clock_data *data) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct clk *clk; 32062306a36Sopenharmony_ci void __iomem *base = data->base; 32162306a36Sopenharmony_ci int i; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci for (i = 0; i < nums; i++) { 32462306a36Sopenharmony_ci clk = hi6220_register_clkdiv(NULL, clks[i].name, 32562306a36Sopenharmony_ci clks[i].parent_name, 32662306a36Sopenharmony_ci clks[i].flags, 32762306a36Sopenharmony_ci base + clks[i].offset, 32862306a36Sopenharmony_ci clks[i].shift, 32962306a36Sopenharmony_ci clks[i].width, 33062306a36Sopenharmony_ci clks[i].mask_bit, 33162306a36Sopenharmony_ci &hisi_clk_lock); 33262306a36Sopenharmony_ci if (IS_ERR(clk)) { 33362306a36Sopenharmony_ci pr_err("%s: failed to register clock %s\n", 33462306a36Sopenharmony_ci __func__, clks[i].name); 33562306a36Sopenharmony_ci continue; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (clks[i].alias) 33962306a36Sopenharmony_ci clk_register_clkdev(clk, clks[i].alias, NULL); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci data->clk_data.clks[clks[i].id] = clk; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci} 344