blob: 6d6f12578db7027ab6890335c181804fa0852096 [file] [log] [blame]
Claudiu Beznea731bddd2020-09-07 17:46:40 +03001// 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 <claudiu.beznea@microchip.com>
8 */
9
Claudiu Beznea731bddd2020-09-07 17:46:40 +030010#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
23struct 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
32static 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
45static const struct clk_ops sam9x60_sckc_ops = {
46 .of_xlate = sam9x60_sckc_of_xlate,
47 .get_rate = clk_generic_get_rate,
48};
49
50static 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
67static 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
72static 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
107free:
108 for (; i >= 0; i--)
109 kfree(sckc->parent_names[i]);
110 kfree(sckc->parent_names);
111
112 return ERR_PTR(ret);
113}
114
115U_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
122static int at91_sam9x60_sckc_probe(struct udevice *dev)
123{
124 struct sam9x60_sckc *sckc = dev_get_priv(dev);
Johan Jonker2f9f7752023-03-13 01:32:44 +0100125 void __iomem *base = devfdt_get_addr_ptr(dev);
Claudiu Beznea731bddd2020-09-07 17:46:40 +0300126 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
158static const struct udevice_id sam9x60_sckc_ids[] = {
159 { .compatible = "microchip,sam9x60-sckc" },
160 { /* Sentinel. */ },
161};
162
163U_BOOT_DRIVER(at91_sckc) = {
164 .name = UBOOT_DM_CLK_AT91_SCKC,
165 .id = UCLASS_CLK,
166 .of_match = sam9x60_sckc_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700167 .priv_auto = sizeof(struct sam9x60_sckc) * 2,
Claudiu Beznea731bddd2020-09-07 17:46:40 +0300168 .ops = &sam9x60_sckc_ops,
169 .probe = at91_sam9x60_sckc_probe,
170 .flags = DM_FLAG_PRE_RELOC,
171};