brintos

brintos / linux-shallow public Read only

0
0
Text · 7.6 KiB · 09368fd Raw
344 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Hisilicon clock driver4 *5 * Copyright (c) 2012-2013 Hisilicon Limited.6 * Copyright (c) 2012-2013 Linaro Limited.7 *8 * Author: Haojian Zhuang <haojian.zhuang@linaro.org>9 *	   Xin Li <li.xin@linaro.org>10 */11 12#include <linux/kernel.h>13#include <linux/clkdev.h>14#include <linux/clk-provider.h>15#include <linux/delay.h>16#include <linux/io.h>17#include <linux/of.h>18#include <linux/of_address.h>19#include <linux/platform_device.h>20#include <linux/slab.h>21 22#include "clk.h"23 24static DEFINE_SPINLOCK(hisi_clk_lock);25 26struct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev,27						int nr_clks)28{29	struct hisi_clock_data *clk_data;30	struct resource *res;31	struct clk **clk_table;32 33	clk_data = devm_kmalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);34	if (!clk_data)35		return NULL;36 37	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);38	if (!res)39		return NULL;40	clk_data->base = devm_ioremap(&pdev->dev,41				res->start, resource_size(res));42	if (!clk_data->base)43		return NULL;44 45	clk_table = devm_kmalloc_array(&pdev->dev, nr_clks,46				       sizeof(*clk_table),47				       GFP_KERNEL);48	if (!clk_table)49		return NULL;50 51	clk_data->clk_data.clks = clk_table;52	clk_data->clk_data.clk_num = nr_clks;53 54	return clk_data;55}56EXPORT_SYMBOL_GPL(hisi_clk_alloc);57 58struct hisi_clock_data *hisi_clk_init(struct device_node *np,59					     int nr_clks)60{61	struct hisi_clock_data *clk_data;62	struct clk **clk_table;63	void __iomem *base;64 65	base = of_iomap(np, 0);66	if (!base) {67		pr_err("%s: failed to map clock registers\n", __func__);68		goto err;69	}70 71	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);72	if (!clk_data)73		goto err;74 75	clk_data->base = base;76	clk_table = kcalloc(nr_clks, sizeof(*clk_table), GFP_KERNEL);77	if (!clk_table)78		goto err_data;79 80	clk_data->clk_data.clks = clk_table;81	clk_data->clk_data.clk_num = nr_clks;82	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);83	return clk_data;84err_data:85	kfree(clk_data);86err:87	return NULL;88}89EXPORT_SYMBOL_GPL(hisi_clk_init);90 91int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks,92					 int nums, struct hisi_clock_data *data)93{94	struct clk *clk;95	int i;96 97	for (i = 0; i < nums; i++) {98		clk = clk_register_fixed_rate(NULL, clks[i].name,99					      clks[i].parent_name,100					      clks[i].flags,101					      clks[i].fixed_rate);102		if (IS_ERR(clk)) {103			pr_err("%s: failed to register clock %s\n",104			       __func__, clks[i].name);105			goto err;106		}107		data->clk_data.clks[clks[i].id] = clk;108	}109 110	return 0;111 112err:113	while (i--)114		clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);115 116	return PTR_ERR(clk);117}118EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate);119 120int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks,121					   int nums,122					   struct hisi_clock_data *data)123{124	struct clk *clk;125	int i;126 127	for (i = 0; i < nums; i++) {128		clk = clk_register_fixed_factor(NULL, clks[i].name,129						clks[i].parent_name,130						clks[i].flags, clks[i].mult,131						clks[i].div);132		if (IS_ERR(clk)) {133			pr_err("%s: failed to register clock %s\n",134			       __func__, clks[i].name);135			goto err;136		}137		data->clk_data.clks[clks[i].id] = clk;138	}139 140	return 0;141 142err:143	while (i--)144		clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);145 146	return PTR_ERR(clk);147}148EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor);149 150int hisi_clk_register_mux(const struct hisi_mux_clock *clks,151				  int nums, struct hisi_clock_data *data)152{153	struct clk *clk;154	void __iomem *base = data->base;155	int i;156 157	for (i = 0; i < nums; i++) {158		u32 mask = BIT(clks[i].width) - 1;159 160		clk = clk_register_mux_table(NULL, clks[i].name,161					clks[i].parent_names,162					clks[i].num_parents, clks[i].flags,163					base + clks[i].offset, clks[i].shift,164					mask, clks[i].mux_flags,165					clks[i].table, &hisi_clk_lock);166		if (IS_ERR(clk)) {167			pr_err("%s: failed to register clock %s\n",168			       __func__, clks[i].name);169			goto err;170		}171 172		if (clks[i].alias)173			clk_register_clkdev(clk, clks[i].alias, NULL);174 175		data->clk_data.clks[clks[i].id] = clk;176	}177 178	return 0;179 180err:181	while (i--)182		clk_unregister_mux(data->clk_data.clks[clks[i].id]);183 184	return PTR_ERR(clk);185}186EXPORT_SYMBOL_GPL(hisi_clk_register_mux);187 188int hisi_clk_register_phase(struct device *dev,189			    const struct hisi_phase_clock *clks,190			    int nums, struct hisi_clock_data *data)191{192	void __iomem *base = data->base;193	struct clk *clk;194	int i;195 196	for (i = 0; i < nums; i++) {197		clk = clk_register_hisi_phase(dev, &clks[i], base,198					      &hisi_clk_lock);199		if (IS_ERR(clk)) {200			pr_err("%s: failed to register clock %s\n", __func__,201			       clks[i].name);202			return PTR_ERR(clk);203		}204 205		data->clk_data.clks[clks[i].id] = clk;206	}207 208	return 0;209}210EXPORT_SYMBOL_GPL(hisi_clk_register_phase);211 212int hisi_clk_register_divider(const struct hisi_divider_clock *clks,213				      int nums, struct hisi_clock_data *data)214{215	struct clk *clk;216	void __iomem *base = data->base;217	int i;218 219	for (i = 0; i < nums; i++) {220		clk = clk_register_divider_table(NULL, clks[i].name,221						 clks[i].parent_name,222						 clks[i].flags,223						 base + clks[i].offset,224						 clks[i].shift, clks[i].width,225						 clks[i].div_flags,226						 clks[i].table,227						 &hisi_clk_lock);228		if (IS_ERR(clk)) {229			pr_err("%s: failed to register clock %s\n",230			       __func__, clks[i].name);231			goto err;232		}233 234		if (clks[i].alias)235			clk_register_clkdev(clk, clks[i].alias, NULL);236 237		data->clk_data.clks[clks[i].id] = clk;238	}239 240	return 0;241 242err:243	while (i--)244		clk_unregister_divider(data->clk_data.clks[clks[i].id]);245 246	return PTR_ERR(clk);247}248EXPORT_SYMBOL_GPL(hisi_clk_register_divider);249 250int hisi_clk_register_gate(const struct hisi_gate_clock *clks,251				       int nums, struct hisi_clock_data *data)252{253	struct clk *clk;254	void __iomem *base = data->base;255	int i;256 257	for (i = 0; i < nums; i++) {258		clk = clk_register_gate(NULL, clks[i].name,259						clks[i].parent_name,260						clks[i].flags,261						base + clks[i].offset,262						clks[i].bit_idx,263						clks[i].gate_flags,264						&hisi_clk_lock);265		if (IS_ERR(clk)) {266			pr_err("%s: failed to register clock %s\n",267			       __func__, clks[i].name);268			goto err;269		}270 271		if (clks[i].alias)272			clk_register_clkdev(clk, clks[i].alias, NULL);273 274		data->clk_data.clks[clks[i].id] = clk;275	}276 277	return 0;278 279err:280	while (i--)281		clk_unregister_gate(data->clk_data.clks[clks[i].id]);282 283	return PTR_ERR(clk);284}285EXPORT_SYMBOL_GPL(hisi_clk_register_gate);286 287void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks,288				       int nums, struct hisi_clock_data *data)289{290	struct clk *clk;291	void __iomem *base = data->base;292	int i;293 294	for (i = 0; i < nums; i++) {295		clk = hisi_register_clkgate_sep(NULL, clks[i].name,296						clks[i].parent_name,297						clks[i].flags,298						base + clks[i].offset,299						clks[i].bit_idx,300						clks[i].gate_flags,301						&hisi_clk_lock);302		if (IS_ERR(clk)) {303			pr_err("%s: failed to register clock %s\n",304			       __func__, clks[i].name);305			continue;306		}307 308		if (clks[i].alias)309			clk_register_clkdev(clk, clks[i].alias, NULL);310 311		data->clk_data.clks[clks[i].id] = clk;312	}313}314EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep);315 316void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks,317					int nums, struct hisi_clock_data *data)318{319	struct clk *clk;320	void __iomem *base = data->base;321	int i;322 323	for (i = 0; i < nums; i++) {324		clk = hi6220_register_clkdiv(NULL, clks[i].name,325						clks[i].parent_name,326						clks[i].flags,327						base + clks[i].offset,328						clks[i].shift,329						clks[i].width,330						clks[i].mask_bit,331						&hisi_clk_lock);332		if (IS_ERR(clk)) {333			pr_err("%s: failed to register clock %s\n",334			       __func__, clks[i].name);335			continue;336		}337 338		if (clks[i].alias)339			clk_register_clkdev(clk, clks[i].alias, NULL);340 341		data->clk_data.clks[clks[i].id] = clk;342	}343}344