All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] nvmem: patches for v4.12
@ 2017-03-31 12:44 Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 01/11] MAINTAINERS: nvmem: Remove myself from maintainers Srinivas Kandagatla
                   ` (10 more replies)
  0 siblings, 11 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, maxime.ripard, Srinivas Kandagatla

Hi Greg, 

This patchset contains new driver support for imx-iim, few enhancements for
sunxi and imx-octop driver and a fix for nvmem core.

Can you please queue these for v4.12.

Thanks,
srini

Aban Bedel (1):
  nvmem: core: Allow allocating several anonymous nvmem devices

Icenowy Zheng (2):
  nvmem: sunxi-sid: read NVMEM size from device compatible
  nvmem: sunxi-sid: add support for H3's SID controller

Maxime Ripard (1):
  MAINTAINERS: nvmem: Remove myself from maintainers

Michael Grzeschik (1):
  nvmem: Add driver for the i.MX IIM

Peng Fan (2):
  dt-bindings: imx-ocotp: add compatible string for i.MX7D/S
  nvmem: octop: Add i.MX7D support

Richard Leitner (3):
  nvmem: imx-ocotp: fix usage of "dev" pointers
  nvmem: imx-ocotp: clear error bit after reading locked values
  nvmem: imx-ocotp: add write support

Sascha Hauer (1):
  dt-bindings: nvmem: Add i.MX IIM binding doc

 .../bindings/nvmem/allwinner,sunxi-sid.txt         |   6 +-
 .../devicetree/bindings/nvmem/imx-iim.txt          |  22 ++
 .../devicetree/bindings/nvmem/imx-ocotp.txt        |   5 +
 MAINTAINERS                                        |   1 -
 drivers/nvmem/Kconfig                              |  11 +
 drivers/nvmem/Makefile                             |   2 +
 drivers/nvmem/core.c                               |   3 +-
 drivers/nvmem/imx-iim.c                            | 173 ++++++++++++++
 drivers/nvmem/imx-ocotp.c                          | 254 ++++++++++++++++++++-
 drivers/nvmem/sunxi_sid.c                          |  89 +++++++-
 10 files changed, 554 insertions(+), 12 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/nvmem/imx-iim.txt
 create mode 100644 drivers/nvmem/imx-iim.c

-- 
2.7.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 01/11] MAINTAINERS: nvmem: Remove myself from maintainers
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 02/11] nvmem: core: Allow allocating several anonymous nvmem devices Srinivas Kandagatla
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, maxime.ripard, Srinivas Kandagatla

From: Maxime Ripard <maxime.ripard@free-electrons.com>

I've never been really been maintaining nvmem, so make that official.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 MAINTAINERS | 1 -
 1 file changed, 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index c776906..5db21b8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9027,7 +9027,6 @@ F:	drivers/nvme/target/fcloop.c
 
 NVMEM FRAMEWORK
 M:	Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-M:	Maxime Ripard <maxime.ripard@free-electrons.com>
 S:	Maintained
 F:	drivers/nvmem/
 F:	Documentation/devicetree/bindings/nvmem/
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 02/11] nvmem: core: Allow allocating several anonymous nvmem devices
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 01/11] MAINTAINERS: nvmem: Remove myself from maintainers Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 03/11] nvmem: sunxi-sid: read NVMEM size from device compatible Srinivas Kandagatla
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, maxime.ripard, Aban Bedel, Srinivas Kandagatla

From: Aban Bedel <albeu@free.fr>

Currently the nvmem core expect the config to provide a name and ID
that are then used to create the device name. When no device name is
given 'nvmem' is used. However if there is several such anonymous
devices they all get named 'nvmem0', which doesn't work.

To fix this problem use the ID from the config only when the config
also provides a name. When no name is provided take the uinque ID of
the nvmem device instead.

Signed-off-by: Aban Bedel <albeu@free.fr>
Reviewed-by: Moritz Fischer <mdf@kernel.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/nvmem/core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 408b521..8c830a8 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -468,7 +468,8 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
 	np = config->dev->of_node;
 	nvmem->dev.of_node = np;
 	dev_set_name(&nvmem->dev, "%s%d",
-		     config->name ? : "nvmem", config->id);
+		     config->name ? : "nvmem",
+		     config->name ? config->id : nvmem->id);
 
 	nvmem->read_only = of_property_read_bool(np, "read-only") |
 			   config->read_only;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 03/11] nvmem: sunxi-sid: read NVMEM size from device compatible
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 01/11] MAINTAINERS: nvmem: Remove myself from maintainers Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 02/11] nvmem: core: Allow allocating several anonymous nvmem devices Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 04/11] nvmem: sunxi-sid: add support for H3's SID controller Srinivas Kandagatla
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, maxime.ripard, Icenowy Zheng, Srinivas Kandagatla

From: Icenowy Zheng <icenowy@aosc.xyz>

Sometimes the SID device have more memory address space than the real
NVMEM size (for the registers used to read/write the SID).

Fetch the NVMEM size from device compatible, rather than the memory
address space's length, in order to prepare for adding some
registers-based read support.

Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/nvmem/sunxi_sid.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index 1567ccc..69524b6 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/nvmem-provider.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/random.h>
@@ -32,6 +33,10 @@ static struct nvmem_config econfig = {
 	.owner = THIS_MODULE,
 };
 
+struct sunxi_sid_cfg {
+	u32	size;
+};
+
 struct sunxi_sid {
 	void __iomem		*base;
 };
@@ -72,18 +77,24 @@ static int sunxi_sid_probe(struct platform_device *pdev)
 	struct sunxi_sid *sid;
 	int ret, i, size;
 	char *randomness;
+	const struct sunxi_sid_cfg *cfg;
 
 	sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL);
 	if (!sid)
 		return -ENOMEM;
 
+	cfg = of_device_get_match_data(dev);
+	if (!cfg)
+		return -EINVAL;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	sid->base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(sid->base))
 		return PTR_ERR(sid->base);
 
-	size = resource_size(res) - 1;
-	econfig.size = resource_size(res);
+	size = cfg->size;
+
+	econfig.size = size;
 	econfig.dev = dev;
 	econfig.reg_read = sunxi_sid_read;
 	econfig.priv = sid;
@@ -119,9 +130,17 @@ static int sunxi_sid_remove(struct platform_device *pdev)
 	return nvmem_unregister(nvmem);
 }
 
+static const struct sunxi_sid_cfg sun4i_a10_cfg = {
+	.size = 0x10,
+};
+
+static const struct sunxi_sid_cfg sun7i_a20_cfg = {
+	.size = 0x200,
+};
+
 static const struct of_device_id sunxi_sid_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-sid" },
-	{ .compatible = "allwinner,sun7i-a20-sid" },
+	{ .compatible = "allwinner,sun4i-a10-sid", .data = &sun4i_a10_cfg },
+	{ .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg },
 	{/* sentinel */},
 };
 MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 04/11] nvmem: sunxi-sid: add support for H3's SID controller
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
                   ` (2 preceding siblings ...)
  2017-03-31 12:44 ` [PATCH 03/11] nvmem: sunxi-sid: read NVMEM size from device compatible Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 05/11] nvmem: imx-ocotp: fix usage of "dev" pointers Srinivas Kandagatla
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, maxime.ripard, Icenowy Zheng, Srinivas Kandagatla

From: Icenowy Zheng <icenowy@aosc.xyz>

The H3 SoC have a bigger SID controller, which has its direct read
address at 0x200 position in the SID block, not 0x0.

Also, H3 SID controller has some silicon bug that makes the direct read
value wrong at cold boot, add code to workaround the bug. (This bug has
already been fixed on A64 and later SoCs)

Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../bindings/nvmem/allwinner,sunxi-sid.txt         |  6 ++-
 drivers/nvmem/sunxi_sid.c                          | 62 ++++++++++++++++++++++
 2 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
index d543ed3..ef06d06 100644
--- a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
+++ b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
@@ -1,7 +1,11 @@
 Allwinner sunxi-sid
 
 Required properties:
-- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
+- compatible: Should be one of the following:
+  "allwinner,sun4i-a10-sid"
+  "allwinner,sun7i-a20-sid"
+  "allwinner,sun8i-h3-sid"
+
 - reg: Should contain registers location and length
 
 = Data cells =
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index 69524b6..0d6648b 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -17,6 +17,7 @@
 
 #include <linux/device.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/nvmem-provider.h>
 #include <linux/of.h>
@@ -25,6 +26,15 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 
+/* Registers and special values for doing register-based SID readout on H3 */
+#define SUN8I_SID_PRCTL		0x40
+#define SUN8I_SID_RDKEY		0x60
+
+#define SUN8I_SID_OFFSET_MASK	0x1FF
+#define SUN8I_SID_OFFSET_SHIFT	16
+#define SUN8I_SID_OP_LOCK	(0xAC << 8)
+#define SUN8I_SID_READ		BIT(1)
+
 static struct nvmem_config econfig = {
 	.name = "sunxi-sid",
 	.read_only = true,
@@ -34,11 +44,14 @@ static struct nvmem_config econfig = {
 };
 
 struct sunxi_sid_cfg {
+	u32	value_offset;
 	u32	size;
+	bool	need_register_readout;
 };
 
 struct sunxi_sid {
 	void __iomem		*base;
+	u32			value_offset;
 };
 
 /* We read the entire key, due to a 32 bit read alignment requirement. Since we
@@ -63,12 +76,36 @@ static int sunxi_sid_read(void *context, unsigned int offset,
 	struct sunxi_sid *sid = context;
 	u8 *buf = val;
 
+	/* Offset the read operation to the real position of SID */
+	offset += sid->value_offset;
+
 	while (bytes--)
 		*buf++ = sunxi_sid_read_byte(sid, offset++);
 
 	return 0;
 }
 
+static int sun8i_sid_register_readout(const struct sunxi_sid *sid,
+				      const unsigned int word)
+{
+	u32 reg_val;
+	int ret;
+
+	/* Set word, lock access, and set read command */
+	reg_val = (word & SUN8I_SID_OFFSET_MASK)
+		  << SUN8I_SID_OFFSET_SHIFT;
+	reg_val |= SUN8I_SID_OP_LOCK | SUN8I_SID_READ;
+	writel(reg_val, sid->base + SUN8I_SID_PRCTL);
+
+	ret = readl_poll_timeout(sid->base + SUN8I_SID_PRCTL, reg_val,
+				 !(reg_val & SUN8I_SID_READ), 100, 250000);
+	if (ret)
+		return ret;
+
+	writel(0, sid->base + SUN8I_SID_PRCTL);
+	return 0;
+}
+
 static int sunxi_sid_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -86,6 +123,7 @@ static int sunxi_sid_probe(struct platform_device *pdev)
 	cfg = of_device_get_match_data(dev);
 	if (!cfg)
 		return -EINVAL;
+	sid->value_offset = cfg->value_offset;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	sid->base = devm_ioremap_resource(dev, res);
@@ -94,6 +132,23 @@ static int sunxi_sid_probe(struct platform_device *pdev)
 
 	size = cfg->size;
 
+	if (cfg->need_register_readout) {
+		/*
+		 * H3's SID controller have a bug that the value at 0x200
+		 * offset is not the correct value when the hardware is reseted.
+		 * However, after doing a register-based read operation, the
+		 * value become right.
+		 * Do a full read operation here, but ignore its value
+		 * (as it's more fast to read by direct MMIO value than
+		 * with registers)
+		 */
+		for (i = 0; i < (size >> 2); i++) {
+			ret = sun8i_sid_register_readout(sid, i);
+			if (ret)
+				return ret;
+		}
+	}
+
 	econfig.size = size;
 	econfig.dev = dev;
 	econfig.reg_read = sunxi_sid_read;
@@ -138,9 +193,16 @@ static const struct sunxi_sid_cfg sun7i_a20_cfg = {
 	.size = 0x200,
 };
 
+static const struct sunxi_sid_cfg sun8i_h3_cfg = {
+	.value_offset = 0x200,
+	.size = 0x100,
+	.need_register_readout = true,
+};
+
 static const struct of_device_id sunxi_sid_of_match[] = {
 	{ .compatible = "allwinner,sun4i-a10-sid", .data = &sun4i_a10_cfg },
 	{ .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg },
+	{ .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg },
 	{/* sentinel */},
 };
 MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 05/11] nvmem: imx-ocotp: fix usage of "dev" pointers
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
                   ` (3 preceding siblings ...)
  2017-03-31 12:44 ` [PATCH 04/11] nvmem: sunxi-sid: add support for H3's SID controller Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 06/11] nvmem: Add driver for the i.MX IIM Srinivas Kandagatla
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, maxime.ripard, Richard Leitner, Srinivas Kandagatla

From: Richard Leitner <richard.leitner@skidata.com>

Assign the correct dev pointer to struct ocotp_priv during probe. This
is needed to display dev_* messages correctly. Furthermore harmonize
the usage of dev (instead of &pdev->dev) in the probe function.

Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/nvmem/imx-ocotp.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index b8ca1e6..549177d 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -90,12 +90,14 @@ static int imx_ocotp_probe(struct platform_device *pdev)
 	if (!priv)
 		return -ENOMEM;
 
+	priv->dev = dev;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	priv->base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(priv->base))
 		return PTR_ERR(priv->base);
 
-	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	priv->clk = devm_clk_get(dev, NULL);
 	if (IS_ERR(priv->clk))
 		return PTR_ERR(priv->clk);
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 06/11] nvmem: Add driver for the i.MX IIM
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
                   ` (4 preceding siblings ...)
  2017-03-31 12:44 ` [PATCH 05/11] nvmem: imx-ocotp: fix usage of "dev" pointers Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 07/11] dt-bindings: nvmem: Add i.MX IIM binding doc Srinivas Kandagatla
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh
  Cc: linux-kernel, maxime.ripard, Michael Grzeschik, Sascha Hauer,
	Srinivas Kandagatla

From: Michael Grzeschik <m.grzeschik@pengutronix.de>

This adds a readonly nvmem driver for the i.MX IC Identification Module
(IIM). The IIM is found on the older i.MX SoCs like the i.MX25, i.MX27,
i.MX31, i.MX35, i.MX51 and the i.MX53.

The IIM can control up to 8 fuse banks with 256 bit each. Not all of the
banks are equipped on the different SoCs. The actual number of fuses
differ from 512 on the i.MX27 and 1152 on the i.MX53.

The fuses are one time writable, but writing is currently not supported
in the driver.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/nvmem/Kconfig   |  11 +++
 drivers/nvmem/Makefile  |   2 +
 drivers/nvmem/imx-iim.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 186 insertions(+)
 create mode 100644 drivers/nvmem/imx-iim.c

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 650f1b1..101ced4 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -13,6 +13,17 @@ menuconfig NVMEM
 
 if NVMEM
 
+config NVMEM_IMX_IIM
+	tristate "i.MX IC Identification Module support"
+	depends on ARCH_MXC || COMPILE_TEST
+	help
+	  This is a driver for the IC Identification Module (IIM) available on
+	  i.MX SoCs, providing access to 4 Kbits of programmable
+	  eFuses.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called nvmem-imx-iim.
+
 config NVMEM_IMX_OCOTP
 	tristate "i.MX6 On-Chip OTP Controller support"
 	depends on SOC_IMX6 || COMPILE_TEST
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 86e4599..1731406 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -8,6 +8,8 @@ nvmem_core-y			:= core.o
 # Devices
 obj-$(CONFIG_NVMEM_BCM_OCOTP)	+= nvmem-bcm-ocotp.o
 nvmem-bcm-ocotp-y		:= bcm-ocotp.o
+obj-$(CONFIG_NVMEM_IMX_IIM)	+= nvmem-imx-iim.o
+nvmem-imx-iim-y			:= imx-iim.o
 obj-$(CONFIG_NVMEM_IMX_OCOTP)	+= nvmem-imx-ocotp.o
 nvmem-imx-ocotp-y		:= imx-ocotp.o
 obj-$(CONFIG_NVMEM_LPC18XX_EEPROM)	+= nvmem_lpc18xx_eeprom.o
diff --git a/drivers/nvmem/imx-iim.c b/drivers/nvmem/imx-iim.c
new file mode 100644
index 0000000..52ff65e
--- /dev/null
+++ b/drivers/nvmem/imx-iim.c
@@ -0,0 +1,173 @@
+/*
+ * i.MX IIM driver
+ *
+ * Copyright (c) 2017 Pengutronix, Michael Grzeschik <m.grzeschik@pengutronix.de>
+ *
+ * Based on the barebox iim driver,
+ * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>,
+ *	Orex Computed Radiography
+ *
+ * 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.
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#define IIM_BANK_BASE(n)	(0x800 + 0x400 * (n))
+
+struct imx_iim_drvdata {
+	unsigned int nregs;
+};
+
+struct iim_priv {
+	void __iomem *base;
+	struct clk *clk;
+	struct nvmem_config nvmem;
+};
+
+static int imx_iim_read(void *context, unsigned int offset,
+			  void *buf, size_t bytes)
+{
+	struct iim_priv *iim = context;
+	int i, ret;
+	u8 *buf8 = buf;
+
+	ret = clk_prepare_enable(iim->clk);
+	if (ret)
+		return ret;
+
+	for (i = offset; i < offset + bytes; i++) {
+		int bank = i >> 5;
+		int reg = i & 0x1f;
+
+		*buf8++ = readl(iim->base + IIM_BANK_BASE(bank) + reg * 4);
+	}
+
+	clk_disable_unprepare(iim->clk);
+
+	return 0;
+}
+
+static struct imx_iim_drvdata imx27_drvdata = {
+	.nregs = 2 * 32,
+};
+
+static struct imx_iim_drvdata imx25_imx31_imx35_drvdata = {
+	.nregs = 3 * 32,
+};
+
+static struct imx_iim_drvdata imx51_drvdata = {
+	.nregs = 4 * 32,
+};
+
+static struct imx_iim_drvdata imx53_drvdata = {
+	.nregs = 4 * 32 + 16,
+};
+
+static const struct of_device_id imx_iim_dt_ids[] = {
+	{
+		.compatible = "fsl,imx25-iim",
+		.data = &imx25_imx31_imx35_drvdata,
+	}, {
+		.compatible = "fsl,imx27-iim",
+		.data = &imx27_drvdata,
+	}, {
+		.compatible = "fsl,imx31-iim",
+		.data = &imx25_imx31_imx35_drvdata,
+	}, {
+		.compatible = "fsl,imx35-iim",
+		.data = &imx25_imx31_imx35_drvdata,
+	}, {
+		.compatible = "fsl,imx51-iim",
+		.data = &imx51_drvdata,
+	}, {
+		.compatible = "fsl,imx53-iim",
+		.data = &imx53_drvdata,
+	}, {
+		/* sentinel */
+	},
+};
+MODULE_DEVICE_TABLE(of, imx_iim_dt_ids);
+
+static int imx_iim_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct iim_priv *iim;
+	struct nvmem_device *nvmem;
+	struct nvmem_config *cfg;
+	const struct imx_iim_drvdata *drvdata = NULL;
+
+	iim = devm_kzalloc(dev, sizeof(*iim), GFP_KERNEL);
+	if (!iim)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	iim->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(iim->base))
+		return PTR_ERR(iim->base);
+
+	of_id = of_match_device(imx_iim_dt_ids, dev);
+	if (!of_id)
+		return -ENODEV;
+
+	drvdata = of_id->data;
+
+	iim->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(iim->clk))
+		return PTR_ERR(iim->clk);
+
+	cfg = &iim->nvmem;
+
+	cfg->name = "imx-iim",
+	cfg->read_only = true,
+	cfg->word_size = 1,
+	cfg->stride = 1,
+	cfg->owner = THIS_MODULE,
+	cfg->reg_read = imx_iim_read,
+	cfg->dev = dev;
+	cfg->size = drvdata->nregs;
+	cfg->priv = iim;
+
+	nvmem = nvmem_register(cfg);
+	if (IS_ERR(nvmem))
+		return PTR_ERR(nvmem);
+
+	platform_set_drvdata(pdev, nvmem);
+
+	return 0;
+}
+
+static int imx_iim_remove(struct platform_device *pdev)
+{
+	struct nvmem_device *nvmem = platform_get_drvdata(pdev);
+
+	return nvmem_unregister(nvmem);
+}
+
+static struct platform_driver imx_iim_driver = {
+	.probe	= imx_iim_probe,
+	.remove	= imx_iim_remove,
+	.driver = {
+		.name	= "imx-iim",
+		.of_match_table = imx_iim_dt_ids,
+	},
+};
+module_platform_driver(imx_iim_driver);
+
+MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX IIM driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 07/11] dt-bindings: nvmem: Add i.MX IIM binding doc
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
                   ` (5 preceding siblings ...)
  2017-03-31 12:44 ` [PATCH 06/11] nvmem: Add driver for the i.MX IIM Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 08/11] dt-bindings: imx-ocotp: add compatible string for i.MX7D/S Srinivas Kandagatla
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, maxime.ripard, Sascha Hauer, Srinivas Kandagatla

From: Sascha Hauer <s.hauer@pengutronix.de>

The IIM is part of the i.MX device trees for long already, add a binding
document for it.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/nvmem/imx-iim.txt          | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/nvmem/imx-iim.txt

diff --git a/Documentation/devicetree/bindings/nvmem/imx-iim.txt b/Documentation/devicetree/bindings/nvmem/imx-iim.txt
new file mode 100644
index 0000000..1978c5b
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/imx-iim.txt
@@ -0,0 +1,22 @@
+Freescale i.MX IC Identification Module (IIM) device tree bindings
+
+This binding represents the IC Identification Module (IIM) found on
+i.MX25, i.MX27, i.MX31, i.MX35, i.MX51 and i.MX53 SoCs.
+
+Required properties:
+- compatible: should be one of
+	"fsl,imx25-iim", "fsl,imx27-iim",
+	"fsl,imx31-iim", "fsl,imx35-iim",
+	"fsl,imx51-iim", "fsl,imx53-iim",
+- reg: Should contain the register base and length.
+- interrupts: Should contain the interrupt for the IIM
+- clocks: Should contain a phandle pointing to the gated peripheral clock.
+
+Example:
+
+	iim: iim@63f98000 {
+		compatible = "fsl,imx53-iim", "fsl,imx27-iim";
+		reg = <0x63f98000 0x4000>;
+		interrupts = <69>;
+                clocks = <&clks IMX5_CLK_IIM_GATE>;
+	};
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 08/11] dt-bindings: imx-ocotp: add compatible string for i.MX7D/S
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
                   ` (6 preceding siblings ...)
  2017-03-31 12:44 ` [PATCH 07/11] dt-bindings: nvmem: Add i.MX IIM binding doc Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  2017-04-03 12:41   ` Rob Herring
  2017-03-31 12:44 ` [PATCH 09/11] nvmem: octop: Add i.MX7D support Srinivas Kandagatla
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh
  Cc: linux-kernel, maxime.ripard, Peng Fan, Shawn Guo,
	Srinivas Kandagatla, Rob Herring, Mark Rutland

From: Peng Fan <peng.fan@nxp.com>

Add compatible string for i.MX7D/S

Signed-off-by: Peng Fan <peng.fan@nxp.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/devicetree/bindings/nvmem/imx-ocotp.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
index 966a72e..bbde2e4 100644
--- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
+++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
@@ -9,6 +9,7 @@ Required properties:
 	"fsl,imx6sl-ocotp" (i.MX6SL), or
 	"fsl,imx6sx-ocotp" (i.MX6SX),
 	"fsl,imx6ul-ocotp" (i.MX6UL),
+	"fsl,imx7d-ocotp" (i.MX7D/S),
 	followed by "syscon".
 - reg: Should contain the register base and length.
 - clocks: Should contain a phandle pointing to the gated peripheral clock.
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 09/11] nvmem: octop: Add i.MX7D support
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
                   ` (7 preceding siblings ...)
  2017-03-31 12:44 ` [PATCH 08/11] dt-bindings: imx-ocotp: add compatible string for i.MX7D/S Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 10/11] nvmem: imx-ocotp: clear error bit after reading locked values Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 11/11] nvmem: imx-ocotp: add write support Srinivas Kandagatla
  10 siblings, 0 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh
  Cc: linux-kernel, maxime.ripard, Peng Fan, Srinivas Kandagatla, Shawn Guo

From: Peng Fan <peng.fan@nxp.com>

Add i.MX7D support.
There is 16 banks, each bank 4 words.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/nvmem/imx-ocotp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index 549177d..0d33705 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -74,6 +74,7 @@ static const struct of_device_id imx_ocotp_dt_ids[] = {
 	{ .compatible = "fsl,imx6sl-ocotp", (void *)64 },
 	{ .compatible = "fsl,imx6sx-ocotp", (void *)128 },
 	{ .compatible = "fsl,imx6ul-ocotp", (void *)128 },
+	{ .compatible = "fsl,imx7d-ocotp", (void *)64 },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 10/11] nvmem: imx-ocotp: clear error bit after reading locked values
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
                   ` (8 preceding siblings ...)
  2017-03-31 12:44 ` [PATCH 09/11] nvmem: octop: Add i.MX7D support Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  2017-03-31 12:44 ` [PATCH 11/11] nvmem: imx-ocotp: add write support Srinivas Kandagatla
  10 siblings, 0 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, maxime.ripard, Richard Leitner, Srinivas Kandagatla

