162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2014 Google, Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/clk.h> 762306a36Sopenharmony_ci#include <linux/clk-provider.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/of.h> 1062306a36Sopenharmony_ci#include <linux/of_address.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "clk.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct pistachio_clk_provider * 1662306a36Sopenharmony_cipistachio_clk_alloc_provider(struct device_node *node, unsigned int num_clks) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci struct pistachio_clk_provider *p; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci p = kzalloc(sizeof(*p), GFP_KERNEL); 2162306a36Sopenharmony_ci if (!p) 2262306a36Sopenharmony_ci return p; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci p->clk_data.clks = kcalloc(num_clks, sizeof(struct clk *), GFP_KERNEL); 2562306a36Sopenharmony_ci if (!p->clk_data.clks) 2662306a36Sopenharmony_ci goto free_provider; 2762306a36Sopenharmony_ci p->clk_data.clk_num = num_clks; 2862306a36Sopenharmony_ci p->node = node; 2962306a36Sopenharmony_ci p->base = of_iomap(node, 0); 3062306a36Sopenharmony_ci if (!p->base) { 3162306a36Sopenharmony_ci pr_err("Failed to map clock provider registers\n"); 3262306a36Sopenharmony_ci goto free_clks; 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci return p; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cifree_clks: 3862306a36Sopenharmony_ci kfree(p->clk_data.clks); 3962306a36Sopenharmony_cifree_provider: 4062306a36Sopenharmony_ci kfree(p); 4162306a36Sopenharmony_ci return NULL; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_civoid pistachio_clk_register_provider(struct pistachio_clk_provider *p) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci unsigned int i; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci for (i = 0; i < p->clk_data.clk_num; i++) { 4962306a36Sopenharmony_ci if (IS_ERR(p->clk_data.clks[i])) 5062306a36Sopenharmony_ci pr_warn("Failed to register clock %d: %ld\n", i, 5162306a36Sopenharmony_ci PTR_ERR(p->clk_data.clks[i])); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci of_clk_add_provider(p->node, of_clk_src_onecell_get, &p->clk_data); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_civoid pistachio_clk_register_gate(struct pistachio_clk_provider *p, 5862306a36Sopenharmony_ci struct pistachio_gate *gate, 5962306a36Sopenharmony_ci unsigned int num) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct clk *clk; 6262306a36Sopenharmony_ci unsigned int i; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci for (i = 0; i < num; i++) { 6562306a36Sopenharmony_ci clk = clk_register_gate(NULL, gate[i].name, gate[i].parent, 6662306a36Sopenharmony_ci CLK_SET_RATE_PARENT, 6762306a36Sopenharmony_ci p->base + gate[i].reg, gate[i].shift, 6862306a36Sopenharmony_ci 0, NULL); 6962306a36Sopenharmony_ci p->clk_data.clks[gate[i].id] = clk; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_civoid pistachio_clk_register_mux(struct pistachio_clk_provider *p, 7462306a36Sopenharmony_ci struct pistachio_mux *mux, 7562306a36Sopenharmony_ci unsigned int num) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct clk *clk; 7862306a36Sopenharmony_ci unsigned int i; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci for (i = 0; i < num; i++) { 8162306a36Sopenharmony_ci clk = clk_register_mux(NULL, mux[i].name, mux[i].parents, 8262306a36Sopenharmony_ci mux[i].num_parents, 8362306a36Sopenharmony_ci CLK_SET_RATE_NO_REPARENT, 8462306a36Sopenharmony_ci p->base + mux[i].reg, mux[i].shift, 8562306a36Sopenharmony_ci get_count_order(mux[i].num_parents), 8662306a36Sopenharmony_ci 0, NULL); 8762306a36Sopenharmony_ci p->clk_data.clks[mux[i].id] = clk; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_civoid pistachio_clk_register_div(struct pistachio_clk_provider *p, 9262306a36Sopenharmony_ci struct pistachio_div *div, 9362306a36Sopenharmony_ci unsigned int num) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct clk *clk; 9662306a36Sopenharmony_ci unsigned int i; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci for (i = 0; i < num; i++) { 9962306a36Sopenharmony_ci clk = clk_register_divider(NULL, div[i].name, div[i].parent, 10062306a36Sopenharmony_ci 0, p->base + div[i].reg, 0, 10162306a36Sopenharmony_ci div[i].width, div[i].div_flags, 10262306a36Sopenharmony_ci NULL); 10362306a36Sopenharmony_ci p->clk_data.clks[div[i].id] = clk; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_civoid pistachio_clk_register_fixed_factor(struct pistachio_clk_provider *p, 10862306a36Sopenharmony_ci struct pistachio_fixed_factor *ff, 10962306a36Sopenharmony_ci unsigned int num) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct clk *clk; 11262306a36Sopenharmony_ci unsigned int i; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci for (i = 0; i < num; i++) { 11562306a36Sopenharmony_ci clk = clk_register_fixed_factor(NULL, ff[i].name, ff[i].parent, 11662306a36Sopenharmony_ci 0, 1, ff[i].div); 11762306a36Sopenharmony_ci p->clk_data.clks[ff[i].id] = clk; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_civoid pistachio_clk_force_enable(struct pistachio_clk_provider *p, 12262306a36Sopenharmony_ci unsigned int *clk_ids, unsigned int num) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci unsigned int i; 12562306a36Sopenharmony_ci int err; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci for (i = 0; i < num; i++) { 12862306a36Sopenharmony_ci struct clk *clk = p->clk_data.clks[clk_ids[i]]; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (IS_ERR(clk)) 13162306a36Sopenharmony_ci continue; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci err = clk_prepare_enable(clk); 13462306a36Sopenharmony_ci if (err) 13562306a36Sopenharmony_ci pr_err("Failed to enable clock %s: %d\n", 13662306a36Sopenharmony_ci __clk_get_name(clk), err); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci} 139