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