1/* 2 * Copyright (C) 2014 Google, Inc. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 */ 8 9#include <linux/clk.h> 10#include <linux/clk-provider.h> 11#include <linux/kernel.h> 12#include <linux/of.h> 13#include <linux/of_address.h> 14#include <linux/slab.h> 15 16#include "clk.h" 17 18struct pistachio_clk_provider * 19pistachio_clk_alloc_provider(struct device_node *node, unsigned int num_clks) 20{ 21 struct pistachio_clk_provider *p; 22 23 p = kzalloc(sizeof(*p), GFP_KERNEL); 24 if (!p) 25 return p; 26 27 p->clk_data.clks = kcalloc(num_clks, sizeof(struct clk *), GFP_KERNEL); 28 if (!p->clk_data.clks) 29 goto free_provider; 30 p->clk_data.clk_num = num_clks; 31 p->node = node; 32 p->base = of_iomap(node, 0); 33 if (!p->base) { 34 pr_err("Failed to map clock provider registers\n"); 35 goto free_clks; 36 } 37 38 return p; 39 40free_clks: 41 kfree(p->clk_data.clks); 42free_provider: 43 kfree(p); 44 return NULL; 45} 46 47void pistachio_clk_register_provider(struct pistachio_clk_provider *p) 48{ 49 unsigned int i; 50 51 for (i = 0; i < p->clk_data.clk_num; i++) { 52 if (IS_ERR(p->clk_data.clks[i])) 53 pr_warn("Failed to register clock %d: %ld\n", i, 54 PTR_ERR(p->clk_data.clks[i])); 55 } 56 57 of_clk_add_provider(p->node, of_clk_src_onecell_get, &p->clk_data); 58} 59 60void pistachio_clk_register_gate(struct pistachio_clk_provider *p, 61 struct pistachio_gate *gate, 62 unsigned int num) 63{ 64 struct clk *clk; 65 unsigned int i; 66 67 for (i = 0; i < num; i++) { 68 clk = clk_register_gate(NULL, gate[i].name, gate[i].parent, 69 CLK_SET_RATE_PARENT, 70 p->base + gate[i].reg, gate[i].shift, 71 0, NULL); 72 p->clk_data.clks[gate[i].id] = clk; 73 } 74} 75 76void pistachio_clk_register_mux(struct pistachio_clk_provider *p, 77 struct pistachio_mux *mux, 78 unsigned int num) 79{ 80 struct clk *clk; 81 unsigned int i; 82 83 for (i = 0; i < num; i++) { 84 clk = clk_register_mux(NULL, mux[i].name, mux[i].parents, 85 mux[i].num_parents, 86 CLK_SET_RATE_NO_REPARENT, 87 p->base + mux[i].reg, mux[i].shift, 88 get_count_order(mux[i].num_parents), 89 0, NULL); 90 p->clk_data.clks[mux[i].id] = clk; 91 } 92} 93 94void pistachio_clk_register_div(struct pistachio_clk_provider *p, 95 struct pistachio_div *div, 96 unsigned int num) 97{ 98 struct clk *clk; 99 unsigned int i; 100 101 for (i = 0; i < num; i++) { 102 clk = clk_register_divider(NULL, div[i].name, div[i].parent, 103 0, p->base + div[i].reg, 0, 104 div[i].width, div[i].div_flags, 105 NULL); 106 p->clk_data.clks[div[i].id] = clk; 107 } 108} 109 110void pistachio_clk_register_fixed_factor(struct pistachio_clk_provider *p, 111 struct pistachio_fixed_factor *ff, 112 unsigned int num) 113{ 114 struct clk *clk; 115 unsigned int i; 116 117 for (i = 0; i < num; i++) { 118 clk = clk_register_fixed_factor(NULL, ff[i].name, ff[i].parent, 119 0, 1, ff[i].div); 120 p->clk_data.clks[ff[i].id] = clk; 121 } 122} 123 124void pistachio_clk_force_enable(struct pistachio_clk_provider *p, 125 unsigned int *clk_ids, unsigned int num) 126{ 127 unsigned int i; 128 int err; 129 130 for (i = 0; i < num; i++) { 131 struct clk *clk = p->clk_data.clks[clk_ids[i]]; 132 133 if (IS_ERR(clk)) 134 continue; 135 136 err = clk_prepare_enable(clk); 137 if (err) 138 pr_err("Failed to enable clock %s: %d\n", 139 __clk_get_name(clk), err); 140 } 141} 142