mirror of https://github.com/OpenIPC/firmware.git
				
				
				
			
		
			
				
	
	
		
			193 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Diff
		
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Diff
		
	
	
| --- linux-4.9.37/drivers/clk/goke/clk.c	1970-01-01 03:00:00.000000000 +0300
 | |
| +++ linux-4.9.y/drivers/clk/goke/clk.c	2021-06-07 13:01:33.000000000 +0300
 | |
| @@ -0,0 +1,188 @@
 | |
| +/*
 | |
| + * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved.
 | |
| + */
 | |
| +
 | |
| +#include <linux/kernel.h>
 | |
| +#include <linux/clkdev.h>
 | |
| +#include <linux/clk-provider.h>
 | |
| +#include <linux/delay.h>
 | |
| +#include <linux/io.h>
 | |
| +#include <linux/of.h>
 | |
| +#include <linux/of_address.h>
 | |
| +#include <linux/of_device.h>
 | |
| +#include <linux/slab.h>
 | |
| +
 | |
| +#include "clk.h"
 | |
| +
 | |
| +static DEFINE_SPINLOCK(gk_clk_lock);
 | |
| +
 | |
| +struct gk_clock_data *gk_clk_init(struct device_node *np,
 | |
| +					     int nr_clks)
 | |
| +{
 | |
| +	struct gk_clock_data *clk_data;
 | |
| +	struct clk **clk_table;
 | |
| +	void __iomem *base;
 | |
| +
 | |
| +	base = of_iomap(np, 0);
 | |
| +	if (!base) {
 | |
| +		pr_err("%s: failed to map clock registers\n", __func__);
 | |
| +		goto err;
 | |
| +	}
 | |
| +
 | |
| +	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
 | |
| +	if (!clk_data) {
 | |
| +		pr_err("%s: could not allocate clock data\n", __func__);
 | |
| +		goto err;
 | |
| +	}
 | |
| +	clk_data->base = base;
 | |
| +
 | |
| +	clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
 | |
| +	if (!clk_table) {
 | |
| +		pr_err("%s: could not allocate clock lookup table\n", __func__);
 | |
| +		goto err_data;
 | |
| +	}
 | |
| +	clk_data->clk_data.clks = clk_table;
 | |
| +	clk_data->clk_data.clk_num = nr_clks;
 | |
| +	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
 | |
| +	return clk_data;
 | |
| +err_data:
 | |
| +	kfree(clk_data);
 | |
| +err:
 | |
| +	return NULL;
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(gk_clk_init);
 | |
| +
 | |
| +int gk_clk_register_fixed_rate(const struct gk_fixed_rate_clock *clks,
 | |
| +					 int nums, struct gk_clock_data *data)
 | |
| +{
 | |
| +	struct clk *clk;
 | |
| +	int i;
 | |
| +
 | |
| +	for (i = 0; i < nums; i++) {
 | |
| +		clk = clk_register_fixed_rate(NULL, clks[i].name,
 | |
| +					      clks[i].parent_name,
 | |
| +					      clks[i].flags,
 | |
| +					      clks[i].fixed_rate);
 | |
| +		if (IS_ERR(clk)) {
 | |
| +			pr_err("%s: failed to register clock %s\n",
 | |
| +			       __func__, clks[i].name);
 | |
| +			goto err;
 | |
| +		}
 | |
| +		data->clk_data.clks[clks[i].id] = clk;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +
 | |
| +err:
 | |
| +	while (i--)
 | |
| +		clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);
 | |
| +
 | |
| +	return PTR_ERR(clk);
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(gk_clk_register_fixed_rate);
 | |
| +
 | |
| +int gk_clk_register_fixed_factor(const struct gk_fixed_factor_clock *clks,
 | |
| +					   int nums,
 | |
| +					   struct gk_clock_data *data)
 | |
| +{
 | |
| +	struct clk *clk;
 | |
| +	int i;
 | |
| +
 | |
| +	for (i = 0; i < nums; i++) {
 | |
| +		clk = clk_register_fixed_factor(NULL, clks[i].name,
 | |
| +						clks[i].parent_name,
 | |
| +						clks[i].flags, clks[i].mult,
 | |
| +						clks[i].div);
 | |
| +		if (IS_ERR(clk)) {
 | |
| +			pr_err("%s: failed to register clock %s\n",
 | |
| +			       __func__, clks[i].name);
 | |
| +			goto err;
 | |
| +		}
 | |
| +		data->clk_data.clks[clks[i].id] = clk;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +
 | |
| +err:
 | |
| +	while (i--)
 | |
| +		clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);
 | |
| +
 | |
| +	return PTR_ERR(clk);
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(gk_clk_register_fixed_factor);
 | |
| +
 | |
| +int gk_clk_register_mux(const struct gk_mux_clock *clks,
 | |
| +				  int nums, struct gk_clock_data *data)
 | |
| +{
 | |
| +	struct clk *clk;
 | |
| +	void __iomem *base = data->base;
 | |
| +	int i;
 | |
| +
 | |
| +	for (i = 0; i < nums; i++) {
 | |
| +		u32 mask = BIT(clks[i].width) - 1;
 | |
| +
 | |
| +		clk = clk_register_mux_table(NULL, clks[i].name,
 | |
| +					clks[i].parent_names,
 | |
| +					clks[i].num_parents, clks[i].flags,
 | |
| +					base + clks[i].offset, clks[i].shift,
 | |
| +					mask, clks[i].mux_flags,
 | |
| +					clks[i].table, &gk_clk_lock);
 | |
| +		if (IS_ERR(clk)) {
 | |
| +			pr_err("%s: failed to register clock %s\n",
 | |
| +			       __func__, clks[i].name);
 | |
| +			goto err;
 | |
| +		}
 | |
| +
 | |
| +		if (clks[i].alias)
 | |
| +			clk_register_clkdev(clk, clks[i].alias, NULL);
 | |
| +
 | |
| +		data->clk_data.clks[clks[i].id] = clk;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +
 | |
| +err:
 | |
| +	while (i--)
 | |
| +		clk_unregister_mux(data->clk_data.clks[clks[i].id]);
 | |
| +
 | |
| +	return PTR_ERR(clk);
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(gk_clk_register_mux);
 | |
| +
 | |
| +
 | |
| +int gk_clk_register_gate(const struct gk_gate_clock *clks,
 | |
| +				       int nums, struct gk_clock_data *data)
 | |
| +{
 | |
| +	struct clk *clk;
 | |
| +	void __iomem *base = data->base;
 | |
| +	int i;
 | |
| +
 | |
| +	for (i = 0; i < nums; i++) {
 | |
| +		clk = clk_register_gate(NULL, clks[i].name,
 | |
| +						clks[i].parent_name,
 | |
| +						clks[i].flags,
 | |
| +						base + clks[i].offset,
 | |
| +						clks[i].bit_idx,
 | |
| +						clks[i].gate_flags,
 | |
| +						&gk_clk_lock);
 | |
| +		if (IS_ERR(clk)) {
 | |
| +			pr_err("%s: failed to register clock %s\n",
 | |
| +			       __func__, clks[i].name);
 | |
| +			goto err;
 | |
| +		}
 | |
| +
 | |
| +		if (clks[i].alias)
 | |
| +			clk_register_clkdev(clk, clks[i].alias, NULL);
 | |
| +
 | |
| +		data->clk_data.clks[clks[i].id] = clk;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +
 | |
| +err:
 | |
| +	while (i--)
 | |
| +		clk_unregister_gate(data->clk_data.clks[clks[i].id]);
 | |
| +
 | |
| +	return PTR_ERR(clk);
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(gk_clk_register_gate); 
 | |
| \ No newline at end of file
 |