xref: /openbmc/linux/drivers/clk/pistachio/clk.c (revision cb58e14efbc4d72542b9d62f5ee0522fe0147259)
18e4b7721SAndrew Bresticker /*
28e4b7721SAndrew Bresticker  * Copyright (C) 2014 Google, Inc.
38e4b7721SAndrew Bresticker  *
48e4b7721SAndrew Bresticker  * This program is free software; you can redistribute it and/or modify it
58e4b7721SAndrew Bresticker  * under the terms and conditions of the GNU General Public License,
68e4b7721SAndrew Bresticker  * version 2, as published by the Free Software Foundation.
78e4b7721SAndrew Bresticker  */
88e4b7721SAndrew Bresticker 
9*cb58e14eSStephen Boyd #include <linux/clk.h>
108e4b7721SAndrew Bresticker #include <linux/clk-provider.h>
118e4b7721SAndrew Bresticker #include <linux/kernel.h>
128e4b7721SAndrew Bresticker #include <linux/of.h>
138e4b7721SAndrew Bresticker #include <linux/of_address.h>
148e4b7721SAndrew Bresticker #include <linux/slab.h>
158e4b7721SAndrew Bresticker 
168e4b7721SAndrew Bresticker #include "clk.h"
178e4b7721SAndrew Bresticker 
188e4b7721SAndrew Bresticker struct pistachio_clk_provider *
198e4b7721SAndrew Bresticker pistachio_clk_alloc_provider(struct device_node *node, unsigned int num_clks)
208e4b7721SAndrew Bresticker {
218e4b7721SAndrew Bresticker 	struct pistachio_clk_provider *p;
228e4b7721SAndrew Bresticker 
238e4b7721SAndrew Bresticker 	p = kzalloc(sizeof(*p), GFP_KERNEL);
248e4b7721SAndrew Bresticker 	if (!p)
258e4b7721SAndrew Bresticker 		return p;
268e4b7721SAndrew Bresticker 
278e4b7721SAndrew Bresticker 	p->clk_data.clks = kcalloc(num_clks, sizeof(struct clk *), GFP_KERNEL);
288e4b7721SAndrew Bresticker 	if (!p->clk_data.clks)
298e4b7721SAndrew Bresticker 		goto free_provider;
308e4b7721SAndrew Bresticker 	p->clk_data.clk_num = num_clks;
318e4b7721SAndrew Bresticker 	p->node = node;
328e4b7721SAndrew Bresticker 	p->base = of_iomap(node, 0);
338e4b7721SAndrew Bresticker 	if (!p->base) {
348e4b7721SAndrew Bresticker 		pr_err("Failed to map clock provider registers\n");
358e4b7721SAndrew Bresticker 		goto free_clks;
368e4b7721SAndrew Bresticker 	}
378e4b7721SAndrew Bresticker 
388e4b7721SAndrew Bresticker 	return p;
398e4b7721SAndrew Bresticker 
408e4b7721SAndrew Bresticker free_clks:
418e4b7721SAndrew Bresticker 	kfree(p->clk_data.clks);
428e4b7721SAndrew Bresticker free_provider:
438e4b7721SAndrew Bresticker 	kfree(p);
448e4b7721SAndrew Bresticker 	return NULL;
458e4b7721SAndrew Bresticker }
468e4b7721SAndrew Bresticker 
478e4b7721SAndrew Bresticker void pistachio_clk_register_provider(struct pistachio_clk_provider *p)
488e4b7721SAndrew Bresticker {
498e4b7721SAndrew Bresticker 	unsigned int i;
508e4b7721SAndrew Bresticker 
518e4b7721SAndrew Bresticker 	for (i = 0; i < p->clk_data.clk_num; i++) {
528e4b7721SAndrew Bresticker 		if (IS_ERR(p->clk_data.clks[i]))
538e4b7721SAndrew Bresticker 			pr_warn("Failed to register clock %d: %ld\n", i,
548e4b7721SAndrew Bresticker 				PTR_ERR(p->clk_data.clks[i]));
558e4b7721SAndrew Bresticker 	}
568e4b7721SAndrew Bresticker 
578e4b7721SAndrew Bresticker 	of_clk_add_provider(p->node, of_clk_src_onecell_get, &p->clk_data);
588e4b7721SAndrew Bresticker }
598e4b7721SAndrew Bresticker 
608e4b7721SAndrew Bresticker void pistachio_clk_register_gate(struct pistachio_clk_provider *p,
618e4b7721SAndrew Bresticker 				 struct pistachio_gate *gate,
628e4b7721SAndrew Bresticker 				 unsigned int num)
638e4b7721SAndrew Bresticker {
648e4b7721SAndrew Bresticker 	struct clk *clk;
658e4b7721SAndrew Bresticker 	unsigned int i;
668e4b7721SAndrew Bresticker 
678e4b7721SAndrew Bresticker 	for (i = 0; i < num; i++) {
688e4b7721SAndrew Bresticker 		clk = clk_register_gate(NULL, gate[i].name, gate[i].parent,
698e4b7721SAndrew Bresticker 					CLK_SET_RATE_PARENT,
708e4b7721SAndrew Bresticker 					p->base + gate[i].reg, gate[i].shift,
718e4b7721SAndrew Bresticker 					0, NULL);
728e4b7721SAndrew Bresticker 		p->clk_data.clks[gate[i].id] = clk;
738e4b7721SAndrew Bresticker 	}
748e4b7721SAndrew Bresticker }
758e4b7721SAndrew Bresticker 
768e4b7721SAndrew Bresticker void pistachio_clk_register_mux(struct pistachio_clk_provider *p,
778e4b7721SAndrew Bresticker 				struct pistachio_mux *mux,
788e4b7721SAndrew Bresticker 				unsigned int num)
798e4b7721SAndrew Bresticker {
808e4b7721SAndrew Bresticker 	struct clk *clk;
818e4b7721SAndrew Bresticker 	unsigned int i;
828e4b7721SAndrew Bresticker 
838e4b7721SAndrew Bresticker 	for (i = 0; i < num; i++) {
848e4b7721SAndrew Bresticker 		clk = clk_register_mux(NULL, mux[i].name, mux[i].parents,
858e4b7721SAndrew Bresticker 				       mux[i].num_parents,
868e4b7721SAndrew Bresticker 				       CLK_SET_RATE_NO_REPARENT,
878e4b7721SAndrew Bresticker 				       p->base + mux[i].reg, mux[i].shift,
888e4b7721SAndrew Bresticker 				       get_count_order(mux[i].num_parents),
898e4b7721SAndrew Bresticker 				       0, NULL);
908e4b7721SAndrew Bresticker 		p->clk_data.clks[mux[i].id] = clk;
918e4b7721SAndrew Bresticker 	}
928e4b7721SAndrew Bresticker }
938e4b7721SAndrew Bresticker 
948e4b7721SAndrew Bresticker void pistachio_clk_register_div(struct pistachio_clk_provider *p,
958e4b7721SAndrew Bresticker 				struct pistachio_div *div,
968e4b7721SAndrew Bresticker 				unsigned int num)
978e4b7721SAndrew Bresticker {
988e4b7721SAndrew Bresticker 	struct clk *clk;
998e4b7721SAndrew Bresticker 	unsigned int i;
1008e4b7721SAndrew Bresticker 
1018e4b7721SAndrew Bresticker 	for (i = 0; i < num; i++) {
1028e4b7721SAndrew Bresticker 		clk = clk_register_divider(NULL, div[i].name, div[i].parent,
1038e4b7721SAndrew Bresticker 					   0, p->base + div[i].reg, 0,
1048e4b7721SAndrew Bresticker 					   div[i].width, div[i].div_flags,
1058e4b7721SAndrew Bresticker 					   NULL);
1068e4b7721SAndrew Bresticker 		p->clk_data.clks[div[i].id] = clk;
1078e4b7721SAndrew Bresticker 	}
1088e4b7721SAndrew Bresticker }
1098e4b7721SAndrew Bresticker 
1108e4b7721SAndrew Bresticker void pistachio_clk_register_fixed_factor(struct pistachio_clk_provider *p,
1118e4b7721SAndrew Bresticker 					 struct pistachio_fixed_factor *ff,
1128e4b7721SAndrew Bresticker 					 unsigned int num)
1138e4b7721SAndrew Bresticker {
1148e4b7721SAndrew Bresticker 	struct clk *clk;
1158e4b7721SAndrew Bresticker 	unsigned int i;
1168e4b7721SAndrew Bresticker 
1178e4b7721SAndrew Bresticker 	for (i = 0; i < num; i++) {
1188e4b7721SAndrew Bresticker 		clk = clk_register_fixed_factor(NULL, ff[i].name, ff[i].parent,
1198e4b7721SAndrew Bresticker 						0, 1, ff[i].div);
1208e4b7721SAndrew Bresticker 		p->clk_data.clks[ff[i].id] = clk;
1218e4b7721SAndrew Bresticker 	}
1228e4b7721SAndrew Bresticker }
1238e4b7721SAndrew Bresticker 
1248e4b7721SAndrew Bresticker void pistachio_clk_force_enable(struct pistachio_clk_provider *p,
1258e4b7721SAndrew Bresticker 				unsigned int *clk_ids, unsigned int num)
1268e4b7721SAndrew Bresticker {
1278e4b7721SAndrew Bresticker 	unsigned int i;
1288e4b7721SAndrew Bresticker 	int err;
1298e4b7721SAndrew Bresticker 
1308e4b7721SAndrew Bresticker 	for (i = 0; i < num; i++) {
1318e4b7721SAndrew Bresticker 		struct clk *clk = p->clk_data.clks[clk_ids[i]];
1328e4b7721SAndrew Bresticker 
1338e4b7721SAndrew Bresticker 		if (IS_ERR(clk))
1348e4b7721SAndrew Bresticker 			continue;
1358e4b7721SAndrew Bresticker 
1368e4b7721SAndrew Bresticker 		err = clk_prepare_enable(clk);
1378e4b7721SAndrew Bresticker 		if (err)
1388e4b7721SAndrew Bresticker 			pr_err("Failed to enable clock %s: %d\n",
1398e4b7721SAndrew Bresticker 			       __clk_get_name(clk), err);
1408e4b7721SAndrew Bresticker 	}
1418e4b7721SAndrew Bresticker }
142