| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067 |
- // SPDX-License-Identifier: GPL-2.0
- #include <linux/clk-provider.h>
- #include <linux/clk/at91_pmc.h>
- #include <linux/of.h>
- #include <linux/mfd/syscon.h>
- #include <linux/regmap.h>
- #include <linux/slab.h>
- #include "pmc.h"
- #define MASTER_SOURCE_MAX 4
- #define PERIPHERAL_AT91RM9200 0
- #define PERIPHERAL_AT91SAM9X5 1
- #define PERIPHERAL_MAX 64
- #define PERIPHERAL_ID_MIN 2
- #define PROG_SOURCE_MAX 5
- #define PROG_ID_MAX 7
- #define SYSTEM_MAX_ID 31
- #define GCK_INDEX_DT_AUDIO_PLL 5
- static DEFINE_SPINLOCK(mck_lock);
- #ifdef CONFIG_HAVE_AT91_AUDIO_PLL
- static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *name = np->name;
- const char *parent_name;
- struct regmap *regmap;
- struct device_node *parent_np;
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- parent_name = of_clk_get_parent_name(np, 0);
- hw = at91_clk_register_audio_pll_frac(regmap, name, parent_name);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup,
- "atmel,sama5d2-clk-audio-pll-frac",
- of_sama5d2_clk_audio_pll_frac_setup);
- static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *name = np->name;
- const char *parent_name;
- struct regmap *regmap;
- struct device_node *parent_np;
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- parent_name = of_clk_get_parent_name(np, 0);
- hw = at91_clk_register_audio_pll_pad(regmap, name, parent_name);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup,
- "atmel,sama5d2-clk-audio-pll-pad",
- of_sama5d2_clk_audio_pll_pad_setup);
- static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *name = np->name;
- const char *parent_name;
- struct regmap *regmap;
- struct device_node *parent_np;
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- parent_name = of_clk_get_parent_name(np, 0);
- hw = at91_clk_register_audio_pll_pmc(regmap, name, parent_name);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
- "atmel,sama5d2-clk-audio-pll-pmc",
- of_sama5d2_clk_audio_pll_pmc_setup);
- #endif /* CONFIG_HAVE_AT91_AUDIO_PLL */
- static const struct clk_pcr_layout dt_pcr_layout = {
- .offset = 0x10c,
- .cmd = BIT(12),
- .pid_mask = GENMASK(5, 0),
- .div_mask = GENMASK(17, 16),
- .gckcss_mask = GENMASK(10, 8),
- };
- #ifdef CONFIG_HAVE_AT91_GENERATED_CLK
- #define GENERATED_SOURCE_MAX 6
- #define GCK_ID_I2S0 54
- #define GCK_ID_I2S1 55
- #define GCK_ID_CLASSD 59
- static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
- {
- int num;
- u32 id;
- const char *name;
- struct clk_hw *hw;
- unsigned int num_parents;
- const char *parent_names[GENERATED_SOURCE_MAX];
- struct device_node *gcknp, *parent_np;
- struct clk_range range = CLK_RANGE(0, 0);
- struct regmap *regmap;
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
- return;
- of_clk_parent_fill(np, parent_names, num_parents);
- num = of_get_child_count(np);
- if (!num || num > PERIPHERAL_MAX)
- return;
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- for_each_child_of_node(np, gcknp) {
- int chg_pid = INT_MIN;
- if (of_property_read_u32(gcknp, "reg", &id))
- continue;
- if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX)
- continue;
- if (of_property_read_string(np, "clock-output-names", &name))
- name = gcknp->name;
- of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
- &range);
- if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") &&
- (id == GCK_ID_I2S0 || id == GCK_ID_I2S1 ||
- id == GCK_ID_CLASSD))
- chg_pid = GCK_INDEX_DT_AUDIO_PLL;
- hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
- &dt_pcr_layout, name,
- parent_names, NULL, NULL,
- num_parents, id, &range,
- chg_pid);
- if (IS_ERR(hw))
- continue;
- of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw);
- }
- }
- CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
- of_sama5d2_clk_generated_setup);
- #endif /* CONFIG_HAVE_AT91_GENERATED_CLK */
- #ifdef CONFIG_HAVE_AT91_H32MX
- static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *name = np->name;
- const char *parent_name;
- struct regmap *regmap;
- struct device_node *parent_np;
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- parent_name = of_clk_get_parent_name(np, 0);
- hw = at91_clk_register_h32mx(regmap, name, parent_name);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
- of_sama5d4_clk_h32mx_setup);
- #endif /* CONFIG_HAVE_AT91_H32MX */
- #ifdef CONFIG_HAVE_AT91_I2S_MUX_CLK
- #define I2S_BUS_NR 2
- static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np)
- {
- struct regmap *regmap_sfr;
- u8 bus_id;
- const char *parent_names[2];
- struct device_node *i2s_mux_np;
- struct clk_hw *hw;
- int ret;
- regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
- if (IS_ERR(regmap_sfr))
- return;
- for_each_child_of_node(np, i2s_mux_np) {
- if (of_property_read_u8(i2s_mux_np, "reg", &bus_id))
- continue;
- if (bus_id > I2S_BUS_NR)
- continue;
- ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2);
- if (ret != 2)
- continue;
- hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name,
- parent_names, 2, bus_id);
- if (IS_ERR(hw))
- continue;
- of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw);
- }
- }
- CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux",
- of_sama5d2_clk_i2s_mux_setup);
- #endif /* CONFIG_HAVE_AT91_I2S_MUX_CLK */
- static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *name = np->name;
- const char *parent_name;
- struct regmap *regmap;
- bool bypass;
- struct device_node *parent_np;
- of_property_read_string(np, "clock-output-names", &name);
- bypass = of_property_read_bool(np, "atmel,osc-bypass");
- parent_name = of_clk_get_parent_name(np, 0);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- hw = at91_clk_register_main_osc(regmap, name, parent_name, NULL, bypass);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc",
- of_at91rm9200_clk_main_osc_setup);
- static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- u32 frequency = 0;
- u32 accuracy = 0;
- const char *name = np->name;
- struct regmap *regmap;
- struct device_node *parent_np;
- of_property_read_string(np, "clock-output-names", &name);
- of_property_read_u32(np, "clock-frequency", &frequency);
- of_property_read_u32(np, "clock-accuracy", &accuracy);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc",
- of_at91sam9x5_clk_main_rc_osc_setup);
- static void __init of_at91rm9200_clk_main_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *parent_name;
- const char *name = np->name;
- struct regmap *regmap;
- struct device_node *parent_np;
- parent_name = of_clk_get_parent_name(np, 0);
- of_property_read_string(np, "clock-output-names", &name);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- hw = at91_clk_register_rm9200_main(regmap, name, parent_name, NULL);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main",
- of_at91rm9200_clk_main_setup);
- static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *parent_names[2];
- unsigned int num_parents;
- const char *name = np->name;
- struct regmap *regmap;
- struct device_node *parent_np;
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > 2)
- return;
- of_clk_parent_fill(np, parent_names, num_parents);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- of_property_read_string(np, "clock-output-names", &name);
- hw = at91_clk_register_sam9x5_main(regmap, name, parent_names, NULL,
- num_parents);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
- of_at91sam9x5_clk_main_setup);
- static struct clk_master_characteristics * __init
- of_at91_clk_master_get_characteristics(struct device_node *np)
- {
- struct clk_master_characteristics *characteristics;
- characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
- if (!characteristics)
- return NULL;
- if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output))
- goto out_free_characteristics;
- of_property_read_u32_array(np, "atmel,clk-divisors",
- characteristics->divisors, 4);
- characteristics->have_div3_pres =
- of_property_read_bool(np, "atmel,master-clk-have-div3-pres");
- return characteristics;
- out_free_characteristics:
- kfree(characteristics);
- return NULL;
- }
- static void __init
- of_at91_clk_master_setup(struct device_node *np,
- const struct clk_master_layout *layout)
- {
- struct clk_hw *hw;
- unsigned int num_parents;
- const char *parent_names[MASTER_SOURCE_MAX];
- const char *name = np->name;
- struct clk_master_characteristics *characteristics;
- struct regmap *regmap;
- struct device_node *parent_np;
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > MASTER_SOURCE_MAX)
- return;
- of_clk_parent_fill(np, parent_names, num_parents);
- of_property_read_string(np, "clock-output-names", &name);
- characteristics = of_at91_clk_master_get_characteristics(np);
- if (!characteristics)
- return;
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- hw = at91_clk_register_master_pres(regmap, "masterck_pres", num_parents,
- parent_names, NULL, layout,
- characteristics, &mck_lock);
- if (IS_ERR(hw))
- goto out_free_characteristics;
- hw = at91_clk_register_master_div(regmap, name, "masterck_pres", NULL,
- layout, characteristics,
- &mck_lock, CLK_SET_RATE_GATE, 0);
- if (IS_ERR(hw))
- goto out_free_characteristics;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- return;
- out_free_characteristics:
- kfree(characteristics);
- }
- static void __init of_at91rm9200_clk_master_setup(struct device_node *np)
- {
- of_at91_clk_master_setup(np, &at91rm9200_master_layout);
- }
- CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master",
- of_at91rm9200_clk_master_setup);
- static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
- {
- of_at91_clk_master_setup(np, &at91sam9x5_master_layout);
- }
- CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master",
- of_at91sam9x5_clk_master_setup);
- static void __init
- of_at91_clk_periph_setup(struct device_node *np, u8 type)
- {
- int num;
- u32 id;
- struct clk_hw *hw;
- const char *parent_name;
- const char *name;
- struct device_node *periphclknp;
- struct regmap *regmap;
- struct device_node *parent_np;
- parent_name = of_clk_get_parent_name(np, 0);
- if (!parent_name)
- return;
- num = of_get_child_count(np);
- if (!num || num > PERIPHERAL_MAX)
- return;
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- for_each_child_of_node(np, periphclknp) {
- if (of_property_read_u32(periphclknp, "reg", &id))
- continue;
- if (id >= PERIPHERAL_MAX)
- continue;
- if (of_property_read_string(np, "clock-output-names", &name))
- name = periphclknp->name;
- if (type == PERIPHERAL_AT91RM9200) {
- hw = at91_clk_register_peripheral(regmap, name,
- parent_name, NULL, id);
- } else {
- struct clk_range range = CLK_RANGE(0, 0);
- unsigned long flags = 0;
- of_at91_get_clk_range(periphclknp,
- "atmel,clk-output-range",
- &range);
- /*
- * mpddr_clk feed DDR controller and is enabled by
- * bootloader thus we need to keep it enabled in case
- * there is no Linux consumer for it.
- */
- if (!strcmp(periphclknp->name, "mpddr_clk"))
- flags = CLK_IS_CRITICAL;
- hw = at91_clk_register_sam9x5_peripheral(regmap,
- &pmc_pcr_lock,
- &dt_pcr_layout,
- name,
- parent_name,
- NULL,
- id, &range,
- INT_MIN,
- flags);
- }
- if (IS_ERR(hw))
- continue;
- of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw);
- }
- }
- static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
- {
- of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
- }
- CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
- of_at91rm9200_clk_periph_setup);
- static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
- {
- of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
- }
- CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
- of_at91sam9x5_clk_periph_setup);
- static struct clk_pll_characteristics * __init
- of_at91_clk_pll_get_characteristics(struct device_node *np)
- {
- int i;
- int offset;
- u32 tmp;
- int num_output;
- u32 num_cells;
- struct clk_range input;
- struct clk_range *output;
- u8 *out = NULL;
- u16 *icpll = NULL;
- struct clk_pll_characteristics *characteristics;
- if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input))
- return NULL;
- if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells",
- &num_cells))
- return NULL;
- if (num_cells < 2 || num_cells > 4)
- return NULL;
- num_output = of_property_count_u32_elems(np, "atmel,pll-clk-output-ranges");
- if (num_output <= 0)
- return NULL;
- num_output /= num_cells;
- characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
- if (!characteristics)
- return NULL;
- output = kcalloc(num_output, sizeof(*output), GFP_KERNEL);
- if (!output)
- goto out_free_characteristics;
- if (num_cells > 2) {
- out = kcalloc(num_output, sizeof(*out), GFP_KERNEL);
- if (!out)
- goto out_free_output;
- }
- if (num_cells > 3) {
- icpll = kcalloc(num_output, sizeof(*icpll), GFP_KERNEL);
- if (!icpll)
- goto out_free_output;
- }
- for (i = 0; i < num_output; i++) {
- offset = i * num_cells;
- if (of_property_read_u32_index(np,
- "atmel,pll-clk-output-ranges",
- offset, &tmp))
- goto out_free_output;
- output[i].min = tmp;
- if (of_property_read_u32_index(np,
- "atmel,pll-clk-output-ranges",
- offset + 1, &tmp))
- goto out_free_output;
- output[i].max = tmp;
- if (num_cells == 2)
- continue;
- if (of_property_read_u32_index(np,
- "atmel,pll-clk-output-ranges",
- offset + 2, &tmp))
- goto out_free_output;
- out[i] = tmp;
- if (num_cells == 3)
- continue;
- if (of_property_read_u32_index(np,
- "atmel,pll-clk-output-ranges",
- offset + 3, &tmp))
- goto out_free_output;
- icpll[i] = tmp;
- }
- characteristics->input = input;
- characteristics->num_output = num_output;
- characteristics->output = output;
- characteristics->out = out;
- characteristics->icpll = icpll;
- return characteristics;
- out_free_output:
- kfree(icpll);
- kfree(out);
- kfree(output);
- out_free_characteristics:
- kfree(characteristics);
- return NULL;
- }
- static void __init
- of_at91_clk_pll_setup(struct device_node *np,
- const struct clk_pll_layout *layout)
- {
- u32 id;
- struct clk_hw *hw;
- struct regmap *regmap;
- const char *parent_name;
- const char *name = np->name;
- struct device_node *parent_np;
- struct clk_pll_characteristics *characteristics;
- if (of_property_read_u32(np, "reg", &id))
- return;
- parent_name = of_clk_get_parent_name(np, 0);
- of_property_read_string(np, "clock-output-names", &name);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- characteristics = of_at91_clk_pll_get_characteristics(np);
- if (!characteristics)
- return;
- hw = at91_clk_register_pll(regmap, name, parent_name, id, layout,
- characteristics);
- if (IS_ERR(hw))
- goto out_free_characteristics;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- return;
- out_free_characteristics:
- kfree(characteristics);
- }
- static void __init of_at91rm9200_clk_pll_setup(struct device_node *np)
- {
- of_at91_clk_pll_setup(np, &at91rm9200_pll_layout);
- }
- CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll",
- of_at91rm9200_clk_pll_setup);
- static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np)
- {
- of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout);
- }
- CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll",
- of_at91sam9g45_clk_pll_setup);
- static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np)
- {
- of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout);
- }
- CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb",
- of_at91sam9g20_clk_pllb_setup);
- static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
- {
- of_at91_clk_pll_setup(np, &sama5d3_pll_layout);
- }
- CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll",
- of_sama5d3_clk_pll_setup);
- static void __init
- of_at91sam9x5_clk_plldiv_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *parent_name;
- const char *name = np->name;
- struct regmap *regmap;
- struct device_node *parent_np;
- parent_name = of_clk_get_parent_name(np, 0);
- of_property_read_string(np, "clock-output-names", &name);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- hw = at91_clk_register_plldiv(regmap, name, parent_name);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
- of_at91sam9x5_clk_plldiv_setup);
- static void __init
- of_at91_clk_prog_setup(struct device_node *np,
- const struct clk_programmable_layout *layout,
- u32 *mux_table)
- {
- int num;
- u32 id;
- struct clk_hw *hw;
- unsigned int num_parents;
- const char *parent_names[PROG_SOURCE_MAX];
- const char *name;
- struct device_node *progclknp, *parent_np;
- struct regmap *regmap;
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > PROG_SOURCE_MAX)
- return;
- of_clk_parent_fill(np, parent_names, num_parents);
- num = of_get_child_count(np);
- if (!num || num > (PROG_ID_MAX + 1))
- return;
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- for_each_child_of_node(np, progclknp) {
- if (of_property_read_u32(progclknp, "reg", &id))
- continue;
- if (of_property_read_string(np, "clock-output-names", &name))
- name = progclknp->name;
- hw = at91_clk_register_programmable(regmap, name,
- parent_names, NULL, num_parents,
- id, layout, mux_table);
- if (IS_ERR(hw))
- continue;
- of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw);
- }
- }
- static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
- {
- of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout, NULL);
- }
- CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
- of_at91rm9200_clk_prog_setup);
- static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
- {
- of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout, NULL);
- }
- CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
- of_at91sam9g45_clk_prog_setup);
- static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
- {
- of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout, NULL);
- }
- CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
- of_at91sam9x5_clk_prog_setup);
- static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *parent_names[2];
- unsigned int num_parents;
- const char *name = np->name;
- struct regmap *regmap;
- struct device_node *parent_np;
- num_parents = of_clk_get_parent_count(np);
- if (num_parents != 2)
- return;
- of_clk_parent_fill(np, parent_names, num_parents);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- of_property_read_string(np, "clock-output-names", &name);
- hw = at91_clk_register_sam9260_slow(regmap, name, parent_names,
- num_parents);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
- of_at91sam9260_clk_slow_setup);
- #ifdef CONFIG_HAVE_AT91_SMD
- #define SMD_SOURCE_MAX 2
- static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- unsigned int num_parents;
- const char *parent_names[SMD_SOURCE_MAX];
- const char *name = np->name;
- struct regmap *regmap;
- struct device_node *parent_np;
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > SMD_SOURCE_MAX)
- return;
- of_clk_parent_fill(np, parent_names, num_parents);
- of_property_read_string(np, "clock-output-names", &name);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- hw = at91sam9x5_clk_register_smd(regmap, name, parent_names,
- num_parents);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd",
- of_at91sam9x5_clk_smd_setup);
- #endif /* CONFIG_HAVE_AT91_SMD */
- static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
- {
- int num;
- u32 id;
- struct clk_hw *hw;
- const char *name;
- struct device_node *sysclknp, *parent_np;
- const char *parent_name;
- struct regmap *regmap;
- num = of_get_child_count(np);
- if (num > (SYSTEM_MAX_ID + 1))
- return;
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- for_each_child_of_node(np, sysclknp) {
- unsigned long flags = 0;
- if (of_property_read_u32(sysclknp, "reg", &id))
- continue;
- if (of_property_read_string(np, "clock-output-names", &name))
- name = sysclknp->name;
- parent_name = of_clk_get_parent_name(sysclknp, 0);
- /*
- * ddrck feeds DDR controller and is enabled by bootloader thus
- * we need to keep it enabled in case there is no Linux consumer
- * for it.
- */
- if (!strcmp(sysclknp->name, "ddrck"))
- flags = CLK_IS_CRITICAL;
- hw = at91_clk_register_system(regmap, name, parent_name, NULL,
- id, flags);
- if (IS_ERR(hw))
- continue;
- of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw);
- }
- }
- CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
- of_at91rm9200_clk_sys_setup);
- #ifdef CONFIG_HAVE_AT91_USB_CLK
- #define USB_SOURCE_MAX 2
- static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- unsigned int num_parents;
- const char *parent_names[USB_SOURCE_MAX];
- const char *name = np->name;
- struct regmap *regmap;
- struct device_node *parent_np;
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > USB_SOURCE_MAX)
- return;
- of_clk_parent_fill(np, parent_names, num_parents);
- of_property_read_string(np, "clock-output-names", &name);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- hw = at91sam9x5_clk_register_usb(regmap, name, parent_names,
- num_parents);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb",
- of_at91sam9x5_clk_usb_setup);
- static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *parent_name;
- const char *name = np->name;
- struct regmap *regmap;
- struct device_node *parent_np;
- parent_name = of_clk_get_parent_name(np, 0);
- if (!parent_name)
- return;
- of_property_read_string(np, "clock-output-names", &name);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- hw = at91sam9n12_clk_register_usb(regmap, name, parent_name);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb",
- of_at91sam9n12_clk_usb_setup);
- static void __init of_at91rm9200_clk_usb_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *parent_name;
- const char *name = np->name;
- u32 divisors[4] = {0, 0, 0, 0};
- struct regmap *regmap;
- struct device_node *parent_np;
- parent_name = of_clk_get_parent_name(np, 0);
- if (!parent_name)
- return;
- of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4);
- if (!divisors[0])
- return;
- of_property_read_string(np, "clock-output-names", &name);
- parent_np = of_get_parent(np);
- regmap = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap))
- return;
- hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb",
- of_at91rm9200_clk_usb_setup);
- #endif /* CONFIG_HAVE_AT91_USB_CLK */
- #ifdef CONFIG_HAVE_AT91_UTMI
- static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
- {
- struct clk_hw *hw;
- const char *parent_name;
- const char *name = np->name;
- struct regmap *regmap_pmc, *regmap_sfr;
- struct device_node *parent_np;
- parent_name = of_clk_get_parent_name(np, 0);
- of_property_read_string(np, "clock-output-names", &name);
- parent_np = of_get_parent(np);
- regmap_pmc = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap_pmc))
- return;
- /*
- * If the device supports different mainck rates, this value has to be
- * set in the UTMI Clock Trimming register.
- * - 9x5: mainck supports several rates but it is indicated that a
- * 12 MHz is needed in case of USB.
- * - sama5d3 and sama5d2: mainck supports several rates. Configuring
- * the FREQ field of the UTMI Clock Trimming register is mandatory.
- * - sama5d4: mainck is at 12 MHz.
- *
- * We only need to retrieve sama5d3 or sama5d2 sfr regmap.
- */
- regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d3-sfr");
- if (IS_ERR(regmap_sfr)) {
- regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
- if (IS_ERR(regmap_sfr))
- regmap_sfr = NULL;
- }
- hw = at91_clk_register_utmi(regmap_pmc, regmap_sfr, name, parent_name, NULL);
- if (IS_ERR(hw))
- return;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- }
- CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
- of_at91sam9x5_clk_utmi_setup);
- #endif /* CONFIG_HAVE_AT91_UTMI */
|