From: Steffen Trumtrar <s.trumtrar@xxxxxxxxxxxxxx> SNVS LPGPR is Non Volatile Low Power Generic Purpose Register which can be used as part of nvmem framework. Signed-off-by: Steffen Trumtrar <s.trumtrar@xxxxxxxxxxxxxx> Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx> --- drivers/nvmem/Kconfig | 9 ++++ drivers/nvmem/Makefile | 4 ++ drivers/nvmem/snvs_lpgpr.c | 122 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 drivers/nvmem/snvs_lpgpr.c diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 218be05b2..1b0ca2757 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -6,3 +6,12 @@ menuconfig NVMEM This framework is designed to provide a generic interface to NVMEM If unsure, say no. + +if NVMEM + +config NVMEM_SNVS_LPGPR + tristate "Freescale SNVS LPGPR support" + help + If you say yes here you get NVMEM support for the Freescale SNVS + Low Power Generic Purpose Register (LPGPR). +endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 6df2c6952..32522e9fb 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -4,3 +4,7 @@ obj-$(CONFIG_NVMEM) += nvmem_core.o nvmem_core-y := core.o + +# Devices +obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o +nvmem_snvs_lpgpr-y := snvs_lpgpr.o diff --git a/drivers/nvmem/snvs_lpgpr.c b/drivers/nvmem/snvs_lpgpr.c new file mode 100644 index 000000000..ebe91d755 --- /dev/null +++ b/drivers/nvmem/snvs_lpgpr.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015 Pengutronix, Steffen Trumtrar <kernel@xxxxxxxxxxxxxx> + * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ +#include <common.h> +#include <driver.h> +#include <init.h> +#include <io.h> +#include <of.h> +#include <malloc.h> +#include <linux/nvmem-provider.h> + +struct snvs_lpgpr_priv { + struct device_d *dev; + void __iomem *base; + int offset; +}; + +static int snvs_lpgpr_write(struct device_d *dev, const int reg, const void *_val, + int bytes) +{ + struct snvs_lpgpr_priv *priv = dev->parent->priv; + const u32 *val = _val; + int i = 0, words = bytes / 4; + + while (words--) + writel(*val++, priv->base + reg + (i++ * 4)); + + return 0; +} + +static int snvs_lpgpr_read(struct device_d *dev, const int reg, void *_val, + int bytes) +{ + struct snvs_lpgpr_priv *priv = dev->parent->priv; + u32 *val = _val; + int i = 0, words = bytes / 4; + + while (words--) + *val++ = readl(priv->base + reg + (i++ * 4)); + + return 0; +} + +static const struct nvmem_bus snvs_lpgpr_nvmem_bus = { + .write = snvs_lpgpr_write, + .read = snvs_lpgpr_read, +}; + +static struct nvmem_config snvs_lpgpr_cfg = { + .stride = 4, + .word_size = 4, + .size = 4, + .bus = &snvs_lpgpr_nvmem_bus, +}; + +static int snvs_lpgpr_probe(struct device_d *dev) +{ + struct device_node *node = dev->device_node; + struct snvs_lpgpr_priv *priv; + struct nvmem_device *nvmem; + struct resource *res; + int err; + + if (!node) + return -ENOENT; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = dev_get_resource(dev, IORESOURCE_MEM, 0); + if (IS_ERR(res)) { + res = dev_get_resource(dev->parent, IORESOURCE_MEM, 0); + if (IS_ERR(res)) { + free(priv); + return PTR_ERR(res); + } + } + + res = request_iomem_region(dev_name(dev), res->start, res->end); + if (IS_ERR(res)) { + free(priv); + return PTR_ERR(res); + } + + err = of_property_read_u32(node, "offset", &priv->offset); + if (err) + return err; + + priv->base = (void __iomem *)res->start + priv->offset; + + snvs_lpgpr_cfg.name = dev_name(dev); + snvs_lpgpr_cfg.dev = dev; + + nvmem = nvmem_register(&snvs_lpgpr_cfg); + if (IS_ERR(nvmem)) { + free(priv); + return PTR_ERR(nvmem); + } + + dev->priv = priv; + + return 0; +} + +static __maybe_unused struct of_device_id snvs_lpgpr_dt_ids[] = { + { .compatible = "fsl,imx6sl-snvs-lpgpr", }, + { .compatible = "fsl,imx6q-snvs-lpgpr", }, + { }, +}; + +static struct driver_d snvs_lpgpr_driver = { + .name = "nvmem-snvs-lpgpr", + .probe = snvs_lpgpr_probe, + .of_compatible = DRV_OF_COMPAT(snvs_lpgpr_dt_ids), +}; +device_platform_driver(snvs_lpgpr_driver); -- 2.11.0 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox