diff options
-rw-r--r-- | drivers/clk/at91/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/at91/at91sam9rl.c | 171 |
2 files changed, 172 insertions, 1 deletions
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 78dc71d653de..0752def6271a 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile | |||
@@ -14,6 +14,6 @@ obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o | |||
14 | obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o | 14 | obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o |
15 | obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o | 15 | obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o |
16 | obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o | 16 | obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o |
17 | obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9x5.o | 17 | obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o |
18 | obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o | 18 | obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o |
19 | obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o | 19 | obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o |
diff --git a/drivers/clk/at91/at91sam9rl.c b/drivers/clk/at91/at91sam9rl.c new file mode 100644 index 000000000000..5aeef68b4bdd --- /dev/null +++ b/drivers/clk/at91/at91sam9rl.c | |||
@@ -0,0 +1,171 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <linux/clk-provider.h> | ||
3 | #include <linux/mfd/syscon.h> | ||
4 | #include <linux/slab.h> | ||
5 | |||
6 | #include <dt-bindings/clock/at91.h> | ||
7 | |||
8 | #include "pmc.h" | ||
9 | |||
10 | static const struct clk_master_characteristics sam9rl_mck_characteristics = { | ||
11 | .output = { .min = 0, .max = 94000000 }, | ||
12 | .divisors = { 1, 2, 4, 0 }, | ||
13 | }; | ||
14 | |||
15 | static u8 sam9rl_plla_out[] = { 0, 2 }; | ||
16 | |||
17 | static struct clk_range sam9rl_plla_outputs[] = { | ||
18 | { .min = 80000000, .max = 200000000 }, | ||
19 | { .min = 190000000, .max = 240000000 }, | ||
20 | }; | ||
21 | |||
22 | static const struct clk_pll_characteristics sam9rl_plla_characteristics = { | ||
23 | .input = { .min = 1000000, .max = 32000000 }, | ||
24 | .num_output = ARRAY_SIZE(sam9rl_plla_outputs), | ||
25 | .output = sam9rl_plla_outputs, | ||
26 | .out = sam9rl_plla_out, | ||
27 | }; | ||
28 | |||
29 | static const struct { | ||
30 | char *n; | ||
31 | char *p; | ||
32 | u8 id; | ||
33 | } at91sam9rl_systemck[] = { | ||
34 | { .n = "pck0", .p = "prog0", .id = 8 }, | ||
35 | { .n = "pck1", .p = "prog1", .id = 9 }, | ||
36 | }; | ||
37 | |||
38 | static const struct { | ||
39 | char *n; | ||
40 | u8 id; | ||
41 | } at91sam9rl_periphck[] = { | ||
42 | { .n = "pioA_clk", .id = 2, }, | ||
43 | { .n = "pioB_clk", .id = 3, }, | ||
44 | { .n = "pioC_clk", .id = 4, }, | ||
45 | { .n = "pioD_clk", .id = 5, }, | ||
46 | { .n = "usart0_clk", .id = 6, }, | ||
47 | { .n = "usart1_clk", .id = 7, }, | ||
48 | { .n = "usart2_clk", .id = 8, }, | ||
49 | { .n = "usart3_clk", .id = 9, }, | ||
50 | { .n = "mci0_clk", .id = 10, }, | ||
51 | { .n = "twi0_clk", .id = 11, }, | ||
52 | { .n = "twi1_clk", .id = 12, }, | ||
53 | { .n = "spi0_clk", .id = 13, }, | ||
54 | { .n = "ssc0_clk", .id = 14, }, | ||
55 | { .n = "ssc1_clk", .id = 15, }, | ||
56 | { .n = "tc0_clk", .id = 16, }, | ||
57 | { .n = "tc1_clk", .id = 17, }, | ||
58 | { .n = "tc2_clk", .id = 18, }, | ||
59 | { .n = "pwm_clk", .id = 19, }, | ||
60 | { .n = "adc_clk", .id = 20, }, | ||
61 | { .n = "dma0_clk", .id = 21, }, | ||
62 | { .n = "udphs_clk", .id = 22, }, | ||
63 | { .n = "lcd_clk", .id = 23, }, | ||
64 | }; | ||
65 | |||
66 | static void __init at91sam9rl_pmc_setup(struct device_node *np) | ||
67 | { | ||
68 | const char *slck_name, *mainxtal_name; | ||
69 | struct pmc_data *at91sam9rl_pmc; | ||
70 | const char *parent_names[6]; | ||
71 | struct regmap *regmap; | ||
72 | struct clk_hw *hw; | ||
73 | int i; | ||
74 | |||
75 | i = of_property_match_string(np, "clock-names", "slow_clk"); | ||
76 | if (i < 0) | ||
77 | return; | ||
78 | |||
79 | slck_name = of_clk_get_parent_name(np, i); | ||
80 | |||
81 | i = of_property_match_string(np, "clock-names", "main_xtal"); | ||
82 | if (i < 0) | ||
83 | return; | ||
84 | mainxtal_name = of_clk_get_parent_name(np, i); | ||
85 | |||
86 | regmap = syscon_node_to_regmap(np); | ||
87 | if (IS_ERR(regmap)) | ||
88 | return; | ||
89 | |||
90 | at91sam9rl_pmc = pmc_data_allocate(PMC_MAIN + 1, | ||
91 | nck(at91sam9rl_systemck), | ||
92 | nck(at91sam9rl_periphck), 0); | ||
93 | if (!at91sam9rl_pmc) | ||
94 | return; | ||
95 | |||
96 | hw = at91_clk_register_rm9200_main(regmap, "mainck", mainxtal_name); | ||
97 | if (IS_ERR(hw)) | ||
98 | goto err_free; | ||
99 | |||
100 | at91sam9rl_pmc->chws[PMC_MAIN] = hw; | ||
101 | |||
102 | hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, | ||
103 | &at91rm9200_pll_layout, | ||
104 | &sam9rl_plla_characteristics); | ||
105 | if (IS_ERR(hw)) | ||
106 | goto err_free; | ||
107 | |||
108 | hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck"); | ||
109 | if (IS_ERR(hw)) | ||
110 | goto err_free; | ||
111 | |||
112 | at91sam9rl_pmc->chws[PMC_UTMI] = hw; | ||
113 | |||
114 | parent_names[0] = slck_name; | ||
115 | parent_names[1] = "mainck"; | ||
116 | parent_names[2] = "pllack"; | ||
117 | parent_names[3] = "utmick"; | ||
118 | hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, | ||
119 | &at91rm9200_master_layout, | ||
120 | &sam9rl_mck_characteristics); | ||
121 | if (IS_ERR(hw)) | ||
122 | goto err_free; | ||
123 | |||
124 | at91sam9rl_pmc->chws[PMC_MCK] = hw; | ||
125 | |||
126 | parent_names[0] = slck_name; | ||
127 | parent_names[1] = "mainck"; | ||
128 | parent_names[2] = "pllack"; | ||
129 | parent_names[3] = "utmick"; | ||
130 | parent_names[4] = "masterck"; | ||
131 | for (i = 0; i < 2; i++) { | ||
132 | char name[6]; | ||
133 | |||
134 | snprintf(name, sizeof(name), "prog%d", i); | ||
135 | |||
136 | hw = at91_clk_register_programmable(regmap, name, | ||
137 | parent_names, 5, i, | ||
138 | &at91rm9200_programmable_layout); | ||
139 | if (IS_ERR(hw)) | ||
140 | goto err_free; | ||
141 | } | ||
142 | |||
143 | for (i = 0; i < ARRAY_SIZE(at91sam9rl_systemck); i++) { | ||
144 | hw = at91_clk_register_system(regmap, at91sam9rl_systemck[i].n, | ||
145 | at91sam9rl_systemck[i].p, | ||
146 | at91sam9rl_systemck[i].id); | ||
147 | if (IS_ERR(hw)) | ||
148 | goto err_free; | ||
149 | |||
150 | at91sam9rl_pmc->shws[at91sam9rl_systemck[i].id] = hw; | ||
151 | } | ||
152 | |||
153 | for (i = 0; i < ARRAY_SIZE(at91sam9rl_periphck); i++) { | ||
154 | hw = at91_clk_register_peripheral(regmap, | ||
155 | at91sam9rl_periphck[i].n, | ||
156 | "masterck", | ||
157 | at91sam9rl_periphck[i].id); | ||
158 | if (IS_ERR(hw)) | ||
159 | goto err_free; | ||
160 | |||
161 | at91sam9rl_pmc->phws[at91sam9rl_periphck[i].id] = hw; | ||
162 | } | ||
163 | |||
164 | of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9rl_pmc); | ||
165 | |||
166 | return; | ||
167 | |||
168 | err_free: | ||
169 | pmc_data_free(at91sam9rl_pmc); | ||
170 | } | ||
171 | CLK_OF_DECLARE_DRIVER(at91sam9rl_pmc, "atmel,at91sam9rl-pmc", at91sam9rl_pmc_setup); | ||