diff options
author | Wenyou Yang <wenyou.yang@microchip.com> | 2018-02-09 11:34:51 +0800 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2018-03-16 07:30:04 -0400 |
commit | fed0509c92e0fe29d0ddc9c743719d22c95b7596 (patch) | |
tree | efe417a3aa1f19076069eb4138e31ffa8731a66b /drivers/clk/at91 | |
parent | cb0cb1b0cf20687cf980fbd64c56224f06d566aa (diff) | |
download | u-boot-fed0509c92e0fe29d0ddc9c743719d22c95b7596.tar.gz u-boot-fed0509c92e0fe29d0ddc9c743719d22c95b7596.tar.bz2 u-boot-fed0509c92e0fe29d0ddc9c743719d22c95b7596.zip |
clk: at91: add PLLADIV driver
As said in the SAMA5D2 datasheet, the PLLA clock must be divided
by 2 by writing the PLLADIV2 bit in PMC_MCKR, if the ratio between
PCK and MCK is 3 (MDIV = 3). This is the purpose of the driver.
Signed-off-by: Wenyou Yang <wenyou.yang@microchip.com>
Diffstat (limited to 'drivers/clk/at91')
-rw-r--r-- | drivers/clk/at91/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/at91/clk-plladiv.c | 88 |
2 files changed, 89 insertions, 1 deletions
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 8cac3f9e18..8c197ff949 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -3,7 +3,7 @@ # obj-y += pmc.o sckc.o -obj-y += clk-slow.o clk-main.o clk-plla.o clk-master.o +obj-y += clk-slow.o clk-main.o clk-plla.o clk-plladiv.o clk-master.o obj-y += clk-system.o clk-peripheral.o obj-$(CONFIG_AT91_UTMI) += clk-utmi.o diff --git a/drivers/clk/at91/clk-plladiv.c b/drivers/clk/at91/clk-plladiv.c new file mode 100644 index 0000000000..0599d2893b --- /dev/null +++ b/drivers/clk/at91/clk-plladiv.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2018 Microhip / Atmel Corporation + * Wenyou.Yang <wenyou.yang@microchip.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm/device.h> +#include <linux/io.h> +#include <mach/at91_pmc.h> +#include "pmc.h" + +DECLARE_GLOBAL_DATA_PTR; + +static int at91_plladiv_clk_enable(struct clk *clk) +{ + return 0; +} + +static ulong at91_plladiv_clk_get_rate(struct clk *clk) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + struct clk source; + ulong clk_rate; + int ret; + + ret = clk_get_by_index(clk->dev, 0, &source); + if (ret) + return -EINVAL; + + clk_rate = clk_get_rate(&source); + if (readl(&pmc->mckr) & AT91_PMC_MCKR_PLLADIV_2) + clk_rate /= 2; + + return clk_rate; +} + +static ulong at91_plladiv_clk_set_rate(struct clk *clk, ulong rate) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + struct clk source; + ulong parent_rate; + int ret; + + ret = clk_get_by_index(clk->dev, 0, &source); + if (ret) + return -EINVAL; + + parent_rate = clk_get_rate(&source); + if ((parent_rate != rate) && ((parent_rate) / 2 != rate)) + return -EINVAL; + + if (parent_rate != rate) { + writel((readl(&pmc->mckr) | AT91_PMC_MCKR_PLLADIV_2), + &pmc->mckr); + } + + return 0; +} + +static struct clk_ops at91_plladiv_clk_ops = { + .enable = at91_plladiv_clk_enable, + .get_rate = at91_plladiv_clk_get_rate, + .set_rate = at91_plladiv_clk_set_rate, +}; + +static int at91_plladiv_clk_probe(struct udevice *dev) +{ + return at91_pmc_core_probe(dev); +} + +static const struct udevice_id at91_plladiv_clk_match[] = { + { .compatible = "atmel,at91sam9x5-clk-plldiv" }, + {} +}; + +U_BOOT_DRIVER(at91_plladiv_clk) = { + .name = "at91-plladiv-clk", + .id = UCLASS_CLK, + .of_match = at91_plladiv_clk_match, + .probe = at91_plladiv_clk_probe, + .platdata_auto_alloc_size = sizeof(struct pmc_platdata), + .ops = &at91_plladiv_clk_ops, +}; |