112 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * clkgen-mux.c: ST GEN-MUX Clock driver4 *5 * Copyright (C) 2014 STMicroelectronics (R&D) Limited6 *7 * Authors: Stephen Gallimore <stephen.gallimore@st.com>8 * Pankaj Dev <pankaj.dev@st.com>9 */10 11#include <linux/slab.h>12#include <linux/io.h>13#include <linux/of_address.h>14#include <linux/clk.h>15#include <linux/clk-provider.h>16#include "clkgen.h"17 18static const char ** __init clkgen_mux_get_parents(struct device_node *np,19 int *num_parents)20{21 const char **parents;22 unsigned int nparents;23 24 nparents = of_clk_get_parent_count(np);25 if (WARN_ON(!nparents))26 return ERR_PTR(-EINVAL);27 28 parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL);29 if (!parents)30 return ERR_PTR(-ENOMEM);31 32 *num_parents = of_clk_parent_fill(np, parents, nparents);33 return parents;34}35 36struct clkgen_mux_data {37 u32 offset;38 u8 shift;39 u8 width;40 spinlock_t *lock;41 unsigned long clk_flags;42 u8 mux_flags;43};44 45static struct clkgen_mux_data stih407_a9_mux_data = {46 .offset = 0x1a4,47 .shift = 0,48 .width = 2,49 .lock = &clkgen_a9_lock,50};51 52static void __init st_of_clkgen_mux_setup(struct device_node *np,53 struct clkgen_mux_data *data)54{55 struct clk *clk;56 void __iomem *reg;57 const char **parents;58 int num_parents = 0;59 struct device_node *parent_np;60 61 /*62 * First check for reg property within the node to keep backward63 * compatibility, then if reg doesn't exist look at the parent node64 */65 reg = of_iomap(np, 0);66 if (!reg) {67 parent_np = of_get_parent(np);68 reg = of_iomap(parent_np, 0);69 of_node_put(parent_np);70 if (!reg) {71 pr_err("%s: Failed to get base address\n", __func__);72 return;73 }74 }75 76 parents = clkgen_mux_get_parents(np, &num_parents);77 if (IS_ERR(parents)) {78 pr_err("%s: Failed to get parents (%ld)\n",79 __func__, PTR_ERR(parents));80 goto err_parents;81 }82 83 clk = clk_register_mux(NULL, np->name, parents, num_parents,84 data->clk_flags | CLK_SET_RATE_PARENT,85 reg + data->offset,86 data->shift, data->width, data->mux_flags,87 data->lock);88 if (IS_ERR(clk))89 goto err;90 91 pr_debug("%s: parent %s rate %u\n",92 __clk_get_name(clk),93 __clk_get_name(clk_get_parent(clk)),94 (unsigned int)clk_get_rate(clk));95 96 kfree(parents);97 of_clk_add_provider(np, of_clk_src_simple_get, clk);98 return;99 100err:101 kfree(parents);102err_parents:103 iounmap(reg);104}105 106static void __init st_of_clkgen_a9_mux_setup(struct device_node *np)107{108 st_of_clkgen_mux_setup(np, &stih407_a9_mux_data);109}110CLK_OF_DECLARE(clkgen_a9mux, "st,stih407-clkgen-a9-mux",111 st_of_clkgen_a9_mux_setup);112