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/of.h>
108c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
118c2ecf20Sopenharmony_ci#include <linux/regmap.h>
128c2ecf20Sopenharmony_ci#include <soc/at91/atmel-sfr.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "pmc.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/*
178c2ecf20Sopenharmony_ci * The purpose of this clock is to generate a 480 MHz signal. A different
188c2ecf20Sopenharmony_ci * rate can't be configured.
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ci#define UTMI_RATE	480000000
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistruct clk_utmi {
238c2ecf20Sopenharmony_ci	struct clk_hw hw;
248c2ecf20Sopenharmony_ci	struct regmap *regmap_pmc;
258c2ecf20Sopenharmony_ci	struct regmap *regmap_sfr;
268c2ecf20Sopenharmony_ci};
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic inline bool clk_utmi_ready(struct regmap *regmap)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	unsigned int status;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	regmap_read(regmap, AT91_PMC_SR, &status);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	return status & AT91_PMC_LOCKU;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int clk_utmi_prepare(struct clk_hw *hw)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct clk_hw *hw_parent;
428c2ecf20Sopenharmony_ci	struct clk_utmi *utmi = to_clk_utmi(hw);
438c2ecf20Sopenharmony_ci	unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
448c2ecf20Sopenharmony_ci			    AT91_PMC_BIASEN;
458c2ecf20Sopenharmony_ci	unsigned int utmi_ref_clk_freq;
468c2ecf20Sopenharmony_ci	unsigned long parent_rate;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/*
498c2ecf20Sopenharmony_ci	 * If mainck rate is different from 12 MHz, we have to configure the
508c2ecf20Sopenharmony_ci	 * FREQ field of the SFR_UTMICKTRIM register to generate properly
518c2ecf20Sopenharmony_ci	 * the utmi clock.
528c2ecf20Sopenharmony_ci	 */
538c2ecf20Sopenharmony_ci	hw_parent = clk_hw_get_parent(hw);
548c2ecf20Sopenharmony_ci	parent_rate = clk_hw_get_rate(hw_parent);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	switch (parent_rate) {
578c2ecf20Sopenharmony_ci	case 12000000:
588c2ecf20Sopenharmony_ci		utmi_ref_clk_freq = 0;
598c2ecf20Sopenharmony_ci		break;
608c2ecf20Sopenharmony_ci	case 16000000:
618c2ecf20Sopenharmony_ci		utmi_ref_clk_freq = 1;
628c2ecf20Sopenharmony_ci		break;
638c2ecf20Sopenharmony_ci	case 24000000:
648c2ecf20Sopenharmony_ci		utmi_ref_clk_freq = 2;
658c2ecf20Sopenharmony_ci		break;
668c2ecf20Sopenharmony_ci	/*
678c2ecf20Sopenharmony_ci	 * Not supported on SAMA5D2 but it's not an issue since MAINCK
688c2ecf20Sopenharmony_ci	 * maximum value is 24 MHz.
698c2ecf20Sopenharmony_ci	 */
708c2ecf20Sopenharmony_ci	case 48000000:
718c2ecf20Sopenharmony_ci		utmi_ref_clk_freq = 3;
728c2ecf20Sopenharmony_ci		break;
738c2ecf20Sopenharmony_ci	default:
748c2ecf20Sopenharmony_ci		pr_err("UTMICK: unsupported mainck rate\n");
758c2ecf20Sopenharmony_ci		return -EINVAL;
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (utmi->regmap_sfr) {
798c2ecf20Sopenharmony_ci		regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM,
808c2ecf20Sopenharmony_ci				   AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq);
818c2ecf20Sopenharmony_ci	} else if (utmi_ref_clk_freq) {
828c2ecf20Sopenharmony_ci		pr_err("UTMICK: sfr node required\n");
838c2ecf20Sopenharmony_ci		return -EINVAL;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR, uckr, uckr);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	while (!clk_utmi_ready(utmi->regmap_pmc))
898c2ecf20Sopenharmony_ci		cpu_relax();
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	return 0;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic int clk_utmi_is_prepared(struct clk_hw *hw)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct clk_utmi *utmi = to_clk_utmi(hw);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return clk_utmi_ready(utmi->regmap_pmc);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic void clk_utmi_unprepare(struct clk_hw *hw)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct clk_utmi *utmi = to_clk_utmi(hw);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR,
1068c2ecf20Sopenharmony_ci			   AT91_PMC_UPLLEN, 0);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
1108c2ecf20Sopenharmony_ci					  unsigned long parent_rate)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	/* UTMI clk rate is fixed. */
1138c2ecf20Sopenharmony_ci	return UTMI_RATE;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic const struct clk_ops utmi_ops = {
1178c2ecf20Sopenharmony_ci	.prepare = clk_utmi_prepare,
1188c2ecf20Sopenharmony_ci	.unprepare = clk_utmi_unprepare,
1198c2ecf20Sopenharmony_ci	.is_prepared = clk_utmi_is_prepared,
1208c2ecf20Sopenharmony_ci	.recalc_rate = clk_utmi_recalc_rate,
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic struct clk_hw * __init
1248c2ecf20Sopenharmony_ciat91_clk_register_utmi_internal(struct regmap *regmap_pmc,
1258c2ecf20Sopenharmony_ci				struct regmap *regmap_sfr,
1268c2ecf20Sopenharmony_ci				const char *name, const char *parent_name,
1278c2ecf20Sopenharmony_ci				const struct clk_ops *ops, unsigned long flags)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	struct clk_utmi *utmi;
1308c2ecf20Sopenharmony_ci	struct clk_hw *hw;
1318c2ecf20Sopenharmony_ci	struct clk_init_data init;
1328c2ecf20Sopenharmony_ci	int ret;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
1358c2ecf20Sopenharmony_ci	if (!utmi)
1368c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	init.name = name;
1398c2ecf20Sopenharmony_ci	init.ops = ops;
1408c2ecf20Sopenharmony_ci	init.parent_names = parent_name ? &parent_name : NULL;
1418c2ecf20Sopenharmony_ci	init.num_parents = parent_name ? 1 : 0;
1428c2ecf20Sopenharmony_ci	init.flags = flags;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	utmi->hw.init = &init;
1458c2ecf20Sopenharmony_ci	utmi->regmap_pmc = regmap_pmc;
1468c2ecf20Sopenharmony_ci	utmi->regmap_sfr = regmap_sfr;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	hw = &utmi->hw;
1498c2ecf20Sopenharmony_ci	ret = clk_hw_register(NULL, &utmi->hw);
1508c2ecf20Sopenharmony_ci	if (ret) {
1518c2ecf20Sopenharmony_ci		kfree(utmi);
1528c2ecf20Sopenharmony_ci		hw = ERR_PTR(ret);
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return hw;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistruct clk_hw * __init
1598c2ecf20Sopenharmony_ciat91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
1608c2ecf20Sopenharmony_ci		       const char *name, const char *parent_name)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	return at91_clk_register_utmi_internal(regmap_pmc, regmap_sfr, name,
1638c2ecf20Sopenharmony_ci			parent_name, &utmi_ops, CLK_SET_RATE_GATE);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int clk_utmi_sama7g5_prepare(struct clk_hw *hw)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct clk_utmi *utmi = to_clk_utmi(hw);
1698c2ecf20Sopenharmony_ci	struct clk_hw *hw_parent;
1708c2ecf20Sopenharmony_ci	unsigned long parent_rate;
1718c2ecf20Sopenharmony_ci	unsigned int val;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	hw_parent = clk_hw_get_parent(hw);
1748c2ecf20Sopenharmony_ci	parent_rate = clk_hw_get_rate(hw_parent);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	switch (parent_rate) {
1778c2ecf20Sopenharmony_ci	case 16000000:
1788c2ecf20Sopenharmony_ci		val = 0;
1798c2ecf20Sopenharmony_ci		break;
1808c2ecf20Sopenharmony_ci	case 20000000:
1818c2ecf20Sopenharmony_ci		val = 2;
1828c2ecf20Sopenharmony_ci		break;
1838c2ecf20Sopenharmony_ci	case 24000000:
1848c2ecf20Sopenharmony_ci		val = 3;
1858c2ecf20Sopenharmony_ci		break;
1868c2ecf20Sopenharmony_ci	case 32000000:
1878c2ecf20Sopenharmony_ci		val = 5;
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci	default:
1908c2ecf20Sopenharmony_ci		pr_err("UTMICK: unsupported main_xtal rate\n");
1918c2ecf20Sopenharmony_ci		return -EINVAL;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	regmap_write(utmi->regmap_pmc, AT91_PMC_XTALF, val);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	return 0;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic int clk_utmi_sama7g5_is_prepared(struct clk_hw *hw)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	struct clk_utmi *utmi = to_clk_utmi(hw);
2038c2ecf20Sopenharmony_ci	struct clk_hw *hw_parent;
2048c2ecf20Sopenharmony_ci	unsigned long parent_rate;
2058c2ecf20Sopenharmony_ci	unsigned int val;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	hw_parent = clk_hw_get_parent(hw);
2088c2ecf20Sopenharmony_ci	parent_rate = clk_hw_get_rate(hw_parent);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	regmap_read(utmi->regmap_pmc, AT91_PMC_XTALF, &val);
2118c2ecf20Sopenharmony_ci	switch (val & 0x7) {
2128c2ecf20Sopenharmony_ci	case 0:
2138c2ecf20Sopenharmony_ci		if (parent_rate == 16000000)
2148c2ecf20Sopenharmony_ci			return 1;
2158c2ecf20Sopenharmony_ci		break;
2168c2ecf20Sopenharmony_ci	case 2:
2178c2ecf20Sopenharmony_ci		if (parent_rate == 20000000)
2188c2ecf20Sopenharmony_ci			return 1;
2198c2ecf20Sopenharmony_ci		break;
2208c2ecf20Sopenharmony_ci	case 3:
2218c2ecf20Sopenharmony_ci		if (parent_rate == 24000000)
2228c2ecf20Sopenharmony_ci			return 1;
2238c2ecf20Sopenharmony_ci		break;
2248c2ecf20Sopenharmony_ci	case 5:
2258c2ecf20Sopenharmony_ci		if (parent_rate == 32000000)
2268c2ecf20Sopenharmony_ci			return 1;
2278c2ecf20Sopenharmony_ci		break;
2288c2ecf20Sopenharmony_ci	default:
2298c2ecf20Sopenharmony_ci		break;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return 0;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic const struct clk_ops sama7g5_utmi_ops = {
2368c2ecf20Sopenharmony_ci	.prepare = clk_utmi_sama7g5_prepare,
2378c2ecf20Sopenharmony_ci	.is_prepared = clk_utmi_sama7g5_is_prepared,
2388c2ecf20Sopenharmony_ci	.recalc_rate = clk_utmi_recalc_rate,
2398c2ecf20Sopenharmony_ci};
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistruct clk_hw * __init
2428c2ecf20Sopenharmony_ciat91_clk_sama7g5_register_utmi(struct regmap *regmap_pmc, const char *name,
2438c2ecf20Sopenharmony_ci			       const char *parent_name)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	return at91_clk_register_utmi_internal(regmap_pmc, NULL, name,
2468c2ecf20Sopenharmony_ci			parent_name, &sama7g5_utmi_ops, 0);
2478c2ecf20Sopenharmony_ci}
248