From: Richard Leitner <richard.leitner@skidata.com>

When reading a "read locked" value from the OCOTP controller on i.MX6
SoC's an error bit is set. This bit has to be cleared by software before
any new write, read or reload access can be issued.

Therefore clear it after we detect such an "locked read".

Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/nvmem/imx-ocotp.c | 41 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index 0d33705..0bb8d0d 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -25,6 +25,19 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
+#define IMX_OCOTP_OFFSET_B0W0		0x400 /* Offset from base address of the
+					       * OTP Bank0 Word0
+					       */
+#define IMX_OCOTP_OFFSET_PER_WORD	0x10  /* Offset between the start addr
+					       * of two consecutive OTP words.
+					       */
+#define IMX_OCOTP_ADDR_CTRL		0x0000
+#define IMX_OCOTP_ADDR_CTRL_CLR		0x0008
+
+#define IMX_OCOTP_BM_CTRL_ERROR		0x00000200
+
+#define IMX_OCOTP_READ_LOCKED_VAL	0xBADABADA
+
 struct ocotp_priv {
 	struct device *dev;
 	struct clk *clk;
@@ -32,6 +45,17 @@ struct ocotp_priv {
 	unsigned int nregs;
 };
 
+static void imx_ocotp_clr_err_if_set(void __iomem *base)
+{
+	u32 c;
+
+	c = readl(base + IMX_OCOTP_ADDR_CTRL);
+	if (!(c & IMX_OCOTP_BM_CTRL_ERROR))
+		return;
+
+	writel(IMX_OCOTP_BM_CTRL_ERROR, base + IMX_OCOTP_ADDR_CTRL_CLR);
+}
+
 static int imx_ocotp_read(void *context, unsigned int offset,
 			  void *val, size_t bytes)
 {
@@ -52,11 +76,22 @@ static int imx_ocotp_read(void *context, unsigned int offset,
 		dev_err(priv->dev, "failed to prepare/enable ocotp clk\n");
 		return ret;
 	}
-	for (i = index; i < (index + count); i++)
-		*buf++ = readl(priv->base + 0x400 + i * 0x10);
 
-	clk_disable_unprepare(priv->clk);
+	for (i = index; i < (index + count); i++) {
+		*buf++ = readl(priv->base + IMX_OCOTP_OFFSET_B0W0 +
+			       i * IMX_OCOTP_OFFSET_PER_WORD);
+
+		/* 47.3.1.2
+		 * For "read locked" registers 0xBADABADA will be returned and
+		 * HW_OCOTP_CTRL[ERROR] will be set. It must be cleared by
+		 * software before any new write, read or reload access can be
+		 * issued
+		 */
+		if (*(buf - 1) == IMX_OCOTP_READ_LOCKED_VAL)
+			imx_ocotp_clr_err_if_set(priv->base);
+	}
 
+	clk_disable_unprepare(priv->clk);
 	return 0;
 }
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 11/11] nvmem: imx-ocotp: add write support
  2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
                   ` (9 preceding siblings ...)
  2017-03-31 12:44 ` [PATCH 10/11] nvmem: imx-ocotp: clear error bit after reading locked values Srinivas Kandagatla
