xref: /openbmc/linux/drivers/clk/at91/clk-slow.c (revision 1bdf02326b71eae7e9b4b335b881856aaf9d1af6)
180eded6cSBoris BREZILLON /*
280eded6cSBoris BREZILLON  * drivers/clk/at91/clk-slow.c
380eded6cSBoris BREZILLON  *
480eded6cSBoris BREZILLON  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
580eded6cSBoris BREZILLON  *
680eded6cSBoris BREZILLON  * This program is free software; you can redistribute it and/or modify
780eded6cSBoris BREZILLON  * it under the terms of the GNU General Public License as published by
880eded6cSBoris BREZILLON  * the Free Software Foundation; either version 2 of the License, or
980eded6cSBoris BREZILLON  * (at your option) any later version.
1080eded6cSBoris BREZILLON  *
1180eded6cSBoris BREZILLON  */
1280eded6cSBoris BREZILLON 
1380eded6cSBoris BREZILLON #include <linux/clk-provider.h>
1480eded6cSBoris BREZILLON #include <linux/clkdev.h>
156a8ce8c9SStephen Boyd #include <linux/slab.h>
1680eded6cSBoris BREZILLON #include <linux/clk/at91_pmc.h>
1780eded6cSBoris BREZILLON #include <linux/delay.h>
1880eded6cSBoris BREZILLON #include <linux/of.h>
1980eded6cSBoris BREZILLON #include <linux/of_address.h>
2080eded6cSBoris BREZILLON #include <linux/of_irq.h>
2180eded6cSBoris BREZILLON #include <linux/io.h>
2280eded6cSBoris BREZILLON #include <linux/interrupt.h>
2380eded6cSBoris BREZILLON #include <linux/irq.h>
24*1bdf0232SBoris Brezillon #include <linux/mfd/syscon.h>
25*1bdf0232SBoris Brezillon #include <linux/regmap.h>
2680eded6cSBoris BREZILLON #include <linux/sched.h>
2780eded6cSBoris BREZILLON #include <linux/wait.h>
2880eded6cSBoris BREZILLON 
2980eded6cSBoris BREZILLON #include "pmc.h"
3080eded6cSBoris BREZILLON #include "sckc.h"
3180eded6cSBoris BREZILLON 
3280eded6cSBoris BREZILLON #define SLOW_CLOCK_FREQ		32768
3380eded6cSBoris BREZILLON #define SLOWCK_SW_CYCLES	5
3480eded6cSBoris BREZILLON #define SLOWCK_SW_TIME_USEC	((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
3580eded6cSBoris BREZILLON 				 SLOW_CLOCK_FREQ)
3680eded6cSBoris BREZILLON 
3780eded6cSBoris BREZILLON #define	AT91_SCKC_CR			0x00
3880eded6cSBoris BREZILLON #define		AT91_SCKC_RCEN		(1 << 0)
3980eded6cSBoris BREZILLON #define		AT91_SCKC_OSC32EN	(1 << 1)
4080eded6cSBoris BREZILLON #define		AT91_SCKC_OSC32BYP	(1 << 2)
4180eded6cSBoris BREZILLON #define		AT91_SCKC_OSCSEL	(1 << 3)
4280eded6cSBoris BREZILLON 
4380eded6cSBoris BREZILLON struct clk_slow_osc {
4480eded6cSBoris BREZILLON 	struct clk_hw hw;
4580eded6cSBoris BREZILLON 	void __iomem *sckcr;
4680eded6cSBoris BREZILLON 	unsigned long startup_usec;
4780eded6cSBoris BREZILLON };
4880eded6cSBoris BREZILLON 
4980eded6cSBoris BREZILLON #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
5080eded6cSBoris BREZILLON 
5180eded6cSBoris BREZILLON struct clk_slow_rc_osc {
5280eded6cSBoris BREZILLON 	struct clk_hw hw;
5380eded6cSBoris BREZILLON 	void __iomem *sckcr;
5480eded6cSBoris BREZILLON 	unsigned long frequency;
5580eded6cSBoris BREZILLON 	unsigned long accuracy;
5680eded6cSBoris BREZILLON 	unsigned long startup_usec;
5780eded6cSBoris BREZILLON };
5880eded6cSBoris BREZILLON 
5980eded6cSBoris BREZILLON #define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
6080eded6cSBoris BREZILLON 
6180eded6cSBoris BREZILLON struct clk_sam9260_slow {
6280eded6cSBoris BREZILLON 	struct clk_hw hw;
63*1bdf0232SBoris Brezillon 	struct regmap *regmap;
6480eded6cSBoris BREZILLON };
6580eded6cSBoris BREZILLON 
6680eded6cSBoris BREZILLON #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
6780eded6cSBoris BREZILLON 
6880eded6cSBoris BREZILLON struct clk_sam9x5_slow {
6980eded6cSBoris BREZILLON 	struct clk_hw hw;
7080eded6cSBoris BREZILLON 	void __iomem *sckcr;
7180eded6cSBoris BREZILLON 	u8 parent;
7280eded6cSBoris BREZILLON };
7380eded6cSBoris BREZILLON 
7480eded6cSBoris BREZILLON #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
7580eded6cSBoris BREZILLON 
7680eded6cSBoris BREZILLON static int clk_slow_osc_prepare(struct clk_hw *hw)
7780eded6cSBoris BREZILLON {
7880eded6cSBoris BREZILLON 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
7980eded6cSBoris BREZILLON 	void __iomem *sckcr = osc->sckcr;
8080eded6cSBoris BREZILLON 	u32 tmp = readl(sckcr);
8180eded6cSBoris BREZILLON 
8280eded6cSBoris BREZILLON 	if (tmp & AT91_SCKC_OSC32BYP)
8380eded6cSBoris BREZILLON 		return 0;
8480eded6cSBoris BREZILLON 
8580eded6cSBoris BREZILLON 	writel(tmp | AT91_SCKC_OSC32EN, sckcr);
8680eded6cSBoris BREZILLON 
8780eded6cSBoris BREZILLON 	usleep_range(osc->startup_usec, osc->startup_usec + 1);
8880eded6cSBoris BREZILLON 
8980eded6cSBoris BREZILLON 	return 0;
9080eded6cSBoris BREZILLON }
9180eded6cSBoris BREZILLON 
9280eded6cSBoris BREZILLON static void clk_slow_osc_unprepare(struct clk_hw *hw)
9380eded6cSBoris BREZILLON {
9480eded6cSBoris BREZILLON 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
9580eded6cSBoris BREZILLON 	void __iomem *sckcr = osc->sckcr;
9680eded6cSBoris BREZILLON 	u32 tmp = readl(sckcr);
9780eded6cSBoris BREZILLON 
9880eded6cSBoris BREZILLON 	if (tmp & AT91_SCKC_OSC32BYP)
9980eded6cSBoris BREZILLON 		return;
10080eded6cSBoris BREZILLON 
10180eded6cSBoris BREZILLON 	writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
10280eded6cSBoris BREZILLON }
10380eded6cSBoris BREZILLON 
10480eded6cSBoris BREZILLON static int clk_slow_osc_is_prepared(struct clk_hw *hw)
10580eded6cSBoris BREZILLON {
10680eded6cSBoris BREZILLON 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
10780eded6cSBoris BREZILLON 	void __iomem *sckcr = osc->sckcr;
10880eded6cSBoris BREZILLON 	u32 tmp = readl(sckcr);
10980eded6cSBoris BREZILLON 
11080eded6cSBoris BREZILLON 	if (tmp & AT91_SCKC_OSC32BYP)
11180eded6cSBoris BREZILLON 		return 1;
11280eded6cSBoris BREZILLON 
11380eded6cSBoris BREZILLON 	return !!(tmp & AT91_SCKC_OSC32EN);
11480eded6cSBoris BREZILLON }
11580eded6cSBoris BREZILLON 
11680eded6cSBoris BREZILLON static const struct clk_ops slow_osc_ops = {
11780eded6cSBoris BREZILLON 	.prepare = clk_slow_osc_prepare,
11880eded6cSBoris BREZILLON 	.unprepare = clk_slow_osc_unprepare,
11980eded6cSBoris BREZILLON 	.is_prepared = clk_slow_osc_is_prepared,
12080eded6cSBoris BREZILLON };
12180eded6cSBoris BREZILLON 
12280eded6cSBoris BREZILLON static struct clk * __init
12380eded6cSBoris BREZILLON at91_clk_register_slow_osc(void __iomem *sckcr,
12480eded6cSBoris BREZILLON 			   const char *name,
12580eded6cSBoris BREZILLON 			   const char *parent_name,
12680eded6cSBoris BREZILLON 			   unsigned long startup,
12780eded6cSBoris BREZILLON 			   bool bypass)
12880eded6cSBoris BREZILLON {
12980eded6cSBoris BREZILLON 	struct clk_slow_osc *osc;
13080eded6cSBoris BREZILLON 	struct clk *clk = NULL;
13180eded6cSBoris BREZILLON 	struct clk_init_data init;
13280eded6cSBoris BREZILLON 
13380eded6cSBoris BREZILLON 	if (!sckcr || !name || !parent_name)
13480eded6cSBoris BREZILLON 		return ERR_PTR(-EINVAL);
13580eded6cSBoris BREZILLON 
13680eded6cSBoris BREZILLON 	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
13780eded6cSBoris BREZILLON 	if (!osc)
13880eded6cSBoris BREZILLON 		return ERR_PTR(-ENOMEM);
13980eded6cSBoris BREZILLON 
14080eded6cSBoris BREZILLON 	init.name = name;
14180eded6cSBoris BREZILLON 	init.ops = &slow_osc_ops;
14280eded6cSBoris BREZILLON 	init.parent_names = &parent_name;
14380eded6cSBoris BREZILLON 	init.num_parents = 1;
14480eded6cSBoris BREZILLON 	init.flags = CLK_IGNORE_UNUSED;
14580eded6cSBoris BREZILLON 
14680eded6cSBoris BREZILLON 	osc->hw.init = &init;
14780eded6cSBoris BREZILLON 	osc->sckcr = sckcr;
14880eded6cSBoris BREZILLON 	osc->startup_usec = startup;
14980eded6cSBoris BREZILLON 
15080eded6cSBoris BREZILLON 	if (bypass)
15180eded6cSBoris BREZILLON 		writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
15280eded6cSBoris BREZILLON 		       sckcr);
15380eded6cSBoris BREZILLON 
15480eded6cSBoris BREZILLON 	clk = clk_register(NULL, &osc->hw);
15580eded6cSBoris BREZILLON 	if (IS_ERR(clk))
15680eded6cSBoris BREZILLON 		kfree(osc);
15780eded6cSBoris BREZILLON 
15880eded6cSBoris BREZILLON 	return clk;
15980eded6cSBoris BREZILLON }
16080eded6cSBoris BREZILLON 
16180eded6cSBoris BREZILLON void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np,
16280eded6cSBoris BREZILLON 					     void __iomem *sckcr)
16380eded6cSBoris BREZILLON {
16480eded6cSBoris BREZILLON 	struct clk *clk;
16580eded6cSBoris BREZILLON 	const char *parent_name;
16680eded6cSBoris BREZILLON 	const char *name = np->name;
16780eded6cSBoris BREZILLON 	u32 startup;
16880eded6cSBoris BREZILLON 	bool bypass;
16980eded6cSBoris BREZILLON 
17080eded6cSBoris BREZILLON 	parent_name = of_clk_get_parent_name(np, 0);
17180eded6cSBoris BREZILLON 	of_property_read_string(np, "clock-output-names", &name);
17280eded6cSBoris BREZILLON 	of_property_read_u32(np, "atmel,startup-time-usec", &startup);
17380eded6cSBoris BREZILLON 	bypass = of_property_read_bool(np, "atmel,osc-bypass");
17480eded6cSBoris BREZILLON 
17580eded6cSBoris BREZILLON 	clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
17680eded6cSBoris BREZILLON 					 bypass);
17780eded6cSBoris BREZILLON 	if (IS_ERR(clk))
17880eded6cSBoris BREZILLON 		return;
17980eded6cSBoris BREZILLON 
18080eded6cSBoris BREZILLON 	of_clk_add_provider(np, of_clk_src_simple_get, clk);
18180eded6cSBoris BREZILLON }
18280eded6cSBoris BREZILLON 
18380eded6cSBoris BREZILLON static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
18480eded6cSBoris BREZILLON 						 unsigned long parent_rate)
18580eded6cSBoris BREZILLON {
18680eded6cSBoris BREZILLON 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
18780eded6cSBoris BREZILLON 
18880eded6cSBoris BREZILLON 	return osc->frequency;
18980eded6cSBoris BREZILLON }
19080eded6cSBoris BREZILLON 
19180eded6cSBoris BREZILLON static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
19280eded6cSBoris BREZILLON 						     unsigned long parent_acc)
19380eded6cSBoris BREZILLON {
19480eded6cSBoris BREZILLON 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
19580eded6cSBoris BREZILLON 
19680eded6cSBoris BREZILLON 	return osc->accuracy;
19780eded6cSBoris BREZILLON }
19880eded6cSBoris BREZILLON 
19980eded6cSBoris BREZILLON static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
20080eded6cSBoris BREZILLON {
20180eded6cSBoris BREZILLON 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
20280eded6cSBoris BREZILLON 	void __iomem *sckcr = osc->sckcr;
20380eded6cSBoris BREZILLON 
20480eded6cSBoris BREZILLON 	writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
20580eded6cSBoris BREZILLON 
20680eded6cSBoris BREZILLON 	usleep_range(osc->startup_usec, osc->startup_usec + 1);
20780eded6cSBoris BREZILLON 
20880eded6cSBoris BREZILLON 	return 0;
20980eded6cSBoris BREZILLON }
21080eded6cSBoris BREZILLON 
21180eded6cSBoris BREZILLON static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
21280eded6cSBoris BREZILLON {
21380eded6cSBoris BREZILLON 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
21480eded6cSBoris BREZILLON 	void __iomem *sckcr = osc->sckcr;
21580eded6cSBoris BREZILLON 
21680eded6cSBoris BREZILLON 	writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
21780eded6cSBoris BREZILLON }
21880eded6cSBoris BREZILLON 
21980eded6cSBoris BREZILLON static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
22080eded6cSBoris BREZILLON {
22180eded6cSBoris BREZILLON 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
22280eded6cSBoris BREZILLON 
22380eded6cSBoris BREZILLON 	return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
22480eded6cSBoris BREZILLON }
22580eded6cSBoris BREZILLON 
22680eded6cSBoris BREZILLON static const struct clk_ops slow_rc_osc_ops = {
22780eded6cSBoris BREZILLON 	.prepare = clk_slow_rc_osc_prepare,
22880eded6cSBoris BREZILLON 	.unprepare = clk_slow_rc_osc_unprepare,
22980eded6cSBoris BREZILLON 	.is_prepared = clk_slow_rc_osc_is_prepared,
23080eded6cSBoris BREZILLON 	.recalc_rate = clk_slow_rc_osc_recalc_rate,
23180eded6cSBoris BREZILLON 	.recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
23280eded6cSBoris BREZILLON };
23380eded6cSBoris BREZILLON 
23480eded6cSBoris BREZILLON static struct clk * __init
23580eded6cSBoris BREZILLON at91_clk_register_slow_rc_osc(void __iomem *sckcr,
23680eded6cSBoris BREZILLON 			      const char *name,
23780eded6cSBoris BREZILLON 			      unsigned long frequency,
23880eded6cSBoris BREZILLON 			      unsigned long accuracy,
23980eded6cSBoris BREZILLON 			      unsigned long startup)
24080eded6cSBoris BREZILLON {
24180eded6cSBoris BREZILLON 	struct clk_slow_rc_osc *osc;
24280eded6cSBoris BREZILLON 	struct clk *clk = NULL;
24380eded6cSBoris BREZILLON 	struct clk_init_data init;
24480eded6cSBoris BREZILLON 
24580eded6cSBoris BREZILLON 	if (!sckcr || !name)
24680eded6cSBoris BREZILLON 		return ERR_PTR(-EINVAL);
24780eded6cSBoris BREZILLON 
24880eded6cSBoris BREZILLON 	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
24980eded6cSBoris BREZILLON 	if (!osc)
25080eded6cSBoris BREZILLON 		return ERR_PTR(-ENOMEM);
25180eded6cSBoris BREZILLON 
25280eded6cSBoris BREZILLON 	init.name = name;
25380eded6cSBoris BREZILLON 	init.ops = &slow_rc_osc_ops;
25480eded6cSBoris BREZILLON 	init.parent_names = NULL;
25580eded6cSBoris BREZILLON 	init.num_parents = 0;
25680eded6cSBoris BREZILLON 	init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED;
25780eded6cSBoris BREZILLON 
25880eded6cSBoris BREZILLON 	osc->hw.init = &init;
25980eded6cSBoris BREZILLON 	osc->sckcr = sckcr;
26080eded6cSBoris BREZILLON 	osc->frequency = frequency;
26180eded6cSBoris BREZILLON 	osc->accuracy = accuracy;
26280eded6cSBoris BREZILLON 	osc->startup_usec = startup;
26380eded6cSBoris BREZILLON 
26480eded6cSBoris BREZILLON 	clk = clk_register(NULL, &osc->hw);
26580eded6cSBoris BREZILLON 	if (IS_ERR(clk))
26680eded6cSBoris BREZILLON 		kfree(osc);
26780eded6cSBoris BREZILLON 
26880eded6cSBoris BREZILLON 	return clk;
26980eded6cSBoris BREZILLON }
27080eded6cSBoris BREZILLON 
27180eded6cSBoris BREZILLON void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np,
27280eded6cSBoris BREZILLON 						void __iomem *sckcr)
27380eded6cSBoris BREZILLON {
27480eded6cSBoris BREZILLON 	struct clk *clk;
27580eded6cSBoris BREZILLON 	u32 frequency = 0;
27680eded6cSBoris BREZILLON 	u32 accuracy = 0;
27780eded6cSBoris BREZILLON 	u32 startup = 0;
27880eded6cSBoris BREZILLON 	const char *name = np->name;
27980eded6cSBoris BREZILLON 
28080eded6cSBoris BREZILLON 	of_property_read_string(np, "clock-output-names", &name);
28180eded6cSBoris BREZILLON 	of_property_read_u32(np, "clock-frequency", &frequency);
28280eded6cSBoris BREZILLON 	of_property_read_u32(np, "clock-accuracy", &accuracy);
28380eded6cSBoris BREZILLON 	of_property_read_u32(np, "atmel,startup-time-usec", &startup);
28480eded6cSBoris BREZILLON 
28580eded6cSBoris BREZILLON 	clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
28680eded6cSBoris BREZILLON 					    startup);
28780eded6cSBoris BREZILLON 	if (IS_ERR(clk))
28880eded6cSBoris BREZILLON 		return;
28980eded6cSBoris BREZILLON 
29080eded6cSBoris BREZILLON 	of_clk_add_provider(np, of_clk_src_simple_get, clk);
29180eded6cSBoris BREZILLON }
29280eded6cSBoris BREZILLON 
29380eded6cSBoris BREZILLON static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
29480eded6cSBoris BREZILLON {
29580eded6cSBoris BREZILLON 	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
29680eded6cSBoris BREZILLON 	void __iomem *sckcr = slowck->sckcr;
29780eded6cSBoris BREZILLON 	u32 tmp;
29880eded6cSBoris BREZILLON 
29980eded6cSBoris BREZILLON 	if (index > 1)
30080eded6cSBoris BREZILLON 		return -EINVAL;
30180eded6cSBoris BREZILLON 
30280eded6cSBoris BREZILLON 	tmp = readl(sckcr);
30380eded6cSBoris BREZILLON 
30480eded6cSBoris BREZILLON 	if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
30580eded6cSBoris BREZILLON 	    (index && (tmp & AT91_SCKC_OSCSEL)))
30680eded6cSBoris BREZILLON 		return 0;
30780eded6cSBoris BREZILLON 
30880eded6cSBoris BREZILLON 	if (index)
30980eded6cSBoris BREZILLON 		tmp |= AT91_SCKC_OSCSEL;
31080eded6cSBoris BREZILLON 	else
31180eded6cSBoris BREZILLON 		tmp &= ~AT91_SCKC_OSCSEL;
31280eded6cSBoris BREZILLON 
31380eded6cSBoris BREZILLON 	writel(tmp, sckcr);
31480eded6cSBoris BREZILLON 
31580eded6cSBoris BREZILLON 	usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
31680eded6cSBoris BREZILLON 
31780eded6cSBoris BREZILLON 	return 0;
31880eded6cSBoris BREZILLON }
31980eded6cSBoris BREZILLON 
32080eded6cSBoris BREZILLON static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
32180eded6cSBoris BREZILLON {
32280eded6cSBoris BREZILLON 	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
32380eded6cSBoris BREZILLON 
32480eded6cSBoris BREZILLON 	return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
32580eded6cSBoris BREZILLON }
32680eded6cSBoris BREZILLON 
32780eded6cSBoris BREZILLON static const struct clk_ops sam9x5_slow_ops = {
32880eded6cSBoris BREZILLON 	.set_parent = clk_sam9x5_slow_set_parent,
32980eded6cSBoris BREZILLON 	.get_parent = clk_sam9x5_slow_get_parent,
33080eded6cSBoris BREZILLON };
33180eded6cSBoris BREZILLON 
33280eded6cSBoris BREZILLON static struct clk * __init
33380eded6cSBoris BREZILLON at91_clk_register_sam9x5_slow(void __iomem *sckcr,
33480eded6cSBoris BREZILLON 			      const char *name,
33580eded6cSBoris BREZILLON 			      const char **parent_names,
33680eded6cSBoris BREZILLON 			      int num_parents)
33780eded6cSBoris BREZILLON {
33880eded6cSBoris BREZILLON 	struct clk_sam9x5_slow *slowck;
33980eded6cSBoris BREZILLON 	struct clk *clk = NULL;
34080eded6cSBoris BREZILLON 	struct clk_init_data init;
34180eded6cSBoris BREZILLON 
34280eded6cSBoris BREZILLON 	if (!sckcr || !name || !parent_names || !num_parents)
34380eded6cSBoris BREZILLON 		return ERR_PTR(-EINVAL);
34480eded6cSBoris BREZILLON 
34580eded6cSBoris BREZILLON 	slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
34680eded6cSBoris BREZILLON 	if (!slowck)
34780eded6cSBoris BREZILLON 		return ERR_PTR(-ENOMEM);
34880eded6cSBoris BREZILLON 
34980eded6cSBoris BREZILLON 	init.name = name;
35080eded6cSBoris BREZILLON 	init.ops = &sam9x5_slow_ops;
35180eded6cSBoris BREZILLON 	init.parent_names = parent_names;
35280eded6cSBoris BREZILLON 	init.num_parents = num_parents;
35380eded6cSBoris BREZILLON 	init.flags = 0;
35480eded6cSBoris BREZILLON 
35580eded6cSBoris BREZILLON 	slowck->hw.init = &init;
35680eded6cSBoris BREZILLON 	slowck->sckcr = sckcr;
35780eded6cSBoris BREZILLON 	slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
35880eded6cSBoris BREZILLON 
35980eded6cSBoris BREZILLON 	clk = clk_register(NULL, &slowck->hw);
36080eded6cSBoris BREZILLON 	if (IS_ERR(clk))
36180eded6cSBoris BREZILLON 		kfree(slowck);
36280eded6cSBoris BREZILLON 
36380eded6cSBoris BREZILLON 	return clk;
36480eded6cSBoris BREZILLON }
36580eded6cSBoris BREZILLON 
36680eded6cSBoris BREZILLON void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
36780eded6cSBoris BREZILLON 					 void __iomem *sckcr)
36880eded6cSBoris BREZILLON {
36980eded6cSBoris BREZILLON 	struct clk *clk;
37080eded6cSBoris BREZILLON 	const char *parent_names[2];
37180eded6cSBoris BREZILLON 	int num_parents;
37280eded6cSBoris BREZILLON 	const char *name = np->name;
37380eded6cSBoris BREZILLON 
37451a43be9SGeert Uytterhoeven 	num_parents = of_clk_get_parent_count(np);
37580eded6cSBoris BREZILLON 	if (num_parents <= 0 || num_parents > 2)
37680eded6cSBoris BREZILLON 		return;
37780eded6cSBoris BREZILLON 
378f0557fbeSDinh Nguyen 	of_clk_parent_fill(np, parent_names, num_parents);
37980eded6cSBoris BREZILLON 
38080eded6cSBoris BREZILLON 	of_property_read_string(np, "clock-output-names", &name);
38180eded6cSBoris BREZILLON 
38280eded6cSBoris BREZILLON 	clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
38380eded6cSBoris BREZILLON 					    num_parents);
38480eded6cSBoris BREZILLON 	if (IS_ERR(clk))
38580eded6cSBoris BREZILLON 		return;
38680eded6cSBoris BREZILLON 
38780eded6cSBoris BREZILLON 	of_clk_add_provider(np, of_clk_src_simple_get, clk);
38880eded6cSBoris BREZILLON }
38980eded6cSBoris BREZILLON 
39080eded6cSBoris BREZILLON static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
39180eded6cSBoris BREZILLON {
39280eded6cSBoris BREZILLON 	struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
393*1bdf0232SBoris Brezillon 	unsigned int status;
39480eded6cSBoris BREZILLON 
395*1bdf0232SBoris Brezillon 	regmap_read(slowck->regmap, AT91_PMC_SR, &status);
396*1bdf0232SBoris Brezillon 
397*1bdf0232SBoris Brezillon 	return status & AT91_PMC_OSCSEL ? 1 : 0;
39880eded6cSBoris BREZILLON }
39980eded6cSBoris BREZILLON 
40080eded6cSBoris BREZILLON static const struct clk_ops sam9260_slow_ops = {
40180eded6cSBoris BREZILLON 	.get_parent = clk_sam9260_slow_get_parent,
40280eded6cSBoris BREZILLON };
40380eded6cSBoris BREZILLON 
40480eded6cSBoris BREZILLON static struct clk * __init
405*1bdf0232SBoris Brezillon at91_clk_register_sam9260_slow(struct regmap *regmap,
40680eded6cSBoris BREZILLON 			       const char *name,
40780eded6cSBoris BREZILLON 			       const char **parent_names,
40880eded6cSBoris BREZILLON 			       int num_parents)
40980eded6cSBoris BREZILLON {
41080eded6cSBoris BREZILLON 	struct clk_sam9260_slow *slowck;
41180eded6cSBoris BREZILLON 	struct clk *clk = NULL;
41280eded6cSBoris BREZILLON 	struct clk_init_data init;
41380eded6cSBoris BREZILLON 
414*1bdf0232SBoris Brezillon 	if (!name)
41580eded6cSBoris BREZILLON 		return ERR_PTR(-EINVAL);
41680eded6cSBoris BREZILLON 
41780eded6cSBoris BREZILLON 	if (!parent_names || !num_parents)
41880eded6cSBoris BREZILLON 		return ERR_PTR(-EINVAL);
41980eded6cSBoris BREZILLON 
42080eded6cSBoris BREZILLON 	slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
42180eded6cSBoris BREZILLON 	if (!slowck)
42280eded6cSBoris BREZILLON 		return ERR_PTR(-ENOMEM);
42380eded6cSBoris BREZILLON 
42480eded6cSBoris BREZILLON 	init.name = name;
42580eded6cSBoris BREZILLON 	init.ops = &sam9260_slow_ops;
42680eded6cSBoris BREZILLON 	init.parent_names = parent_names;
42780eded6cSBoris BREZILLON 	init.num_parents = num_parents;
42880eded6cSBoris BREZILLON 	init.flags = 0;
42980eded6cSBoris BREZILLON 
43080eded6cSBoris BREZILLON 	slowck->hw.init = &init;
431*1bdf0232SBoris Brezillon 	slowck->regmap = regmap;
43280eded6cSBoris BREZILLON 
43380eded6cSBoris BREZILLON 	clk = clk_register(NULL, &slowck->hw);
43480eded6cSBoris BREZILLON 	if (IS_ERR(clk))
43580eded6cSBoris BREZILLON 		kfree(slowck);
43680eded6cSBoris BREZILLON 
43780eded6cSBoris BREZILLON 	return clk;
43880eded6cSBoris BREZILLON }
43980eded6cSBoris BREZILLON 
440*1bdf0232SBoris Brezillon static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
44180eded6cSBoris BREZILLON {
44280eded6cSBoris BREZILLON 	struct clk *clk;
44380eded6cSBoris BREZILLON 	const char *parent_names[2];
44480eded6cSBoris BREZILLON 	int num_parents;
44580eded6cSBoris BREZILLON 	const char *name = np->name;
446*1bdf0232SBoris Brezillon 	struct regmap *regmap;
44780eded6cSBoris BREZILLON 
44851a43be9SGeert Uytterhoeven 	num_parents = of_clk_get_parent_count(np);
449e8531ac8SBoris BREZILLON 	if (num_parents != 2)
45080eded6cSBoris BREZILLON 		return;
45180eded6cSBoris BREZILLON 
452f0557fbeSDinh Nguyen 	of_clk_parent_fill(np, parent_names, num_parents);
453*1bdf0232SBoris Brezillon 	regmap = syscon_node_to_regmap(of_get_parent(np));
454*1bdf0232SBoris Brezillon 	if (IS_ERR(regmap))
455*1bdf0232SBoris Brezillon 		return;
45680eded6cSBoris BREZILLON 
45780eded6cSBoris BREZILLON 	of_property_read_string(np, "clock-output-names", &name);
45880eded6cSBoris BREZILLON 
459*1bdf0232SBoris Brezillon 	clk = at91_clk_register_sam9260_slow(regmap, name, parent_names,
46080eded6cSBoris BREZILLON 					     num_parents);
46180eded6cSBoris BREZILLON 	if (IS_ERR(clk))
46280eded6cSBoris BREZILLON 		return;
46380eded6cSBoris BREZILLON 
46480eded6cSBoris BREZILLON 	of_clk_add_provider(np, of_clk_src_simple_get, clk);
46580eded6cSBoris BREZILLON }
466*1bdf0232SBoris Brezillon 
467*1bdf0232SBoris Brezillon CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
468*1bdf0232SBoris Brezillon 	       of_at91sam9260_clk_slow_setup);
469