summaryrefslogtreecommitdiff
path: root/drivers/clk/at91/clk-system.c
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-10-05 17:54:27 +0300
committerTom Rini <trini@konsulko.com>2020-10-05 17:54:27 +0300
commitcaebff09efe8c061b4d99b82262c67fb2db9bbcf (patch)
tree24fcdb0737bea1d87c0a36f7eb371017af83e5c2 /drivers/clk/at91/clk-system.c
parent17e76b33cc0ec2eb2c519b66b6f6c491718e8046 (diff)
parent01c35f269f21398fa9d1db1b90b73f7e95a3bf22 (diff)
downloadu-boot-caebff09efe8c061b4d99b82262c67fb2db9bbcf.tar.xz
Merge tag 'u-boot-atmel-2021.01-a' of https://gitlab.denx.de/u-boot/custodians/u-boot-atmel into next
First set of u-boot-atmel features for 2021.01 cycle: This feature set includes a new CPU driver for at91 family, new driver for PIT64B hardware timer, support for new at91 family SoC named sama7g5 which adds: clock support, including conversion of the clock tree to CCF; SoC support in mach-at91, pinctrl and mmc drivers update. The feature set also includes updates for mmc driver and some other minor fixes and features regarding building without the old Atmel PIT and the possibility to read a secondary MAC address from a second i2c EEPROM.
Diffstat (limited to 'drivers/clk/at91/clk-system.c')
-rw-r--r--drivers/clk/at91/clk-system.c143
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,
};