From: Claudiu Beznea Date: Mon, 7 Sep 2020 14:46:45 +0000 (+0300) Subject: clk: at91: clk-utmi: add driver compatible with ccf X-Git-Tag: v2025.01-rc5-pxa1908~2192^2^2~18 X-Git-Url: http://git.dujemihanovic.xyz/img/static/gitweb.css?a=commitdiff_plain;h=ad4d39a964e1d3abb4f2c3d933234f86a7960d54;p=u-boot.git clk: at91: clk-utmi: add driver compatible with ccf Add clk-utmi driver compatible with common clock framework. Signed-off-by: Claudiu Beznea --- diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index a4e397066e..9c38bda5e6 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -4,6 +4,7 @@ ifdef CONFIG_CLK_CCF obj-y += pmc.o sckc.o clk-main.o clk-master.o +obj-$(CONFIG_AT91_UTMI) += clk-utmi.o obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o else obj-y += compat.o diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c new file mode 100644 index 0000000000..b60fd35b6b --- /dev/null +++ b/drivers/clk/at91/clk-utmi.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UTMI clock support for AT91 architectures. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on drivers/clk/at91/clk-utmi.c from Linux. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_UTMI "at91-utmi-clk" + +/* + * The purpose of this clock is to generate a 480 MHz signal. A different + * rate can't be configured. + */ +#define UTMI_RATE 480000000 + +struct clk_utmi { + void __iomem *base; + struct regmap *regmap_sfr; + struct clk clk; +}; + +#define to_clk_utmi(_clk) container_of(_clk, struct clk_utmi, clk) + +static inline bool clk_utmi_ready(struct regmap *regmap) +{ + unsigned int status; + + pmc_read(regmap, AT91_PMC_SR, &status); + + return !!(status & AT91_PMC_LOCKU); +} + +static int clk_utmi_enable(struct clk *clk) +{ + struct clk_utmi *utmi = to_clk_utmi(clk); + unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT | + AT91_PMC_BIASEN; + unsigned int utmi_ref_clk_freq; + ulong parent_rate = clk_get_parent_rate(clk); + + /* + * If mainck rate is different from 12 MHz, we have to configure the + * FREQ field of the SFR_UTMICKTRIM register to generate properly + * the utmi clock. + */ + switch (parent_rate) { + case 12000000: + utmi_ref_clk_freq = 0; + break; + case 16000000: + utmi_ref_clk_freq = 1; + break; + case 24000000: + utmi_ref_clk_freq = 2; + break; + /* + * Not supported on SAMA5D2 but it's not an issue since MAINCK + * maximum value is 24 MHz. + */ + case 48000000: + utmi_ref_clk_freq = 3; + break; + default: + debug("UTMICK: unsupported mainck rate\n"); + return -EINVAL; + } + + if (utmi->regmap_sfr) { + regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM, + AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq); + } else if (utmi_ref_clk_freq) { + debug("UTMICK: sfr node required\n"); + return -EINVAL; + } + + pmc_update_bits(utmi->base, AT91_CKGR_UCKR, uckr, uckr); + + while (!clk_utmi_ready(utmi->base)) { + debug("waiting for utmi...\n"); + cpu_relax(); + } + + return 0; +} + +static int clk_utmi_disable(struct clk *clk) +{ + struct clk_utmi *utmi = to_clk_utmi(clk); + + pmc_update_bits(utmi->base, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0); + + return 0; +} + +static ulong clk_utmi_get_rate(struct clk *clk) +{ + /* UTMI clk rate is fixed. */ + return UTMI_RATE; +} + +static const struct clk_ops utmi_ops = { + .enable = clk_utmi_enable, + .disable = clk_utmi_disable, + .get_rate = clk_utmi_get_rate, +}; + +struct clk *at91_clk_register_utmi(void __iomem *base, struct udevice *dev, + const char *name, const char *parent_name) +{ + struct udevice *syscon; + struct clk_utmi *utmi; + struct clk *clk; + int ret; + + if (!base || !dev || !name || !parent_name) + return ERR_PTR(-EINVAL); + + ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, + "regmap-sfr", &syscon); + if (ret) + return ERR_PTR(ret); + + utmi = kzalloc(sizeof(*utmi), GFP_KERNEL); + if (!utmi) + return ERR_PTR(-ENOMEM); + + utmi->base = base; + utmi->regmap_sfr = syscon_get_regmap(syscon); + if (!utmi->regmap_sfr) { + kfree(utmi); + return ERR_PTR(-ENODEV); + } + + clk = &utmi->clk; + clk->flags = CLK_GET_RATE_NOCACHE; + ret = clk_register(clk, UBOOT_DM_CLK_AT91_UTMI, name, parent_name); + if (ret) { + kfree(utmi); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_utmi_clk) = { + .name = UBOOT_DM_CLK_AT91_UTMI, + .id = UCLASS_CLK, + .ops = &utmi_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 49e1e372b8..264b36c7b4 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -85,6 +85,9 @@ at91_clk_sama7g5_register_master(void __iomem *base, const char *name, const char * const *parent_names, int num_parents, const u32 *mux_table, const u32 *clk_mux_table, bool critical, u8 id); +struct clk * +at91_clk_register_utmi(void __iomem *base, struct udevice *dev, + const char *name, const char *parent_name); int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index);