1 /* 2 * clkgen-mux.c: ST GEN-MUX Clock driver 3 * 4 * Copyright (C) 2014 STMicroelectronics (R&D) Limited 5 * 6 * Authors: Stephen Gallimore <stephen.gallimore@st.com> 7 * Pankaj Dev <pankaj.dev@st.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 */ 15 16 #include <linux/slab.h> 17 #include <linux/io.h> 18 #include <linux/of_address.h> 19 #include <linux/clk.h> 20 #include <linux/clk-provider.h> 21 #include "clkgen.h" 22 23 static const char ** __init clkgen_mux_get_parents(struct device_node *np, 24 int *num_parents) 25 { 26 const char **parents; 27 unsigned int nparents; 28 29 nparents = of_clk_get_parent_count(np); 30 if (WARN_ON(!nparents)) 31 return ERR_PTR(-EINVAL); 32 33 parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL); 34 if (!parents) 35 return ERR_PTR(-ENOMEM); 36 37 *num_parents = of_clk_parent_fill(np, parents, nparents); 38 return parents; 39 } 40 41 struct clkgen_mux_data { 42 u32 offset; 43 u8 shift; 44 u8 width; 45 spinlock_t *lock; 46 unsigned long clk_flags; 47 u8 mux_flags; 48 }; 49 50 static struct clkgen_mux_data stih407_a9_mux_data = { 51 .offset = 0x1a4, 52 .shift = 0, 53 .width = 2, 54 .lock = &clkgen_a9_lock, 55 }; 56 57 static void __init st_of_clkgen_mux_setup(struct device_node *np, 58 struct clkgen_mux_data *data) 59 { 60 struct clk *clk; 61 void __iomem *reg; 62 const char **parents; 63 int num_parents = 0; 64 65 reg = of_iomap(np, 0); 66 if (!reg) { 67 pr_err("%s: Failed to get base address\n", __func__); 68 return; 69 } 70 71 parents = clkgen_mux_get_parents(np, &num_parents); 72 if (IS_ERR(parents)) { 73 pr_err("%s: Failed to get parents (%ld)\n", 74 __func__, PTR_ERR(parents)); 75 goto err_parents; 76 } 77 78 clk = clk_register_mux(NULL, np->name, parents, num_parents, 79 data->clk_flags | CLK_SET_RATE_PARENT, 80 reg + data->offset, 81 data->shift, data->width, data->mux_flags, 82 data->lock); 83 if (IS_ERR(clk)) 84 goto err; 85 86 pr_debug("%s: parent %s rate %u\n", 87 __clk_get_name(clk), 88 __clk_get_name(clk_get_parent(clk)), 89 (unsigned int)clk_get_rate(clk)); 90 91 kfree(parents); 92 of_clk_add_provider(np, of_clk_src_simple_get, clk); 93 return; 94 95 err: 96 kfree(parents); 97 err_parents: 98 iounmap(reg); 99 } 100 101 static void __init st_of_clkgen_a9_mux_setup(struct device_node *np) 102 { 103 st_of_clkgen_mux_setup(np, &stih407_a9_mux_data); 104 } 105 CLK_OF_DECLARE(clkgen_a9mux, "st,stih407-clkgen-a9-mux", 106 st_of_clkgen_a9_mux_setup); 107