diff options
author | Tom Rini <trini@konsulko.com> | 2020-10-05 20:05:46 +0300 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-10-05 21:10:59 +0300 |
commit | b7e7831e5d5be047f421ddc1f308afc22764a893 (patch) | |
tree | 7d5f27c82b260278ed0b3ea96bce592b0505b898 /drivers/clk/at91/clk-system.c | |
parent | 050acee119b3757fee3bd128f55d720fdd9bb890 (diff) | |
parent | caebff09efe8c061b4d99b82262c67fb2db9bbcf (diff) | |
download | u-boot-b7e7831e5d5be047f421ddc1f308afc22764a893.tar.xz |
Merge branch 'next'
Bring in the assorted changes that have been staged in the 'next' branch
prior to release.
Signed-off-by: Tom Rini <trini@konsulko.com>
Diffstat (limited to 'drivers/clk/at91/clk-system.c')
-rw-r--r-- | drivers/clk/at91/clk-system.c | 143 |
1 files changed, 72 insertions, 71 deletions
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c index 76b1958670..82f79e74a1 100644 --- a/drivers/clk/at91/clk-system.c +++ b/drivers/clk/at91/clk-system.c @@ -1,111 +1,112 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang <wenyou.yang@atmel.com> + * System clock support for AT91 architectures. + * + * Copyright (C) Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea <claudiu.beznea@microchip.com> + * + * Based on drivers/clk/at91/clk-system.c from Linux. */ - +#include <asm/processor.h> #include <common.h> #include <clk-uclass.h> #include <dm.h> -#include <linux/bitops.h> #include <linux/io.h> -#include <mach/at91_pmc.h> +#include <linux/clk-provider.h> +#include <linux/clk/at91_pmc.h> + #include "pmc.h" -#define SYSTEM_MAX_ID 31 +#define UBOOT_DM_CLK_AT91_SYSTEM "at91-system-clk" -/** - * at91_system_clk_bind() - for the system clock driver - * Recursively bind its children as clk devices. - * - * @return: 0 on success, or negative error code on failure - */ -static int at91_system_clk_bind(struct udevice *dev) -{ - return at91_clk_sub_device_bind(dev, "system-clk"); -} - -static const struct udevice_id at91_system_clk_match[] = { - { .compatible = "atmel,at91rm9200-clk-system" }, - {} -}; +#define SYSTEM_MAX_ID 31 -U_BOOT_DRIVER(at91_system_clk) = { - .name = "at91-system-clk", - .id = UCLASS_MISC, - .of_match = at91_system_clk_match, - .bind = at91_system_clk_bind, +struct clk_system { + void __iomem *base; + struct clk clk; + u8 id; }; -/*----------------------------------------------------------*/ +#define to_clk_system(_c) container_of(_c, struct clk_system, clk) static inline int is_pck(int id) { return (id >= 8) && (id <= 15); } -static ulong system_clk_get_rate(struct clk *clk) +static inline bool clk_system_ready(void __iomem *base, int id) { - struct clk clk_dev; - int ret; + unsigned int status; - ret = clk_get_by_index(clk->dev, 0, &clk_dev); - if (ret) - return -EINVAL; + pmc_read(base, AT91_PMC_SR, &status); - return clk_get_rate(&clk_dev); + return !!(status & (1 << id)); } -static ulong system_clk_set_rate(struct clk *clk, ulong rate) +static int clk_system_enable(struct clk *clk) { - struct clk clk_dev; - int ret; + struct clk_system *sys = to_clk_system(clk); - ret = clk_get_by_index(clk->dev, 0, &clk_dev); - if (ret) - return -EINVAL; + pmc_write(sys->base, AT91_PMC_SCER, 1 << sys->id); - return clk_set_rate(&clk_dev, rate); + if (!is_pck(sys->id)) + return 0; + + while (!clk_system_ready(sys->base, sys->id)) { + debug("waiting for pck%u\n", sys->id); + cpu_relax(); + } + + return 0; } -static int system_clk_enable(struct clk *clk) +static int clk_system_disable(struct clk *clk) { - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - u32 mask; + struct clk_system *sys = to_clk_system(clk); - if (clk->id > SYSTEM_MAX_ID) - return -EINVAL; + pmc_write(sys->base, AT91_PMC_SCDR, 1 << sys->id); - mask = BIT(clk->id); + return 0; +} - writel(mask, &pmc->scer); +static const struct clk_ops system_ops = { + .enable = clk_system_enable, + .disable = clk_system_disable, + .get_rate = clk_generic_get_rate, +}; - /** - * For the programmable clocks the Ready status in the PMC - * status register should be checked after enabling. - * For other clocks this is unnecessary. - */ - if (!is_pck(clk->id)) - return 0; +struct clk *at91_clk_register_system(void __iomem *base, const char *name, + const char *parent_name, u8 id) +{ + struct clk_system *sys; + struct clk *clk; + int ret; - while (!(readl(&pmc->sr) & mask)) - ; + if (!base || !name || !parent_name || id > SYSTEM_MAX_ID) + return ERR_PTR(-EINVAL); - return 0; -} + sys = kzalloc(sizeof(*sys), GFP_KERNEL); + if (!sys) + return ERR_PTR(-ENOMEM); -static struct clk_ops system_clk_ops = { - .of_xlate = at91_clk_of_xlate, - .get_rate = system_clk_get_rate, - .set_rate = system_clk_set_rate, - .enable = system_clk_enable, -}; + sys->id = id; + sys->base = base; -U_BOOT_DRIVER(system_clk) = { - .name = "system-clk", + clk = &sys->clk; + clk->flags = CLK_GET_RATE_NOCACHE; + ret = clk_register(clk, UBOOT_DM_CLK_AT91_SYSTEM, name, parent_name); + if (ret) { + kfree(sys); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_system_clk) = { + .name = UBOOT_DM_CLK_AT91_SYSTEM, .id = UCLASS_CLK, - .probe = at91_clk_probe, - .platdata_auto_alloc_size = sizeof(struct pmc_platdata), - .ops = &system_clk_ops, + .ops = &system_ops, + .flags = DM_FLAG_PRE_RELOC, }; |