18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * clkgen-mux.c: ST GEN-MUX Clock driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 STMicroelectronics (R&D) Limited 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Stephen Gallimore <stephen.gallimore@st.com> 88c2ecf20Sopenharmony_ci * Pankaj Dev <pankaj.dev@st.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/of_address.h> 148c2ecf20Sopenharmony_ci#include <linux/clk.h> 158c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 168c2ecf20Sopenharmony_ci#include "clkgen.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic const char ** __init clkgen_mux_get_parents(struct device_node *np, 198c2ecf20Sopenharmony_ci int *num_parents) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci const char **parents; 228c2ecf20Sopenharmony_ci unsigned int nparents; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci nparents = of_clk_get_parent_count(np); 258c2ecf20Sopenharmony_ci if (WARN_ON(!nparents)) 268c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL); 298c2ecf20Sopenharmony_ci if (!parents) 308c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci *num_parents = of_clk_parent_fill(np, parents, nparents); 338c2ecf20Sopenharmony_ci return parents; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct clkgen_mux_data { 378c2ecf20Sopenharmony_ci u32 offset; 388c2ecf20Sopenharmony_ci u8 shift; 398c2ecf20Sopenharmony_ci u8 width; 408c2ecf20Sopenharmony_ci spinlock_t *lock; 418c2ecf20Sopenharmony_ci unsigned long clk_flags; 428c2ecf20Sopenharmony_ci u8 mux_flags; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic struct clkgen_mux_data stih407_a9_mux_data = { 468c2ecf20Sopenharmony_ci .offset = 0x1a4, 478c2ecf20Sopenharmony_ci .shift = 0, 488c2ecf20Sopenharmony_ci .width = 2, 498c2ecf20Sopenharmony_ci .lock = &clkgen_a9_lock, 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic void __init st_of_clkgen_mux_setup(struct device_node *np, 538c2ecf20Sopenharmony_ci struct clkgen_mux_data *data) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct clk *clk; 568c2ecf20Sopenharmony_ci void __iomem *reg; 578c2ecf20Sopenharmony_ci const char **parents; 588c2ecf20Sopenharmony_ci int num_parents = 0; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci reg = of_iomap(np, 0); 618c2ecf20Sopenharmony_ci if (!reg) { 628c2ecf20Sopenharmony_ci pr_err("%s: Failed to get base address\n", __func__); 638c2ecf20Sopenharmony_ci return; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci parents = clkgen_mux_get_parents(np, &num_parents); 678c2ecf20Sopenharmony_ci if (IS_ERR(parents)) { 688c2ecf20Sopenharmony_ci pr_err("%s: Failed to get parents (%ld)\n", 698c2ecf20Sopenharmony_ci __func__, PTR_ERR(parents)); 708c2ecf20Sopenharmony_ci goto err_parents; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci clk = clk_register_mux(NULL, np->name, parents, num_parents, 748c2ecf20Sopenharmony_ci data->clk_flags | CLK_SET_RATE_PARENT, 758c2ecf20Sopenharmony_ci reg + data->offset, 768c2ecf20Sopenharmony_ci data->shift, data->width, data->mux_flags, 778c2ecf20Sopenharmony_ci data->lock); 788c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 798c2ecf20Sopenharmony_ci goto err; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci pr_debug("%s: parent %s rate %u\n", 828c2ecf20Sopenharmony_ci __clk_get_name(clk), 838c2ecf20Sopenharmony_ci __clk_get_name(clk_get_parent(clk)), 848c2ecf20Sopenharmony_ci (unsigned int)clk_get_rate(clk)); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci kfree(parents); 878c2ecf20Sopenharmony_ci of_clk_add_provider(np, of_clk_src_simple_get, clk); 888c2ecf20Sopenharmony_ci return; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cierr: 918c2ecf20Sopenharmony_ci kfree(parents); 928c2ecf20Sopenharmony_cierr_parents: 938c2ecf20Sopenharmony_ci iounmap(reg); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void __init st_of_clkgen_a9_mux_setup(struct device_node *np) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci st_of_clkgen_mux_setup(np, &stih407_a9_mux_data); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ciCLK_OF_DECLARE(clkgen_a9mux, "st,stih407-clkgen-a9-mux", 1018c2ecf20Sopenharmony_ci st_of_clkgen_a9_mux_setup); 102