1 // SPDX-License-Identifier: GPL-2.0+
3 * Slow clock support for AT91 architectures.
5 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
10 #include <clk-uclass.h>
12 #include <dt-bindings/clk/at91.h>
13 #include <linux/clk-provider.h>
17 #define UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK "at91-sam9x60-td-slck"
18 #define UBOOT_DM_CLK_AT91_SCKC "at91-sckc"
20 #define AT91_OSC_SEL BIT(24)
21 #define AT91_OSC_SEL_SHIFT (24)
25 const char **parent_names;
26 unsigned int num_parents;
30 #define to_sam9x60_sckc(c) container_of(c, struct sam9x60_sckc, clk)
32 static int sam9x60_sckc_of_xlate(struct clk *clk,
33 struct ofnode_phandle_args *args)
35 if (args->args_count != 1) {
36 debug("AT91: SCKC: Invalid args_count: %d\n", args->args_count);
40 clk->id = AT91_TO_CLK_ID(PMC_TYPE_SLOW, args->args[0]);
45 static const struct clk_ops sam9x60_sckc_ops = {
46 .of_xlate = sam9x60_sckc_of_xlate,
47 .get_rate = clk_generic_get_rate,
50 static int sam9x60_td_slck_set_parent(struct clk *clk, struct clk *parent)
52 struct sam9x60_sckc *sckc = to_sam9x60_sckc(clk);
55 for (i = 0; i < sckc->num_parents; i++) {
56 if (!strcmp(parent->dev->name, sckc->parent_names[i]))
59 if (i == sckc->num_parents)
62 pmc_update_bits(sckc->reg, 0, AT91_OSC_SEL, (i << AT91_OSC_SEL_SHIFT));
67 static const struct clk_ops sam9x60_td_slck_ops = {
68 .get_rate = clk_generic_get_rate,
69 .set_parent = sam9x60_td_slck_set_parent,
72 static struct clk *at91_sam9x60_clk_register_td_slck(struct sam9x60_sckc *sckc,
73 const char *name, const char * const *parent_names,
80 if (!sckc || !name || !parent_names || num_parents != 2)
81 return ERR_PTR(-EINVAL);
83 sckc->parent_names = kzalloc(sizeof(*sckc->parent_names) * num_parents,
85 if (!sckc->parent_names)
88 for (i = 0; i < num_parents; i++) {
89 sckc->parent_names[i] = kmemdup(parent_names[i],
90 strlen(parent_names[i]) + 1, GFP_KERNEL);
91 if (!sckc->parent_names[i])
94 sckc->num_parents = num_parents;
96 pmc_read(sckc->reg, 0, &val);
97 val = (val & AT91_OSC_SEL) >> AT91_OSC_SEL_SHIFT;
100 ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK, name,
109 kfree(sckc->parent_names[i]);
110 kfree(sckc->parent_names);
115 U_BOOT_DRIVER(at91_sam9x60_td_slck) = {
116 .name = UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK,
118 .ops = &sam9x60_td_slck_ops,
119 .flags = DM_FLAG_PRE_RELOC,
122 static int at91_sam9x60_sckc_probe(struct udevice *dev)
124 struct sam9x60_sckc *sckc = dev_get_priv(dev);
125 void __iomem *base = devfdt_get_addr_ptr(dev);
126 const char *slow_rc_osc, *slow_osc;
127 const char *parents[2];
131 ret = clk_get_by_index(dev, 0, &c);
134 slow_rc_osc = clk_hw_get_name(&c);
136 ret = clk_get_by_index(dev, 1, &c);
139 slow_osc = clk_hw_get_name(&c);
141 clk = clk_register_fixed_factor(NULL, "md_slck", slow_rc_osc, 0, 1, 1);
144 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 0), clk);
146 parents[0] = slow_rc_osc;
147 parents[1] = slow_osc;
149 clk = at91_sam9x60_clk_register_td_slck(&sckc[1], "td_slck",
153 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 1), clk);
158 static const struct udevice_id sam9x60_sckc_ids[] = {
159 { .compatible = "microchip,sam9x60-sckc" },
163 U_BOOT_DRIVER(at91_sckc) = {
164 .name = UBOOT_DM_CLK_AT91_SCKC,
166 .of_match = sam9x60_sckc_ids,
167 .priv_auto = sizeof(struct sam9x60_sckc) * 2,
168 .ops = &sam9x60_sckc_ops,
169 .probe = at91_sam9x60_sckc_probe,
170 .flags = DM_FLAG_PRE_RELOC,