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