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 <claudiu.beznea@microchip.com>
8  */
9 
10 #include <common.h>
11 #include <clk-uclass.h>
12 #include <dm.h>
13 #include <dt-bindings/clk/at91.h>
14 #include <linux/clk-provider.h>
15 
16 #include "pmc.h"
17 
18 #define UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK	"at91-sam9x60-td-slck"
19 #define UBOOT_DM_CLK_AT91_SCKC			"at91-sckc"
20 
21 #define AT91_OSC_SEL		BIT(24)
22 #define AT91_OSC_SEL_SHIFT	(24)
23 
24 struct sam9x60_sckc {
25 	void __iomem *reg;
26 	const char **parent_names;
27 	unsigned int num_parents;
28 	struct clk clk;
29 };
30 
31 #define to_sam9x60_sckc(c)	container_of(c, struct sam9x60_sckc, clk)
32 
sam9x60_sckc_of_xlate(struct clk * clk,struct ofnode_phandle_args * args)33 static int sam9x60_sckc_of_xlate(struct clk *clk,
34 				 struct ofnode_phandle_args *args)
35 {
36 	if (args->args_count != 1) {
37 		debug("AT91: SCKC: Invalid args_count: %d\n", args->args_count);
38 		return -EINVAL;
39 	}
40 
41 	clk->id = AT91_TO_CLK_ID(PMC_TYPE_SLOW, args->args[0]);
42 
43 	return 0;
44 }
45 
46 static const struct clk_ops sam9x60_sckc_ops = {
47 	.of_xlate = sam9x60_sckc_of_xlate,
48 	.get_rate = clk_generic_get_rate,
49 };
50 
sam9x60_td_slck_set_parent(struct clk * clk,struct clk * parent)51 static int sam9x60_td_slck_set_parent(struct clk *clk, struct clk *parent)
52 {
53 	struct sam9x60_sckc *sckc = to_sam9x60_sckc(clk);
54 	u32 i;
55 
56 	for (i = 0; i < sckc->num_parents; i++) {
57 		if (!strcmp(parent->dev->name, sckc->parent_names[i]))
58 			break;
59 	}
60 	if (i == sckc->num_parents)
61 		return -EINVAL;
62 
63 	pmc_update_bits(sckc->reg, 0, AT91_OSC_SEL, (i << AT91_OSC_SEL_SHIFT));
64 
65 	return 0;
66 }
67 
68 static const struct clk_ops sam9x60_td_slck_ops = {
69 	.get_rate = clk_generic_get_rate,
70 	.set_parent = sam9x60_td_slck_set_parent,
71 };
72 
at91_sam9x60_clk_register_td_slck(struct sam9x60_sckc * sckc,const char * name,const char * const * parent_names,int num_parents)73 static struct clk *at91_sam9x60_clk_register_td_slck(struct sam9x60_sckc *sckc,
74 		const char *name, const char * const *parent_names,
75 		int num_parents)
76 {
77 	struct clk *clk;
78 	int ret = -ENOMEM;
79 	u32 val, i;
80 
81 	if (!sckc || !name || !parent_names || num_parents != 2)
82 		return ERR_PTR(-EINVAL);
83 
84 	sckc->parent_names = kzalloc(sizeof(*sckc->parent_names) * num_parents,
85 				     GFP_KERNEL);
86 	if (!sckc->parent_names)
87 		return ERR_PTR(ret);
88 
89 	for (i = 0; i < num_parents; i++) {
90 		sckc->parent_names[i] = kmemdup(parent_names[i],
91 				strlen(parent_names[i]) + 1, GFP_KERNEL);
92 		if (!sckc->parent_names[i])
93 			goto free;
94 	}
95 	sckc->num_parents = num_parents;
96 
97 	pmc_read(sckc->reg, 0, &val);
98 	val = (val & AT91_OSC_SEL) >> AT91_OSC_SEL_SHIFT;
99 
100 	clk = &sckc->clk;
101 	ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK, name,
102 			   parent_names[val]);
103 	if (ret)
104 		goto free;
105 
106 	return clk;
107 
108 free:
109 	for (; i >= 0; i--)
110 		kfree(sckc->parent_names[i]);
111 	kfree(sckc->parent_names);
112 
113 	return ERR_PTR(ret);
114 }
115 
116 U_BOOT_DRIVER(at91_sam9x60_td_slck) = {
117 	.name = UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK,
118 	.id = UCLASS_CLK,
119 	.ops = &sam9x60_td_slck_ops,
120 	.flags = DM_FLAG_PRE_RELOC,
121 };
122 
at91_sam9x60_sckc_probe(struct udevice * dev)123 static int at91_sam9x60_sckc_probe(struct udevice *dev)
124 {
125 	struct sam9x60_sckc *sckc = dev_get_priv(dev);
126 	void __iomem *base = (void *)devfdt_get_addr(dev);
127 	const char *slow_rc_osc, *slow_osc;
128 	const char *parents[2];
129 	struct clk *clk, c;
130 	int ret;
131 
132 	ret = clk_get_by_index(dev, 0, &c);
133 	if (ret)
134 		return ret;
135 	slow_rc_osc = clk_hw_get_name(&c);
136 
137 	ret = clk_get_by_index(dev, 1, &c);
138 	if (ret)
139 		return ret;
140 	slow_osc = clk_hw_get_name(&c);
141 
142 	clk = clk_register_fixed_factor(NULL, "md_slck", slow_rc_osc, 0, 1, 1);
143 	if (IS_ERR(clk))
144 		return PTR_ERR(clk);
145 	clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 0), clk);
146 
147 	parents[0] = slow_rc_osc;
148 	parents[1] = slow_osc;
149 	sckc[1].reg = base;
150 	clk = at91_sam9x60_clk_register_td_slck(&sckc[1], "td_slck",
151 						parents, 2);
152 	if (IS_ERR(clk))
153 		return PTR_ERR(clk);
154 	clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 1), clk);
155 
156 	return 0;
157 }
158 
159 static const struct udevice_id sam9x60_sckc_ids[] = {
160 	{ .compatible = "microchip,sam9x60-sckc" },
161 	{ /* Sentinel. */ },
162 };
163 
164 U_BOOT_DRIVER(at91_sckc) = {
165 	.name = UBOOT_DM_CLK_AT91_SCKC,
166 	.id = UCLASS_CLK,
167 	.of_match = sam9x60_sckc_ids,
168 	.priv_auto	= sizeof(struct sam9x60_sckc) * 2,
169 	.ops = &sam9x60_sckc_ops,
170 	.probe = at91_sam9x60_sckc_probe,
171 	.flags = DM_FLAG_PRE_RELOC,
172 };
173