@ 2017-03-31 12:44 ` Srinivas Kandagatla
  10 siblings, 0 replies; 13+ messages in thread
From: Srinivas Kandagatla @ 2017-03-31 12:44 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, maxime.ripard, Richard Leitner, Srinivas Kandagatla

From: Richard Leitner <richard.leitner@skidata.com>

Implement write routine for OCOTP controller found in i.MX6 SoC's.
Furthermore add locking to the read function to prevent race conditions.
The write routine code is based on the fsl_otp driver from Freescale.

Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/nvmem/imx-ocotp.txt        |   4 +
 drivers/nvmem/imx-ocotp.c                          | 210 ++++++++++++++++++++-
 2 files changed, 212 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
index bbde2e4..70d791b 100644
--- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
+++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
@@ -14,10 +14,14 @@ Required properties:
 - reg: Should contain the register base and length.
 - clocks: Should contain a phandle pointing to the gated peripheral clock.
 
+Optional properties:
+- read-only: disable write access
+
 Example:
 
 	ocotp: ocotp@021bc000 {
 		compatible = "fsl,imx6q-ocotp", "syscon";
 		reg = <0x021bc000 0x4000>;
 		clocks = <&clks IMX6QDL_CLK_IIM>;
+		read-only;
 	};
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index 0bb8d0d..193ca8f 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -7,6 +7,9 @@
  * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>,
  *	Orex Computed Radiography
  *
+ * Write support based on the fsl_otp driver,
+ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc
+ *
  * 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.
@@ -24,6 +27,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #define IMX_OCOTP_OFFSET_B0W0		0x400 /* Offset from base address of the
 					       * OTP Bank0 Word0
@@ -31,20 +35,69 @@
 #define IMX_OCOTP_OFFSET_PER_WORD	0x10  /* Offset between the start addr
 					       * of two consecutive OTP words.
 					       */
+
 #define IMX_OCOTP_ADDR_CTRL		0x0000
+#define IMX_OCOTP_ADDR_CTRL_SET		0x0004
 #define IMX_OCOTP_ADDR_CTRL_CLR		0x0008
+#define IMX_OCOTP_ADDR_TIMING		0x0010
+#define IMX_OCOTP_ADDR_DATA		0x0020
 
+#define IMX_OCOTP_BM_CTRL_ADDR		0x0000007F
+#define IMX_OCOTP_BM_CTRL_BUSY		0x00000100
 #define IMX_OCOTP_BM_CTRL_ERROR		0x00000200
+#define IMX_OCOTP_BM_CTRL_REL_SHADOWS	0x00000400
 
+#define DEF_RELAX			20 /* > 16.5ns */
+#define IMX_OCOTP_WR_UNLOCK		0x3E770000
 #define IMX_OCOTP_READ_LOCKED_VAL	0xBADABADA
 
+static DEFINE_MUTEX(ocotp_mutex);
+
 struct ocotp_priv {
 	struct device *dev;
 	struct clk *clk;
 	void __iomem *base;
 	unsigned int nregs;
+	struct nvmem_config *config;
 };
 
+static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags)
+{
+	int count;
+	u32 c, mask;
+
+	mask = IMX_OCOTP_BM_CTRL_BUSY | IMX_OCOTP_BM_CTRL_ERROR | flags;
+
+	for (count = 10000; count >= 0; count--) {
+		c = readl(base + IMX_OCOTP_ADDR_CTRL);
+		if (!(c & mask))
+			break;
+		cpu_relax();
+	}
+
+	if (count < 0) {
+		/* HW_OCOTP_CTRL[ERROR] will be set under the following
+		 * conditions:
+		 * - A write is performed to a shadow register during a shadow
+		 *   reload (essentially, while HW_OCOTP_CTRL[RELOAD_SHADOWS] is
+		 *   set. In addition, the contents of the shadow register shall
+		 *   not be updated.
+		 * - A write is performed to a shadow register which has been
+		 *   locked.
+		 * - A read is performed to from a shadow register which has
+		 *   been read locked.
+		 * - A program is performed to a fuse word which has been locked
+		 * - A read is performed to from a fuse word which has been read
+		 *   locked.
+		 */
+		if (c & IMX_OCOTP_BM_CTRL_ERROR)
+			return -EPERM;
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
 static void imx_ocotp_clr_err_if_set(void __iomem *base)
 {
 	u32 c;
@@ -71,12 +124,21 @@ static int imx_ocotp_read(void *context, unsigned int offset,
 	if (count > (priv->nregs - index))
 		count = priv->nregs - index;
 
+	mutex_lock(&ocotp_mutex);
+
 	ret = clk_prepare_enable(priv->clk);
 	if (ret < 0) {
+		mutex_unlock(&ocotp_mutex);
 		dev_err(priv->dev, "failed to prepare/enable ocotp clk\n");
 		return ret;
 	}
 
+	ret = imx_ocotp_wait_for_busy(priv->base, 0);
+	if (ret < 0) {
+		dev_err(priv->dev, "timeout during read setup\n");
+		goto read_end;
+	}
+
 	for (i = index; i < (index + count); i++) {
 		*buf++ = readl(priv->base + IMX_OCOTP_OFFSET_B0W0 +
 			       i * IMX_OCOTP_OFFSET_PER_WORD);
@@ -90,18 +152,160 @@ static int imx_ocotp_read(void *context, unsigned int offset,
 		if (*(buf - 1) == IMX_OCOTP_READ_LOCKED_VAL)
 			imx_ocotp_clr_err_if_set(priv->base);
 	}
+	ret = 0;
 
+read_end:
 	clk_disable_unprepare(priv->clk);
-	return 0;
+	mutex_unlock(&ocotp_mutex);
+	return ret;
+}
+
+static int imx_ocotp_write(void *context, unsigned int offset, void *val,
+			   size_t bytes)
+{
+	struct ocotp_priv *priv = context;
+	u32 *buf = val;
+	int ret;
+
+	unsigned long clk_rate = 0;
+	unsigned long strobe_read, relax, strobe_prog;
+	u32 timing = 0;
+	u32 ctrl;
+	u8 waddr;
+
+	/* allow only writing one complete OTP word at a time */
+	if ((bytes != priv->config->word_size) ||
+	    (offset % priv->config->word_size))
+		return -EINVAL;
+
+	mutex_lock(&ocotp_mutex);
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret < 0) {
+		mutex_unlock(&ocotp_mutex);
+		dev_err(priv->dev, "failed to prepare/enable ocotp clk\n");
+		return ret;
+	}
+
+	/* 47.3.1.3.1
+	 * Program HW_OCOTP_TIMING[STROBE_PROG] and HW_OCOTP_TIMING[RELAX]
+	 * fields with timing values to match the current frequency of the
+	 * ipg_clk. OTP writes will work at maximum bus frequencies as long
+	 * as the HW_OCOTP_TIMING parameters are set correctly.
+	 */
+	clk_rate = clk_get_rate(priv->clk);
+
+	relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
+	strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
+	strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
+
+	timing = strobe_prog & 0x00000FFF;
+	timing |= (relax       << 12) & 0x0000F000;
+	timing |= (strobe_read << 16) & 0x003F0000;
+
+	writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING);
+
+	/* 47.3.1.3.2
+	 * Check that HW_OCOTP_CTRL[BUSY] and HW_OCOTP_CTRL[ERROR] are clear.
+	 * Overlapped accesses are not supported by the controller. Any pending
+	 * write or reload must be completed before a write access can be
+	 * requested.
+	 */
+	ret = imx_ocotp_wait_for_busy(priv->base, 0);
+	if (ret < 0) {
+		dev_err(priv->dev, "timeout during timing setup\n");
+		goto write_end;
+	}
+
+	/* 47.3.1.3.3
+	 * Write the requested address to HW_OCOTP_CTRL[ADDR] and program the
+	 * unlock code into HW_OCOTP_CTRL[WR_UNLOCK]. This must be programmed
+	 * for each write access. The lock code is documented in the register
+	 * description. Both the unlock code and address can be written in the
+	 * same operation.
+	 */
+	/* OTP write/read address specifies one of 128 word address locations */
+	waddr = offset / 4;
+
+	ctrl = readl(priv->base + IMX_OCOTP_ADDR_CTRL);
+	ctrl &= ~IMX_OCOTP_BM_CTRL_ADDR;
+	ctrl |= waddr & IMX_OCOTP_BM_CTRL_ADDR;
+	ctrl |= IMX_OCOTP_WR_UNLOCK;
+
+	writel(ctrl, priv->base + IMX_OCOTP_ADDR_CTRL);
+
+	/* 47.3.1.3.4
+	 * Write the data to the HW_OCOTP_DATA register. This will automatically
+	 * set HW_OCOTP_CTRL[BUSY] and clear HW_OCOTP_CTRL[WR_UNLOCK]. To
+	 * protect programming same OTP bit twice, before program OCOTP will
+	 * automatically read fuse value in OTP and use read value to mask
+	 * program data. The controller will use masked program data to program
+	 * a 32-bit word in the OTP per the address in HW_OCOTP_CTRL[ADDR]. Bit
+	 * fields with 1's will result in that OTP bit being programmed. Bit
+	 * fields with 0's will be ignored. At the same time that the write is
+	 * accepted, the controller makes an internal copy of
+	 * HW_OCOTP_CTRL[ADDR] which cannot be updated until the next write
+	 * sequence is initiated. This copy guarantees that erroneous writes to
+	 * HW_OCOTP_CTRL[ADDR] will not affect an active write operation. It
+	 * should also be noted that during the programming HW_OCOTP_DATA will
+	 * shift right (with zero fill). This shifting is required to program
+	 * the OTP serially. During the write operation, HW_OCOTP_DATA cannot be
+	 * modified.
+	 */
+	writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA);
+
+	/* 47.4.1.4.5
+	 * Once complete, the controller will clear BUSY. A write request to a
+	 * protected or locked region will result in no OTP access and no
+	 * setting of HW_OCOTP_CTRL[BUSY]. In addition HW_OCOTP_CTRL[ERROR] will
+	 * be set. It must be cleared by software before any new write access
+	 * can be issued.
+	 */
+	ret = imx_ocotp_wait_for_busy(priv->base, 0);
+	if (ret < 0) {
+		if (ret == -EPERM) {
+			dev_err(priv->dev, "failed write to locked region");
+			imx_ocotp_clr_err_if_set(priv->base);
+		} else {
+			dev_err(priv->dev, "timeout during data write\n");
+		}
+		goto write_end;
+	}
+
+	/* 47.3.1.4
+	 * Write Postamble: Due to internal electrical characteristics of the
+	 * OTP during writes, all OTP operations following a write must be
+	 * separated by 2 us after the clearing of HW_OCOTP_CTRL_BUSY following
+	 * the write.
+	 */
+	udelay(2);
+
+	/* reload all shadow registers */
+	writel(IMX_OCOTP_BM_CTRL_REL_SHADOWS,
+	       priv->base + IMX_OCOTP_ADDR_CTRL_SET);
+	ret = imx_ocotp_wait_for_busy(priv->base,
+				      IMX_OCOTP_BM_CTRL_REL_SHADOWS);
+	if (ret < 0) {
+		dev_err(priv->dev, "timeout during shadow register reload\n");
+		goto write_end;
+	}
+
+write_end:
+	clk_disable_unprepare(priv->clk);
+	mutex_unlock(&ocotp_mutex);
+	if (ret < 0)
+		return ret;
+	return bytes;
 }
 
 static struct nvmem_config imx_ocotp_nvmem_config = {
 	.name = "imx-ocotp",
-	.read_only = true,
+	.read_only = false,
 	.word_size = 4,
 	.stride = 4,
 	.owner = THIS_MODULE,
 	.reg_read = imx_ocotp_read,
+	.reg_write = imx_ocotp_write,
 };
 
 static const struct of_device_id imx_ocotp_dt_ids[] = {
@@ -142,7 +346,9 @@ static int imx_ocotp_probe(struct platform_device *pdev)
 	imx_ocotp_nvmem_config.size = 4 * priv->nregs;
 	imx_ocotp_nvmem_config.dev = dev;
 	imx_ocotp_nvmem_config.priv = priv;
+	priv->config = &imx_ocotp_nvmem_config;
 	nvmem = nvmem_register(&imx_ocotp_nvmem_config);
+
 	if (IS_ERR(nvmem))
 		return PTR_ERR(nvmem);
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 08/11] dt-bindings: imx-ocotp: add compatible string for i.MX7D/S
  2017-03-31 12:44 ` [PATCH 08/11] dt-bindings: imx-ocotp: add compatible string for i.MX7D/S Srinivas Kandagatla
@ 2017-04-03 12:41   ` Rob Herring
  0 siblings, 0 replies; 13+ messages in thread
From: Rob Herring @ 2017-04-03 12:41 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Greg Kroah-Hartman, linux-kernel, Maxime Ripard, Peng Fan,
	Shawn Guo, Mark Rutland

On Fri, Mar 31, 2017 at 7:44 AM, Srinivas Kandagatla
<srinivas.kandagatla@linaro.org> wrote:
> From: Peng Fan <peng.fan@nxp.com>
>
> Add compatible string for i.MX7D/S
>
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  Documentation/devicetree/bindings/nvmem/imx-ocotp.txt | 1 +
>  1 file changed, 1 insertion(+)

Needs to go to DT list, but this is trivial.

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2017-04-03 12:41 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-31 12:44 [PATCH 00/11] nvmem: patches for v4.12 Srinivas Kandagatla
2017-03-31 12:44 ` [PATCH 01/11] MAINTAINERS: nvmem: Remove myself from maintainers Srinivas Kandagatla
2017-03-31 12:44 ` [PATCH 02/11] nvmem: core: Allow allocating several anonymous nvmem devices Srinivas Kandagatla
2017-03-31 12:44 ` [PATCH 03/11] nvmem: sunxi-sid: read NVMEM size from device compatible Srinivas Kandagatla
2017-03-31 12:44 ` [PATCH 04/11] nvmem: sunxi-sid: add support for H3's SID controller Srinivas Kandagatla
2017-03-31 12:44 ` [PATCH 05/11] nvmem: imx-ocotp: fix usage of "dev" pointers Srinivas Kandagatla
2017-03-31 12:44 ` [PATCH 06/11] nvmem: Add driver for the i.MX IIM Srinivas Kandagatla
2017-03-31 12:44 ` [PATCH 07/11] dt-bindings: nvmem: Add i.MX IIM binding doc Srinivas Kandagatla
2017-03-31 12:44 ` [PATCH 08/11] dt-bindings: imx-ocotp: add compatible string for i.MX7D/S Srinivas Kandagatla
2017-04-03 12:41   ` Rob Herring
2017-03-31 12:44 ` [PATCH 09/11] nvmem: octop: Add i.MX7D support Srinivas Kandagatla
2017-03-31 12:44 ` [PATCH 10/11] nvmem: imx-ocotp: clear error bit after reading locked values Srinivas Kandagatla
2017-03-31 12:44 ` [PATCH 11/11] nvmem: imx-ocotp: add write support Srinivas Kandagatla

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.