12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
238d34c31SBoris BREZILLON /*
338d34c31SBoris BREZILLON * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
438d34c31SBoris BREZILLON */
538d34c31SBoris BREZILLON
638d34c31SBoris BREZILLON #include <linux/clk-provider.h>
738d34c31SBoris BREZILLON #include <linux/clkdev.h>
838d34c31SBoris BREZILLON #include <linux/clk/at91_pmc.h>
938d34c31SBoris BREZILLON #include <linux/delay.h>
101bdf0232SBoris Brezillon #include <linux/mfd/syscon.h>
111bdf0232SBoris Brezillon #include <linux/regmap.h>
1238d34c31SBoris BREZILLON
1338d34c31SBoris BREZILLON #include "pmc.h"
1438d34c31SBoris BREZILLON
1538d34c31SBoris BREZILLON #define SLOW_CLOCK_FREQ 32768
1638d34c31SBoris BREZILLON #define MAINF_DIV 16
1738d34c31SBoris BREZILLON #define MAINFRDY_TIMEOUT (((MAINF_DIV + 1) * USEC_PER_SEC) / \
1838d34c31SBoris BREZILLON SLOW_CLOCK_FREQ)
1938d34c31SBoris BREZILLON #define MAINF_LOOP_MIN_WAIT (USEC_PER_SEC / SLOW_CLOCK_FREQ)
2038d34c31SBoris BREZILLON #define MAINF_LOOP_MAX_WAIT MAINFRDY_TIMEOUT
2138d34c31SBoris BREZILLON
2227cb1c20SBoris BREZILLON #define MOR_KEY_MASK (0xff << 16)
2327cb1c20SBoris BREZILLON
2469a6bcdeSEugen Hristev #define clk_main_parent_select(s) (((s) & \
2569a6bcdeSEugen Hristev (AT91_PMC_MOSCEN | \
2669a6bcdeSEugen Hristev AT91_PMC_OSCBYPASS)) ? 1 : 0)
2769a6bcdeSEugen Hristev
2827cb1c20SBoris BREZILLON struct clk_main_osc {
2938d34c31SBoris BREZILLON struct clk_hw hw;
301bdf0232SBoris Brezillon struct regmap *regmap;
3136971566SClaudiu Beznea struct at91_clk_pms pms;
3238d34c31SBoris BREZILLON };
3338d34c31SBoris BREZILLON
3427cb1c20SBoris BREZILLON #define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
3538d34c31SBoris BREZILLON
3627cb1c20SBoris BREZILLON struct clk_main_rc_osc {
3727cb1c20SBoris BREZILLON struct clk_hw hw;
381bdf0232SBoris Brezillon struct regmap *regmap;
3927cb1c20SBoris BREZILLON unsigned long frequency;
4027cb1c20SBoris BREZILLON unsigned long accuracy;
4136971566SClaudiu Beznea struct at91_clk_pms pms;
4227cb1c20SBoris BREZILLON };
4327cb1c20SBoris BREZILLON
4427cb1c20SBoris BREZILLON #define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
4527cb1c20SBoris BREZILLON
4627cb1c20SBoris BREZILLON struct clk_rm9200_main {
4727cb1c20SBoris BREZILLON struct clk_hw hw;
481bdf0232SBoris Brezillon struct regmap *regmap;
4927cb1c20SBoris BREZILLON };
5027cb1c20SBoris BREZILLON
5127cb1c20SBoris BREZILLON #define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)
5227cb1c20SBoris BREZILLON
5327cb1c20SBoris BREZILLON struct clk_sam9x5_main {
5427cb1c20SBoris BREZILLON struct clk_hw hw;
551bdf0232SBoris Brezillon struct regmap *regmap;
5636971566SClaudiu Beznea struct at91_clk_pms pms;
5727cb1c20SBoris BREZILLON u8 parent;
5827cb1c20SBoris BREZILLON };
5927cb1c20SBoris BREZILLON
6027cb1c20SBoris BREZILLON #define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
6127cb1c20SBoris BREZILLON
clk_main_osc_ready(struct regmap * regmap)621bdf0232SBoris Brezillon static inline bool clk_main_osc_ready(struct regmap *regmap)
631bdf0232SBoris Brezillon {
641bdf0232SBoris Brezillon unsigned int status;
651bdf0232SBoris Brezillon
661bdf0232SBoris Brezillon regmap_read(regmap, AT91_PMC_SR, &status);
671bdf0232SBoris Brezillon
681bdf0232SBoris Brezillon return status & AT91_PMC_MOSCS;
691bdf0232SBoris Brezillon }
701bdf0232SBoris Brezillon
clk_main_osc_prepare(struct clk_hw * hw)7127cb1c20SBoris BREZILLON static int clk_main_osc_prepare(struct clk_hw *hw)
7238d34c31SBoris BREZILLON {
7327cb1c20SBoris BREZILLON struct clk_main_osc *osc = to_clk_main_osc(hw);
741bdf0232SBoris Brezillon struct regmap *regmap = osc->regmap;
7538d34c31SBoris BREZILLON u32 tmp;
7638d34c31SBoris BREZILLON
771bdf0232SBoris Brezillon regmap_read(regmap, AT91_CKGR_MOR, &tmp);
781bdf0232SBoris Brezillon tmp &= ~MOR_KEY_MASK;
791bdf0232SBoris Brezillon
8027cb1c20SBoris BREZILLON if (tmp & AT91_PMC_OSCBYPASS)
8127cb1c20SBoris BREZILLON return 0;
8227cb1c20SBoris BREZILLON
8327cb1c20SBoris BREZILLON if (!(tmp & AT91_PMC_MOSCEN)) {
8427cb1c20SBoris BREZILLON tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
851bdf0232SBoris Brezillon regmap_write(regmap, AT91_CKGR_MOR, tmp);
8627cb1c20SBoris BREZILLON }
8727cb1c20SBoris BREZILLON
8899a81706SAlexandre Belloni while (!clk_main_osc_ready(regmap))
8999a81706SAlexandre Belloni cpu_relax();
9038d34c31SBoris BREZILLON
9138d34c31SBoris BREZILLON return 0;
9227cb1c20SBoris BREZILLON }
9327cb1c20SBoris BREZILLON
clk_main_osc_unprepare(struct clk_hw * hw)9427cb1c20SBoris BREZILLON static void clk_main_osc_unprepare(struct clk_hw *hw)
9527cb1c20SBoris BREZILLON {
9627cb1c20SBoris BREZILLON struct clk_main_osc *osc = to_clk_main_osc(hw);
971bdf0232SBoris Brezillon struct regmap *regmap = osc->regmap;
981bdf0232SBoris Brezillon u32 tmp;
9927cb1c20SBoris BREZILLON
1001bdf0232SBoris Brezillon regmap_read(regmap, AT91_CKGR_MOR, &tmp);
10127cb1c20SBoris BREZILLON if (tmp & AT91_PMC_OSCBYPASS)
10227cb1c20SBoris BREZILLON return;
10327cb1c20SBoris BREZILLON
10427cb1c20SBoris BREZILLON if (!(tmp & AT91_PMC_MOSCEN))
10527cb1c20SBoris BREZILLON return;
10627cb1c20SBoris BREZILLON
10727cb1c20SBoris BREZILLON tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
1081bdf0232SBoris Brezillon regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
10927cb1c20SBoris BREZILLON }
11027cb1c20SBoris BREZILLON
clk_main_osc_is_prepared(struct clk_hw * hw)11127cb1c20SBoris BREZILLON static int clk_main_osc_is_prepared(struct clk_hw *hw)
11227cb1c20SBoris BREZILLON {
11327cb1c20SBoris BREZILLON struct clk_main_osc *osc = to_clk_main_osc(hw);
1141bdf0232SBoris Brezillon struct regmap *regmap = osc->regmap;
1151bdf0232SBoris Brezillon u32 tmp, status;
11627cb1c20SBoris BREZILLON
1171bdf0232SBoris Brezillon regmap_read(regmap, AT91_CKGR_MOR, &tmp);
11827cb1c20SBoris BREZILLON if (tmp & AT91_PMC_OSCBYPASS)
11927cb1c20SBoris BREZILLON return 1;
12027cb1c20SBoris BREZILLON
1211bdf0232SBoris Brezillon regmap_read(regmap, AT91_PMC_SR, &status);
1221bdf0232SBoris Brezillon
12369a6bcdeSEugen Hristev return (status & AT91_PMC_MOSCS) && clk_main_parent_select(tmp);
12427cb1c20SBoris BREZILLON }
12527cb1c20SBoris BREZILLON
clk_main_osc_save_context(struct clk_hw * hw)12636971566SClaudiu Beznea static int clk_main_osc_save_context(struct clk_hw *hw)
12736971566SClaudiu Beznea {
12836971566SClaudiu Beznea struct clk_main_osc *osc = to_clk_main_osc(hw);
12936971566SClaudiu Beznea
13036971566SClaudiu Beznea osc->pms.status = clk_main_osc_is_prepared(hw);
13136971566SClaudiu Beznea
13236971566SClaudiu Beznea return 0;
13336971566SClaudiu Beznea }
13436971566SClaudiu Beznea
clk_main_osc_restore_context(struct clk_hw * hw)13536971566SClaudiu Beznea static void clk_main_osc_restore_context(struct clk_hw *hw)
13636971566SClaudiu Beznea {
13736971566SClaudiu Beznea struct clk_main_osc *osc = to_clk_main_osc(hw);
13836971566SClaudiu Beznea
13936971566SClaudiu Beznea if (osc->pms.status)
14036971566SClaudiu Beznea clk_main_osc_prepare(hw);
14136971566SClaudiu Beznea }
14236971566SClaudiu Beznea
14327cb1c20SBoris BREZILLON static const struct clk_ops main_osc_ops = {
14427cb1c20SBoris BREZILLON .prepare = clk_main_osc_prepare,
14527cb1c20SBoris BREZILLON .unprepare = clk_main_osc_unprepare,
14627cb1c20SBoris BREZILLON .is_prepared = clk_main_osc_is_prepared,
14736971566SClaudiu Beznea .save_context = clk_main_osc_save_context,
14836971566SClaudiu Beznea .restore_context = clk_main_osc_restore_context,
14927cb1c20SBoris BREZILLON };
15027cb1c20SBoris BREZILLON
151b2e39dc0SAlexandre Belloni struct clk_hw * __init
at91_clk_register_main_osc(struct regmap * regmap,const char * name,const char * parent_name,struct clk_parent_data * parent_data,bool bypass)1521bdf0232SBoris Brezillon at91_clk_register_main_osc(struct regmap *regmap,
15327cb1c20SBoris BREZILLON const char *name,
15427cb1c20SBoris BREZILLON const char *parent_name,
155*b5105e37SClaudiu Beznea struct clk_parent_data *parent_data,
15627cb1c20SBoris BREZILLON bool bypass)
15727cb1c20SBoris BREZILLON {
15827cb1c20SBoris BREZILLON struct clk_main_osc *osc;
159*b5105e37SClaudiu Beznea struct clk_init_data init = {};
160f5644f10SStephen Boyd struct clk_hw *hw;
161f5644f10SStephen Boyd int ret;
16227cb1c20SBoris BREZILLON
163*b5105e37SClaudiu Beznea if (!name || !(parent_name || parent_data))
16427cb1c20SBoris BREZILLON return ERR_PTR(-EINVAL);
16527cb1c20SBoris BREZILLON
16627cb1c20SBoris BREZILLON osc = kzalloc(sizeof(*osc), GFP_KERNEL);
16727cb1c20SBoris BREZILLON if (!osc)
16827cb1c20SBoris BREZILLON return ERR_PTR(-ENOMEM);
16927cb1c20SBoris BREZILLON
17027cb1c20SBoris BREZILLON init.name = name;
17127cb1c20SBoris BREZILLON init.ops = &main_osc_ops;
172*b5105e37SClaudiu Beznea if (parent_data)
173*b5105e37SClaudiu Beznea init.parent_data = (const struct clk_parent_data *)parent_data;
174*b5105e37SClaudiu Beznea else
17527cb1c20SBoris BREZILLON init.parent_names = &parent_name;
17627cb1c20SBoris BREZILLON init.num_parents = 1;
17727cb1c20SBoris BREZILLON init.flags = CLK_IGNORE_UNUSED;
17827cb1c20SBoris BREZILLON
17927cb1c20SBoris BREZILLON osc->hw.init = &init;
1801bdf0232SBoris Brezillon osc->regmap = regmap;
18127cb1c20SBoris BREZILLON
18227cb1c20SBoris BREZILLON if (bypass)
1831bdf0232SBoris Brezillon regmap_update_bits(regmap,
1841bdf0232SBoris Brezillon AT91_CKGR_MOR, MOR_KEY_MASK |
185263eaf8fSEugen Hristev AT91_PMC_OSCBYPASS,
18627cb1c20SBoris BREZILLON AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
18727cb1c20SBoris BREZILLON
188f5644f10SStephen Boyd hw = &osc->hw;
189f5644f10SStephen Boyd ret = clk_hw_register(NULL, &osc->hw);
190f5644f10SStephen Boyd if (ret) {
19127cb1c20SBoris BREZILLON kfree(osc);
192f5644f10SStephen Boyd hw = ERR_PTR(ret);
193f5644f10SStephen Boyd }
19427cb1c20SBoris BREZILLON
195f5644f10SStephen Boyd return hw;
19627cb1c20SBoris BREZILLON }
19727cb1c20SBoris BREZILLON
clk_main_rc_osc_ready(struct regmap * regmap)1981bdf0232SBoris Brezillon static bool clk_main_rc_osc_ready(struct regmap *regmap)
1991bdf0232SBoris Brezillon {
2001bdf0232SBoris Brezillon unsigned int status;
2011bdf0232SBoris Brezillon
2021bdf0232SBoris Brezillon regmap_read(regmap, AT91_PMC_SR, &status);
2031bdf0232SBoris Brezillon
20442324d95SClaudiu Beznea return !!(status & AT91_PMC_MOSCRCS);
2051bdf0232SBoris Brezillon }
2061bdf0232SBoris Brezillon
clk_main_rc_osc_prepare(struct clk_hw * hw)20727cb1c20SBoris BREZILLON static int clk_main_rc_osc_prepare(struct clk_hw *hw)
20827cb1c20SBoris BREZILLON {
20927cb1c20SBoris BREZILLON struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
2101bdf0232SBoris Brezillon struct regmap *regmap = osc->regmap;
2111bdf0232SBoris Brezillon unsigned int mor;
21227cb1c20SBoris BREZILLON
2131bdf0232SBoris Brezillon regmap_read(regmap, AT91_CKGR_MOR, &mor);
21427cb1c20SBoris BREZILLON
2151bdf0232SBoris Brezillon if (!(mor & AT91_PMC_MOSCRCEN))
2161bdf0232SBoris Brezillon regmap_update_bits(regmap, AT91_CKGR_MOR,
2171bdf0232SBoris Brezillon MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
2181bdf0232SBoris Brezillon AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
21927cb1c20SBoris BREZILLON
22099a81706SAlexandre Belloni while (!clk_main_rc_osc_ready(regmap))
22199a81706SAlexandre Belloni cpu_relax();
22227cb1c20SBoris BREZILLON
22327cb1c20SBoris BREZILLON return 0;
22427cb1c20SBoris BREZILLON }
22527cb1c20SBoris BREZILLON
clk_main_rc_osc_unprepare(struct clk_hw * hw)22627cb1c20SBoris BREZILLON static void clk_main_rc_osc_unprepare(struct clk_hw *hw)
22727cb1c20SBoris BREZILLON {
22827cb1c20SBoris BREZILLON struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
2291bdf0232SBoris Brezillon struct regmap *regmap = osc->regmap;
2301bdf0232SBoris Brezillon unsigned int mor;
23127cb1c20SBoris BREZILLON
2321bdf0232SBoris Brezillon regmap_read(regmap, AT91_CKGR_MOR, &mor);
2331bdf0232SBoris Brezillon
2341bdf0232SBoris Brezillon if (!(mor & AT91_PMC_MOSCRCEN))
23527cb1c20SBoris BREZILLON return;
23627cb1c20SBoris BREZILLON
2371bdf0232SBoris Brezillon regmap_update_bits(regmap, AT91_CKGR_MOR,
2381bdf0232SBoris Brezillon MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
23927cb1c20SBoris BREZILLON }
24027cb1c20SBoris BREZILLON
clk_main_rc_osc_is_prepared(struct clk_hw * hw)24127cb1c20SBoris BREZILLON static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
24227cb1c20SBoris BREZILLON {
24327cb1c20SBoris BREZILLON struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
2441bdf0232SBoris Brezillon struct regmap *regmap = osc->regmap;
2451bdf0232SBoris Brezillon unsigned int mor, status;
24627cb1c20SBoris BREZILLON
2471bdf0232SBoris Brezillon regmap_read(regmap, AT91_CKGR_MOR, &mor);
2481bdf0232SBoris Brezillon regmap_read(regmap, AT91_PMC_SR, &status);
2491bdf0232SBoris Brezillon
2501bdf0232SBoris Brezillon return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
25127cb1c20SBoris BREZILLON }
25227cb1c20SBoris BREZILLON
clk_main_rc_osc_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)25327cb1c20SBoris BREZILLON static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
25427cb1c20SBoris BREZILLON unsigned long parent_rate)
25527cb1c20SBoris BREZILLON {
25627cb1c20SBoris BREZILLON struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
25727cb1c20SBoris BREZILLON
25827cb1c20SBoris BREZILLON return osc->frequency;
25927cb1c20SBoris BREZILLON }
26027cb1c20SBoris BREZILLON
clk_main_rc_osc_recalc_accuracy(struct clk_hw * hw,unsigned long parent_acc)26127cb1c20SBoris BREZILLON static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,
26227cb1c20SBoris BREZILLON unsigned long parent_acc)
26327cb1c20SBoris BREZILLON {
26427cb1c20SBoris BREZILLON struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
26527cb1c20SBoris BREZILLON
26627cb1c20SBoris BREZILLON return osc->accuracy;
26727cb1c20SBoris BREZILLON }
26827cb1c20SBoris BREZILLON
clk_main_rc_osc_save_context(struct clk_hw * hw)26936971566SClaudiu Beznea static int clk_main_rc_osc_save_context(struct clk_hw *hw)
27036971566SClaudiu Beznea {
27136971566SClaudiu Beznea struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
27236971566SClaudiu Beznea
27336971566SClaudiu Beznea osc->pms.status = clk_main_rc_osc_is_prepared(hw);
27436971566SClaudiu Beznea
27536971566SClaudiu Beznea return 0;
27636971566SClaudiu Beznea }
27736971566SClaudiu Beznea
clk_main_rc_osc_restore_context(struct clk_hw * hw)27836971566SClaudiu Beznea static void clk_main_rc_osc_restore_context(struct clk_hw *hw)
27936971566SClaudiu Beznea {
28036971566SClaudiu Beznea struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
28136971566SClaudiu Beznea
28236971566SClaudiu Beznea if (osc->pms.status)
28336971566SClaudiu Beznea clk_main_rc_osc_prepare(hw);
28436971566SClaudiu Beznea }
28536971566SClaudiu Beznea
28627cb1c20SBoris BREZILLON static const struct clk_ops main_rc_osc_ops = {
28727cb1c20SBoris BREZILLON .prepare = clk_main_rc_osc_prepare,
28827cb1c20SBoris BREZILLON .unprepare = clk_main_rc_osc_unprepare,
28927cb1c20SBoris BREZILLON .is_prepared = clk_main_rc_osc_is_prepared,
29027cb1c20SBoris BREZILLON .recalc_rate = clk_main_rc_osc_recalc_rate,
29127cb1c20SBoris BREZILLON .recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
29236971566SClaudiu Beznea .save_context = clk_main_rc_osc_save_context,
29336971566SClaudiu Beznea .restore_context = clk_main_rc_osc_restore_context,
29427cb1c20SBoris BREZILLON };
29527cb1c20SBoris BREZILLON
296b2e39dc0SAlexandre Belloni struct clk_hw * __init
at91_clk_register_main_rc_osc(struct regmap * regmap,const char * name,u32 frequency,u32 accuracy)2971bdf0232SBoris Brezillon at91_clk_register_main_rc_osc(struct regmap *regmap,
29827cb1c20SBoris BREZILLON const char *name,
29927cb1c20SBoris BREZILLON u32 frequency, u32 accuracy)
30027cb1c20SBoris BREZILLON {
30127cb1c20SBoris BREZILLON struct clk_main_rc_osc *osc;
30227cb1c20SBoris BREZILLON struct clk_init_data init;
303f5644f10SStephen Boyd struct clk_hw *hw;
304f5644f10SStephen Boyd int ret;
30527cb1c20SBoris BREZILLON
3061bdf0232SBoris Brezillon if (!name || !frequency)
30727cb1c20SBoris BREZILLON return ERR_PTR(-EINVAL);
30827cb1c20SBoris BREZILLON
30927cb1c20SBoris BREZILLON osc = kzalloc(sizeof(*osc), GFP_KERNEL);
31027cb1c20SBoris BREZILLON if (!osc)
31127cb1c20SBoris BREZILLON return ERR_PTR(-ENOMEM);
31227cb1c20SBoris BREZILLON
31327cb1c20SBoris BREZILLON init.name = name;
31427cb1c20SBoris BREZILLON init.ops = &main_rc_osc_ops;
31527cb1c20SBoris BREZILLON init.parent_names = NULL;
31627cb1c20SBoris BREZILLON init.num_parents = 0;
317a9bb2ef7SStephen Boyd init.flags = CLK_IGNORE_UNUSED;
31827cb1c20SBoris BREZILLON
31927cb1c20SBoris BREZILLON osc->hw.init = &init;
3201bdf0232SBoris Brezillon osc->regmap = regmap;
32127cb1c20SBoris BREZILLON osc->frequency = frequency;
32227cb1c20SBoris BREZILLON osc->accuracy = accuracy;
32327cb1c20SBoris BREZILLON
324f5644f10SStephen Boyd hw = &osc->hw;
325f5644f10SStephen Boyd ret = clk_hw_register(NULL, hw);
326f5644f10SStephen Boyd if (ret) {
32727cb1c20SBoris BREZILLON kfree(osc);
328f5644f10SStephen Boyd hw = ERR_PTR(ret);
329f5644f10SStephen Boyd }
33027cb1c20SBoris BREZILLON
331f5644f10SStephen Boyd return hw;
33227cb1c20SBoris BREZILLON }
33327cb1c20SBoris BREZILLON
clk_main_probe_frequency(struct regmap * regmap)3341bdf0232SBoris Brezillon static int clk_main_probe_frequency(struct regmap *regmap)
33527cb1c20SBoris BREZILLON {
33627cb1c20SBoris BREZILLON unsigned long prep_time, timeout;
3371bdf0232SBoris Brezillon unsigned int mcfr;
33838d34c31SBoris BREZILLON
33938d34c31SBoris BREZILLON timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
34038d34c31SBoris BREZILLON do {
34127cb1c20SBoris BREZILLON prep_time = jiffies;
3421bdf0232SBoris Brezillon regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
3431bdf0232SBoris Brezillon if (mcfr & AT91_PMC_MAINRDY)
34438d34c31SBoris BREZILLON return 0;
345658fd65cSAlexandre Belloni if (system_state < SYSTEM_RUNNING)
346658fd65cSAlexandre Belloni udelay(MAINF_LOOP_MIN_WAIT);
347658fd65cSAlexandre Belloni else
34838d34c31SBoris BREZILLON usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
34927cb1c20SBoris BREZILLON } while (time_before(prep_time, timeout));
35038d34c31SBoris BREZILLON
35127cb1c20SBoris BREZILLON return -ETIMEDOUT;
35238d34c31SBoris BREZILLON }
35338d34c31SBoris BREZILLON
clk_main_recalc_rate(struct regmap * regmap,unsigned long parent_rate)3541bdf0232SBoris Brezillon static unsigned long clk_main_recalc_rate(struct regmap *regmap,
35538d34c31SBoris BREZILLON unsigned long parent_rate)
35638d34c31SBoris BREZILLON {
3571bdf0232SBoris Brezillon unsigned int mcfr;
35838d34c31SBoris BREZILLON
35927cb1c20SBoris BREZILLON if (parent_rate)
36027cb1c20SBoris BREZILLON return parent_rate;
36138d34c31SBoris BREZILLON
3624da66b63SAlexandre Belloni pr_warn("Main crystal frequency not set, using approximate value\n");
3631bdf0232SBoris Brezillon regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
3641bdf0232SBoris Brezillon if (!(mcfr & AT91_PMC_MAINRDY))
36527cb1c20SBoris BREZILLON return 0;
36638d34c31SBoris BREZILLON
3671bdf0232SBoris Brezillon return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
36838d34c31SBoris BREZILLON }
36938d34c31SBoris BREZILLON
clk_rm9200_main_prepare(struct clk_hw * hw)37027cb1c20SBoris BREZILLON static int clk_rm9200_main_prepare(struct clk_hw *hw)
37127cb1c20SBoris BREZILLON {
37227cb1c20SBoris BREZILLON struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
37327cb1c20SBoris BREZILLON
3741bdf0232SBoris Brezillon return clk_main_probe_frequency(clkmain->regmap);
37527cb1c20SBoris BREZILLON }
37627cb1c20SBoris BREZILLON
clk_rm9200_main_is_prepared(struct clk_hw * hw)37727cb1c20SBoris BREZILLON static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
37827cb1c20SBoris BREZILLON {
37927cb1c20SBoris BREZILLON struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
3801bdf0232SBoris Brezillon unsigned int status;
38127cb1c20SBoris BREZILLON
3821bdf0232SBoris Brezillon regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
3831bdf0232SBoris Brezillon
38442324d95SClaudiu Beznea return !!(status & AT91_PMC_MAINRDY);
38527cb1c20SBoris BREZILLON }
38627cb1c20SBoris BREZILLON
clk_rm9200_main_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)38727cb1c20SBoris BREZILLON static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
38827cb1c20SBoris BREZILLON unsigned long parent_rate)
38927cb1c20SBoris BREZILLON {
39027cb1c20SBoris BREZILLON struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
39127cb1c20SBoris BREZILLON
3921bdf0232SBoris Brezillon return clk_main_recalc_rate(clkmain->regmap, parent_rate);
39327cb1c20SBoris BREZILLON }
39427cb1c20SBoris BREZILLON
39527cb1c20SBoris BREZILLON static const struct clk_ops rm9200_main_ops = {
39627cb1c20SBoris BREZILLON .prepare = clk_rm9200_main_prepare,
39727cb1c20SBoris BREZILLON .is_prepared = clk_rm9200_main_is_prepared,
39827cb1c20SBoris BREZILLON .recalc_rate = clk_rm9200_main_recalc_rate,
39938d34c31SBoris BREZILLON };
40038d34c31SBoris BREZILLON
401b2e39dc0SAlexandre Belloni struct clk_hw * __init
at91_clk_register_rm9200_main(struct regmap * regmap,const char * name,const char * parent_name,struct clk_hw * parent_hw)4021bdf0232SBoris Brezillon at91_clk_register_rm9200_main(struct regmap *regmap,
40338d34c31SBoris BREZILLON const char *name,
404*b5105e37SClaudiu Beznea const char *parent_name,
405*b5105e37SClaudiu Beznea struct clk_hw *parent_hw)
40638d34c31SBoris BREZILLON {
40727cb1c20SBoris BREZILLON struct clk_rm9200_main *clkmain;
408*b5105e37SClaudiu Beznea struct clk_init_data init = {};
409f5644f10SStephen Boyd struct clk_hw *hw;
410f5644f10SStephen Boyd int ret;
41138d34c31SBoris BREZILLON
4121bdf0232SBoris Brezillon if (!name)
41338d34c31SBoris BREZILLON return ERR_PTR(-EINVAL);
41438d34c31SBoris BREZILLON
415*b5105e37SClaudiu Beznea if (!(parent_name || parent_hw))
41638d34c31SBoris BREZILLON return ERR_PTR(-EINVAL);
41738d34c31SBoris BREZILLON
41838d34c31SBoris BREZILLON clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
41938d34c31SBoris BREZILLON if (!clkmain)
42038d34c31SBoris BREZILLON return ERR_PTR(-ENOMEM);
42138d34c31SBoris BREZILLON
42238d34c31SBoris BREZILLON init.name = name;
42327cb1c20SBoris BREZILLON init.ops = &rm9200_main_ops;
424*b5105e37SClaudiu Beznea if (parent_hw)
425*b5105e37SClaudiu Beznea init.parent_hws = (const struct clk_hw **)&parent_hw;
426*b5105e37SClaudiu Beznea else
42727cb1c20SBoris BREZILLON init.parent_names = &parent_name;
42827cb1c20SBoris BREZILLON init.num_parents = 1;
42927cb1c20SBoris BREZILLON init.flags = 0;
43038d34c31SBoris BREZILLON
43138d34c31SBoris BREZILLON clkmain->hw.init = &init;
4321bdf0232SBoris Brezillon clkmain->regmap = regmap;
43327cb1c20SBoris BREZILLON
434f5644f10SStephen Boyd hw = &clkmain->hw;
435f5644f10SStephen Boyd ret = clk_hw_register(NULL, &clkmain->hw);
436f5644f10SStephen Boyd if (ret) {
43727cb1c20SBoris BREZILLON kfree(clkmain);
438f5644f10SStephen Boyd hw = ERR_PTR(ret);
439f5644f10SStephen Boyd }
44027cb1c20SBoris BREZILLON
441f5644f10SStephen Boyd return hw;
44227cb1c20SBoris BREZILLON }
44327cb1c20SBoris BREZILLON
clk_sam9x5_main_ready(struct regmap * regmap)4441bdf0232SBoris Brezillon static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
4451bdf0232SBoris Brezillon {
4461bdf0232SBoris Brezillon unsigned int status;
4471bdf0232SBoris Brezillon
4481bdf0232SBoris Brezillon regmap_read(regmap, AT91_PMC_SR, &status);
4491bdf0232SBoris Brezillon
45042324d95SClaudiu Beznea return !!(status & AT91_PMC_MOSCSELS);
4511bdf0232SBoris Brezillon }
4521bdf0232SBoris Brezillon
clk_sam9x5_main_prepare(struct clk_hw * hw)45327cb1c20SBoris BREZILLON static int clk_sam9x5_main_prepare(struct clk_hw *hw)
45427cb1c20SBoris BREZILLON {
45527cb1c20SBoris BREZILLON struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
4561bdf0232SBoris Brezillon struct regmap *regmap = clkmain->regmap;
45727cb1c20SBoris BREZILLON
45899a81706SAlexandre Belloni while (!clk_sam9x5_main_ready(regmap))
45999a81706SAlexandre Belloni cpu_relax();
46027cb1c20SBoris BREZILLON
4611bdf0232SBoris Brezillon return clk_main_probe_frequency(regmap);
46227cb1c20SBoris BREZILLON }
46327cb1c20SBoris BREZILLON
clk_sam9x5_main_is_prepared(struct clk_hw * hw)46427cb1c20SBoris BREZILLON static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
46527cb1c20SBoris BREZILLON {
46627cb1c20SBoris BREZILLON struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
46727cb1c20SBoris BREZILLON
4681bdf0232SBoris Brezillon return clk_sam9x5_main_ready(clkmain->regmap);
46927cb1c20SBoris BREZILLON }
47027cb1c20SBoris BREZILLON
clk_sam9x5_main_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)47127cb1c20SBoris BREZILLON static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
47227cb1c20SBoris BREZILLON unsigned long parent_rate)
47327cb1c20SBoris BREZILLON {
47427cb1c20SBoris BREZILLON struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
47527cb1c20SBoris BREZILLON
4761bdf0232SBoris Brezillon return clk_main_recalc_rate(clkmain->regmap, parent_rate);
47727cb1c20SBoris BREZILLON }
47827cb1c20SBoris BREZILLON
clk_sam9x5_main_set_parent(struct clk_hw * hw,u8 index)47927cb1c20SBoris BREZILLON static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
48027cb1c20SBoris BREZILLON {
48127cb1c20SBoris BREZILLON struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
4821bdf0232SBoris Brezillon struct regmap *regmap = clkmain->regmap;
4831bdf0232SBoris Brezillon unsigned int tmp;
48427cb1c20SBoris BREZILLON
48527cb1c20SBoris BREZILLON if (index > 1)
48627cb1c20SBoris BREZILLON return -EINVAL;
48727cb1c20SBoris BREZILLON
4881bdf0232SBoris Brezillon regmap_read(regmap, AT91_CKGR_MOR, &tmp);
48927cb1c20SBoris BREZILLON
49027cb1c20SBoris BREZILLON if (index && !(tmp & AT91_PMC_MOSCSEL))
49185d071e7SClaudiu Beznea tmp = AT91_PMC_MOSCSEL;
49227cb1c20SBoris BREZILLON else if (!index && (tmp & AT91_PMC_MOSCSEL))
49385d071e7SClaudiu Beznea tmp = 0;
49485d071e7SClaudiu Beznea else
49585d071e7SClaudiu Beznea return 0;
49685d071e7SClaudiu Beznea
49785d071e7SClaudiu Beznea regmap_update_bits(regmap, AT91_CKGR_MOR,
49885d071e7SClaudiu Beznea AT91_PMC_MOSCSEL | MOR_KEY_MASK,
49985d071e7SClaudiu Beznea tmp | AT91_PMC_KEY);
50027cb1c20SBoris BREZILLON
50199a81706SAlexandre Belloni while (!clk_sam9x5_main_ready(regmap))
50299a81706SAlexandre Belloni cpu_relax();
50327cb1c20SBoris BREZILLON
50427cb1c20SBoris BREZILLON return 0;
50527cb1c20SBoris BREZILLON }
50627cb1c20SBoris BREZILLON
clk_sam9x5_main_get_parent(struct clk_hw * hw)50727cb1c20SBoris BREZILLON static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
50827cb1c20SBoris BREZILLON {
50927cb1c20SBoris BREZILLON struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
5101bdf0232SBoris Brezillon unsigned int status;
51127cb1c20SBoris BREZILLON
5121bdf0232SBoris Brezillon regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
5131bdf0232SBoris Brezillon
51469a6bcdeSEugen Hristev return clk_main_parent_select(status);
51527cb1c20SBoris BREZILLON }
51627cb1c20SBoris BREZILLON
clk_sam9x5_main_save_context(struct clk_hw * hw)51736971566SClaudiu Beznea static int clk_sam9x5_main_save_context(struct clk_hw *hw)
51836971566SClaudiu Beznea {
51936971566SClaudiu Beznea struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
52036971566SClaudiu Beznea
52136971566SClaudiu Beznea clkmain->pms.status = clk_main_rc_osc_is_prepared(&clkmain->hw);
52236971566SClaudiu Beznea clkmain->pms.parent = clk_sam9x5_main_get_parent(&clkmain->hw);
52336971566SClaudiu Beznea
52436971566SClaudiu Beznea return 0;
52536971566SClaudiu Beznea }
52636971566SClaudiu Beznea
clk_sam9x5_main_restore_context(struct clk_hw * hw)52736971566SClaudiu Beznea static void clk_sam9x5_main_restore_context(struct clk_hw *hw)
52836971566SClaudiu Beznea {
52936971566SClaudiu Beznea struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
53036971566SClaudiu Beznea int ret;
53136971566SClaudiu Beznea
53236971566SClaudiu Beznea ret = clk_sam9x5_main_set_parent(hw, clkmain->pms.parent);
53336971566SClaudiu Beznea if (ret)
53436971566SClaudiu Beznea return;
53536971566SClaudiu Beznea
53636971566SClaudiu Beznea if (clkmain->pms.status)
53736971566SClaudiu Beznea clk_sam9x5_main_prepare(hw);
53836971566SClaudiu Beznea }
53936971566SClaudiu Beznea
54027cb1c20SBoris BREZILLON static const struct clk_ops sam9x5_main_ops = {
54127cb1c20SBoris BREZILLON .prepare = clk_sam9x5_main_prepare,
54227cb1c20SBoris BREZILLON .is_prepared = clk_sam9x5_main_is_prepared,
54327cb1c20SBoris BREZILLON .recalc_rate = clk_sam9x5_main_recalc_rate,
54463ec5653SMaxime Ripard .determine_rate = clk_hw_determine_rate_no_reparent,
54527cb1c20SBoris BREZILLON .set_parent = clk_sam9x5_main_set_parent,
54627cb1c20SBoris BREZILLON .get_parent = clk_sam9x5_main_get_parent,
54736971566SClaudiu Beznea .save_context = clk_sam9x5_main_save_context,
54836971566SClaudiu Beznea .restore_context = clk_sam9x5_main_restore_context,
54927cb1c20SBoris BREZILLON };
55027cb1c20SBoris BREZILLON
551b2e39dc0SAlexandre Belloni struct clk_hw * __init
at91_clk_register_sam9x5_main(struct regmap * regmap,const char * name,const char ** parent_names,struct clk_hw ** parent_hws,int num_parents)5521bdf0232SBoris Brezillon at91_clk_register_sam9x5_main(struct regmap *regmap,
55327cb1c20SBoris BREZILLON const char *name,
55427cb1c20SBoris BREZILLON const char **parent_names,
555*b5105e37SClaudiu Beznea struct clk_hw **parent_hws,
55627cb1c20SBoris BREZILLON int num_parents)
55727cb1c20SBoris BREZILLON {
55827cb1c20SBoris BREZILLON struct clk_sam9x5_main *clkmain;
559*b5105e37SClaudiu Beznea struct clk_init_data init = {};
5601bdf0232SBoris Brezillon unsigned int status;
561f5644f10SStephen Boyd struct clk_hw *hw;
562f5644f10SStephen Boyd int ret;
56327cb1c20SBoris BREZILLON
5641bdf0232SBoris Brezillon if (!name)
56527cb1c20SBoris BREZILLON return ERR_PTR(-EINVAL);
56627cb1c20SBoris BREZILLON
567*b5105e37SClaudiu Beznea if (!(parent_hws || parent_names) || !num_parents)
56827cb1c20SBoris BREZILLON return ERR_PTR(-EINVAL);
56927cb1c20SBoris BREZILLON
57027cb1c20SBoris BREZILLON clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
57127cb1c20SBoris BREZILLON if (!clkmain)
57227cb1c20SBoris BREZILLON return ERR_PTR(-ENOMEM);
57327cb1c20SBoris BREZILLON
57427cb1c20SBoris BREZILLON init.name = name;
57527cb1c20SBoris BREZILLON init.ops = &sam9x5_main_ops;
576*b5105e37SClaudiu Beznea if (parent_hws)
577*b5105e37SClaudiu Beznea init.parent_hws = (const struct clk_hw **)parent_hws;
578*b5105e37SClaudiu Beznea else
57927cb1c20SBoris BREZILLON init.parent_names = parent_names;
58027cb1c20SBoris BREZILLON init.num_parents = num_parents;
58127cb1c20SBoris BREZILLON init.flags = CLK_SET_PARENT_GATE;
58227cb1c20SBoris BREZILLON
58327cb1c20SBoris BREZILLON clkmain->hw.init = &init;
5841bdf0232SBoris Brezillon clkmain->regmap = regmap;
5851bdf0232SBoris Brezillon regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
58669a6bcdeSEugen Hristev clkmain->parent = clk_main_parent_select(status);
58738d34c31SBoris BREZILLON
588f5644f10SStephen Boyd hw = &clkmain->hw;
589f5644f10SStephen Boyd ret = clk_hw_register(NULL, &clkmain->hw);
590f5644f10SStephen Boyd if (ret) {
59138d34c31SBoris BREZILLON kfree(clkmain);
592f5644f10SStephen Boyd hw = ERR_PTR(ret);
593f5644f10SStephen Boyd }
59438d34c31SBoris BREZILLON
595f5644f10SStephen Boyd return hw;
59638d34c31SBoris BREZILLON }
597