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 * 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 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 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 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 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 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 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