18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
78c2ecf20Sopenharmony_ci#include <linux/clkdev.h>
88c2ecf20Sopenharmony_ci#include <linux/clk/at91_pmc.h>
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
118c2ecf20Sopenharmony_ci#include <linux/regmap.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "pmc.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define SLOW_CLOCK_FREQ		32768
168c2ecf20Sopenharmony_ci#define MAINF_DIV		16
178c2ecf20Sopenharmony_ci#define MAINFRDY_TIMEOUT	(((MAINF_DIV + 1) * USEC_PER_SEC) / \
188c2ecf20Sopenharmony_ci				 SLOW_CLOCK_FREQ)
198c2ecf20Sopenharmony_ci#define MAINF_LOOP_MIN_WAIT	(USEC_PER_SEC / SLOW_CLOCK_FREQ)
208c2ecf20Sopenharmony_ci#define MAINF_LOOP_MAX_WAIT	MAINFRDY_TIMEOUT
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define MOR_KEY_MASK		(0xff << 16)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define clk_main_parent_select(s)	(((s) & \
258c2ecf20Sopenharmony_ci					(AT91_PMC_MOSCEN | \
268c2ecf20Sopenharmony_ci					AT91_PMC_OSCBYPASS)) ? 1 : 0)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct clk_main_osc {
298c2ecf20Sopenharmony_ci	struct clk_hw hw;
308c2ecf20Sopenharmony_ci	struct regmap *regmap;
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct clk_main_rc_osc {
368c2ecf20Sopenharmony_ci	struct clk_hw hw;
378c2ecf20Sopenharmony_ci	struct regmap *regmap;
388c2ecf20Sopenharmony_ci	unsigned long frequency;
398c2ecf20Sopenharmony_ci	unsigned long accuracy;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistruct clk_rm9200_main {
458c2ecf20Sopenharmony_ci	struct clk_hw hw;
468c2ecf20Sopenharmony_ci	struct regmap *regmap;
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistruct clk_sam9x5_main {
528c2ecf20Sopenharmony_ci	struct clk_hw hw;
538c2ecf20Sopenharmony_ci	struct regmap *regmap;
548c2ecf20Sopenharmony_ci	u8 parent;
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline bool clk_main_osc_ready(struct regmap *regmap)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	unsigned int status;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_PMC_SR, &status);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return status & AT91_PMC_MOSCS;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic int clk_main_osc_prepare(struct clk_hw *hw)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct clk_main_osc *osc = to_clk_main_osc(hw);
718c2ecf20Sopenharmony_ci	struct regmap *regmap = osc->regmap;
728c2ecf20Sopenharmony_ci	u32 tmp;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
758c2ecf20Sopenharmony_ci	tmp &= ~MOR_KEY_MASK;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (tmp & AT91_PMC_OSCBYPASS)
788c2ecf20Sopenharmony_ci		return 0;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (!(tmp & AT91_PMC_MOSCEN)) {
818c2ecf20Sopenharmony_ci		tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
828c2ecf20Sopenharmony_ci		regmap_write(regmap, AT91_CKGR_MOR, tmp);
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	while (!clk_main_osc_ready(regmap))
868c2ecf20Sopenharmony_ci		cpu_relax();
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return 0;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic void clk_main_osc_unprepare(struct clk_hw *hw)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct clk_main_osc *osc = to_clk_main_osc(hw);
948c2ecf20Sopenharmony_ci	struct regmap *regmap = osc->regmap;
958c2ecf20Sopenharmony_ci	u32 tmp;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
988c2ecf20Sopenharmony_ci	if (tmp & AT91_PMC_OSCBYPASS)
998c2ecf20Sopenharmony_ci		return;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (!(tmp & AT91_PMC_MOSCEN))
1028c2ecf20Sopenharmony_ci		return;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
1058c2ecf20Sopenharmony_ci	regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic int clk_main_osc_is_prepared(struct clk_hw *hw)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct clk_main_osc *osc = to_clk_main_osc(hw);
1118c2ecf20Sopenharmony_ci	struct regmap *regmap = osc->regmap;
1128c2ecf20Sopenharmony_ci	u32 tmp, status;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
1158c2ecf20Sopenharmony_ci	if (tmp & AT91_PMC_OSCBYPASS)
1168c2ecf20Sopenharmony_ci		return 1;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_PMC_SR, &status);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return (status & AT91_PMC_MOSCS) && clk_main_parent_select(tmp);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic const struct clk_ops main_osc_ops = {
1248c2ecf20Sopenharmony_ci	.prepare = clk_main_osc_prepare,
1258c2ecf20Sopenharmony_ci	.unprepare = clk_main_osc_unprepare,
1268c2ecf20Sopenharmony_ci	.is_prepared = clk_main_osc_is_prepared,
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistruct clk_hw * __init
1308c2ecf20Sopenharmony_ciat91_clk_register_main_osc(struct regmap *regmap,
1318c2ecf20Sopenharmony_ci			   const char *name,
1328c2ecf20Sopenharmony_ci			   const char *parent_name,
1338c2ecf20Sopenharmony_ci			   bool bypass)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct clk_main_osc *osc;
1368c2ecf20Sopenharmony_ci	struct clk_init_data init;
1378c2ecf20Sopenharmony_ci	struct clk_hw *hw;
1388c2ecf20Sopenharmony_ci	int ret;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (!name || !parent_name)
1418c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
1448c2ecf20Sopenharmony_ci	if (!osc)
1458c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	init.name = name;
1488c2ecf20Sopenharmony_ci	init.ops = &main_osc_ops;
1498c2ecf20Sopenharmony_ci	init.parent_names = &parent_name;
1508c2ecf20Sopenharmony_ci	init.num_parents = 1;
1518c2ecf20Sopenharmony_ci	init.flags = CLK_IGNORE_UNUSED;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	osc->hw.init = &init;
1548c2ecf20Sopenharmony_ci	osc->regmap = regmap;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (bypass)
1578c2ecf20Sopenharmony_ci		regmap_update_bits(regmap,
1588c2ecf20Sopenharmony_ci				   AT91_CKGR_MOR, MOR_KEY_MASK |
1598c2ecf20Sopenharmony_ci				   AT91_PMC_OSCBYPASS,
1608c2ecf20Sopenharmony_ci				   AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	hw = &osc->hw;
1638c2ecf20Sopenharmony_ci	ret = clk_hw_register(NULL, &osc->hw);
1648c2ecf20Sopenharmony_ci	if (ret) {
1658c2ecf20Sopenharmony_ci		kfree(osc);
1668c2ecf20Sopenharmony_ci		hw = ERR_PTR(ret);
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	return hw;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic bool clk_main_rc_osc_ready(struct regmap *regmap)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	unsigned int status;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_PMC_SR, &status);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return !!(status & AT91_PMC_MOSCRCS);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int clk_main_rc_osc_prepare(struct clk_hw *hw)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
1848c2ecf20Sopenharmony_ci	struct regmap *regmap = osc->regmap;
1858c2ecf20Sopenharmony_ci	unsigned int mor;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_CKGR_MOR, &mor);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (!(mor & AT91_PMC_MOSCRCEN))
1908c2ecf20Sopenharmony_ci		regmap_update_bits(regmap, AT91_CKGR_MOR,
1918c2ecf20Sopenharmony_ci				   MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
1928c2ecf20Sopenharmony_ci				   AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	while (!clk_main_rc_osc_ready(regmap))
1958c2ecf20Sopenharmony_ci		cpu_relax();
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return 0;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic void clk_main_rc_osc_unprepare(struct clk_hw *hw)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
2038c2ecf20Sopenharmony_ci	struct regmap *regmap = osc->regmap;
2048c2ecf20Sopenharmony_ci	unsigned int mor;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_CKGR_MOR, &mor);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if (!(mor & AT91_PMC_MOSCRCEN))
2098c2ecf20Sopenharmony_ci		return;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	regmap_update_bits(regmap, AT91_CKGR_MOR,
2128c2ecf20Sopenharmony_ci			   MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
2188c2ecf20Sopenharmony_ci	struct regmap *regmap = osc->regmap;
2198c2ecf20Sopenharmony_ci	unsigned int mor, status;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_CKGR_MOR, &mor);
2228c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_PMC_SR, &status);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
2288c2ecf20Sopenharmony_ci						 unsigned long parent_rate)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return osc->frequency;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,
2368c2ecf20Sopenharmony_ci						     unsigned long parent_acc)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return osc->accuracy;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic const struct clk_ops main_rc_osc_ops = {
2448c2ecf20Sopenharmony_ci	.prepare = clk_main_rc_osc_prepare,
2458c2ecf20Sopenharmony_ci	.unprepare = clk_main_rc_osc_unprepare,
2468c2ecf20Sopenharmony_ci	.is_prepared = clk_main_rc_osc_is_prepared,
2478c2ecf20Sopenharmony_ci	.recalc_rate = clk_main_rc_osc_recalc_rate,
2488c2ecf20Sopenharmony_ci	.recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
2498c2ecf20Sopenharmony_ci};
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistruct clk_hw * __init
2528c2ecf20Sopenharmony_ciat91_clk_register_main_rc_osc(struct regmap *regmap,
2538c2ecf20Sopenharmony_ci			      const char *name,
2548c2ecf20Sopenharmony_ci			      u32 frequency, u32 accuracy)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct clk_main_rc_osc *osc;
2578c2ecf20Sopenharmony_ci	struct clk_init_data init;
2588c2ecf20Sopenharmony_ci	struct clk_hw *hw;
2598c2ecf20Sopenharmony_ci	int ret;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (!name || !frequency)
2628c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
2658c2ecf20Sopenharmony_ci	if (!osc)
2668c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	init.name = name;
2698c2ecf20Sopenharmony_ci	init.ops = &main_rc_osc_ops;
2708c2ecf20Sopenharmony_ci	init.parent_names = NULL;
2718c2ecf20Sopenharmony_ci	init.num_parents = 0;
2728c2ecf20Sopenharmony_ci	init.flags = CLK_IGNORE_UNUSED;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	osc->hw.init = &init;
2758c2ecf20Sopenharmony_ci	osc->regmap = regmap;
2768c2ecf20Sopenharmony_ci	osc->frequency = frequency;
2778c2ecf20Sopenharmony_ci	osc->accuracy = accuracy;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	hw = &osc->hw;
2808c2ecf20Sopenharmony_ci	ret = clk_hw_register(NULL, hw);
2818c2ecf20Sopenharmony_ci	if (ret) {
2828c2ecf20Sopenharmony_ci		kfree(osc);
2838c2ecf20Sopenharmony_ci		hw = ERR_PTR(ret);
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return hw;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic int clk_main_probe_frequency(struct regmap *regmap)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	unsigned long prep_time, timeout;
2928c2ecf20Sopenharmony_ci	unsigned int mcfr;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
2958c2ecf20Sopenharmony_ci	do {
2968c2ecf20Sopenharmony_ci		prep_time = jiffies;
2978c2ecf20Sopenharmony_ci		regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
2988c2ecf20Sopenharmony_ci		if (mcfr & AT91_PMC_MAINRDY)
2998c2ecf20Sopenharmony_ci			return 0;
3008c2ecf20Sopenharmony_ci		if (system_state < SYSTEM_RUNNING)
3018c2ecf20Sopenharmony_ci			udelay(MAINF_LOOP_MIN_WAIT);
3028c2ecf20Sopenharmony_ci		else
3038c2ecf20Sopenharmony_ci			usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
3048c2ecf20Sopenharmony_ci	} while (time_before(prep_time, timeout));
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic unsigned long clk_main_recalc_rate(struct regmap *regmap,
3108c2ecf20Sopenharmony_ci					  unsigned long parent_rate)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	unsigned int mcfr;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (parent_rate)
3158c2ecf20Sopenharmony_ci		return parent_rate;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	pr_warn("Main crystal frequency not set, using approximate value\n");
3188c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
3198c2ecf20Sopenharmony_ci	if (!(mcfr & AT91_PMC_MAINRDY))
3208c2ecf20Sopenharmony_ci		return 0;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic int clk_rm9200_main_prepare(struct clk_hw *hw)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return clk_main_probe_frequency(clkmain->regmap);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int clk_rm9200_main_is_prepared(struct clk_hw *hw)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
3358c2ecf20Sopenharmony_ci	unsigned int status;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	return !!(status & AT91_PMC_MAINRDY);
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
3438c2ecf20Sopenharmony_ci						 unsigned long parent_rate)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	return clk_main_recalc_rate(clkmain->regmap, parent_rate);
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic const struct clk_ops rm9200_main_ops = {
3518c2ecf20Sopenharmony_ci	.prepare = clk_rm9200_main_prepare,
3528c2ecf20Sopenharmony_ci	.is_prepared = clk_rm9200_main_is_prepared,
3538c2ecf20Sopenharmony_ci	.recalc_rate = clk_rm9200_main_recalc_rate,
3548c2ecf20Sopenharmony_ci};
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistruct clk_hw * __init
3578c2ecf20Sopenharmony_ciat91_clk_register_rm9200_main(struct regmap *regmap,
3588c2ecf20Sopenharmony_ci			      const char *name,
3598c2ecf20Sopenharmony_ci			      const char *parent_name)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct clk_rm9200_main *clkmain;
3628c2ecf20Sopenharmony_ci	struct clk_init_data init;
3638c2ecf20Sopenharmony_ci	struct clk_hw *hw;
3648c2ecf20Sopenharmony_ci	int ret;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (!name)
3678c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (!parent_name)
3708c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
3738c2ecf20Sopenharmony_ci	if (!clkmain)
3748c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	init.name = name;
3778c2ecf20Sopenharmony_ci	init.ops = &rm9200_main_ops;
3788c2ecf20Sopenharmony_ci	init.parent_names = &parent_name;
3798c2ecf20Sopenharmony_ci	init.num_parents = 1;
3808c2ecf20Sopenharmony_ci	init.flags = 0;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	clkmain->hw.init = &init;
3838c2ecf20Sopenharmony_ci	clkmain->regmap = regmap;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	hw = &clkmain->hw;
3868c2ecf20Sopenharmony_ci	ret = clk_hw_register(NULL, &clkmain->hw);
3878c2ecf20Sopenharmony_ci	if (ret) {
3888c2ecf20Sopenharmony_ci		kfree(clkmain);
3898c2ecf20Sopenharmony_ci		hw = ERR_PTR(ret);
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return hw;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic inline bool clk_sam9x5_main_ready(struct regmap *regmap)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	unsigned int status;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_PMC_SR, &status);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	return !!(status & AT91_PMC_MOSCSELS);
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic int clk_sam9x5_main_prepare(struct clk_hw *hw)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
4078c2ecf20Sopenharmony_ci	struct regmap *regmap = clkmain->regmap;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	while (!clk_sam9x5_main_ready(regmap))
4108c2ecf20Sopenharmony_ci		cpu_relax();
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	return clk_main_probe_frequency(regmap);
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return clk_sam9x5_main_ready(clkmain->regmap);
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
4238c2ecf20Sopenharmony_ci						 unsigned long parent_rate)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return clk_main_recalc_rate(clkmain->regmap, parent_rate);
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
4338c2ecf20Sopenharmony_ci	struct regmap *regmap = clkmain->regmap;
4348c2ecf20Sopenharmony_ci	unsigned int tmp;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (index > 1)
4378c2ecf20Sopenharmony_ci		return -EINVAL;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (index && !(tmp & AT91_PMC_MOSCSEL))
4428c2ecf20Sopenharmony_ci		tmp = AT91_PMC_MOSCSEL;
4438c2ecf20Sopenharmony_ci	else if (!index && (tmp & AT91_PMC_MOSCSEL))
4448c2ecf20Sopenharmony_ci		tmp = 0;
4458c2ecf20Sopenharmony_ci	else
4468c2ecf20Sopenharmony_ci		return 0;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	regmap_update_bits(regmap, AT91_CKGR_MOR,
4498c2ecf20Sopenharmony_ci			   AT91_PMC_MOSCSEL | MOR_KEY_MASK,
4508c2ecf20Sopenharmony_ci			   tmp | AT91_PMC_KEY);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	while (!clk_sam9x5_main_ready(regmap))
4538c2ecf20Sopenharmony_ci		cpu_relax();
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	return 0;
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
4618c2ecf20Sopenharmony_ci	unsigned int status;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	return clk_main_parent_select(status);
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic const struct clk_ops sam9x5_main_ops = {
4698c2ecf20Sopenharmony_ci	.prepare = clk_sam9x5_main_prepare,
4708c2ecf20Sopenharmony_ci	.is_prepared = clk_sam9x5_main_is_prepared,
4718c2ecf20Sopenharmony_ci	.recalc_rate = clk_sam9x5_main_recalc_rate,
4728c2ecf20Sopenharmony_ci	.set_parent = clk_sam9x5_main_set_parent,
4738c2ecf20Sopenharmony_ci	.get_parent = clk_sam9x5_main_get_parent,
4748c2ecf20Sopenharmony_ci};
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistruct clk_hw * __init
4778c2ecf20Sopenharmony_ciat91_clk_register_sam9x5_main(struct regmap *regmap,
4788c2ecf20Sopenharmony_ci			      const char *name,
4798c2ecf20Sopenharmony_ci			      const char **parent_names,
4808c2ecf20Sopenharmony_ci			      int num_parents)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	struct clk_sam9x5_main *clkmain;
4838c2ecf20Sopenharmony_ci	struct clk_init_data init;
4848c2ecf20Sopenharmony_ci	unsigned int status;
4858c2ecf20Sopenharmony_ci	struct clk_hw *hw;
4868c2ecf20Sopenharmony_ci	int ret;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (!name)
4898c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	if (!parent_names || !num_parents)
4928c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
4958c2ecf20Sopenharmony_ci	if (!clkmain)
4968c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	init.name = name;
4998c2ecf20Sopenharmony_ci	init.ops = &sam9x5_main_ops;
5008c2ecf20Sopenharmony_ci	init.parent_names = parent_names;
5018c2ecf20Sopenharmony_ci	init.num_parents = num_parents;
5028c2ecf20Sopenharmony_ci	init.flags = CLK_SET_PARENT_GATE;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	clkmain->hw.init = &init;
5058c2ecf20Sopenharmony_ci	clkmain->regmap = regmap;
5068c2ecf20Sopenharmony_ci	regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
5078c2ecf20Sopenharmony_ci	clkmain->parent = clk_main_parent_select(status);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	hw = &clkmain->hw;
5108c2ecf20Sopenharmony_ci	ret = clk_hw_register(NULL, &clkmain->hw);
5118c2ecf20Sopenharmony_ci	if (ret) {
5128c2ecf20Sopenharmony_ci		kfree(clkmain);
5138c2ecf20Sopenharmony_ci		hw = ERR_PTR(ret);
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	return hw;
5178c2ecf20Sopenharmony_ci}
518