162061d35SAlexandre Belloni // SPDX-License-Identifier: GPL-2.0 262061d35SAlexandre Belloni #include <linux/clk-provider.h> 362061d35SAlexandre Belloni #include <linux/clk/at91_pmc.h> 462061d35SAlexandre Belloni #include <linux/of.h> 562061d35SAlexandre Belloni #include <linux/mfd/syscon.h> 662061d35SAlexandre Belloni #include <linux/regmap.h> 762061d35SAlexandre Belloni #include <linux/slab.h> 862061d35SAlexandre Belloni 962061d35SAlexandre Belloni #include "pmc.h" 1062061d35SAlexandre Belloni 1162061d35SAlexandre Belloni #define MASTER_SOURCE_MAX 4 1262061d35SAlexandre Belloni 1362061d35SAlexandre Belloni #define PERIPHERAL_AT91RM9200 0 1462061d35SAlexandre Belloni #define PERIPHERAL_AT91SAM9X5 1 1562061d35SAlexandre Belloni 1662061d35SAlexandre Belloni #define PERIPHERAL_MAX 64 1762061d35SAlexandre Belloni 1862061d35SAlexandre Belloni #define PERIPHERAL_ID_MIN 2 1962061d35SAlexandre Belloni 2062061d35SAlexandre Belloni #define PROG_SOURCE_MAX 5 2162061d35SAlexandre Belloni #define PROG_ID_MAX 7 2262061d35SAlexandre Belloni 2362061d35SAlexandre Belloni #define SYSTEM_MAX_ID 31 2462061d35SAlexandre Belloni 2564c9247bSClaudiu Beznea #define GCK_INDEX_DT_AUDIO_PLL 5 2664c9247bSClaudiu Beznea 277a110b91SClaudiu Beznea static DEFINE_SPINLOCK(mck_lock); 287a110b91SClaudiu Beznea 2962061d35SAlexandre Belloni #ifdef CONFIG_HAVE_AT91_AUDIO_PLL 3062061d35SAlexandre Belloni static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np) 3162061d35SAlexandre Belloni { 3262061d35SAlexandre Belloni struct clk_hw *hw; 3362061d35SAlexandre Belloni const char *name = np->name; 3462061d35SAlexandre Belloni const char *parent_name; 3562061d35SAlexandre Belloni struct regmap *regmap; 36*b3ff02c5SLiang He struct device_node *parent_np; 3762061d35SAlexandre Belloni 38*b3ff02c5SLiang He parent_np = of_get_parent(np); 39*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 40*b3ff02c5SLiang He of_node_put(parent_np); 4162061d35SAlexandre Belloni if (IS_ERR(regmap)) 4262061d35SAlexandre Belloni return; 4362061d35SAlexandre Belloni 4462061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 4562061d35SAlexandre Belloni 4662061d35SAlexandre Belloni hw = at91_clk_register_audio_pll_frac(regmap, name, parent_name); 4762061d35SAlexandre Belloni if (IS_ERR(hw)) 4862061d35SAlexandre Belloni return; 4962061d35SAlexandre Belloni 5062061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 5162061d35SAlexandre Belloni } 5262061d35SAlexandre Belloni CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup, 5362061d35SAlexandre Belloni "atmel,sama5d2-clk-audio-pll-frac", 5462061d35SAlexandre Belloni of_sama5d2_clk_audio_pll_frac_setup); 5562061d35SAlexandre Belloni 5662061d35SAlexandre Belloni static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np) 5762061d35SAlexandre Belloni { 5862061d35SAlexandre Belloni struct clk_hw *hw; 5962061d35SAlexandre Belloni const char *name = np->name; 6062061d35SAlexandre Belloni const char *parent_name; 6162061d35SAlexandre Belloni struct regmap *regmap; 62*b3ff02c5SLiang He struct device_node *parent_np; 6362061d35SAlexandre Belloni 64*b3ff02c5SLiang He parent_np = of_get_parent(np); 65*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 66*b3ff02c5SLiang He of_node_put(parent_np); 6762061d35SAlexandre Belloni if (IS_ERR(regmap)) 6862061d35SAlexandre Belloni return; 6962061d35SAlexandre Belloni 7062061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 7162061d35SAlexandre Belloni 7262061d35SAlexandre Belloni hw = at91_clk_register_audio_pll_pad(regmap, name, parent_name); 7362061d35SAlexandre Belloni if (IS_ERR(hw)) 7462061d35SAlexandre Belloni return; 7562061d35SAlexandre Belloni 7662061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 7762061d35SAlexandre Belloni } 7862061d35SAlexandre Belloni CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup, 7962061d35SAlexandre Belloni "atmel,sama5d2-clk-audio-pll-pad", 8062061d35SAlexandre Belloni of_sama5d2_clk_audio_pll_pad_setup); 8162061d35SAlexandre Belloni 8262061d35SAlexandre Belloni static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np) 8362061d35SAlexandre Belloni { 8462061d35SAlexandre Belloni struct clk_hw *hw; 8562061d35SAlexandre Belloni const char *name = np->name; 8662061d35SAlexandre Belloni const char *parent_name; 8762061d35SAlexandre Belloni struct regmap *regmap; 88*b3ff02c5SLiang He struct device_node *parent_np; 8962061d35SAlexandre Belloni 90*b3ff02c5SLiang He parent_np = of_get_parent(np); 91*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 92*b3ff02c5SLiang He of_node_put(parent_np); 9362061d35SAlexandre Belloni if (IS_ERR(regmap)) 9462061d35SAlexandre Belloni return; 9562061d35SAlexandre Belloni 9662061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 9762061d35SAlexandre Belloni 9862061d35SAlexandre Belloni hw = at91_clk_register_audio_pll_pmc(regmap, name, parent_name); 9962061d35SAlexandre Belloni if (IS_ERR(hw)) 10062061d35SAlexandre Belloni return; 10162061d35SAlexandre Belloni 10262061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 10362061d35SAlexandre Belloni } 10462061d35SAlexandre Belloni CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup, 10562061d35SAlexandre Belloni "atmel,sama5d2-clk-audio-pll-pmc", 10662061d35SAlexandre Belloni of_sama5d2_clk_audio_pll_pmc_setup); 10762061d35SAlexandre Belloni #endif /* CONFIG_HAVE_AT91_AUDIO_PLL */ 10862061d35SAlexandre Belloni 109cb4f4949SAlexandre Belloni static const struct clk_pcr_layout dt_pcr_layout = { 110cb4f4949SAlexandre Belloni .offset = 0x10c, 111cb4f4949SAlexandre Belloni .cmd = BIT(12), 112cb4f4949SAlexandre Belloni .pid_mask = GENMASK(5, 0), 113cb4f4949SAlexandre Belloni .div_mask = GENMASK(17, 16), 114cb4f4949SAlexandre Belloni .gckcss_mask = GENMASK(10, 8), 115cb4f4949SAlexandre Belloni }; 116cb4f4949SAlexandre Belloni 11762061d35SAlexandre Belloni #ifdef CONFIG_HAVE_AT91_GENERATED_CLK 11862061d35SAlexandre Belloni #define GENERATED_SOURCE_MAX 6 11962061d35SAlexandre Belloni 12062061d35SAlexandre Belloni #define GCK_ID_I2S0 54 12162061d35SAlexandre Belloni #define GCK_ID_I2S1 55 12262061d35SAlexandre Belloni #define GCK_ID_CLASSD 59 12362061d35SAlexandre Belloni 12462061d35SAlexandre Belloni static void __init of_sama5d2_clk_generated_setup(struct device_node *np) 12562061d35SAlexandre Belloni { 12662061d35SAlexandre Belloni int num; 12762061d35SAlexandre Belloni u32 id; 12862061d35SAlexandre Belloni const char *name; 12962061d35SAlexandre Belloni struct clk_hw *hw; 13062061d35SAlexandre Belloni unsigned int num_parents; 13162061d35SAlexandre Belloni const char *parent_names[GENERATED_SOURCE_MAX]; 132*b3ff02c5SLiang He struct device_node *gcknp, *parent_np; 13362061d35SAlexandre Belloni struct clk_range range = CLK_RANGE(0, 0); 13462061d35SAlexandre Belloni struct regmap *regmap; 13562061d35SAlexandre Belloni 13662061d35SAlexandre Belloni num_parents = of_clk_get_parent_count(np); 13762061d35SAlexandre Belloni if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX) 13862061d35SAlexandre Belloni return; 13962061d35SAlexandre Belloni 14062061d35SAlexandre Belloni of_clk_parent_fill(np, parent_names, num_parents); 14162061d35SAlexandre Belloni 14262061d35SAlexandre Belloni num = of_get_child_count(np); 14362061d35SAlexandre Belloni if (!num || num > PERIPHERAL_MAX) 14462061d35SAlexandre Belloni return; 14562061d35SAlexandre Belloni 146*b3ff02c5SLiang He parent_np = of_get_parent(np); 147*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 148*b3ff02c5SLiang He of_node_put(parent_np); 14962061d35SAlexandre Belloni if (IS_ERR(regmap)) 15062061d35SAlexandre Belloni return; 15162061d35SAlexandre Belloni 15262061d35SAlexandre Belloni for_each_child_of_node(np, gcknp) { 15364c9247bSClaudiu Beznea int chg_pid = INT_MIN; 15462061d35SAlexandre Belloni 15562061d35SAlexandre Belloni if (of_property_read_u32(gcknp, "reg", &id)) 15662061d35SAlexandre Belloni continue; 15762061d35SAlexandre Belloni 15862061d35SAlexandre Belloni if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX) 15962061d35SAlexandre Belloni continue; 16062061d35SAlexandre Belloni 16162061d35SAlexandre Belloni if (of_property_read_string(np, "clock-output-names", &name)) 16262061d35SAlexandre Belloni name = gcknp->name; 16362061d35SAlexandre Belloni 16462061d35SAlexandre Belloni of_at91_get_clk_range(gcknp, "atmel,clk-output-range", 16562061d35SAlexandre Belloni &range); 16662061d35SAlexandre Belloni 16762061d35SAlexandre Belloni if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") && 16862061d35SAlexandre Belloni (id == GCK_ID_I2S0 || id == GCK_ID_I2S1 || 16962061d35SAlexandre Belloni id == GCK_ID_CLASSD)) 17064c9247bSClaudiu Beznea chg_pid = GCK_INDEX_DT_AUDIO_PLL; 17162061d35SAlexandre Belloni 172e4cfb823SAlexandre Belloni hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, 173e4cfb823SAlexandre Belloni &dt_pcr_layout, name, 17422a1dfe9SClaudiu Beznea parent_names, NULL, 17522a1dfe9SClaudiu Beznea num_parents, id, &range, 17622a1dfe9SClaudiu Beznea chg_pid); 17762061d35SAlexandre Belloni if (IS_ERR(hw)) 17862061d35SAlexandre Belloni continue; 17962061d35SAlexandre Belloni 18062061d35SAlexandre Belloni of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw); 18162061d35SAlexandre Belloni } 18262061d35SAlexandre Belloni } 18362061d35SAlexandre Belloni CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated", 18462061d35SAlexandre Belloni of_sama5d2_clk_generated_setup); 18562061d35SAlexandre Belloni #endif /* CONFIG_HAVE_AT91_GENERATED_CLK */ 18662061d35SAlexandre Belloni 18762061d35SAlexandre Belloni #ifdef CONFIG_HAVE_AT91_H32MX 18862061d35SAlexandre Belloni static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np) 18962061d35SAlexandre Belloni { 19062061d35SAlexandre Belloni struct clk_hw *hw; 19162061d35SAlexandre Belloni const char *name = np->name; 19262061d35SAlexandre Belloni const char *parent_name; 19362061d35SAlexandre Belloni struct regmap *regmap; 194*b3ff02c5SLiang He struct device_node *parent_np; 19562061d35SAlexandre Belloni 196*b3ff02c5SLiang He parent_np = of_get_parent(np); 197*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 198*b3ff02c5SLiang He of_node_put(parent_np); 19962061d35SAlexandre Belloni if (IS_ERR(regmap)) 20062061d35SAlexandre Belloni return; 20162061d35SAlexandre Belloni 20262061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 20362061d35SAlexandre Belloni 20462061d35SAlexandre Belloni hw = at91_clk_register_h32mx(regmap, name, parent_name); 20562061d35SAlexandre Belloni if (IS_ERR(hw)) 20662061d35SAlexandre Belloni return; 20762061d35SAlexandre Belloni 20862061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 20962061d35SAlexandre Belloni } 21062061d35SAlexandre Belloni CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx", 21162061d35SAlexandre Belloni of_sama5d4_clk_h32mx_setup); 21262061d35SAlexandre Belloni #endif /* CONFIG_HAVE_AT91_H32MX */ 21362061d35SAlexandre Belloni 21462061d35SAlexandre Belloni #ifdef CONFIG_HAVE_AT91_I2S_MUX_CLK 21562061d35SAlexandre Belloni #define I2S_BUS_NR 2 21662061d35SAlexandre Belloni 21762061d35SAlexandre Belloni static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np) 21862061d35SAlexandre Belloni { 21962061d35SAlexandre Belloni struct regmap *regmap_sfr; 22062061d35SAlexandre Belloni u8 bus_id; 22162061d35SAlexandre Belloni const char *parent_names[2]; 22262061d35SAlexandre Belloni struct device_node *i2s_mux_np; 22362061d35SAlexandre Belloni struct clk_hw *hw; 22462061d35SAlexandre Belloni int ret; 22562061d35SAlexandre Belloni 22662061d35SAlexandre Belloni regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); 22762061d35SAlexandre Belloni if (IS_ERR(regmap_sfr)) 22862061d35SAlexandre Belloni return; 22962061d35SAlexandre Belloni 23062061d35SAlexandre Belloni for_each_child_of_node(np, i2s_mux_np) { 23162061d35SAlexandre Belloni if (of_property_read_u8(i2s_mux_np, "reg", &bus_id)) 23262061d35SAlexandre Belloni continue; 23362061d35SAlexandre Belloni 23462061d35SAlexandre Belloni if (bus_id > I2S_BUS_NR) 23562061d35SAlexandre Belloni continue; 23662061d35SAlexandre Belloni 23762061d35SAlexandre Belloni ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2); 23862061d35SAlexandre Belloni if (ret != 2) 23962061d35SAlexandre Belloni continue; 24062061d35SAlexandre Belloni 24162061d35SAlexandre Belloni hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name, 24262061d35SAlexandre Belloni parent_names, 2, bus_id); 24362061d35SAlexandre Belloni if (IS_ERR(hw)) 24462061d35SAlexandre Belloni continue; 24562061d35SAlexandre Belloni 24662061d35SAlexandre Belloni of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw); 24762061d35SAlexandre Belloni } 24862061d35SAlexandre Belloni } 24962061d35SAlexandre Belloni CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux", 25062061d35SAlexandre Belloni of_sama5d2_clk_i2s_mux_setup); 25162061d35SAlexandre Belloni #endif /* CONFIG_HAVE_AT91_I2S_MUX_CLK */ 25262061d35SAlexandre Belloni 25362061d35SAlexandre Belloni static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np) 25462061d35SAlexandre Belloni { 25562061d35SAlexandre Belloni struct clk_hw *hw; 25662061d35SAlexandre Belloni const char *name = np->name; 25762061d35SAlexandre Belloni const char *parent_name; 25862061d35SAlexandre Belloni struct regmap *regmap; 25962061d35SAlexandre Belloni bool bypass; 260*b3ff02c5SLiang He struct device_node *parent_np; 26162061d35SAlexandre Belloni 26262061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 26362061d35SAlexandre Belloni bypass = of_property_read_bool(np, "atmel,osc-bypass"); 26462061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 26562061d35SAlexandre Belloni 266*b3ff02c5SLiang He parent_np = of_get_parent(np); 267*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 268*b3ff02c5SLiang He of_node_put(parent_np); 26962061d35SAlexandre Belloni if (IS_ERR(regmap)) 27062061d35SAlexandre Belloni return; 27162061d35SAlexandre Belloni 27262061d35SAlexandre Belloni hw = at91_clk_register_main_osc(regmap, name, parent_name, bypass); 27362061d35SAlexandre Belloni if (IS_ERR(hw)) 27462061d35SAlexandre Belloni return; 27562061d35SAlexandre Belloni 27662061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 27762061d35SAlexandre Belloni } 27862061d35SAlexandre Belloni CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc", 27962061d35SAlexandre Belloni of_at91rm9200_clk_main_osc_setup); 28062061d35SAlexandre Belloni 28162061d35SAlexandre Belloni static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np) 28262061d35SAlexandre Belloni { 28362061d35SAlexandre Belloni struct clk_hw *hw; 28462061d35SAlexandre Belloni u32 frequency = 0; 28562061d35SAlexandre Belloni u32 accuracy = 0; 28662061d35SAlexandre Belloni const char *name = np->name; 28762061d35SAlexandre Belloni struct regmap *regmap; 288*b3ff02c5SLiang He struct device_node *parent_np; 28962061d35SAlexandre Belloni 29062061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 29162061d35SAlexandre Belloni of_property_read_u32(np, "clock-frequency", &frequency); 29262061d35SAlexandre Belloni of_property_read_u32(np, "clock-accuracy", &accuracy); 29362061d35SAlexandre Belloni 294*b3ff02c5SLiang He parent_np = of_get_parent(np); 295*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 296*b3ff02c5SLiang He of_node_put(parent_np); 29762061d35SAlexandre Belloni if (IS_ERR(regmap)) 29862061d35SAlexandre Belloni return; 29962061d35SAlexandre Belloni 30062061d35SAlexandre Belloni hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy); 30162061d35SAlexandre Belloni if (IS_ERR(hw)) 30262061d35SAlexandre Belloni return; 30362061d35SAlexandre Belloni 30462061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 30562061d35SAlexandre Belloni } 30662061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc", 30762061d35SAlexandre Belloni of_at91sam9x5_clk_main_rc_osc_setup); 30862061d35SAlexandre Belloni 30962061d35SAlexandre Belloni static void __init of_at91rm9200_clk_main_setup(struct device_node *np) 31062061d35SAlexandre Belloni { 31162061d35SAlexandre Belloni struct clk_hw *hw; 31262061d35SAlexandre Belloni const char *parent_name; 31362061d35SAlexandre Belloni const char *name = np->name; 31462061d35SAlexandre Belloni struct regmap *regmap; 315*b3ff02c5SLiang He struct device_node *parent_np; 31662061d35SAlexandre Belloni 31762061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 31862061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 31962061d35SAlexandre Belloni 320*b3ff02c5SLiang He parent_np = of_get_parent(np); 321*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 322*b3ff02c5SLiang He of_node_put(parent_np); 32362061d35SAlexandre Belloni if (IS_ERR(regmap)) 32462061d35SAlexandre Belloni return; 32562061d35SAlexandre Belloni 32662061d35SAlexandre Belloni hw = at91_clk_register_rm9200_main(regmap, name, parent_name); 32762061d35SAlexandre Belloni if (IS_ERR(hw)) 32862061d35SAlexandre Belloni return; 32962061d35SAlexandre Belloni 33062061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 33162061d35SAlexandre Belloni } 33262061d35SAlexandre Belloni CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main", 33362061d35SAlexandre Belloni of_at91rm9200_clk_main_setup); 33462061d35SAlexandre Belloni 33562061d35SAlexandre Belloni static void __init of_at91sam9x5_clk_main_setup(struct device_node *np) 33662061d35SAlexandre Belloni { 33762061d35SAlexandre Belloni struct clk_hw *hw; 33862061d35SAlexandre Belloni const char *parent_names[2]; 33962061d35SAlexandre Belloni unsigned int num_parents; 34062061d35SAlexandre Belloni const char *name = np->name; 34162061d35SAlexandre Belloni struct regmap *regmap; 342*b3ff02c5SLiang He struct device_node *parent_np; 34362061d35SAlexandre Belloni 34462061d35SAlexandre Belloni num_parents = of_clk_get_parent_count(np); 34562061d35SAlexandre Belloni if (num_parents == 0 || num_parents > 2) 34662061d35SAlexandre Belloni return; 34762061d35SAlexandre Belloni 34862061d35SAlexandre Belloni of_clk_parent_fill(np, parent_names, num_parents); 349*b3ff02c5SLiang He parent_np = of_get_parent(np); 350*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 351*b3ff02c5SLiang He of_node_put(parent_np); 35262061d35SAlexandre Belloni if (IS_ERR(regmap)) 35362061d35SAlexandre Belloni return; 35462061d35SAlexandre Belloni 35562061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 35662061d35SAlexandre Belloni 35762061d35SAlexandre Belloni hw = at91_clk_register_sam9x5_main(regmap, name, parent_names, 35862061d35SAlexandre Belloni num_parents); 35962061d35SAlexandre Belloni if (IS_ERR(hw)) 36062061d35SAlexandre Belloni return; 36162061d35SAlexandre Belloni 36262061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 36362061d35SAlexandre Belloni } 36462061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main", 36562061d35SAlexandre Belloni of_at91sam9x5_clk_main_setup); 36662061d35SAlexandre Belloni 36762061d35SAlexandre Belloni static struct clk_master_characteristics * __init 36862061d35SAlexandre Belloni of_at91_clk_master_get_characteristics(struct device_node *np) 36962061d35SAlexandre Belloni { 37062061d35SAlexandre Belloni struct clk_master_characteristics *characteristics; 37162061d35SAlexandre Belloni 37262061d35SAlexandre Belloni characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); 37362061d35SAlexandre Belloni if (!characteristics) 37462061d35SAlexandre Belloni return NULL; 37562061d35SAlexandre Belloni 37662061d35SAlexandre Belloni if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output)) 37762061d35SAlexandre Belloni goto out_free_characteristics; 37862061d35SAlexandre Belloni 37962061d35SAlexandre Belloni of_property_read_u32_array(np, "atmel,clk-divisors", 38062061d35SAlexandre Belloni characteristics->divisors, 4); 38162061d35SAlexandre Belloni 38262061d35SAlexandre Belloni characteristics->have_div3_pres = 38362061d35SAlexandre Belloni of_property_read_bool(np, "atmel,master-clk-have-div3-pres"); 38462061d35SAlexandre Belloni 38562061d35SAlexandre Belloni return characteristics; 38662061d35SAlexandre Belloni 38762061d35SAlexandre Belloni out_free_characteristics: 38862061d35SAlexandre Belloni kfree(characteristics); 38962061d35SAlexandre Belloni return NULL; 39062061d35SAlexandre Belloni } 39162061d35SAlexandre Belloni 39262061d35SAlexandre Belloni static void __init 39362061d35SAlexandre Belloni of_at91_clk_master_setup(struct device_node *np, 39462061d35SAlexandre Belloni const struct clk_master_layout *layout) 39562061d35SAlexandre Belloni { 39662061d35SAlexandre Belloni struct clk_hw *hw; 39762061d35SAlexandre Belloni unsigned int num_parents; 39862061d35SAlexandre Belloni const char *parent_names[MASTER_SOURCE_MAX]; 39962061d35SAlexandre Belloni const char *name = np->name; 40062061d35SAlexandre Belloni struct clk_master_characteristics *characteristics; 40162061d35SAlexandre Belloni struct regmap *regmap; 402*b3ff02c5SLiang He struct device_node *parent_np; 40362061d35SAlexandre Belloni 40462061d35SAlexandre Belloni num_parents = of_clk_get_parent_count(np); 40562061d35SAlexandre Belloni if (num_parents == 0 || num_parents > MASTER_SOURCE_MAX) 40662061d35SAlexandre Belloni return; 40762061d35SAlexandre Belloni 40862061d35SAlexandre Belloni of_clk_parent_fill(np, parent_names, num_parents); 40962061d35SAlexandre Belloni 41062061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 41162061d35SAlexandre Belloni 41262061d35SAlexandre Belloni characteristics = of_at91_clk_master_get_characteristics(np); 41362061d35SAlexandre Belloni if (!characteristics) 41462061d35SAlexandre Belloni return; 41562061d35SAlexandre Belloni 416*b3ff02c5SLiang He parent_np = of_get_parent(np); 417*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 418*b3ff02c5SLiang He of_node_put(parent_np); 41962061d35SAlexandre Belloni if (IS_ERR(regmap)) 42062061d35SAlexandre Belloni return; 42162061d35SAlexandre Belloni 4227a110b91SClaudiu Beznea hw = at91_clk_register_master_pres(regmap, "masterck_pres", num_parents, 42362061d35SAlexandre Belloni parent_names, layout, 4248e842f02SClaudiu Beznea characteristics, &mck_lock); 4257a110b91SClaudiu Beznea if (IS_ERR(hw)) 4267a110b91SClaudiu Beznea goto out_free_characteristics; 4277a110b91SClaudiu Beznea 4287a110b91SClaudiu Beznea hw = at91_clk_register_master_div(regmap, name, "masterck_pres", 4297a110b91SClaudiu Beznea layout, characteristics, 4307029db09SClaudiu Beznea &mck_lock, CLK_SET_RATE_GATE, 0); 43162061d35SAlexandre Belloni if (IS_ERR(hw)) 43262061d35SAlexandre Belloni goto out_free_characteristics; 43362061d35SAlexandre Belloni 43462061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 43562061d35SAlexandre Belloni return; 43662061d35SAlexandre Belloni 43762061d35SAlexandre Belloni out_free_characteristics: 43862061d35SAlexandre Belloni kfree(characteristics); 43962061d35SAlexandre Belloni } 44062061d35SAlexandre Belloni 44162061d35SAlexandre Belloni static void __init of_at91rm9200_clk_master_setup(struct device_node *np) 44262061d35SAlexandre Belloni { 44362061d35SAlexandre Belloni of_at91_clk_master_setup(np, &at91rm9200_master_layout); 44462061d35SAlexandre Belloni } 44562061d35SAlexandre Belloni CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master", 44662061d35SAlexandre Belloni of_at91rm9200_clk_master_setup); 44762061d35SAlexandre Belloni 44862061d35SAlexandre Belloni static void __init of_at91sam9x5_clk_master_setup(struct device_node *np) 44962061d35SAlexandre Belloni { 45062061d35SAlexandre Belloni of_at91_clk_master_setup(np, &at91sam9x5_master_layout); 45162061d35SAlexandre Belloni } 45262061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master", 45362061d35SAlexandre Belloni of_at91sam9x5_clk_master_setup); 45462061d35SAlexandre Belloni 45562061d35SAlexandre Belloni static void __init 45662061d35SAlexandre Belloni of_at91_clk_periph_setup(struct device_node *np, u8 type) 45762061d35SAlexandre Belloni { 45862061d35SAlexandre Belloni int num; 45962061d35SAlexandre Belloni u32 id; 46062061d35SAlexandre Belloni struct clk_hw *hw; 46162061d35SAlexandre Belloni const char *parent_name; 46262061d35SAlexandre Belloni const char *name; 46362061d35SAlexandre Belloni struct device_node *periphclknp; 46462061d35SAlexandre Belloni struct regmap *regmap; 465*b3ff02c5SLiang He struct device_node *parent_np; 46662061d35SAlexandre Belloni 46762061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 46862061d35SAlexandre Belloni if (!parent_name) 46962061d35SAlexandre Belloni return; 47062061d35SAlexandre Belloni 47162061d35SAlexandre Belloni num = of_get_child_count(np); 47262061d35SAlexandre Belloni if (!num || num > PERIPHERAL_MAX) 47362061d35SAlexandre Belloni return; 47462061d35SAlexandre Belloni 475*b3ff02c5SLiang He parent_np = of_get_parent(np); 476*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 477*b3ff02c5SLiang He of_node_put(parent_np); 47862061d35SAlexandre Belloni if (IS_ERR(regmap)) 47962061d35SAlexandre Belloni return; 48062061d35SAlexandre Belloni 48162061d35SAlexandre Belloni for_each_child_of_node(np, periphclknp) { 48262061d35SAlexandre Belloni if (of_property_read_u32(periphclknp, "reg", &id)) 48362061d35SAlexandre Belloni continue; 48462061d35SAlexandre Belloni 48562061d35SAlexandre Belloni if (id >= PERIPHERAL_MAX) 48662061d35SAlexandre Belloni continue; 48762061d35SAlexandre Belloni 48862061d35SAlexandre Belloni if (of_property_read_string(np, "clock-output-names", &name)) 48962061d35SAlexandre Belloni name = periphclknp->name; 49062061d35SAlexandre Belloni 49162061d35SAlexandre Belloni if (type == PERIPHERAL_AT91RM9200) { 49262061d35SAlexandre Belloni hw = at91_clk_register_peripheral(regmap, name, 49362061d35SAlexandre Belloni parent_name, id); 49462061d35SAlexandre Belloni } else { 49562061d35SAlexandre Belloni struct clk_range range = CLK_RANGE(0, 0); 49662061d35SAlexandre Belloni 49762061d35SAlexandre Belloni of_at91_get_clk_range(periphclknp, 49862061d35SAlexandre Belloni "atmel,clk-output-range", 49962061d35SAlexandre Belloni &range); 50062061d35SAlexandre Belloni 50162061d35SAlexandre Belloni hw = at91_clk_register_sam9x5_peripheral(regmap, 50262061d35SAlexandre Belloni &pmc_pcr_lock, 503cb4f4949SAlexandre Belloni &dt_pcr_layout, 50462061d35SAlexandre Belloni name, 50562061d35SAlexandre Belloni parent_name, 506b4c115c7SClaudiu Beznea id, &range, 507b4c115c7SClaudiu Beznea INT_MIN); 50862061d35SAlexandre Belloni } 50962061d35SAlexandre Belloni 51062061d35SAlexandre Belloni if (IS_ERR(hw)) 51162061d35SAlexandre Belloni continue; 51262061d35SAlexandre Belloni 51362061d35SAlexandre Belloni of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw); 51462061d35SAlexandre Belloni } 51562061d35SAlexandre Belloni } 51662061d35SAlexandre Belloni 51762061d35SAlexandre Belloni static void __init of_at91rm9200_clk_periph_setup(struct device_node *np) 51862061d35SAlexandre Belloni { 51962061d35SAlexandre Belloni of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200); 52062061d35SAlexandre Belloni } 52162061d35SAlexandre Belloni CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral", 52262061d35SAlexandre Belloni of_at91rm9200_clk_periph_setup); 52362061d35SAlexandre Belloni 52462061d35SAlexandre Belloni static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np) 52562061d35SAlexandre Belloni { 52662061d35SAlexandre Belloni of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5); 52762061d35SAlexandre Belloni } 52862061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral", 52962061d35SAlexandre Belloni of_at91sam9x5_clk_periph_setup); 53062061d35SAlexandre Belloni 53162061d35SAlexandre Belloni static struct clk_pll_characteristics * __init 53262061d35SAlexandre Belloni of_at91_clk_pll_get_characteristics(struct device_node *np) 53362061d35SAlexandre Belloni { 53462061d35SAlexandre Belloni int i; 53562061d35SAlexandre Belloni int offset; 53662061d35SAlexandre Belloni u32 tmp; 53762061d35SAlexandre Belloni int num_output; 53862061d35SAlexandre Belloni u32 num_cells; 53962061d35SAlexandre Belloni struct clk_range input; 54062061d35SAlexandre Belloni struct clk_range *output; 54162061d35SAlexandre Belloni u8 *out = NULL; 54262061d35SAlexandre Belloni u16 *icpll = NULL; 54362061d35SAlexandre Belloni struct clk_pll_characteristics *characteristics; 54462061d35SAlexandre Belloni 54562061d35SAlexandre Belloni if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input)) 54662061d35SAlexandre Belloni return NULL; 54762061d35SAlexandre Belloni 54862061d35SAlexandre Belloni if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells", 54962061d35SAlexandre Belloni &num_cells)) 55062061d35SAlexandre Belloni return NULL; 55162061d35SAlexandre Belloni 55262061d35SAlexandre Belloni if (num_cells < 2 || num_cells > 4) 55362061d35SAlexandre Belloni return NULL; 55462061d35SAlexandre Belloni 55562061d35SAlexandre Belloni if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp)) 55662061d35SAlexandre Belloni return NULL; 55762061d35SAlexandre Belloni num_output = tmp / (sizeof(u32) * num_cells); 55862061d35SAlexandre Belloni 55962061d35SAlexandre Belloni characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); 56062061d35SAlexandre Belloni if (!characteristics) 56162061d35SAlexandre Belloni return NULL; 56262061d35SAlexandre Belloni 56362061d35SAlexandre Belloni output = kcalloc(num_output, sizeof(*output), GFP_KERNEL); 56462061d35SAlexandre Belloni if (!output) 56562061d35SAlexandre Belloni goto out_free_characteristics; 56662061d35SAlexandre Belloni 56762061d35SAlexandre Belloni if (num_cells > 2) { 56862061d35SAlexandre Belloni out = kcalloc(num_output, sizeof(*out), GFP_KERNEL); 56962061d35SAlexandre Belloni if (!out) 57062061d35SAlexandre Belloni goto out_free_output; 57162061d35SAlexandre Belloni } 57262061d35SAlexandre Belloni 57362061d35SAlexandre Belloni if (num_cells > 3) { 57462061d35SAlexandre Belloni icpll = kcalloc(num_output, sizeof(*icpll), GFP_KERNEL); 57562061d35SAlexandre Belloni if (!icpll) 57662061d35SAlexandre Belloni goto out_free_output; 57762061d35SAlexandre Belloni } 57862061d35SAlexandre Belloni 57962061d35SAlexandre Belloni for (i = 0; i < num_output; i++) { 58062061d35SAlexandre Belloni offset = i * num_cells; 58162061d35SAlexandre Belloni if (of_property_read_u32_index(np, 58262061d35SAlexandre Belloni "atmel,pll-clk-output-ranges", 58362061d35SAlexandre Belloni offset, &tmp)) 58462061d35SAlexandre Belloni goto out_free_output; 58562061d35SAlexandre Belloni output[i].min = tmp; 58662061d35SAlexandre Belloni if (of_property_read_u32_index(np, 58762061d35SAlexandre Belloni "atmel,pll-clk-output-ranges", 58862061d35SAlexandre Belloni offset + 1, &tmp)) 58962061d35SAlexandre Belloni goto out_free_output; 59062061d35SAlexandre Belloni output[i].max = tmp; 59162061d35SAlexandre Belloni 59262061d35SAlexandre Belloni if (num_cells == 2) 59362061d35SAlexandre Belloni continue; 59462061d35SAlexandre Belloni 59562061d35SAlexandre Belloni if (of_property_read_u32_index(np, 59662061d35SAlexandre Belloni "atmel,pll-clk-output-ranges", 59762061d35SAlexandre Belloni offset + 2, &tmp)) 59862061d35SAlexandre Belloni goto out_free_output; 59962061d35SAlexandre Belloni out[i] = tmp; 60062061d35SAlexandre Belloni 60162061d35SAlexandre Belloni if (num_cells == 3) 60262061d35SAlexandre Belloni continue; 60362061d35SAlexandre Belloni 60462061d35SAlexandre Belloni if (of_property_read_u32_index(np, 60562061d35SAlexandre Belloni "atmel,pll-clk-output-ranges", 60662061d35SAlexandre Belloni offset + 3, &tmp)) 60762061d35SAlexandre Belloni goto out_free_output; 60862061d35SAlexandre Belloni icpll[i] = tmp; 60962061d35SAlexandre Belloni } 61062061d35SAlexandre Belloni 61162061d35SAlexandre Belloni characteristics->input = input; 61262061d35SAlexandre Belloni characteristics->num_output = num_output; 61362061d35SAlexandre Belloni characteristics->output = output; 61462061d35SAlexandre Belloni characteristics->out = out; 61562061d35SAlexandre Belloni characteristics->icpll = icpll; 61662061d35SAlexandre Belloni return characteristics; 61762061d35SAlexandre Belloni 61862061d35SAlexandre Belloni out_free_output: 61962061d35SAlexandre Belloni kfree(icpll); 62062061d35SAlexandre Belloni kfree(out); 62162061d35SAlexandre Belloni kfree(output); 62262061d35SAlexandre Belloni out_free_characteristics: 62362061d35SAlexandre Belloni kfree(characteristics); 62462061d35SAlexandre Belloni return NULL; 62562061d35SAlexandre Belloni } 62662061d35SAlexandre Belloni 62762061d35SAlexandre Belloni static void __init 62862061d35SAlexandre Belloni of_at91_clk_pll_setup(struct device_node *np, 62962061d35SAlexandre Belloni const struct clk_pll_layout *layout) 63062061d35SAlexandre Belloni { 63162061d35SAlexandre Belloni u32 id; 63262061d35SAlexandre Belloni struct clk_hw *hw; 63362061d35SAlexandre Belloni struct regmap *regmap; 63462061d35SAlexandre Belloni const char *parent_name; 63562061d35SAlexandre Belloni const char *name = np->name; 636*b3ff02c5SLiang He struct device_node *parent_np; 63762061d35SAlexandre Belloni struct clk_pll_characteristics *characteristics; 63862061d35SAlexandre Belloni 63962061d35SAlexandre Belloni if (of_property_read_u32(np, "reg", &id)) 64062061d35SAlexandre Belloni return; 64162061d35SAlexandre Belloni 64262061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 64362061d35SAlexandre Belloni 64462061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 64562061d35SAlexandre Belloni 646*b3ff02c5SLiang He parent_np = of_get_parent(np); 647*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 648*b3ff02c5SLiang He of_node_put(parent_np); 64962061d35SAlexandre Belloni if (IS_ERR(regmap)) 65062061d35SAlexandre Belloni return; 65162061d35SAlexandre Belloni 65262061d35SAlexandre Belloni characteristics = of_at91_clk_pll_get_characteristics(np); 65362061d35SAlexandre Belloni if (!characteristics) 65462061d35SAlexandre Belloni return; 65562061d35SAlexandre Belloni 65662061d35SAlexandre Belloni hw = at91_clk_register_pll(regmap, name, parent_name, id, layout, 65762061d35SAlexandre Belloni characteristics); 65862061d35SAlexandre Belloni if (IS_ERR(hw)) 65962061d35SAlexandre Belloni goto out_free_characteristics; 66062061d35SAlexandre Belloni 66162061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 66262061d35SAlexandre Belloni return; 66362061d35SAlexandre Belloni 66462061d35SAlexandre Belloni out_free_characteristics: 66562061d35SAlexandre Belloni kfree(characteristics); 66662061d35SAlexandre Belloni } 66762061d35SAlexandre Belloni 66862061d35SAlexandre Belloni static void __init of_at91rm9200_clk_pll_setup(struct device_node *np) 66962061d35SAlexandre Belloni { 67062061d35SAlexandre Belloni of_at91_clk_pll_setup(np, &at91rm9200_pll_layout); 67162061d35SAlexandre Belloni } 67262061d35SAlexandre Belloni CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll", 67362061d35SAlexandre Belloni of_at91rm9200_clk_pll_setup); 67462061d35SAlexandre Belloni 67562061d35SAlexandre Belloni static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np) 67662061d35SAlexandre Belloni { 67762061d35SAlexandre Belloni of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout); 67862061d35SAlexandre Belloni } 67962061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll", 68062061d35SAlexandre Belloni of_at91sam9g45_clk_pll_setup); 68162061d35SAlexandre Belloni 68262061d35SAlexandre Belloni static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np) 68362061d35SAlexandre Belloni { 68462061d35SAlexandre Belloni of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout); 68562061d35SAlexandre Belloni } 68662061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb", 68762061d35SAlexandre Belloni of_at91sam9g20_clk_pllb_setup); 68862061d35SAlexandre Belloni 68962061d35SAlexandre Belloni static void __init of_sama5d3_clk_pll_setup(struct device_node *np) 69062061d35SAlexandre Belloni { 69162061d35SAlexandre Belloni of_at91_clk_pll_setup(np, &sama5d3_pll_layout); 69262061d35SAlexandre Belloni } 69362061d35SAlexandre Belloni CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll", 69462061d35SAlexandre Belloni of_sama5d3_clk_pll_setup); 69562061d35SAlexandre Belloni 69662061d35SAlexandre Belloni static void __init 69762061d35SAlexandre Belloni of_at91sam9x5_clk_plldiv_setup(struct device_node *np) 69862061d35SAlexandre Belloni { 69962061d35SAlexandre Belloni struct clk_hw *hw; 70062061d35SAlexandre Belloni const char *parent_name; 70162061d35SAlexandre Belloni const char *name = np->name; 70262061d35SAlexandre Belloni struct regmap *regmap; 703*b3ff02c5SLiang He struct device_node *parent_np; 70462061d35SAlexandre Belloni 70562061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 70662061d35SAlexandre Belloni 70762061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 70862061d35SAlexandre Belloni 709*b3ff02c5SLiang He parent_np = of_get_parent(np); 710*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 711*b3ff02c5SLiang He of_node_put(parent_np); 71262061d35SAlexandre Belloni if (IS_ERR(regmap)) 71362061d35SAlexandre Belloni return; 71462061d35SAlexandre Belloni 71562061d35SAlexandre Belloni hw = at91_clk_register_plldiv(regmap, name, parent_name); 71662061d35SAlexandre Belloni if (IS_ERR(hw)) 71762061d35SAlexandre Belloni return; 71862061d35SAlexandre Belloni 71962061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 72062061d35SAlexandre Belloni } 72162061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv", 72262061d35SAlexandre Belloni of_at91sam9x5_clk_plldiv_setup); 72362061d35SAlexandre Belloni 72462061d35SAlexandre Belloni static void __init 72562061d35SAlexandre Belloni of_at91_clk_prog_setup(struct device_node *np, 726c57aaaa2SClaudiu Beznea const struct clk_programmable_layout *layout, 727c57aaaa2SClaudiu Beznea u32 *mux_table) 72862061d35SAlexandre Belloni { 72962061d35SAlexandre Belloni int num; 73062061d35SAlexandre Belloni u32 id; 73162061d35SAlexandre Belloni struct clk_hw *hw; 73262061d35SAlexandre Belloni unsigned int num_parents; 73362061d35SAlexandre Belloni const char *parent_names[PROG_SOURCE_MAX]; 73462061d35SAlexandre Belloni const char *name; 735*b3ff02c5SLiang He struct device_node *progclknp, *parent_np; 73662061d35SAlexandre Belloni struct regmap *regmap; 73762061d35SAlexandre Belloni 73862061d35SAlexandre Belloni num_parents = of_clk_get_parent_count(np); 73962061d35SAlexandre Belloni if (num_parents == 0 || num_parents > PROG_SOURCE_MAX) 74062061d35SAlexandre Belloni return; 74162061d35SAlexandre Belloni 74262061d35SAlexandre Belloni of_clk_parent_fill(np, parent_names, num_parents); 74362061d35SAlexandre Belloni 74462061d35SAlexandre Belloni num = of_get_child_count(np); 74562061d35SAlexandre Belloni if (!num || num > (PROG_ID_MAX + 1)) 74662061d35SAlexandre Belloni return; 74762061d35SAlexandre Belloni 748*b3ff02c5SLiang He parent_np = of_get_parent(np); 749*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 750*b3ff02c5SLiang He of_node_put(parent_np); 75162061d35SAlexandre Belloni if (IS_ERR(regmap)) 75262061d35SAlexandre Belloni return; 75362061d35SAlexandre Belloni 75462061d35SAlexandre Belloni for_each_child_of_node(np, progclknp) { 75562061d35SAlexandre Belloni if (of_property_read_u32(progclknp, "reg", &id)) 75662061d35SAlexandre Belloni continue; 75762061d35SAlexandre Belloni 75862061d35SAlexandre Belloni if (of_property_read_string(np, "clock-output-names", &name)) 75962061d35SAlexandre Belloni name = progclknp->name; 76062061d35SAlexandre Belloni 76162061d35SAlexandre Belloni hw = at91_clk_register_programmable(regmap, name, 76262061d35SAlexandre Belloni parent_names, num_parents, 763c57aaaa2SClaudiu Beznea id, layout, mux_table); 76462061d35SAlexandre Belloni if (IS_ERR(hw)) 76562061d35SAlexandre Belloni continue; 76662061d35SAlexandre Belloni 76762061d35SAlexandre Belloni of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw); 76862061d35SAlexandre Belloni } 76962061d35SAlexandre Belloni } 77062061d35SAlexandre Belloni 77162061d35SAlexandre Belloni static void __init of_at91rm9200_clk_prog_setup(struct device_node *np) 77262061d35SAlexandre Belloni { 773c57aaaa2SClaudiu Beznea of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout, NULL); 77462061d35SAlexandre Belloni } 77562061d35SAlexandre Belloni CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable", 77662061d35SAlexandre Belloni of_at91rm9200_clk_prog_setup); 77762061d35SAlexandre Belloni 77862061d35SAlexandre Belloni static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np) 77962061d35SAlexandre Belloni { 780c57aaaa2SClaudiu Beznea of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout, NULL); 78162061d35SAlexandre Belloni } 78262061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable", 78362061d35SAlexandre Belloni of_at91sam9g45_clk_prog_setup); 78462061d35SAlexandre Belloni 78562061d35SAlexandre Belloni static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np) 78662061d35SAlexandre Belloni { 787c57aaaa2SClaudiu Beznea of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout, NULL); 78862061d35SAlexandre Belloni } 78962061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable", 79062061d35SAlexandre Belloni of_at91sam9x5_clk_prog_setup); 79162061d35SAlexandre Belloni 79262061d35SAlexandre Belloni static void __init of_at91sam9260_clk_slow_setup(struct device_node *np) 79362061d35SAlexandre Belloni { 79462061d35SAlexandre Belloni struct clk_hw *hw; 79562061d35SAlexandre Belloni const char *parent_names[2]; 79662061d35SAlexandre Belloni unsigned int num_parents; 79762061d35SAlexandre Belloni const char *name = np->name; 79862061d35SAlexandre Belloni struct regmap *regmap; 799*b3ff02c5SLiang He struct device_node *parent_np; 80062061d35SAlexandre Belloni 80162061d35SAlexandre Belloni num_parents = of_clk_get_parent_count(np); 80262061d35SAlexandre Belloni if (num_parents != 2) 80362061d35SAlexandre Belloni return; 80462061d35SAlexandre Belloni 80562061d35SAlexandre Belloni of_clk_parent_fill(np, parent_names, num_parents); 806*b3ff02c5SLiang He parent_np = of_get_parent(np); 807*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 808*b3ff02c5SLiang He of_node_put(parent_np); 80962061d35SAlexandre Belloni if (IS_ERR(regmap)) 81062061d35SAlexandre Belloni return; 81162061d35SAlexandre Belloni 81262061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 81362061d35SAlexandre Belloni 81462061d35SAlexandre Belloni hw = at91_clk_register_sam9260_slow(regmap, name, parent_names, 81562061d35SAlexandre Belloni num_parents); 81662061d35SAlexandre Belloni if (IS_ERR(hw)) 81762061d35SAlexandre Belloni return; 81862061d35SAlexandre Belloni 81962061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 82062061d35SAlexandre Belloni } 82162061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow", 82262061d35SAlexandre Belloni of_at91sam9260_clk_slow_setup); 82362061d35SAlexandre Belloni 82462061d35SAlexandre Belloni #ifdef CONFIG_HAVE_AT91_SMD 82562061d35SAlexandre Belloni #define SMD_SOURCE_MAX 2 82662061d35SAlexandre Belloni 82762061d35SAlexandre Belloni static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np) 82862061d35SAlexandre Belloni { 82962061d35SAlexandre Belloni struct clk_hw *hw; 83062061d35SAlexandre Belloni unsigned int num_parents; 83162061d35SAlexandre Belloni const char *parent_names[SMD_SOURCE_MAX]; 83262061d35SAlexandre Belloni const char *name = np->name; 83362061d35SAlexandre Belloni struct regmap *regmap; 834*b3ff02c5SLiang He struct device_node *parent_np; 83562061d35SAlexandre Belloni 83662061d35SAlexandre Belloni num_parents = of_clk_get_parent_count(np); 83762061d35SAlexandre Belloni if (num_parents == 0 || num_parents > SMD_SOURCE_MAX) 83862061d35SAlexandre Belloni return; 83962061d35SAlexandre Belloni 84062061d35SAlexandre Belloni of_clk_parent_fill(np, parent_names, num_parents); 84162061d35SAlexandre Belloni 84262061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 84362061d35SAlexandre Belloni 844*b3ff02c5SLiang He parent_np = of_get_parent(np); 845*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 846*b3ff02c5SLiang He of_node_put(parent_np); 84762061d35SAlexandre Belloni if (IS_ERR(regmap)) 84862061d35SAlexandre Belloni return; 84962061d35SAlexandre Belloni 85062061d35SAlexandre Belloni hw = at91sam9x5_clk_register_smd(regmap, name, parent_names, 85162061d35SAlexandre Belloni num_parents); 85262061d35SAlexandre Belloni if (IS_ERR(hw)) 85362061d35SAlexandre Belloni return; 85462061d35SAlexandre Belloni 85562061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 85662061d35SAlexandre Belloni } 85762061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd", 85862061d35SAlexandre Belloni of_at91sam9x5_clk_smd_setup); 85962061d35SAlexandre Belloni #endif /* CONFIG_HAVE_AT91_SMD */ 86062061d35SAlexandre Belloni 86162061d35SAlexandre Belloni static void __init of_at91rm9200_clk_sys_setup(struct device_node *np) 86262061d35SAlexandre Belloni { 86362061d35SAlexandre Belloni int num; 86462061d35SAlexandre Belloni u32 id; 86562061d35SAlexandre Belloni struct clk_hw *hw; 86662061d35SAlexandre Belloni const char *name; 867*b3ff02c5SLiang He struct device_node *sysclknp, *parent_np; 86862061d35SAlexandre Belloni const char *parent_name; 86962061d35SAlexandre Belloni struct regmap *regmap; 87062061d35SAlexandre Belloni 87162061d35SAlexandre Belloni num = of_get_child_count(np); 87262061d35SAlexandre Belloni if (num > (SYSTEM_MAX_ID + 1)) 87362061d35SAlexandre Belloni return; 87462061d35SAlexandre Belloni 875*b3ff02c5SLiang He parent_np = of_get_parent(np); 876*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 877*b3ff02c5SLiang He of_node_put(parent_np); 87862061d35SAlexandre Belloni if (IS_ERR(regmap)) 87962061d35SAlexandre Belloni return; 88062061d35SAlexandre Belloni 88162061d35SAlexandre Belloni for_each_child_of_node(np, sysclknp) { 88262061d35SAlexandre Belloni if (of_property_read_u32(sysclknp, "reg", &id)) 88362061d35SAlexandre Belloni continue; 88462061d35SAlexandre Belloni 88562061d35SAlexandre Belloni if (of_property_read_string(np, "clock-output-names", &name)) 88662061d35SAlexandre Belloni name = sysclknp->name; 88762061d35SAlexandre Belloni 88862061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(sysclknp, 0); 88962061d35SAlexandre Belloni 89062061d35SAlexandre Belloni hw = at91_clk_register_system(regmap, name, parent_name, id); 89162061d35SAlexandre Belloni if (IS_ERR(hw)) 89262061d35SAlexandre Belloni continue; 89362061d35SAlexandre Belloni 89462061d35SAlexandre Belloni of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw); 89562061d35SAlexandre Belloni } 89662061d35SAlexandre Belloni } 89762061d35SAlexandre Belloni CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system", 89862061d35SAlexandre Belloni of_at91rm9200_clk_sys_setup); 89962061d35SAlexandre Belloni 90062061d35SAlexandre Belloni #ifdef CONFIG_HAVE_AT91_USB_CLK 90162061d35SAlexandre Belloni #define USB_SOURCE_MAX 2 90262061d35SAlexandre Belloni 90362061d35SAlexandre Belloni static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np) 90462061d35SAlexandre Belloni { 90562061d35SAlexandre Belloni struct clk_hw *hw; 90662061d35SAlexandre Belloni unsigned int num_parents; 90762061d35SAlexandre Belloni const char *parent_names[USB_SOURCE_MAX]; 90862061d35SAlexandre Belloni const char *name = np->name; 90962061d35SAlexandre Belloni struct regmap *regmap; 910*b3ff02c5SLiang He struct device_node *parent_np; 91162061d35SAlexandre Belloni 91262061d35SAlexandre Belloni num_parents = of_clk_get_parent_count(np); 91362061d35SAlexandre Belloni if (num_parents == 0 || num_parents > USB_SOURCE_MAX) 91462061d35SAlexandre Belloni return; 91562061d35SAlexandre Belloni 91662061d35SAlexandre Belloni of_clk_parent_fill(np, parent_names, num_parents); 91762061d35SAlexandre Belloni 91862061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 91962061d35SAlexandre Belloni 920*b3ff02c5SLiang He parent_np = of_get_parent(np); 921*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 922*b3ff02c5SLiang He of_node_put(parent_np); 92362061d35SAlexandre Belloni if (IS_ERR(regmap)) 92462061d35SAlexandre Belloni return; 92562061d35SAlexandre Belloni 92662061d35SAlexandre Belloni hw = at91sam9x5_clk_register_usb(regmap, name, parent_names, 92762061d35SAlexandre Belloni num_parents); 92862061d35SAlexandre Belloni if (IS_ERR(hw)) 92962061d35SAlexandre Belloni return; 93062061d35SAlexandre Belloni 93162061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 93262061d35SAlexandre Belloni } 93362061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb", 93462061d35SAlexandre Belloni of_at91sam9x5_clk_usb_setup); 93562061d35SAlexandre Belloni 93662061d35SAlexandre Belloni static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np) 93762061d35SAlexandre Belloni { 93862061d35SAlexandre Belloni struct clk_hw *hw; 93962061d35SAlexandre Belloni const char *parent_name; 94062061d35SAlexandre Belloni const char *name = np->name; 94162061d35SAlexandre Belloni struct regmap *regmap; 942*b3ff02c5SLiang He struct device_node *parent_np; 94362061d35SAlexandre Belloni 94462061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 94562061d35SAlexandre Belloni if (!parent_name) 94662061d35SAlexandre Belloni return; 94762061d35SAlexandre Belloni 94862061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 94962061d35SAlexandre Belloni 950*b3ff02c5SLiang He parent_np = of_get_parent(np); 951*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 952*b3ff02c5SLiang He of_node_put(parent_np); 95362061d35SAlexandre Belloni if (IS_ERR(regmap)) 95462061d35SAlexandre Belloni return; 95562061d35SAlexandre Belloni 95662061d35SAlexandre Belloni hw = at91sam9n12_clk_register_usb(regmap, name, parent_name); 95762061d35SAlexandre Belloni if (IS_ERR(hw)) 95862061d35SAlexandre Belloni return; 95962061d35SAlexandre Belloni 96062061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 96162061d35SAlexandre Belloni } 96262061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb", 96362061d35SAlexandre Belloni of_at91sam9n12_clk_usb_setup); 96462061d35SAlexandre Belloni 96562061d35SAlexandre Belloni static void __init of_at91rm9200_clk_usb_setup(struct device_node *np) 96662061d35SAlexandre Belloni { 96762061d35SAlexandre Belloni struct clk_hw *hw; 96862061d35SAlexandre Belloni const char *parent_name; 96962061d35SAlexandre Belloni const char *name = np->name; 97062061d35SAlexandre Belloni u32 divisors[4] = {0, 0, 0, 0}; 97162061d35SAlexandre Belloni struct regmap *regmap; 972*b3ff02c5SLiang He struct device_node *parent_np; 97362061d35SAlexandre Belloni 97462061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 97562061d35SAlexandre Belloni if (!parent_name) 97662061d35SAlexandre Belloni return; 97762061d35SAlexandre Belloni 97862061d35SAlexandre Belloni of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4); 97962061d35SAlexandre Belloni if (!divisors[0]) 98062061d35SAlexandre Belloni return; 98162061d35SAlexandre Belloni 98262061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 98362061d35SAlexandre Belloni 984*b3ff02c5SLiang He parent_np = of_get_parent(np); 985*b3ff02c5SLiang He regmap = syscon_node_to_regmap(parent_np); 986*b3ff02c5SLiang He of_node_put(parent_np); 98762061d35SAlexandre Belloni if (IS_ERR(regmap)) 98862061d35SAlexandre Belloni return; 98962061d35SAlexandre Belloni hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors); 99062061d35SAlexandre Belloni if (IS_ERR(hw)) 99162061d35SAlexandre Belloni return; 99262061d35SAlexandre Belloni 99362061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 99462061d35SAlexandre Belloni } 99562061d35SAlexandre Belloni CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb", 99662061d35SAlexandre Belloni of_at91rm9200_clk_usb_setup); 99762061d35SAlexandre Belloni #endif /* CONFIG_HAVE_AT91_USB_CLK */ 99862061d35SAlexandre Belloni 99962061d35SAlexandre Belloni #ifdef CONFIG_HAVE_AT91_UTMI 100062061d35SAlexandre Belloni static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np) 100162061d35SAlexandre Belloni { 100262061d35SAlexandre Belloni struct clk_hw *hw; 100362061d35SAlexandre Belloni const char *parent_name; 100462061d35SAlexandre Belloni const char *name = np->name; 100562061d35SAlexandre Belloni struct regmap *regmap_pmc, *regmap_sfr; 1006*b3ff02c5SLiang He struct device_node *parent_np; 100762061d35SAlexandre Belloni 100862061d35SAlexandre Belloni parent_name = of_clk_get_parent_name(np, 0); 100962061d35SAlexandre Belloni 101062061d35SAlexandre Belloni of_property_read_string(np, "clock-output-names", &name); 101162061d35SAlexandre Belloni 1012*b3ff02c5SLiang He parent_np = of_get_parent(np); 1013*b3ff02c5SLiang He regmap_pmc = syscon_node_to_regmap(parent_np); 1014*b3ff02c5SLiang He of_node_put(parent_np); 101562061d35SAlexandre Belloni if (IS_ERR(regmap_pmc)) 101662061d35SAlexandre Belloni return; 101762061d35SAlexandre Belloni 101862061d35SAlexandre Belloni /* 101962061d35SAlexandre Belloni * If the device supports different mainck rates, this value has to be 102062061d35SAlexandre Belloni * set in the UTMI Clock Trimming register. 102162061d35SAlexandre Belloni * - 9x5: mainck supports several rates but it is indicated that a 102262061d35SAlexandre Belloni * 12 MHz is needed in case of USB. 102362061d35SAlexandre Belloni * - sama5d3 and sama5d2: mainck supports several rates. Configuring 102462061d35SAlexandre Belloni * the FREQ field of the UTMI Clock Trimming register is mandatory. 102562061d35SAlexandre Belloni * - sama5d4: mainck is at 12 MHz. 102662061d35SAlexandre Belloni * 102762061d35SAlexandre Belloni * We only need to retrieve sama5d3 or sama5d2 sfr regmap. 102862061d35SAlexandre Belloni */ 102962061d35SAlexandre Belloni regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d3-sfr"); 103062061d35SAlexandre Belloni if (IS_ERR(regmap_sfr)) { 103162061d35SAlexandre Belloni regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); 103262061d35SAlexandre Belloni if (IS_ERR(regmap_sfr)) 103362061d35SAlexandre Belloni regmap_sfr = NULL; 103462061d35SAlexandre Belloni } 103562061d35SAlexandre Belloni 103662061d35SAlexandre Belloni hw = at91_clk_register_utmi(regmap_pmc, regmap_sfr, name, parent_name); 103762061d35SAlexandre Belloni if (IS_ERR(hw)) 103862061d35SAlexandre Belloni return; 103962061d35SAlexandre Belloni 104062061d35SAlexandre Belloni of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 104162061d35SAlexandre Belloni } 104262061d35SAlexandre Belloni CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi", 104362061d35SAlexandre Belloni of_at91sam9x5_clk_utmi_setup); 104462061d35SAlexandre Belloni #endif /* CONFIG_HAVE_AT91_UTMI */ 1045