This commit provides support for setting USDHCx/ECSPIx clocks depending on used bus. Moreover, it is agnostic to the alias numbering as the information about the clock is read from device tree.
Last but not least - the current IMX6Q clock code in mach-imx/mx6/clock.c has been reused to avoid code duplication. Code from this file will be moved to clk-imx6q.c when other iMX6Q based boards adopt usage of this driver. Signed-off-by: Lukasz Majewski <lu...@denx.de> FIX: clk-imx6q --- drivers/clk/imx/Kconfig | 7 ++ drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx6q.c | 176 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 drivers/clk/imx/clk-imx6q.c diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index a6fb58d6cf..7dc261f23e 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -1,3 +1,10 @@ +config CLK_IMX6Q + bool "Clock support for i.MX6Q" + depends on ARCH_MX6 + select CLK + help + This enables support clock driver for i.MX6Q platforms. + config CLK_IMX8 bool "Clock support for i.MX8" depends on ARCH_IMX8 diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 5505ae52e2..b32744812f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -2,4 +2,5 @@ # # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_CLK_IMX6Q) += clk-imx6q.o obj-$(CONFIG_CLK_IMX8) += clk-imx8.o diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c new file mode 100644 index 0000000000..a0aa1f5f45 --- /dev/null +++ b/drivers/clk/imx/clk-imx6q.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 DENX Software Engineering + * Lukasz Majewski, DENX Software Engineering, lu...@denx.de + * + * Based on: clk-imx8.c + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <asm/arch/clock.h> +#include <dt-bindings/clock/imx6qdl-clock.h> + +struct imx6q_clks { + ulong id; + const char *name; +}; + +static struct imx6q_clks imx6q_clk_names[] = { + { IMX6QDL_CLK_ECSPI1, "ECSPI1" }, + { IMX6QDL_CLK_ECSPI2, "ECSPI2" }, + { IMX6QDL_CLK_ECSPI3, "ECSPI3" }, + { IMX6QDL_CLK_ECSPI4, "ECSPI4" }, + { IMX6QDL_CLK_USDHC1, "USDHC1" }, + { IMX6QDL_CLK_USDHC2, "USDHC2" }, + { IMX6QDL_CLK_USDHC3, "USDHC3" }, + { IMX6QDL_CLK_USDHC4, "USDHC4" }, +}; + +static ulong imx6q_clk_get_rate(struct clk *clk) +{ + ulong rate = 0; + + debug("%s(#%lu)\n", __func__, clk->id); + + switch (clk->id) { + case IMX6QDL_CLK_ECSPI1: + case IMX6QDL_CLK_ECSPI2: + case IMX6QDL_CLK_ECSPI3: + case IMX6QDL_CLK_ECSPI4: + return imx6_get_cspi_clk(); + + case IMX6QDL_CLK_USDHC1: + case IMX6QDL_CLK_USDHC2: + case IMX6QDL_CLK_USDHC3: + case IMX6QDL_CLK_USDHC4: + return imx6_get_usdhc_clk(clk->id - IMX6QDL_CLK_USDHC1); + default: + if (clk->id < IMX6QDL_CLK_DUMMY || clk->id >= IMX6QDL_CLK_END) { + printf("%s(Invalid clk ID #%lu)\n", __func__, clk->id); + return -EINVAL; + } + return -ENOTSUPP; + } + + return rate; +} + +static ulong imx6q_clk_set_rate(struct clk *clk, unsigned long rate) +{ + debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate); + + return rate; +} + +static int __imx6q_clk_enable(struct clk *clk, bool enable) +{ + debug("%s(#%lu) en: %d\n", __func__, clk->id, enable); + + switch (clk->id) { + case IMX6QDL_CLK_ECSPI1: + case IMX6QDL_CLK_ECSPI2: + case IMX6QDL_CLK_ECSPI3: + case IMX6QDL_CLK_ECSPI4: + return enable_spi_clk(enable, clk->id - IMX6QDL_CLK_ECSPI1); + + case IMX6QDL_CLK_USDHC1: + case IMX6QDL_CLK_USDHC2: + case IMX6QDL_CLK_USDHC3: + case IMX6QDL_CLK_USDHC4: + return enable_usdhc_clk(enable, clk->id - IMX6QDL_CLK_USDHC1); + + default: + if (clk->id < IMX6QDL_CLK_DUMMY || clk->id >= IMX6QDL_CLK_END) { + printf("%s(Invalid clk ID #%lu)\n", __func__, clk->id); + return -EINVAL; + } + return -ENOTSUPP; + } + + return 0; +} + +static int imx6q_clk_disable(struct clk *clk) +{ + return __imx6q_clk_enable(clk, 0); +} + +static int imx6q_clk_enable(struct clk *clk) +{ + return __imx6q_clk_enable(clk, 1); +} + +#if CONFIG_IS_ENABLED(CMD_CLK) +int soc_clk_dump(void) +{ + struct udevice *dev; + struct clk clk; + unsigned long rate; + int i, ret; + + ret = uclass_get_device_by_driver(UCLASS_CLK, + DM_GET_DRIVER(imx6q_clk), &dev); + if (ret) + return ret; + + printf("Clk\t\tHz\n"); + + for (i = 0; i < ARRAY_SIZE(imx6q_clk_names); i++) { + clk.id = imx6q_clk_names[i].id; + ret = clk_request(dev, &clk); + if (ret < 0) { + debug("%s clk_request() failed: %d\n", __func__, ret); + continue; + } + + ret = clk_get_rate(&clk); + rate = ret; + + clk_free(&clk); + + if (ret == -ENOTSUPP) { + printf("clk ID %lu not supported yet\n", + imx6q_clk_names[i].id); + continue; + } + if (ret < 0) { + printf("%s %lu: get_rate err: %d\n", + __func__, imx6q_clk_names[i].id, ret); + continue; + } + + printf("%s(%3lu):\t%lu\n", + imx6q_clk_names[i].name, imx6q_clk_names[i].id, rate); + } + + return 0; +} +#endif + +static struct clk_ops imx6q_clk_ops = { + .set_rate = imx6q_clk_set_rate, + .get_rate = imx6q_clk_get_rate, + .enable = imx6q_clk_enable, + .disable = imx6q_clk_disable, +}; + +static int imx6q_clk_probe(struct udevice *dev) +{ + return 0; +} + +static const struct udevice_id imx6q_clk_ids[] = { + { .compatible = "fsl,imx6q-ccm" }, + { }, +}; + +U_BOOT_DRIVER(imx6q_clk) = { + .name = "clk_imx6q", + .id = UCLASS_CLK, + .of_match = imx6q_clk_ids, + .ops = &imx6q_clk_ops, + .probe = imx6q_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; -- 2.11.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot