]> Git Repo - u-boot.git/blob - drivers/clk/at91/sckc.c
Merge branch '2024-05-06-remove-include-common_h' into next
[u-boot.git] / drivers / clk / at91 / sckc.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Slow clock support for AT91 architectures.
4  *
5  * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
6  *
7  * Author: Claudiu Beznea <[email protected]>
8  */
9
10 #include <clk-uclass.h>
11 #include <dm.h>
12 #include <dt-bindings/clk/at91.h>
13 #include <linux/clk-provider.h>
14
15 #include "pmc.h"
16
17 #define UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK       "at91-sam9x60-td-slck"
18 #define UBOOT_DM_CLK_AT91_SCKC                  "at91-sckc"
19
20 #define AT91_OSC_SEL            BIT(24)
21 #define AT91_OSC_SEL_SHIFT      (24)
22
23 struct sam9x60_sckc {
24         void __iomem *reg;
25         const char **parent_names;
26         unsigned int num_parents;
27         struct clk clk;
28 };
29
30 #define to_sam9x60_sckc(c)      container_of(c, struct sam9x60_sckc, clk)
31
32 static int sam9x60_sckc_of_xlate(struct clk *clk,
33                                  struct ofnode_phandle_args *args)
34 {
35         if (args->args_count != 1) {
36                 debug("AT91: SCKC: Invalid args_count: %d\n", args->args_count);
37                 return -EINVAL;
38         }
39
40         clk->id = AT91_TO_CLK_ID(PMC_TYPE_SLOW, args->args[0]);
41
42         return 0;
43 }
44
45 static const struct clk_ops sam9x60_sckc_ops = {
46         .of_xlate = sam9x60_sckc_of_xlate,
47         .get_rate = clk_generic_get_rate,
48 };
49
50 static int sam9x60_td_slck_set_parent(struct clk *clk, struct clk *parent)
51 {
52         struct sam9x60_sckc *sckc = to_sam9x60_sckc(clk);
53         u32 i;
54
55         for (i = 0; i < sckc->num_parents; i++) {
56                 if (!strcmp(parent->dev->name, sckc->parent_names[i]))
57                         break;
58         }
59         if (i == sckc->num_parents)
60                 return -EINVAL;
61
62         pmc_update_bits(sckc->reg, 0, AT91_OSC_SEL, (i << AT91_OSC_SEL_SHIFT));
63
64         return 0;
65 }
66
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,
70 };
71
72 static struct clk *at91_sam9x60_clk_register_td_slck(struct sam9x60_sckc *sckc,
73                 const char *name, const char * const *parent_names,
74                 int num_parents)
75 {
76         struct clk *clk;
77         int ret = -ENOMEM;
78         u32 val, i;
79
80         if (!sckc || !name || !parent_names || num_parents != 2)
81                 return ERR_PTR(-EINVAL);
82
83         sckc->parent_names = kzalloc(sizeof(*sckc->parent_names) * num_parents,
84                                      GFP_KERNEL);
85         if (!sckc->parent_names)
86                 return ERR_PTR(ret);
87
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])
92                         goto free;
93         }
94         sckc->num_parents = num_parents;
95
96         pmc_read(sckc->reg, 0, &val);
97         val = (val & AT91_OSC_SEL) >> AT91_OSC_SEL_SHIFT;
98
99         clk = &sckc->clk;
100         ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK, name,
101                            parent_names[val]);
102         if (ret)
103                 goto free;
104
105         return clk;
106
107 free:
108         for (; i >= 0; i--)
109                 kfree(sckc->parent_names[i]);
110         kfree(sckc->parent_names);
111
112         return ERR_PTR(ret);
113 }
114
115 U_BOOT_DRIVER(at91_sam9x60_td_slck) = {
116         .name = UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK,
117         .id = UCLASS_CLK,
118         .ops = &sam9x60_td_slck_ops,
119         .flags = DM_FLAG_PRE_RELOC,
120 };
121
122 static int at91_sam9x60_sckc_probe(struct udevice *dev)
123 {
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];
128         struct clk *clk, c;
129         int ret;
130
131         ret = clk_get_by_index(dev, 0, &c);
132         if (ret)
133                 return ret;
134         slow_rc_osc = clk_hw_get_name(&c);
135
136         ret = clk_get_by_index(dev, 1, &c);
137         if (ret)
138                 return ret;
139         slow_osc = clk_hw_get_name(&c);
140
141         clk = clk_register_fixed_factor(NULL, "md_slck", slow_rc_osc, 0, 1, 1);
142         if (IS_ERR(clk))
143                 return PTR_ERR(clk);
144         clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 0), clk);
145
146         parents[0] = slow_rc_osc;
147         parents[1] = slow_osc;
148         sckc[1].reg = base;
149         clk = at91_sam9x60_clk_register_td_slck(&sckc[1], "td_slck",
150                                                 parents, 2);
151         if (IS_ERR(clk))
152                 return PTR_ERR(clk);
153         clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 1), clk);
154
155         return 0;
156 }
157
158 static const struct udevice_id sam9x60_sckc_ids[] = {
159         { .compatible = "microchip,sam9x60-sckc" },
160         { /* Sentinel. */ },
161 };
162
163 U_BOOT_DRIVER(at91_sckc) = {
164         .name = UBOOT_DM_CLK_AT91_SCKC,
165         .id = UCLASS_CLK,
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,
171 };
This page took 0.03267 seconds and 4 git commands to generate.