LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [RFC PATCH 0/3] Add simple EEPROM Framework via regmap.
@ 2015-02-19 17:07 Srinivas Kandagatla
  2015-02-19 17:08 ` [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework Srinivas Kandagatla
                   ` (3 more replies)
  0 siblings, 4 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-19 17:07 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, Srinivas Kandagatla

This patchset adds a new simple EEPROM framework to kernel.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.
    
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
    
This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
    
Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

patch 1 Introduces the EEPROM framework.
Patch 2 migrates an existing driver to eeprom framework.
Patch 3 Adds Qualcomm specific qfprom driver.

Its also possible to migrate other eeprom drivers to this framework.
Patch 3 can also be made a generic mmio-eeprom driver.

Providers APIs:
	eeprom_register/unregister();

Consumers APIs:
	eeprom_cell_get()/eeprom_cell_get_byname();
	eeprom_cell_read()/eeprom_cell_write();

Device Tree:
	qfprom: qfprom@00700000 {
		#eeprom-cells = <2>;
		compatible 	= "qcom,qfprom";
		reg		= <0x00700000 0x1000>;
	};

	tsens: tsens {
		...
		eeproms = <&qfprom 0x404 0x10>, <&qfprom 0x414 0x10>;
		eeprom-names = "calib", "backup_calib";
		...
	};

userspace interface:

	hexdump /sys/class/eeprom/eeprom0/eeprom
                                                                                                                                                                                                                  
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
0000000 0000 0000 0000 0000 0000 0000 0000 0000
...
*
0001000


Thanks,
srini

Maxime Ripard (2):
  eeprom: Add a simple EEPROM framework
  eeprom: sunxi: Move the SID driver to the eeprom framework

Srinivas Kandagatla (1):
  eeprom: qfprom: Add Qualcomm QFPROM support.

 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 --
 .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/eeprom/Kconfig                             |  35 +++
 drivers/eeprom/Makefile                            |  11 +
 drivers/eeprom/core.c                              | 290 +++++++++++++++++++++
 drivers/eeprom/eeprom-sunxi-sid.c                  | 125 +++++++++
 drivers/eeprom/qfprom.c                            |  75 ++++++
 drivers/misc/eeprom/Kconfig                        |  13 -
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 -----------
 include/linux/eeprom-consumer.h                    |  73 ++++++
 include/linux/eeprom-provider.h                    |  51 ++++
 14 files changed, 711 insertions(+), 192 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
 create mode 100644 drivers/eeprom/Kconfig
 create mode 100644 drivers/eeprom/Makefile
 create mode 100644 drivers/eeprom/core.c
 create mode 100644 drivers/eeprom/eeprom-sunxi-sid.c
 create mode 100644 drivers/eeprom/qfprom.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
 create mode 100644 include/linux/eeprom-consumer.h
 create mode 100644 include/linux/eeprom-provider.h

-- 
1.9.1


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

* [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-19 17:07 [RFC PATCH 0/3] Add simple EEPROM Framework via regmap Srinivas Kandagatla
@ 2015-02-19 17:08 ` Srinivas Kandagatla
  2015-02-19 18:12   ` Andrew Lunn
                     ` (4 more replies)
  2015-02-19 17:08 ` [RFC PATCH 2/3] eeprom: sunxi: Move the SID driver to the eeprom framework Srinivas Kandagatla
                   ` (2 subsequent siblings)
  3 siblings, 5 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-19 17:08 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, Srinivas Kandagatla

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

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.

Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[srinivas.kandagatla: Moved to regmap based and cleanedup apis]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/eeprom/Kconfig                             |  19 ++
 drivers/eeprom/Makefile                            |   9 +
 drivers/eeprom/core.c                              | 290 +++++++++++++++++++++
 include/linux/eeprom-consumer.h                    |  73 ++++++
 include/linux/eeprom-provider.h                    |  51 ++++
 8 files changed, 493 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
 create mode 100644 drivers/eeprom/Kconfig
 create mode 100644 drivers/eeprom/Makefile
 create mode 100644 drivers/eeprom/core.c
 create mode 100644 include/linux/eeprom-consumer.h
 create mode 100644 include/linux/eeprom-provider.h

diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
new file mode 100644
index 0000000..9ec1ec2
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
@@ -0,0 +1,48 @@
+= EEPROM Data Device Tree Bindings =
+
+This binding is intended to represent the location of hardware
+configuration data stored in EEPROMs.
+
+On a significant proportion of boards, the manufacturer has stored
+some data on an EEPROM-like device, for the OS to be able to retrieve
+these information and act upon it. Obviously, the OS has to know
+about where to retrieve these data from, and where they are stored on
+the storage device.
+
+This document is here to document this.
+
+= Data providers =
+
+Required properties:
+#eeprom-cells:	Number of cells in an eeprom specifier; The common
+		case is 2.
+
+For example:
+
+	at24: eeprom@42 {
+		#eeprom-cells = <2>;
+	};
+
+= Data consumers =
+
+Required properties:
+
+eeproms: List of phandle and data cell specifier triplet, one triplet
+	 for each data cell the device might be interested in. The
+	 triplet consists of the phandle to the eeprom provider, then
+	 the offset in byte within that storage device, and the length
+	 in byte of the data we care about.
+
+Optional properties:
+
+eeprom-names: List of data cell name strings sorted in the same order
+ 	      as the resets property. Consumers drivers will use
+ 	      eeprom-names to differentiate between multiple cells,
+ 	      and hence being able to know what these cells are for.
+
+For example:
+
+	device {
+		eeproms = <&at24 14 42>;
+		eeprom-names = "soc-rev-id";
+	};
diff --git a/drivers/Kconfig b/drivers/Kconfig
index c70d6e4..d7afc82 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
 
 source "drivers/android/Kconfig"
 
+source "drivers/eeprom/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 527a6da..57eb5b0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= coresight/
 obj-$(CONFIG_ANDROID)		+= android/
+obj-$(CONFIG_EEPROM)		+= eeprom/
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
new file mode 100644
index 0000000..2c5452a
--- /dev/null
+++ b/drivers/eeprom/Kconfig
@@ -0,0 +1,19 @@
+menuconfig EEPROM
+	bool "EEPROM Support"
+	depends on OF
+	help
+	  Support for EEPROM alike devices.
+
+	  This framework is designed to provide a generic interface to EEPROM
+	  from both the Linux Kernel and the userspace.
+
+	  If unsure, say no.
+
+if EEPROM
+
+config EEPROM_DEBUG
+	bool "EEPROM debug support"
+	help
+	  Say yes here to enable debugging support.
+
+endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
new file mode 100644
index 0000000..e130079
--- /dev/null
+++ b/drivers/eeprom/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for eeprom drivers.
+#
+
+ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
+
+obj-$(CONFIG_EEPROM)		+= core.o
+
+# Devices
diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
new file mode 100644
index 0000000..bc877a6
--- /dev/null
+++ b/drivers/eeprom/core.c
@@ -0,0 +1,290 @@
+/*
+ * EEPROM framework core.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/eeprom-consumer.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+struct eeprom_cell {
+	struct eeprom_device *eeprom;
+	loff_t offset;
+	size_t count;
+};
+
+static DEFINE_MUTEX(eeprom_list_mutex);
+static LIST_HEAD(eeprom_list);
+static DEFINE_IDA(eeprom_ida);
+
+static ssize_t bin_attr_eeprom_read_write(struct kobject *kobj,
+				    char *buf, loff_t offset,
+				    size_t count, bool read)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct eeprom_device *eeprom = container_of(dev, struct eeprom_device,
+						    edev);
+	int rc;
+
+	if (offset > eeprom->size)
+		return 0;
+
+	if (offset + count > eeprom->size)
+		count = eeprom->size - offset;
+
+	if (read)
+		rc = regmap_bulk_read(eeprom->regmap, offset,
+				      buf, count/eeprom->stride);
+	else
+		rc = regmap_bulk_write(eeprom->regmap, offset,
+				       buf, count/eeprom->stride);
+
+	if (IS_ERR_VALUE(rc))
+		return 0;
+
+	return count;
+}
+
+static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
+				    struct bin_attribute *attr,
+				    char *buf, loff_t offset, size_t count)
+{
+	return bin_attr_eeprom_read_write(kobj, buf, offset, count, true);
+}
+
+static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *attr,
+				     char *buf, loff_t offset, size_t count)
+{
+	return bin_attr_eeprom_read_write(kobj, buf, offset, count, false);
+}
+
+static struct bin_attribute bin_attr_eeprom = {
+	.attr	= {
+		.name	= "eeprom",
+		.mode	= 0660,
+	},
+	.read	= bin_attr_eeprom_read,
+	.write	= bin_attr_eeprom_write,
+};
+
+static struct bin_attribute *eeprom_bin_attributes[] = {
+	&bin_attr_eeprom,
+	NULL,
+};
+
+static const struct attribute_group eeprom_bin_group = {
+	.bin_attrs	= eeprom_bin_attributes,
+};
+
+static const struct attribute_group *eeprom_dev_groups[] = {
+	&eeprom_bin_group,
+	NULL,
+};
+
+static struct class eeprom_class = {
+	.name		= "eeprom",
+	.dev_groups	= eeprom_dev_groups,
+};
+
+int eeprom_register(struct eeprom_device *eeprom)
+{
+	int rval;
+
+	if (!eeprom->regmap || !eeprom->size) {
+		dev_err(eeprom->dev, "Regmap not found\n");
+		return -EINVAL;
+	}
+
+	eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
+	if (eeprom->id < 0)
+		return eeprom->id;
+
+	eeprom->edev.class = &eeprom_class;
+	eeprom->edev.parent = eeprom->dev;
+	eeprom->edev.of_node = eeprom->dev ? eeprom->dev->of_node : NULL;
+	dev_set_name(&eeprom->edev, "eeprom%d", eeprom->id);
+
+	device_initialize(&eeprom->edev);
+
+	dev_dbg(&eeprom->edev, "Registering eeprom device %s\n",
+		dev_name(&eeprom->edev));
+
+	rval = device_add(&eeprom->edev);
+	if (rval)
+		return rval;
+
+	mutex_lock(&eeprom_list_mutex);
+	list_add(&eeprom->list, &eeprom_list);
+	mutex_unlock(&eeprom_list_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(eeprom_register);
+
+int eeprom_unregister(struct eeprom_device *eeprom)
+{
+	device_del(&eeprom->edev);
+
+	mutex_lock(&eeprom_list_mutex);
+	list_del(&eeprom->list);
+	mutex_unlock(&eeprom_list_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(eeprom_unregister);
+
+static struct eeprom_cell *__eeprom_cell_get(struct device_node *node,
+					     int index)
+{
+	struct of_phandle_args args;
+	struct eeprom_cell *cell;
+	struct eeprom_device *e, *eeprom = NULL;
+	int ret;
+
+	ret = of_parse_phandle_with_args(node, "eeproms",
+					 "#eeprom-cells", index, &args);
+	if (ret)
+		return ERR_PTR(ret);
+
+	if (args.args_count != 2)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&eeprom_list_mutex);
+
+	list_for_each_entry(e, &eeprom_list, list) {
+		if (args.np == e->edev.of_node) {
+			eeprom = e;
+			break;
+		}
+	}
+	mutex_unlock(&eeprom_list_mutex);
+
+	if (!eeprom)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	cell = kzalloc(sizeof(*cell), GFP_KERNEL);
+	if (!cell)
+		return ERR_PTR(-ENOMEM);
+
+	cell->eeprom = eeprom;
+	cell->offset = args.args[0];
+	cell->count = args.args[1];
+
+	return cell;
+}
+
+static struct eeprom_cell *__eeprom_cell_get_byname(struct device_node *node,
+						    const char *id)
+{
+	int index = 0;
+
+	if (id)
+		index = of_property_match_string(node,
+						 "eeprom-names",
+						 id);
+	return __eeprom_cell_get(node, index);
+
+}
+
+struct eeprom_cell *eeprom_cell_get(struct device *dev, int index)
+{
+	if (!dev)
+		return ERR_PTR(-EINVAL);
+
+	/* First, attempt to retrieve the cell through the DT */
+	if (dev->of_node)
+		return __eeprom_cell_get(dev->of_node, index);
+
+	/* We don't support anything else yet */
+	return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL(eeprom_cell_get);
+
+struct eeprom_cell *eeprom_cell_get_byname(struct device *dev, const char *id)
+{
+	if (!dev)
+		return ERR_PTR(-EINVAL);
+
+	if (id && dev->of_node)
+		return __eeprom_cell_get_byname(dev->of_node, id);
+
+	/* We don't support anything else yet */
+	return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL(eeprom_cell_get_byname);
+
+void eeprom_cell_put(struct eeprom_cell *cell)
+{
+	kfree(cell);
+}
+EXPORT_SYMBOL(eeprom_cell_put);
+
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	char *buf;
+	int rc;
+
+	if (!eeprom || !eeprom->regmap)
+		return ERR_PTR(-EINVAL);
+
+	buf = kzalloc(cell->count, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	rc = regmap_bulk_read(eeprom->regmap, cell->offset,
+			      buf, cell->count/eeprom->stride);
+	if (IS_ERR_VALUE(rc)) {
+		kfree(buf);
+		return ERR_PTR(rc);
+	}
+
+	*len = cell->count;
+
+	return buf;
+}
+EXPORT_SYMBOL(eeprom_cell_read);
+
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+
+	if (!eeprom || !eeprom->regmap)
+		return -EINVAL;
+
+	return regmap_bulk_write(eeprom->regmap, cell->offset,
+				 buf, cell->count/eeprom->stride);
+}
+EXPORT_SYMBOL(eeprom_cell_write);
+
+static int eeprom_init(void)
+{
+	return class_register(&eeprom_class);
+}
+
+static void eeprom_exit(void)
+{
+	class_unregister(&eeprom_class);
+}
+
+subsys_initcall(eeprom_init);
+module_exit(eeprom_exit);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("EEPROM Driver Core");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
new file mode 100644
index 0000000..706ae9d
--- /dev/null
+++ b/include/linux/eeprom-consumer.h
@@ -0,0 +1,73 @@
+/*
+ * EEPROM framework consumer.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_CONSUMER_H
+#define _LINUX_EEPROM_CONSUMER_H
+
+struct eeprom_cell;
+
+/**
+ * eeprom_cell_get(): Get eeprom cell of device form a given index.
+ *
+ * @dev: Device that will be interacted with
+ * @index: Index of the eeprom cell.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *eeprom_cell_get(struct device *dev, int index);
+
+/**
+ * eeprom_cell_get(): Get eeprom cell of device form a given name.
+ *
+ * @dev: Device that will be interacted with
+ * @name: Name of the eeprom cell.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *eeprom_cell_get_byname(struct device *dev,
+					   const char *name);
+
+/**
+ * eeprom_cell_put(): Release previously allocated eeprom cell.
+ *
+ * @cell: Previously allocated eeprom cell by eeprom_cell_get()
+ * or eeprom_cell_get_byname().
+ */
+void eeprom_cell_put(struct eeprom_cell *cell);
+
+/**
+ * eeprom_cell_read(): Read a given eeprom cell
+ *
+ * @cell: eeprom cell to be read.
+ * @len: pointer to length of cell which will be populated on successful read.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a char * bufffer.  The buffer should be freed by the consumer with a
+ * kfree().
+ */
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
+
+/**
+ * eeprom_cell_write(): Write to a given eeprom cell
+ *
+ * @cell: eeprom cell to be written.
+ * @buf: Buffer to be written.
+ * @len: length of buffer to be written to eeprom cell.
+ *
+ * The return value will be an non zero on error or a zero on successful write.
+ */
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
+
+#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */
diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
new file mode 100644
index 0000000..3943c2f
--- /dev/null
+++ b/include/linux/eeprom-provider.h
@@ -0,0 +1,51 @@
+/*
+ * EEPROM framework provider.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_PROVIDER_H
+#define _LINUX_EEPROM_PROVIDER_H
+
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/list.h>
+
+struct eeprom_device {
+	struct regmap		*regmap;
+	int			stride;
+	size_t			size;
+	struct device		*dev;
+
+	/* Internal to framework */
+	struct device		edev;
+	int			id;
+	struct list_head	list;
+};
+
+/**
+ * eeprom_register(): Register a eeprom device for given eeprom.
+ * Also creates an binary entry in /sys/class/eeprom/eeprom[id]/eeprom
+ *
+ * @eeprom: eeprom device that needs to be created
+ *
+ * The return value will be an error code on error or a zero on success.
+ * The eeprom_device and sysfs entery will be freed by the eeprom_unregister().
+ */
+int eeprom_register(struct eeprom_device *eeprom);
+
+/**
+ * eeprom_unregister(): Unregister previously registered eeprom device
+ *
+ * @eeprom: Pointer to previously registered eeprom device.
+ *
+ * The return value will be an non zero on error or a zero on success.
+ */
+int eeprom_unregister(struct eeprom_device *eeprom);
+
+#endif  /* ifndef _LINUX_EEPROM_PROVIDER_H */
-- 
1.9.1


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

* [RFC PATCH 2/3] eeprom: sunxi: Move the SID driver to the eeprom framework
  2015-02-19 17:07 [RFC PATCH 0/3] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  2015-02-19 17:08 ` [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework Srinivas Kandagatla
@ 2015-02-19 17:08 ` Srinivas Kandagatla
  2015-02-20 17:47   ` Russell King - ARM Linux
  2015-02-19 17:08 ` [RFC PATCH 3/3] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
  2015-03-05  9:44 ` [PATCH v1 0/6] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  3 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-19 17:08 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, Srinivas Kandagatla

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

Now that we have the EEPROM framework, we can consolidate the common driver
code. Move the driver to the framework, and hopefully, it will fix the sysfs
file creation race.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[srinivas.kandagatla: Moved to regmap based EEPROM framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/ABI/testing/sysfs-driver-sunxi-sid |  22 ----
 drivers/eeprom/Kconfig                           |  10 ++
 drivers/eeprom/Makefile                          |   1 +
 drivers/eeprom/eeprom-sunxi-sid.c                | 125 ++++++++++++++++++
 drivers/misc/eeprom/Kconfig                      |  13 --
 drivers/misc/eeprom/Makefile                     |   1 -
 drivers/misc/eeprom/sunxi_sid.c                  | 156 -----------------------
 7 files changed, 136 insertions(+), 192 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 drivers/eeprom/eeprom-sunxi-sid.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid
deleted file mode 100644
index ffb9536..0000000
--- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid
+++ /dev/null
@@ -1,22 +0,0 @@
-What:		/sys/devices/*/<our-device>/eeprom
-Date:		August 2013
-Contact:	Oliver Schinagl <oliver@schinagl.nl>
-Description:	read-only access to the SID (Security-ID) on current
-		A-series SoC's from Allwinner. Currently supports A10, A10s, A13
-		and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes,
-		whereas the newer A20 SoC exposes 512 bytes split into sections.
-		Besides the 16 bytes of SID, there's also an SJTAG area,
-		HDMI-HDCP key and some custom keys. Below a quick overview, for
-		details see the user manual:
-		0x000  128 bit root-key (sun[457]i)
-		0x010  128 bit boot-key (sun7i)
-		0x020   64 bit security-jtag-key (sun7i)
-		0x028   16 bit key configuration (sun7i)
-		0x02b   16 bit custom-vendor-key (sun7i)
-		0x02c  320 bit low general key (sun7i)
-		0x040   32 bit read-control access (sun7i)
-		0x064  224 bit low general key (sun7i)
-		0x080 2304 bit HDCP-key (sun7i)
-		0x1a0  768 bit high general key (sun7i)
-Users:		any user space application which wants to read the SID on
-		Allwinner's A-series of CPU's.
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index 2c5452a..39235a9 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -16,4 +16,14 @@ config EEPROM_DEBUG
 	help
 	  Say yes here to enable debugging support.
 
+config EEPROM_SUNXI_SID
+	depends on ARCH_SUNXI
+	tristate "Allwinner SoCs SID support"
+	help
+	  This is a driver for the 'security ID' available on various Allwinner
+	  devices.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called sunxi_sid.
+
 endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index e130079..661422c 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -7,3 +7,4 @@ ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
 obj-$(CONFIG_EEPROM)		+= core.o
 
 # Devices
+obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
diff --git a/drivers/eeprom/eeprom-sunxi-sid.c b/drivers/eeprom/eeprom-sunxi-sid.c
new file mode 100644
index 0000000..f2939b9
--- /dev/null
+++ b/drivers/eeprom/eeprom-sunxi-sid.c
@@ -0,0 +1,125 @@
+/*
+ * Allwinner sunXi SoCs Security ID support.
+ *
+ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct eeprom_sid {
+	void __iomem	*membase;
+	struct eeprom_device eeprom;
+};
+
+/* We read the entire key, due to a 32 bit read alignment requirement. Since we
+ * want to return the requested byte, this results in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarely probed, this is not really an issue.
+ */
+static int sunxi_sid_reg_read(void *context,
+			      unsigned int offset, unsigned int *val)
+{
+	struct eeprom_sid *sid  = context;
+	u32 sid_key;
+
+	sid_key = ioread32be(sid->membase + round_down(offset, 4));
+	sid_key >>= (offset % 4) * 8;
+
+	*val = sid_key;
+
+	return 0;
+}
+
+static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
+	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static struct regmap_config sunxi_sid_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+	.reg_read = sunxi_sid_reg_read,
+	.writeable_reg = sunxi_sid_writeable_reg,
+};
+
+static int sunxi_sid_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *device;
+	struct eeprom_sid *sid;
+	struct resource *res;
+	struct eeprom_device *eeprom;
+	struct device *dev = &pdev->dev;
+	int rval;
+
+	sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL);
+	if (!sid)
+		return -ENOMEM;
+
+	eeprom = &sid->eeprom;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid->membase = devm_ioremap_resource(dev, res);
+	if (IS_ERR(sid->membase))
+		return PTR_ERR(sid->membase);
+
+	device = of_match_device(sunxi_sid_of_match, dev);
+	if (!device)
+		return -ENODEV;
+
+	sunxi_sid_regmap_config.max_register = (unsigned int)device->data - 1;
+
+	eeprom->regmap = devm_regmap_init(dev, NULL,
+					  sid, &sunxi_sid_regmap_config);
+	if (IS_ERR(eeprom->regmap))
+		return PTR_ERR(eeprom->regmap);
+
+	eeprom->dev = dev;
+	eeprom->stride = sunxi_sid_regmap_config.reg_stride;
+	eeprom->size = sunxi_sid_regmap_config.max_register;
+	rval = eeprom_register(eeprom);
+	if (rval)
+		return rval;
+
+	platform_set_drvdata(pdev, eeprom);
+
+	return 0;
+}
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = "sunxi-sid",
+		.of_match_table = sunxi_sid_of_match,
+	},
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 9536852f..04f2e1f 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG
 
 	  If unsure, say N.
 
-config EEPROM_SUNXI_SID
-	tristate "Allwinner sunxi security ID support"
-	depends on ARCH_SUNXI && SYSFS
-	help
-	  This is a driver for the 'security ID' available on various Allwinner
-	  devices.
-
-	  Due to the potential risks involved with changing e-fuses,
-	  this driver is read-only.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called sunxi_sid.
-
 endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 9507aec..fc1e81d 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY)	+= eeprom.o
 obj-$(CONFIG_EEPROM_MAX6875)	+= max6875.o
 obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
 obj-$(CONFIG_EEPROM_93XX46)	+= eeprom_93xx46.o
-obj-$(CONFIG_EEPROM_SUNXI_SID)	+= sunxi_sid.o
 obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
deleted file mode 100644
index 8385177..0000000
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
- * http://www.linux-sunxi.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * This driver exposes the Allwinner security ID, efuses exported in byte-
- * sized chunks.
- */
-
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#define DRV_NAME "sunxi-sid"
-
-struct sunxi_sid_data {
-	void __iomem *reg_base;
-	unsigned int keysize;
-};
-
-/* We read the entire key, due to a 32 bit read alignment requirement. Since we
- * want to return the requested byte, this results in somewhat slower code and
- * uses 4 times more reads as needed but keeps code simpler. Since the SID is
- * only very rarely probed, this is not really an issue.
- */
-static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data,
-			      const unsigned int offset)
-{
-	u32 sid_key;
-
-	if (offset >= sid_data->keysize)
-		return 0;
-
-	sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4));
-	sid_key >>= (offset % 4) * 8;
-
-	return sid_key; /* Only return the last byte */
-}
-
-static ssize_t sid_read(struct file *fd, struct kobject *kobj,
-			struct bin_attribute *attr, char *buf,
-			loff_t pos, size_t size)
-{
-	struct platform_device *pdev;
-	struct sunxi_sid_data *sid_data;
-	int i;
-
-	pdev = to_platform_device(kobj_to_dev(kobj));
-	sid_data = platform_get_drvdata(pdev);
-
-	if (pos < 0 || pos >= sid_data->keysize)
-		return 0;
-	if (size > sid_data->keysize - pos)
-		size = sid_data->keysize - pos;
-
-	for (i = 0; i < size; i++)
-		buf[i] = sunxi_sid_read_byte(sid_data, pos + i);
-
-	return i;
-}
-
-static struct bin_attribute sid_bin_attr = {
-	.attr = { .name = "eeprom", .mode = S_IRUGO, },
-	.read = sid_read,
-};
-
-static int sunxi_sid_remove(struct platform_device *pdev)
-{
-	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
-	dev_dbg(&pdev->dev, "driver unloaded\n");
-
-	return 0;
-}
-
-static const struct of_device_id sunxi_sid_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
-	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
-	{/* sentinel */},
-};
-MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-
-static int sunxi_sid_probe(struct platform_device *pdev)
-{
-	struct sunxi_sid_data *sid_data;
-	struct resource *res;
-	const struct of_device_id *of_dev_id;
-	u8 *entropy;
-	unsigned int i;
-
-	sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data),
-				GFP_KERNEL);
-	if (!sid_data)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(sid_data->reg_base))
-		return PTR_ERR(sid_data->reg_base);
-
-	of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev);
-	if (!of_dev_id)
-		return -ENODEV;
-	sid_data->keysize = (int)of_dev_id->data;
-
-	platform_set_drvdata(pdev, sid_data);
-
-	sid_bin_attr.size = sid_data->keysize;
-	if (device_create_bin_file(&pdev->dev, &sid_bin_attr))
-		return -ENODEV;
-
-	entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL);
-	for (i = 0; i < sid_data->keysize; i++)
-		entropy[i] = sunxi_sid_read_byte(sid_data, i);
-	add_device_randomness(entropy, sid_data->keysize);
-	kfree(entropy);
-
-	dev_dbg(&pdev->dev, "loaded\n");
-
-	return 0;
-}
-
-static struct platform_driver sunxi_sid_driver = {
-	.probe = sunxi_sid_probe,
-	.remove = sunxi_sid_remove,
-	.driver = {
-		.name = DRV_NAME,
-		.of_match_table = sunxi_sid_of_match,
-	},
-};
-module_platform_driver(sunxi_sid_driver);
-
-MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
-MODULE_DESCRIPTION("Allwinner sunxi security id driver");
-MODULE_LICENSE("GPL");
-- 
1.9.1


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

* [RFC PATCH 3/3] eeprom: qfprom: Add Qualcomm QFPROM support.
  2015-02-19 17:07 [RFC PATCH 0/3] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  2015-02-19 17:08 ` [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework Srinivas Kandagatla
  2015-02-19 17:08 ` [RFC PATCH 2/3] eeprom: sunxi: Move the SID driver to the eeprom framework Srinivas Kandagatla
@ 2015-02-19 17:08 ` Srinivas Kandagatla
  2015-02-20 17:48   ` Russell King - ARM Linux
  2015-03-05  9:44 ` [PATCH v1 0/6] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  3 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-19 17:08 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, Srinivas Kandagatla

This patch adds QFPROM support driver which is used by other drivers
like thermal sensor and cpufreq.

On MSM parts there are some efuses (called qfprom) these fuses store things like
calibration data, speed bins.. etc. Drivers like cpufreq, thermal sensors would
read out this data for configuring the driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/Kconfig  |  6 ++++
 drivers/eeprom/Makefile |  1 +
 drivers/eeprom/qfprom.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)
 create mode 100644 drivers/eeprom/qfprom.c

diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index 39235a9..b0c94cb 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -26,4 +26,10 @@ config EEPROM_SUNXI_SID
 	  This driver can also be built as a module. If so, the module
 	  will be called sunxi_sid.
 
+config QCOM_QFPROM
+	tristate "QCOM QFPROM Support"
+        depends on EEPROM
+	help
+          Say y here to enable QFPROM support. The QFPROM provides access
+          functions for QFPROM data to rest of the drivers via eeprom interface.
 endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 661422c..f99c824 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_EEPROM)		+= core.o
 
 # Devices
 obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
+obj-$(CONFIG_QCOM_QFPROM)	+= qfprom.o
diff --git a/drivers/eeprom/qfprom.c b/drivers/eeprom/qfprom.c
new file mode 100644
index 0000000..da31b36
--- /dev/null
+++ b/drivers/eeprom/qfprom.c
@@ -0,0 +1,75 @@
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/eeprom-provider.h>
+
+static struct regmap_config qfprom_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+};
+
+static int qfprom_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+
+static int qfprom_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	void __iomem *base;
+	struct device *dev = &pdev->dev;
+	struct eeprom_device *eeprom;
+	int rval;
+
+	eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);
+	if (!eeprom)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	qfprom_regmap_config.max_register = resource_size(res) - 1;
+
+	eeprom->regmap = devm_regmap_init_mmio(dev, base,
+					       &qfprom_regmap_config);
+	if (IS_ERR(eeprom->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(eeprom->regmap);
+	}
+
+	eeprom->dev = dev;
+	eeprom->stride = qfprom_regmap_config.reg_stride;
+	eeprom->size = resource_size(res) - 1;
+	rval = eeprom_register(eeprom);
+	if (rval)
+		return rval;
+
+	platform_set_drvdata(pdev, eeprom);
+	return 0;
+}
+
+static const struct of_device_id qfprom_of_match[] = {
+	{ .compatible = "qcom,qfprom"},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, qfprom_of_match);
+
+static struct platform_driver qfprom_driver = {
+	.probe = qfprom_probe,
+	.remove = qfprom_remove,
+	.driver = {
+		.name = "qcom,qfprom",
+		.of_match_table = qfprom_of_match,
+	},
+};
+module_platform_driver(qfprom_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm QFPROM driver");
+MODULE_LICENSE("GPL2");
-- 
1.9.1


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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-19 17:08 ` [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework Srinivas Kandagatla
@ 2015-02-19 18:12   ` Andrew Lunn
  2015-02-20  8:27     ` Srinivas Kandagatla
  2015-02-20  2:36   ` Stephen Boyd
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 153+ messages in thread
From: Andrew Lunn @ 2015-02-19 18:12 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api, broonie, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard

On Thu, Feb 19, 2015 at 05:08:28PM +0000, Srinivas Kandagatla wrote:
> From: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
> Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
> duplicate pretty much the same code to register a sysfs file, allow in-kernel
> users to access the content of the devices they were driving, etc.
> 
> This was also a problem as far as other in-kernel users were involved, since
> the solutions used were pretty much different from on driver to another, there
> was a rather big abstraction leak.
> 
> This introduction of this framework aims at solving this. It also introduces DT
> representation for consumer devices to go get the data they require (MAC
> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
> 
> Having regmap interface to this framework would give much better
> abstraction for eeproms on different buses.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> [srinivas.kandagatla: Moved to regmap based and cleanedup apis]
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
>  drivers/Kconfig                                    |   2 +
>  drivers/Makefile                                   |   1 +
>  drivers/eeprom/Kconfig                             |  19 ++
>  drivers/eeprom/Makefile                            |   9 +
>  drivers/eeprom/core.c                              | 290 +++++++++++++++++++++
>  include/linux/eeprom-consumer.h                    |  73 ++++++
>  include/linux/eeprom-provider.h                    |  51 ++++
>  8 files changed, 493 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
>  create mode 100644 drivers/eeprom/Kconfig
>  create mode 100644 drivers/eeprom/Makefile
>  create mode 100644 drivers/eeprom/core.c
>  create mode 100644 include/linux/eeprom-consumer.h
>  create mode 100644 include/linux/eeprom-provider.h
> 
> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> new file mode 100644
> index 0000000..9ec1ec2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> @@ -0,0 +1,48 @@
> += EEPROM Data Device Tree Bindings =
> +
> +This binding is intended to represent the location of hardware
> +configuration data stored in EEPROMs.
> +
> +On a significant proportion of boards, the manufacturer has stored
> +some data on an EEPROM-like device, for the OS to be able to retrieve
> +these information and act upon it. Obviously, the OS has to know
> +about where to retrieve these data from, and where they are stored on
> +the storage device.
> +
> +This document is here to document this.
> +
> += Data providers =
> +
> +Required properties:
> +#eeprom-cells:	Number of cells in an eeprom specifier; The common
> +		case is 2.
> +
> +For example:
> +
> +	at24: eeprom@42 {
> +		#eeprom-cells = <2>;
> +	};
> +
> += Data consumers =
> +
> +Required properties:
> +
> +eeproms: List of phandle and data cell specifier triplet, one triplet
> +	 for each data cell the device might be interested in. The
> +	 triplet consists of the phandle to the eeprom provider, then
> +	 the offset in byte within that storage device, and the length

bytes

> +	 in byte of the data we care about.

bytes

> +
> +Optional properties:
> +
> +eeprom-names: List of data cell name strings sorted in the same order
> + 	      as the resets property. Consumers drivers will use

resets? I guess this text was cut/paste from the reset documentation?\

> + 	      eeprom-names to differentiate between multiple cells,
> + 	      and hence being able to know what these cells are for.
> +
> +For example:
> +
> +	device {
> +		eeproms = <&at24 14 42>;

I like to use 42, but is it realistic to have a soc-rev-id which is 42
bytes long?  How about using 42 as the offset and a sensible length of
say 4?

> +		eeprom-names = "soc-rev-id";
> +	};
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index c70d6e4..d7afc82 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
>  
>  source "drivers/android/Kconfig"
>  
> +source "drivers/eeprom/Kconfig"
> +
>  endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 527a6da..57eb5b0 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
>  obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
>  obj-$(CONFIG_CORESIGHT)		+= coresight/
>  obj-$(CONFIG_ANDROID)		+= android/
> +obj-$(CONFIG_EEPROM)		+= eeprom/
> diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
> new file mode 100644
> index 0000000..2c5452a
> --- /dev/null
> +++ b/drivers/eeprom/Kconfig
> @@ -0,0 +1,19 @@
> +menuconfig EEPROM
> +	bool "EEPROM Support"
> +	depends on OF
> +	help
> +	  Support for EEPROM alike devices.

like.

> +
> +	  This framework is designed to provide a generic interface to EEPROM

EPROMs

> +	  from both the Linux Kernel and the userspace.
> +
> +	  If unsure, say no.
> +
> +if EEPROM
> +
> +config EEPROM_DEBUG
> +	bool "EEPROM debug support"
> +	help
> +	  Say yes here to enable debugging support.
> +
> +endif
> diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
> new file mode 100644
> index 0000000..e130079
> --- /dev/null
> +++ b/drivers/eeprom/Makefile
> @@ -0,0 +1,9 @@
> +#
> +# Makefile for eeprom drivers.
> +#
> +
> +ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
> +
> +obj-$(CONFIG_EEPROM)		+= core.o
> +
> +# Devices
> diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
> new file mode 100644
> index 0000000..bc877a6
> --- /dev/null
> +++ b/drivers/eeprom/core.c
> @@ -0,0 +1,290 @@
> +/*
> + * EEPROM framework core.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/eeprom-provider.h>
> +#include <linux/eeprom-consumer.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/idr.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +
> +struct eeprom_cell {
> +	struct eeprom_device *eeprom;
> +	loff_t offset;
> +	size_t count;
> +};
> +
> +static DEFINE_MUTEX(eeprom_list_mutex);
> +static LIST_HEAD(eeprom_list);
> +static DEFINE_IDA(eeprom_ida);
> +
> +static ssize_t bin_attr_eeprom_read_write(struct kobject *kobj,
> +				    char *buf, loff_t offset,
> +				    size_t count, bool read)
> +{
> +	struct device *dev = container_of(kobj, struct device, kobj);
> +	struct eeprom_device *eeprom = container_of(dev, struct eeprom_device,
> +						    edev);
> +	int rc;
> +
> +	if (offset > eeprom->size)
> +		return 0;
> +
> +	if (offset + count > eeprom->size)
> +		count = eeprom->size - offset;
> +
> +	if (read)
> +		rc = regmap_bulk_read(eeprom->regmap, offset,
> +				      buf, count/eeprom->stride);

This division will round down, so you could get one less byte than
what you expected, and the value you actually return. It seems like
there should be a check here, the count is a multiple of stride and
return an error if it is not.

> +	else
> +		rc = regmap_bulk_write(eeprom->regmap, offset,
> +				       buf, count/eeprom->stride);
> +
> +	if (IS_ERR_VALUE(rc))
> +		return 0;
> +

I don't think returning 0 here, and above is the best thing to
do. Return the real error code from regmap, or EINVAL or some other
error code for going off the end of the eerpom.

> +	return count;
> +}
> +
> +static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
> +				    struct bin_attribute *attr,
> +				    char *buf, loff_t offset, size_t count)
> +{
> +	return bin_attr_eeprom_read_write(kobj, buf, offset, count, true);
> +}
> +
> +static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
> +				     struct bin_attribute *attr,
> +				     char *buf, loff_t offset, size_t count)
> +{
> +	return bin_attr_eeprom_read_write(kobj, buf, offset, count, false);
> +}
> 

These two functions seem to be identical. So just have one of them?

+
> +static struct bin_attribute bin_attr_eeprom = {
> +	.attr	= {
> +		.name	= "eeprom",
> +		.mode	= 0660,

Symbolic values like S_IRUGO | S_IWUSR would be better.

Are you also sure you want group write?

> +	},
> +	.read	= bin_attr_eeprom_read,
> +	.write	= bin_attr_eeprom_write,
> +};
> +
> +static struct bin_attribute *eeprom_bin_attributes[] = {
> +	&bin_attr_eeprom,
> +	NULL,
> +};
> +
> +static const struct attribute_group eeprom_bin_group = {
> +	.bin_attrs	= eeprom_bin_attributes,
> +};
> +
> +static const struct attribute_group *eeprom_dev_groups[] = {
> +	&eeprom_bin_group,
> +	NULL,
> +};
> +
> +static struct class eeprom_class = {
> +	.name		= "eeprom",
> +	.dev_groups	= eeprom_dev_groups,
> +};
> +
> +int eeprom_register(struct eeprom_device *eeprom)
> +{
> +	int rval;
> +
> +	if (!eeprom->regmap || !eeprom->size) {
> +		dev_err(eeprom->dev, "Regmap not found\n");
> +		return -EINVAL;
> +	}
> +
> +	eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
> +	if (eeprom->id < 0)
> +		return eeprom->id;
> +
> +	eeprom->edev.class = &eeprom_class;
> +	eeprom->edev.parent = eeprom->dev;
> +	eeprom->edev.of_node = eeprom->dev ? eeprom->dev->of_node : NULL;
> +	dev_set_name(&eeprom->edev, "eeprom%d", eeprom->id);
> +
> +	device_initialize(&eeprom->edev);
> +
> +	dev_dbg(&eeprom->edev, "Registering eeprom device %s\n",
> +		dev_name(&eeprom->edev));
> +
> +	rval = device_add(&eeprom->edev);
> +	if (rval)
> +		return rval;
> +
> +	mutex_lock(&eeprom_list_mutex);
> +	list_add(&eeprom->list, &eeprom_list);
> +	mutex_unlock(&eeprom_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(eeprom_register);
> +
> +int eeprom_unregister(struct eeprom_device *eeprom)
> +{
> +	device_del(&eeprom->edev);
> +
> +	mutex_lock(&eeprom_list_mutex);
> +	list_del(&eeprom->list);
> +	mutex_unlock(&eeprom_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(eeprom_unregister);
> +
> +static struct eeprom_cell *__eeprom_cell_get(struct device_node *node,
> +					     int index)
> +{
> +	struct of_phandle_args args;
> +	struct eeprom_cell *cell;
> +	struct eeprom_device *e, *eeprom = NULL;
> +	int ret;
> +
> +	ret = of_parse_phandle_with_args(node, "eeproms",
> +					 "#eeprom-cells", index, &args);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	if (args.args_count != 2)
> +		return ERR_PTR(-EINVAL);
> +
> +	mutex_lock(&eeprom_list_mutex);
> +
> +	list_for_each_entry(e, &eeprom_list, list) {
> +		if (args.np == e->edev.of_node) {
> +			eeprom = e;
> +			break;
> +		}
> +	}
> +	mutex_unlock(&eeprom_list_mutex);

Shouldn't you increment a reference count to the eeprom here?  You are
going to have trouble if the eeprom is unregistered and there is a
call still referring to it.

> +
> +	if (!eeprom)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	cell = kzalloc(sizeof(*cell), GFP_KERNEL);
> +	if (!cell)
> +		return ERR_PTR(-ENOMEM);
> +
> +	cell->eeprom = eeprom;
> +	cell->offset = args.args[0];
> +	cell->count = args.args[1];
> +
> +	return cell;
> +}
> +
> +static struct eeprom_cell *__eeprom_cell_get_byname(struct device_node *node,
> +						    const char *id)
> +{
> +	int index = 0;
> +
> +	if (id)
> +		index = of_property_match_string(node,
> +						 "eeprom-names",
> +						 id);
> +	return __eeprom_cell_get(node, index);
> +
> +}
> +
> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index)
> +{
> +	if (!dev)
> +		return ERR_PTR(-EINVAL);
> +
> +	/* First, attempt to retrieve the cell through the DT */
> +	if (dev->of_node)
> +		return __eeprom_cell_get(dev->of_node, index);
> +
> +	/* We don't support anything else yet */
> +	return ERR_PTR(-ENODEV);
> +}
> +EXPORT_SYMBOL(eeprom_cell_get);
> +
> +struct eeprom_cell *eeprom_cell_get_byname(struct device *dev, const char *id)
> +{
> +	if (!dev)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (id && dev->of_node)
> +		return __eeprom_cell_get_byname(dev->of_node, id);
> +
> +	/* We don't support anything else yet */
> +	return ERR_PTR(-ENODEV);
> +}
> +EXPORT_SYMBOL(eeprom_cell_get_byname);
> +
> +void eeprom_cell_put(struct eeprom_cell *cell)
> +{
> +	kfree(cell);
> +}
> +EXPORT_SYMBOL(eeprom_cell_put);
> +
> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
> +{
> +	struct eeprom_device *eeprom = cell->eeprom;
> +	char *buf;
> +	int rc;
> +
> +	if (!eeprom || !eeprom->regmap)
> +		return ERR_PTR(-EINVAL);
> +
> +	buf = kzalloc(cell->count, GFP_KERNEL);
> +	if (!buf)
> +		return ERR_PTR(-ENOMEM);
> +
> +	rc = regmap_bulk_read(eeprom->regmap, cell->offset,
> +			      buf, cell->count/eeprom->stride);

Same comment as above.

> +	if (IS_ERR_VALUE(rc)) {
> +		kfree(buf);
> +		return ERR_PTR(rc);
> +	}
> +
> +	*len = cell->count;
> +
> +	return buf;
> +}
> +EXPORT_SYMBOL(eeprom_cell_read);
> +
> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
> +{
> +	struct eeprom_device *eeprom = cell->eeprom;
> +
> +	if (!eeprom || !eeprom->regmap)
> +		return -EINVAL;
> +
> +	return regmap_bulk_write(eeprom->regmap, cell->offset,
> +				 buf, cell->count/eeprom->stride);
> +}
> +EXPORT_SYMBOL(eeprom_cell_write);
> +
> +static int eeprom_init(void)
> +{
> +	return class_register(&eeprom_class);
> +}
> +
> +static void eeprom_exit(void)
> +{
> +	class_unregister(&eeprom_class);
> +}
> +
> +subsys_initcall(eeprom_init);
> +module_exit(eeprom_exit);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
> +MODULE_DESCRIPTION("EEPROM Driver Core");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
> new file mode 100644
> index 0000000..706ae9d
> --- /dev/null
> +++ b/include/linux/eeprom-consumer.h
> @@ -0,0 +1,73 @@
> +/*
> + * EEPROM framework consumer.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_CONSUMER_H
> +#define _LINUX_EEPROM_CONSUMER_H
> +
> +struct eeprom_cell;
> +
> +/**
> + * eeprom_cell_get(): Get eeprom cell of device form a given index.

of a device for a 

> + *
> + * @dev: Device that will be interacted with
> + * @index: Index of the eeprom cell.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index);
> +
> +/**
> + * eeprom_cell_get(): Get eeprom cell of device form a given name.

same again

> + *
> + * @dev: Device that will be interacted with
> + * @name: Name of the eeprom cell.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *eeprom_cell_get_byname(struct device *dev,
> +					   const char *name);
> +
> +/**
> + * eeprom_cell_put(): Release previously allocated eeprom cell.
> + *
> + * @cell: Previously allocated eeprom cell by eeprom_cell_get()
> + * or eeprom_cell_get_byname().
> + */
> +void eeprom_cell_put(struct eeprom_cell *cell);
> +
> +/**
> + * eeprom_cell_read(): Read a given eeprom cell
> + *
> + * @cell: eeprom cell to be read.
> + * @len: pointer to length of cell which will be populated on successful read.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a char * bufffer.  The buffer should be freed by the consumer with a
> + * kfree().
> + */
> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);

Would void * be better than char *? I guess the contents is mostly
data, not strings.

      Andrew
 
> +
> +/**
> + * eeprom_cell_write(): Write to a given eeprom cell
> + *
> + * @cell: eeprom cell to be written.
> + * @buf: Buffer to be written.
> + * @len: length of buffer to be written to eeprom cell.
> + *
> + * The return value will be an non zero on error or a zero on successful write.
> + */
> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
> +
> +#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */
> diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
> new file mode 100644
> index 0000000..3943c2f
> --- /dev/null
> +++ b/include/linux/eeprom-provider.h
> @@ -0,0 +1,51 @@
> +/*
> + * EEPROM framework provider.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_PROVIDER_H
> +#define _LINUX_EEPROM_PROVIDER_H
> +
> +#include <linux/device.h>
> +#include <linux/regmap.h>
> +#include <linux/list.h>
> +
> +struct eeprom_device {
> +	struct regmap		*regmap;
> +	int			stride;
> +	size_t			size;
> +	struct device		*dev;
> +
> +	/* Internal to framework */
> +	struct device		edev;
> +	int			id;
> +	struct list_head	list;
> +};
> +
> +/**
> + * eeprom_register(): Register a eeprom device for given eeprom.
> + * Also creates an binary entry in /sys/class/eeprom/eeprom[id]/eeprom
> + *
> + * @eeprom: eeprom device that needs to be created
> + *
> + * The return value will be an error code on error or a zero on success.
> + * The eeprom_device and sysfs entery will be freed by the eeprom_unregister().
> + */
> +int eeprom_register(struct eeprom_device *eeprom);
> +
> +/**
> + * eeprom_unregister(): Unregister previously registered eeprom device
> + *
> + * @eeprom: Pointer to previously registered eeprom device.
> + *
> + * The return value will be an non zero on error or a zero on success.
> + */
> +int eeprom_unregister(struct eeprom_device *eeprom);
> +
> +#endif  /* ifndef _LINUX_EEPROM_PROVIDER_H */
> -- 
> 1.9.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-19 17:08 ` [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework Srinivas Kandagatla
  2015-02-19 18:12   ` Andrew Lunn
@ 2015-02-20  2:36   ` Stephen Boyd
  2015-02-20  8:14     ` Srinivas Kandagatla
  2015-02-20 17:21   ` Rob Herring
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 153+ messages in thread
From: Stephen Boyd @ 2015-02-20  2:36 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Arnd Bergmann, broonie,
	Greg Kroah-Hartman

On 02/19/15 09:08, Srinivas Kandagatla wrote:
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index c70d6e4..d7afc82 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
>  
>  source "drivers/android/Kconfig"
>  
> +source "drivers/eeprom/Kconfig"
> +
>  endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 527a6da..57eb5b0 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
>  obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
>  obj-$(CONFIG_CORESIGHT)		+= coresight/
>  obj-$(CONFIG_ANDROID)		+= android/
> +obj-$(CONFIG_EEPROM)		+= eeprom/
> diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
> new file mode 100644
> index 0000000..2c5452a
> --- /dev/null
> +++ b/drivers/eeprom/Kconfig
> @@ -0,0 +1,19 @@
> +menuconfig EEPROM
> +	bool "EEPROM Support"
> +	depends on OF

Doesn't this need some sort of select REGMAP somewhere?

Also, why do we need to use regmap for the eeprom framework read/write
ops? I liked the simple eeprom::{read,write} API that Maxime had. The
regmap part could be a regmap-eeprom driver that implements read/write
ops like you've done in the core.

> +	help
> +	  Support for EEPROM alike devices.
> +
> +	  This framework is designed to provide a generic interface to EEPROM
> +	  from both the Linux Kernel and the userspace.
> +
> +	  If unsure, say no.
> +
> +if EEPROM
> +
> +config EEPROM_DEBUG
> +	bool "EEPROM debug support"
> +	help
> +	  Say yes here to enable debugging support.
> +
> +endif
>
> diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
> new file mode 100644
> index 0000000..3943c2f
> --- /dev/null
> +++ b/include/linux/eeprom-provider.h
> @@ -0,0 +1,51 @@
> +/*
> + * EEPROM framework provider.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_PROVIDER_H
> +#define _LINUX_EEPROM_PROVIDER_H
> +
> +#include <linux/device.h>
> +#include <linux/regmap.h>
> +#include <linux/list.h>
> +
> +struct eeprom_device {
> +	struct regmap		*regmap;
> +	int			stride;
> +	size_t			size;
> +	struct device		*dev;
> +
> +	/* Internal to framework */
> +	struct device		edev;
> +	int			id;
> +	struct list_head	list;

Should there be a module owner here to handle module removal?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-20  2:36   ` Stephen Boyd
@ 2015-02-20  8:14     ` Srinivas Kandagatla
  2015-02-20 10:24       ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-20  8:14 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Arnd Bergmann, broonie,
	Greg Kroah-Hartman



On 20/02/15 02:36, Stephen Boyd wrote:
> On 02/19/15 09:08, Srinivas Kandagatla wrote:
>> diff --git a/drivers/Kconfig b/drivers/Kconfig
>> index c70d6e4..d7afc82 100644
>> --- a/drivers/Kconfig
>> +++ b/drivers/Kconfig
>> @@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
>>
>>   source "drivers/android/Kconfig"
>>
>> +source "drivers/eeprom/Kconfig"
>> +
>>   endmenu
>> diff --git a/drivers/Makefile b/drivers/Makefile
>> index 527a6da..57eb5b0 100644
>> --- a/drivers/Makefile
>> +++ b/drivers/Makefile
>> @@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
>>   obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
>>   obj-$(CONFIG_CORESIGHT)		+= coresight/
>>   obj-$(CONFIG_ANDROID)		+= android/
>> +obj-$(CONFIG_EEPROM)		+= eeprom/
>> diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
>> new file mode 100644
>> index 0000000..2c5452a
>> --- /dev/null
>> +++ b/drivers/eeprom/Kconfig
>> @@ -0,0 +1,19 @@
>> +menuconfig EEPROM
>> +	bool "EEPROM Support"
>> +	depends on OF
>
> Doesn't this need some sort of select REGMAP somewhere?
May be depends REGMAP would be good.

>
> Also, why do we need to use regmap for the eeprom framework read/write
> ops? I liked the simple eeprom::{read,write} API that Maxime had. The
> regmap part could be a regmap-eeprom driver that implements read/write
> ops like you've done in the core.
regmap bus does the same job.

The only reason for using regmap here is to have more generic drivers 
for eeprom providers based on different buses like mmio, i2c, spi...
As of today we could just make the qfprom eeprom provider as more 
generic eeprom-mmio provider. May be sunxi_sid could reuse it too with 
some effort.

In future It may be possible to have eeprom-i2c or eeprom-spi providers.

>

>> +
>> +struct eeprom_device {
>> +	struct regmap		*regmap;
>> +	int			stride;
>> +	size_t			size;
>> +	struct device		*dev;
>> +
>> +	/* Internal to framework */
>> +	struct device		edev;
>> +	int			id;
>> +	struct list_head	list;
>
> Should there be a module owner here to handle module removal?
>

Good point, we should do some reference counting.


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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-19 18:12   ` Andrew Lunn
@ 2015-02-20  8:27     ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-20  8:27 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api, broonie, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard

Thanks Andrew for your comments,

On 19/02/15 18:12, Andrew Lunn wrote:
>> +
>> +Required properties:
>> +
>> +eeproms: List of phandle and data cell specifier triplet, one triplet
>> +	 for each data cell the device might be interested in. The
>> +	 triplet consists of the phandle to the eeprom provider, then
>> +	 the offset in byte within that storage device, and the length
>
> bytes
>
>> +	 in byte of the data we care about.
>
> bytes
Yep will fix it in next version.
>
>> +
>> +Optional properties:
>> +
>> +eeprom-names: List of data cell name strings sorted in the same order
>> + 	      as the resets property. Consumers drivers will use
>
> resets? I guess this text was cut/paste from the reset documentation?\
>
I think so. Will fix it.
>> + 	      eeprom-names to differentiate between multiple cells,
>> + 	      and hence being able to know what these cells are for.
>> +
>> +For example:
>> +
>> +	device {
>> +		eeproms = <&at24 14 42>;
>
> I like to use 42, but is it realistic to have a soc-rev-id which is 42
> bytes long?  How about using 42 as the offset and a sensible length of
> say 4?
Ok, will fix it..
>
>> +		eeprom-names = "soc-rev-id";
>> +menuconfig EEPROM
>> +	bool "EEPROM Support"
>> +	depends on OF
>> +	help
>> +	  Support for EEPROM alike devices.
>
> like.
Ok
>
>> +
>> +	  This framework is designed to provide a generic interface to EEPROM
>
> EPROMs
Ok.
>
>> +
>> +
>> +static ssize_t bin_attr_eeprom_read_write(struct kobject *kobj,
>> +				    char *buf, loff_t offset,
>> +				    size_t count, bool read)
>> +{
>> +	struct device *dev = container_of(kobj, struct device, kobj);
>> +	struct eeprom_device *eeprom = container_of(dev, struct eeprom_device,
>> +						    edev);
>> +	int rc;
>> +
>> +	if (offset > eeprom->size)
>> +		return 0;
>> +
>> +	if (offset + count > eeprom->size)
>> +		count = eeprom->size - offset;
>> +
>> +	if (read)
>> +		rc = regmap_bulk_read(eeprom->regmap, offset,
>> +				      buf, count/eeprom->stride);
>
> This division will round down, so you could get one less byte than
> what you expected, and the value you actually return. It seems like
> there should be a check here, the count is a multiple of stride and
> return an error if it is not.
Thats a good catch, I will fix this for other such instances too.
>
>> +	else
>> +		rc = regmap_bulk_write(eeprom->regmap, offset,
>> +				       buf, count/eeprom->stride);
>> +
>> +	if (IS_ERR_VALUE(rc))
>> +		return 0;
>> +
>
> I don't think returning 0 here, and above is the best thing to
> do. Return the real error code from regmap, or EINVAL or some other
> error code for going off the end of the eerpom.
Ok, I will fix the return value here for both the cases.

>
>> +	return count;
>> +}
>> +
>> +static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
>> +				    struct bin_attribute *attr,
>> +				    char *buf, loff_t offset, size_t count)
>> +{
>> +	return bin_attr_eeprom_read_write(kobj, buf, offset, count, true);
>> +}
>> +
>> +static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
>> +				     struct bin_attribute *attr,
>> +				     char *buf, loff_t offset, size_t count)
>> +{
>> +	return bin_attr_eeprom_read_write(kobj, buf, offset, count, false);
>> +}
>>
>
> These two functions seem to be identical. So just have one of them?

One is read and other is write.. there is a true and false flag at the 
end of the call to bin_attr_eeprom_read_write().
>
> +
>> +static struct bin_attribute bin_attr_eeprom = {
>> +	.attr	= {
>> +		.name	= "eeprom",
>> +		.mode	= 0660,
>
> Symbolic values like S_IRUGO | S_IWUSR would be better.
Yep, thats correct, I will fix it.
>
> Are you also sure you want group write?
>
S_IWUSR should be enough.

>> +	},
>> +	.read	= bin_attr_eeprom_read,
>> +	.write	= bin_attr_eeprom_write,
>> +};
>> +
>> +static struct eeprom_cell *__eeprom_cell_get(struct device_node *node,
>> +					     int index)
>> +{
>> +	struct of_phandle_args args;
>> +	struct eeprom_cell *cell;
>> +	struct eeprom_device *e, *eeprom = NULL;
>> +	int ret;
>> +
>> +	ret = of_parse_phandle_with_args(node, "eeproms",
>> +					 "#eeprom-cells", index, &args);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	if (args.args_count != 2)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	mutex_lock(&eeprom_list_mutex);
>> +
>> +	list_for_each_entry(e, &eeprom_list, list) {
>> +		if (args.np == e->edev.of_node) {
>> +			eeprom = e;
>> +			break;
>> +		}
>> +	}
>> +	mutex_unlock(&eeprom_list_mutex);
>
> Shouldn't you increment a reference count to the eeprom here?  You are
> going to have trouble if the eeprom is unregistered and there is a
> call still referring to it.
Yes, Stephen Byod also pointed the same, having owner in eeprom_device 
should fix this.
I will fix it in next version.

>
>> +
>> +	if (!eeprom)
>> +		return ERR_PTR(-EPROBE_DEFER);
>> +
>> +	cell = kzalloc(sizeof(*cell), GFP_KERNEL);
>> +	if (!cell)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	cell->eeprom = eeprom;
>> +	cell->offset = args.args[0];
>> +	cell->count = args.args[1];
>> +
>> +	return cell;
>> +}
>> +
>> +
>> diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
>> new file mode 100644
>> index 0000000..706ae9d
>> --- /dev/null
>> +++ b/include/linux/eeprom-consumer.h
>> @@ -0,0 +1,73 @@
>> +/*
>> + * EEPROM framework consumer.
>> + *
>> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2.  This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#ifndef _LINUX_EEPROM_CONSUMER_H
>> +#define _LINUX_EEPROM_CONSUMER_H
>> +
>> +struct eeprom_cell;
>> +
>> +/**
>> + * eeprom_cell_get(): Get eeprom cell of device form a given index.
>
> of a device for a
>
Ok, will be fixed in next version.
>> + *
>> + * @dev: Device that will be interacted with
>> + * @index: Index of the eeprom cell.
>> + *
>> + * The return value will be an ERR_PTR() on error or a valid pointer
>> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
>> + * eeprom_cell_put().
>> + */
>> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index);
>> +
>> +/**
>> + * eeprom_cell_get(): Get eeprom cell of device form a given name.
>
> same again
Ok, will be fixed in next version.
>
>> + *
>> + * @dev: Device that will be interacted with
>> + * @name: Name of the eeprom cell.
>> + *
>> + * The return value will be an ERR_PTR() on error or a valid pointer
>> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
>> + * eeprom_cell_put().
>> + */
>> +struct eeprom_cell *eeprom_cell_get_byname(struct device *dev,
>> +					   const char *name);
>> +
>> +/**
>> + * eeprom_cell_put(): Release previously allocated eeprom cell.
>> + *
>> + * @cell: Previously allocated eeprom cell by eeprom_cell_get()
>> + * or eeprom_cell_get_byname().
>> + */
>> +void eeprom_cell_put(struct eeprom_cell *cell);
>> +
>> +/**
>> + * eeprom_cell_read(): Read a given eeprom cell
>> + *
>> + * @cell: eeprom cell to be read.
>> + * @len: pointer to length of cell which will be populated on successful read.
>> + *
>> + * The return value will be an ERR_PTR() on error or a valid pointer
>> + * to a char * bufffer.  The buffer should be freed by the consumer with a
>> + * kfree().
>> + */
>> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
>
> Would void * be better than char *? I guess the contents is mostly
> data, not strings.
Yes, thats sounds sensible.
>
>        Andrew
>
>> +
>> +/**

>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-20  8:14     ` Srinivas Kandagatla
@ 2015-02-20 10:24       ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-20 10:24 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Arnd Bergmann, broonie,
	Greg Kroah-Hartman



On 20/02/15 08:14, Srinivas Kandagatla wrote:
>>
>> Doesn't this need some sort of select REGMAP somewhere?
> May be depends REGMAP would be good.
You are right, just realized that
it should be "select REGMAP"

and for QFPROM it should be "select REGMAP_MMIO"

--srini

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-19 17:08 ` [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework Srinivas Kandagatla
  2015-02-19 18:12   ` Andrew Lunn
  2015-02-20  2:36   ` Stephen Boyd
@ 2015-02-20 17:21   ` Rob Herring
  2015-02-20 19:25     ` Srinivas Kandagatla
  2015-02-20 17:46   ` Russell King - ARM Linux
  2015-02-23 15:04   ` Mark Brown
  4 siblings, 1 reply; 153+ messages in thread
From: Rob Herring @ 2015-02-20 17:21 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

On Thu, Feb 19, 2015 at 11:08 AM, Srinivas Kandagatla
<srinivas.kandagatla@linaro.org> wrote:
> From: Maxime Ripard <maxime.ripard@free-electrons.com>
>
> Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
> duplicate pretty much the same code to register a sysfs file, allow in-kernel
> users to access the content of the devices they were driving, etc.
>
> This was also a problem as far as other in-kernel users were involved, since
> the solutions used were pretty much different from on driver to another, there
> was a rather big abstraction leak.
>
> This introduction of this framework aims at solving this. It also introduces DT
> representation for consumer devices to go get the data they require (MAC
> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
>
> Having regmap interface to this framework would give much better
> abstraction for eeproms on different buses.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> [srinivas.kandagatla: Moved to regmap based and cleanedup apis]
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
>  drivers/Kconfig                                    |   2 +
>  drivers/Makefile                                   |   1 +
>  drivers/eeprom/Kconfig                             |  19 ++
>  drivers/eeprom/Makefile                            |   9 +
>  drivers/eeprom/core.c                              | 290 +++++++++++++++++++++
>  include/linux/eeprom-consumer.h                    |  73 ++++++
>  include/linux/eeprom-provider.h                    |  51 ++++

Who is going to be the maintainer for this?

>  8 files changed, 493 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
>  create mode 100644 drivers/eeprom/Kconfig
>  create mode 100644 drivers/eeprom/Makefile
>  create mode 100644 drivers/eeprom/core.c
>  create mode 100644 include/linux/eeprom-consumer.h
>  create mode 100644 include/linux/eeprom-provider.h
>
> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> new file mode 100644
> index 0000000..9ec1ec2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt

Please make bindings a separate patch.

> @@ -0,0 +1,48 @@
> += EEPROM Data Device Tree Bindings =
> +
> +This binding is intended to represent the location of hardware
> +configuration data stored in EEPROMs.
> +
> +On a significant proportion of boards, the manufacturer has stored
> +some data on an EEPROM-like device, for the OS to be able to retrieve
> +these information and act upon it. Obviously, the OS has to know
> +about where to retrieve these data from, and where they are stored on
> +the storage device.
> +
> +This document is here to document this.
> +
> += Data providers =
> +
> +Required properties:
> +#eeprom-cells: Number of cells in an eeprom specifier; The common
> +               case is 2.

We already have eeproms in DTs, it would be nice to be able to support
them with this framework as well.

> +
> +For example:
> +
> +       at24: eeprom@42 {
> +               #eeprom-cells = <2>;
> +       };
> +
> += Data consumers =
> +
> +Required properties:
> +
> +eeproms: List of phandle and data cell specifier triplet, one triplet
> +        for each data cell the device might be interested in. The
> +        triplet consists of the phandle to the eeprom provider, then
> +        the offset in byte within that storage device, and the length
> +        in byte of the data we care about.

The problem with this is it assumes you know who the consumer is and
that it is a DT node. For example, how would you describe a serial
number?

Rob

> +
> +Optional properties:
> +
> +eeprom-names: List of data cell name strings sorted in the same order
> +             as the resets property. Consumers drivers will use
> +             eeprom-names to differentiate between multiple cells,
> +             and hence being able to know what these cells are for.
> +
> +For example:
> +
> +       device {
> +               eeproms = <&at24 14 42>;
> +               eeprom-names = "soc-rev-id";
> +       };
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index c70d6e4..d7afc82 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
>
>  source "drivers/android/Kconfig"
>
> +source "drivers/eeprom/Kconfig"
> +
>  endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 527a6da..57eb5b0 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)           += ras/
>  obj-$(CONFIG_THUNDERBOLT)      += thunderbolt/
>  obj-$(CONFIG_CORESIGHT)                += coresight/
>  obj-$(CONFIG_ANDROID)          += android/
> +obj-$(CONFIG_EEPROM)           += eeprom/
> diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
> new file mode 100644
> index 0000000..2c5452a
> --- /dev/null
> +++ b/drivers/eeprom/Kconfig
> @@ -0,0 +1,19 @@
> +menuconfig EEPROM
> +       bool "EEPROM Support"
> +       depends on OF
> +       help
> +         Support for EEPROM alike devices.
> +
> +         This framework is designed to provide a generic interface to EEPROM
> +         from both the Linux Kernel and the userspace.
> +
> +         If unsure, say no.
> +
> +if EEPROM
> +
> +config EEPROM_DEBUG
> +       bool "EEPROM debug support"
> +       help
> +         Say yes here to enable debugging support.
> +
> +endif
> diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
> new file mode 100644
> index 0000000..e130079
> --- /dev/null
> +++ b/drivers/eeprom/Makefile
> @@ -0,0 +1,9 @@
> +#
> +# Makefile for eeprom drivers.
> +#
> +
> +ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
> +
> +obj-$(CONFIG_EEPROM)           += core.o
> +
> +# Devices
> diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
> new file mode 100644
> index 0000000..bc877a6
> --- /dev/null
> +++ b/drivers/eeprom/core.c
> @@ -0,0 +1,290 @@
> +/*
> + * EEPROM framework core.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/eeprom-provider.h>
> +#include <linux/eeprom-consumer.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/idr.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +
> +struct eeprom_cell {
> +       struct eeprom_device *eeprom;
> +       loff_t offset;
> +       size_t count;
> +};
> +
> +static DEFINE_MUTEX(eeprom_list_mutex);
> +static LIST_HEAD(eeprom_list);
> +static DEFINE_IDA(eeprom_ida);
> +
> +static ssize_t bin_attr_eeprom_read_write(struct kobject *kobj,
> +                                   char *buf, loff_t offset,
> +                                   size_t count, bool read)
> +{
> +       struct device *dev = container_of(kobj, struct device, kobj);
> +       struct eeprom_device *eeprom = container_of(dev, struct eeprom_device,
> +                                                   edev);
> +       int rc;
> +
> +       if (offset > eeprom->size)
> +               return 0;
> +
> +       if (offset + count > eeprom->size)
> +               count = eeprom->size - offset;
> +
> +       if (read)
> +               rc = regmap_bulk_read(eeprom->regmap, offset,
> +                                     buf, count/eeprom->stride);
> +       else
> +               rc = regmap_bulk_write(eeprom->regmap, offset,
> +                                      buf, count/eeprom->stride);
> +
> +       if (IS_ERR_VALUE(rc))
> +               return 0;
> +
> +       return count;
> +}
> +
> +static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
> +                                   struct bin_attribute *attr,
> +                                   char *buf, loff_t offset, size_t count)
> +{
> +       return bin_attr_eeprom_read_write(kobj, buf, offset, count, true);
> +}
> +
> +static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
> +                                    struct bin_attribute *attr,
> +                                    char *buf, loff_t offset, size_t count)
> +{
> +       return bin_attr_eeprom_read_write(kobj, buf, offset, count, false);
> +}
> +
> +static struct bin_attribute bin_attr_eeprom = {
> +       .attr   = {
> +               .name   = "eeprom",
> +               .mode   = 0660,
> +       },
> +       .read   = bin_attr_eeprom_read,
> +       .write  = bin_attr_eeprom_write,
> +};
> +
> +static struct bin_attribute *eeprom_bin_attributes[] = {
> +       &bin_attr_eeprom,
> +       NULL,
> +};
> +
> +static const struct attribute_group eeprom_bin_group = {
> +       .bin_attrs      = eeprom_bin_attributes,
> +};
> +
> +static const struct attribute_group *eeprom_dev_groups[] = {
> +       &eeprom_bin_group,
> +       NULL,
> +};
> +
> +static struct class eeprom_class = {
> +       .name           = "eeprom",
> +       .dev_groups     = eeprom_dev_groups,
> +};
> +
> +int eeprom_register(struct eeprom_device *eeprom)
> +{
> +       int rval;
> +
> +       if (!eeprom->regmap || !eeprom->size) {
> +               dev_err(eeprom->dev, "Regmap not found\n");
> +               return -EINVAL;
> +       }
> +
> +       eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
> +       if (eeprom->id < 0)
> +               return eeprom->id;
> +
> +       eeprom->edev.class = &eeprom_class;
> +       eeprom->edev.parent = eeprom->dev;
> +       eeprom->edev.of_node = eeprom->dev ? eeprom->dev->of_node : NULL;
> +       dev_set_name(&eeprom->edev, "eeprom%d", eeprom->id);
> +
> +       device_initialize(&eeprom->edev);
> +
> +       dev_dbg(&eeprom->edev, "Registering eeprom device %s\n",
> +               dev_name(&eeprom->edev));
> +
> +       rval = device_add(&eeprom->edev);
> +       if (rval)
> +               return rval;
> +
> +       mutex_lock(&eeprom_list_mutex);
> +       list_add(&eeprom->list, &eeprom_list);
> +       mutex_unlock(&eeprom_list_mutex);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(eeprom_register);
> +
> +int eeprom_unregister(struct eeprom_device *eeprom)
> +{
> +       device_del(&eeprom->edev);
> +
> +       mutex_lock(&eeprom_list_mutex);
> +       list_del(&eeprom->list);
> +       mutex_unlock(&eeprom_list_mutex);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(eeprom_unregister);
> +
> +static struct eeprom_cell *__eeprom_cell_get(struct device_node *node,
> +                                            int index)
> +{
> +       struct of_phandle_args args;
> +       struct eeprom_cell *cell;
> +       struct eeprom_device *e, *eeprom = NULL;
> +       int ret;
> +
> +       ret = of_parse_phandle_with_args(node, "eeproms",
> +                                        "#eeprom-cells", index, &args);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       if (args.args_count != 2)
> +               return ERR_PTR(-EINVAL);
> +
> +       mutex_lock(&eeprom_list_mutex);
> +
> +       list_for_each_entry(e, &eeprom_list, list) {
> +               if (args.np == e->edev.of_node) {
> +                       eeprom = e;
> +                       break;
> +               }
> +       }
> +       mutex_unlock(&eeprom_list_mutex);
> +
> +       if (!eeprom)
> +               return ERR_PTR(-EPROBE_DEFER);
> +
> +       cell = kzalloc(sizeof(*cell), GFP_KERNEL);
> +       if (!cell)
> +               return ERR_PTR(-ENOMEM);
> +
> +       cell->eeprom = eeprom;
> +       cell->offset = args.args[0];
> +       cell->count = args.args[1];
> +
> +       return cell;
> +}
> +
> +static struct eeprom_cell *__eeprom_cell_get_byname(struct device_node *node,
> +                                                   const char *id)
> +{
> +       int index = 0;
> +
> +       if (id)
> +               index = of_property_match_string(node,
> +                                                "eeprom-names",
> +                                                id);
> +       return __eeprom_cell_get(node, index);
> +
> +}
> +
> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index)
> +{
> +       if (!dev)
> +               return ERR_PTR(-EINVAL);
> +
> +       /* First, attempt to retrieve the cell through the DT */
> +       if (dev->of_node)
> +               return __eeprom_cell_get(dev->of_node, index);
> +
> +       /* We don't support anything else yet */
> +       return ERR_PTR(-ENODEV);
> +}
> +EXPORT_SYMBOL(eeprom_cell_get);
> +
> +struct eeprom_cell *eeprom_cell_get_byname(struct device *dev, const char *id)
> +{
> +       if (!dev)
> +               return ERR_PTR(-EINVAL);
> +
> +       if (id && dev->of_node)
> +               return __eeprom_cell_get_byname(dev->of_node, id);
> +
> +       /* We don't support anything else yet */
> +       return ERR_PTR(-ENODEV);
> +}
> +EXPORT_SYMBOL(eeprom_cell_get_byname);
> +
> +void eeprom_cell_put(struct eeprom_cell *cell)
> +{
> +       kfree(cell);
> +}
> +EXPORT_SYMBOL(eeprom_cell_put);
> +
> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
> +{
> +       struct eeprom_device *eeprom = cell->eeprom;
> +       char *buf;
> +       int rc;
> +
> +       if (!eeprom || !eeprom->regmap)
> +               return ERR_PTR(-EINVAL);
> +
> +       buf = kzalloc(cell->count, GFP_KERNEL);
> +       if (!buf)
> +               return ERR_PTR(-ENOMEM);
> +
> +       rc = regmap_bulk_read(eeprom->regmap, cell->offset,
> +                             buf, cell->count/eeprom->stride);
> +       if (IS_ERR_VALUE(rc)) {
> +               kfree(buf);
> +               return ERR_PTR(rc);
> +       }
> +
> +       *len = cell->count;
> +
> +       return buf;
> +}
> +EXPORT_SYMBOL(eeprom_cell_read);
> +
> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
> +{
> +       struct eeprom_device *eeprom = cell->eeprom;
> +
> +       if (!eeprom || !eeprom->regmap)
> +               return -EINVAL;
> +
> +       return regmap_bulk_write(eeprom->regmap, cell->offset,
> +                                buf, cell->count/eeprom->stride);
> +}
> +EXPORT_SYMBOL(eeprom_cell_write);
> +
> +static int eeprom_init(void)
> +{
> +       return class_register(&eeprom_class);
> +}
> +
> +static void eeprom_exit(void)
> +{
> +       class_unregister(&eeprom_class);
> +}
> +
> +subsys_initcall(eeprom_init);
> +module_exit(eeprom_exit);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
> +MODULE_DESCRIPTION("EEPROM Driver Core");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
> new file mode 100644
> index 0000000..706ae9d
> --- /dev/null
> +++ b/include/linux/eeprom-consumer.h
> @@ -0,0 +1,73 @@
> +/*
> + * EEPROM framework consumer.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_CONSUMER_H
> +#define _LINUX_EEPROM_CONSUMER_H
> +
> +struct eeprom_cell;
> +
> +/**
> + * eeprom_cell_get(): Get eeprom cell of device form a given index.
> + *
> + * @dev: Device that will be interacted with
> + * @index: Index of the eeprom cell.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index);
> +
> +/**
> + * eeprom_cell_get(): Get eeprom cell of device form a given name.
> + *
> + * @dev: Device that will be interacted with
> + * @name: Name of the eeprom cell.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *eeprom_cell_get_byname(struct device *dev,
> +                                          const char *name);
> +
> +/**
> + * eeprom_cell_put(): Release previously allocated eeprom cell.
> + *
> + * @cell: Previously allocated eeprom cell by eeprom_cell_get()
> + * or eeprom_cell_get_byname().
> + */
> +void eeprom_cell_put(struct eeprom_cell *cell);
> +
> +/**
> + * eeprom_cell_read(): Read a given eeprom cell
> + *
> + * @cell: eeprom cell to be read.
> + * @len: pointer to length of cell which will be populated on successful read.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a char * bufffer.  The buffer should be freed by the consumer with a
> + * kfree().
> + */
> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
> +
> +/**
> + * eeprom_cell_write(): Write to a given eeprom cell
> + *
> + * @cell: eeprom cell to be written.
> + * @buf: Buffer to be written.
> + * @len: length of buffer to be written to eeprom cell.
> + *
> + * The return value will be an non zero on error or a zero on successful write.
> + */
> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
> +
> +#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */
> diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
> new file mode 100644
> index 0000000..3943c2f
> --- /dev/null
> +++ b/include/linux/eeprom-provider.h
> @@ -0,0 +1,51 @@
> +/*
> + * EEPROM framework provider.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_PROVIDER_H
> +#define _LINUX_EEPROM_PROVIDER_H
> +
> +#include <linux/device.h>
> +#include <linux/regmap.h>
> +#include <linux/list.h>
> +
> +struct eeprom_device {
> +       struct regmap           *regmap;
> +       int                     stride;
> +       size_t                  size;
> +       struct device           *dev;
> +
> +       /* Internal to framework */
> +       struct device           edev;
> +       int                     id;
> +       struct list_head        list;
> +};
> +
> +/**
> + * eeprom_register(): Register a eeprom device for given eeprom.
> + * Also creates an binary entry in /sys/class/eeprom/eeprom[id]/eeprom
> + *
> + * @eeprom: eeprom device that needs to be created
> + *
> + * The return value will be an error code on error or a zero on success.
> + * The eeprom_device and sysfs entery will be freed by the eeprom_unregister().
> + */
> +int eeprom_register(struct eeprom_device *eeprom);
> +
> +/**
> + * eeprom_unregister(): Unregister previously registered eeprom device
> + *
> + * @eeprom: Pointer to previously registered eeprom device.
> + *
> + * The return value will be an non zero on error or a zero on success.
> + */
> +int eeprom_unregister(struct eeprom_device *eeprom);
> +
> +#endif  /* ifndef _LINUX_EEPROM_PROVIDER_H */
> --
> 1.9.1
>

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-19 17:08 ` [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework Srinivas Kandagatla
                     ` (2 preceding siblings ...)
  2015-02-20 17:21   ` Rob Herring
@ 2015-02-20 17:46   ` Russell King - ARM Linux
  2015-02-20 19:00     ` Srinivas Kandagatla
  2015-02-23 15:04   ` Mark Brown
  4 siblings, 1 reply; 153+ messages in thread
From: Russell King - ARM Linux @ 2015-02-20 17:46 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api, broonie, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard

On Thu, Feb 19, 2015 at 05:08:28PM +0000, Srinivas Kandagatla wrote:
> +static struct class eeprom_class = {
> +	.name		= "eeprom",
> +	.dev_groups	= eeprom_dev_groups,
> +};
> +
> +int eeprom_register(struct eeprom_device *eeprom)
> +{
> +	int rval;
> +
> +	if (!eeprom->regmap || !eeprom->size) {
> +		dev_err(eeprom->dev, "Regmap not found\n");
> +		return -EINVAL;
> +	}
> +
> +	eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
> +	if (eeprom->id < 0)
> +		return eeprom->id;
> +
> +	eeprom->edev.class = &eeprom_class;
> +	eeprom->edev.parent = eeprom->dev;
> +	eeprom->edev.of_node = eeprom->dev ? eeprom->dev->of_node : NULL;
> +	dev_set_name(&eeprom->edev, "eeprom%d", eeprom->id);
> +
> +	device_initialize(&eeprom->edev);
> +
> +	dev_dbg(&eeprom->edev, "Registering eeprom device %s\n",
> +		dev_name(&eeprom->edev));
> +
> +	rval = device_add(&eeprom->edev);
> +	if (rval)
> +		return rval;
> +
> +	mutex_lock(&eeprom_list_mutex);
> +	list_add(&eeprom->list, &eeprom_list);
> +	mutex_unlock(&eeprom_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(eeprom_register);
> +
> +int eeprom_unregister(struct eeprom_device *eeprom)
> +{
> +	device_del(&eeprom->edev);
> +
> +	mutex_lock(&eeprom_list_mutex);
> +	list_del(&eeprom->list);
> +	mutex_unlock(&eeprom_list_mutex);
> +
> +	return 0;

There's problems with this.  "edev" is embedded into eeprom, and "edev"
is a refcounted structure - it has a lifetime, and the lifetime of
eeprom is thus determined by edev.

What this means is that calling eeprom_unregister() and then freeing
the eeprom structure is a potentially unsafe operation - the memory
backing edev must only be freed when the release method for the
struct device has been called.

> +struct eeprom_device {
> +	struct regmap		*regmap;
> +	int			stride;
> +	size_t			size;
> +	struct device		*dev;

Failing to understand and address the driver model life time issues is
a major blocker for this patch.  Sorry.

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

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

* Re: [RFC PATCH 2/3] eeprom: sunxi: Move the SID driver to the eeprom framework
  2015-02-19 17:08 ` [RFC PATCH 2/3] eeprom: sunxi: Move the SID driver to the eeprom framework Srinivas Kandagatla
@ 2015-02-20 17:47   ` Russell King - ARM Linux
  0 siblings, 0 replies; 153+ messages in thread
From: Russell King - ARM Linux @ 2015-02-20 17:47 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api, broonie, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard

On Thu, Feb 19, 2015 at 05:08:40PM +0000, Srinivas Kandagatla wrote:
> +static int sunxi_sid_probe(struct platform_device *pdev)
> +{
> +	const struct of_device_id *device;
> +	struct eeprom_sid *sid;
> +	struct resource *res;
> +	struct eeprom_device *eeprom;
> +	struct device *dev = &pdev->dev;
> +	int rval;
> +
> +	sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL);
> +	if (!sid)
> +		return -ENOMEM;
> +
> +	eeprom = &sid->eeprom;
...
> +	rval = eeprom_register(eeprom);
> +	if (rval)
> +		return rval;
...
> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
> +
> +	return eeprom_unregister(eeprom);

As pointed out in the previous patch, this is unsafe as the eeprom
structure contains a struct device.

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

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

* Re: [RFC PATCH 3/3] eeprom: qfprom: Add Qualcomm QFPROM support.
  2015-02-19 17:08 ` [RFC PATCH 3/3] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
@ 2015-02-20 17:48   ` Russell King - ARM Linux
  0 siblings, 0 replies; 153+ messages in thread
From: Russell King - ARM Linux @ 2015-02-20 17:48 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api, broonie, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard

On Thu, Feb 19, 2015 at 05:08:51PM +0000, Srinivas Kandagatla wrote:
> +static int qfprom_remove(struct platform_device *pdev)
> +{
> +	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
> +
> +	return eeprom_unregister(eeprom);

Same problem...

> +static int qfprom_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	void __iomem *base;
> +	struct device *dev = &pdev->dev;
> +	struct eeprom_device *eeprom;
> +	int rval;
> +
> +	eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);
> +	if (!eeprom)
> +		return -ENOMEM;
...
> +	rval = eeprom_register(eeprom);

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-20 17:46   ` Russell King - ARM Linux
@ 2015-02-20 19:00     ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-20 19:00 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api, broonie, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard



On 20/02/15 17:46, Russell King - ARM Linux wrote:
> On Thu, Feb 19, 2015 at 05:08:28PM +0000, Srinivas Kandagatla wrote:
>> +static struct class eeprom_class = {
>> +	.name		= "eeprom",
>> +	.dev_groups	= eeprom_dev_groups,
>> +};
>> +
>> +int eeprom_register(struct eeprom_device *eeprom)
>> +{
>> +	int rval;
>> +
>> +	if (!eeprom->regmap || !eeprom->size) {
>> +		dev_err(eeprom->dev, "Regmap not found\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
>> +	if (eeprom->id < 0)
>> +		return eeprom->id;
>> +
>> +	eeprom->edev.class = &eeprom_class;
>> +	eeprom->edev.parent = eeprom->dev;
>> +	eeprom->edev.of_node = eeprom->dev ? eeprom->dev->of_node : NULL;
>> +	dev_set_name(&eeprom->edev, "eeprom%d", eeprom->id);
>> +
>> +	device_initialize(&eeprom->edev);
>> +
>> +	dev_dbg(&eeprom->edev, "Registering eeprom device %s\n",
>> +		dev_name(&eeprom->edev));
>> +
>> +	rval = device_add(&eeprom->edev);
>> +	if (rval)
>> +		return rval;
>> +
>> +	mutex_lock(&eeprom_list_mutex);
>> +	list_add(&eeprom->list, &eeprom_list);
>> +	mutex_unlock(&eeprom_list_mutex);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(eeprom_register);
>> +
>> +int eeprom_unregister(struct eeprom_device *eeprom)
>> +{
>> +	device_del(&eeprom->edev);
>> +
>> +	mutex_lock(&eeprom_list_mutex);
>> +	list_del(&eeprom->list);
>> +	mutex_unlock(&eeprom_list_mutex);
>> +
>> +	return 0;
>
> There's problems with this.  "edev" is embedded into eeprom, and "edev"
> is a refcounted structure - it has a lifetime, and the lifetime of
> eeprom is thus determined by edev.
>
> What this means is that calling eeprom_unregister() and then freeing
> the eeprom structure is a potentially unsafe operation - the memory
> backing edev must only be freed when the release method for the
> struct device has been called.

Thats a good catch, Yes I see the issue.

Moving the struct eeprom_device allocation to eeprom core.c should 
address this issue. This makes eeprom self contained and can safely free 
the eeprom_device memory in eeprom_class.eeprom_release().

Will fix this in next version.

>
>> +struct eeprom_device {
>> +	struct regmap		*regmap;
>> +	int			stride;
>> +	size_t			size;
>> +	struct device		*dev;
>
> Failing to understand and address the driver model life time issues is
> a major blocker for this patch.  Sorry.
>

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-20 17:21   ` Rob Herring
@ 2015-02-20 19:25     ` Srinivas Kandagatla
  2015-02-20 22:01       ` Rob Herring
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-20 19:25 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman



On 20/02/15 17:21, Rob Herring wrote:
> On Thu, Feb 19, 2015 at 11:08 AM, Srinivas Kandagatla
> <srinivas.kandagatla@linaro.org> wrote:
>> From: Maxime Ripard <maxime.ripard@free-electrons.com>
>>
>> Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
>> duplicate pretty much the same code to register a sysfs file, allow in-kernel
>> users to access the content of the devices they were driving, etc.
>>
>> This was also a problem as far as other in-kernel users were involved, since
>> the solutions used were pretty much different from on driver to another, there
>> was a rather big abstraction leak.
>>
>> This introduction of this framework aims at solving this. It also introduces DT
>> representation for consumer devices to go get the data they require (MAC
>> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
>>
>> Having regmap interface to this framework would give much better
>> abstraction for eeproms on different buses.
>>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> [srinivas.kandagatla: Moved to regmap based and cleanedup apis]
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> ---
>>   .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
>>   drivers/Kconfig                                    |   2 +
>>   drivers/Makefile                                   |   1 +
>>   drivers/eeprom/Kconfig                             |  19 ++
>>   drivers/eeprom/Makefile                            |   9 +
>>   drivers/eeprom/core.c                              | 290 +++++++++++++++++++++
>>   include/linux/eeprom-consumer.h                    |  73 ++++++
>>   include/linux/eeprom-provider.h                    |  51 ++++
>
> Who is going to be the maintainer for this?

Am happy to be one.

>
>>   8 files changed, 493 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
>>   create mode 100644 drivers/eeprom/Kconfig
>>   create mode 100644 drivers/eeprom/Makefile
>>   create mode 100644 drivers/eeprom/core.c
>>   create mode 100644 include/linux/eeprom-consumer.h
>>   create mode 100644 include/linux/eeprom-provider.h
>>
>> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
>> new file mode 100644
>> index 0000000..9ec1ec2
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
>
> Please make bindings a separate patch.
Sure, Will do it in next version.

>
>> @@ -0,0 +1,48 @@
>> += EEPROM Data Device Tree Bindings =
>> +
>> +This binding is intended to represent the location of hardware
>> +configuration data stored in EEPROMs.
>> +
>> +On a significant proportion of boards, the manufacturer has stored
>> +some data on an EEPROM-like device, for the OS to be able to retrieve
>> +these information and act upon it. Obviously, the OS has to know
>> +about where to retrieve these data from, and where they are stored on
>> +the storage device.
>> +
>> +This document is here to document this.
>> +
>> += Data providers =
>> +
>> +Required properties:
>> +#eeprom-cells: Number of cells in an eeprom specifier; The common
>> +               case is 2.
>
> We already have eeproms in DTs, it would be nice to be able to support
> them with this framework as well.

Yes, I can see more than 60% of them are atmel,at24* eeproms in DT. We 
have some plans to migrate at24 and at25 eeproms to this framework once 
the the framework itself is accepted.

>
>> +
>> +For example:
>> +
>> +       at24: eeprom@42 {
>> +               #eeprom-cells = <2>;
>> +       };
>> +
>> += Data consumers =
>> +
>> +Required properties:
>> +
>> +eeproms: List of phandle and data cell specifier triplet, one triplet
>> +        for each data cell the device might be interested in. The
>> +        triplet consists of the phandle to the eeprom provider, then
>> +        the offset in byte within that storage device, and the length
>> +        in byte of the data we care about.
>
> The problem with this is it assumes you know who the consumer is and
> that it is a DT node. For example, how would you describe a serial
> number?
Correct me if I miss understood.
Is serial number any different?
Am hoping that the eeprom consumer would be aware of offset and size of 
serial number in the eeprom

Cant the consumer do:

eeprom-consumer {
	eeproms = <&at24 0 4>;
	eeprom-names = "device-serial-number";
};

--srini

>
> Rob
>

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-20 19:25     ` Srinivas Kandagatla
@ 2015-02-20 22:01       ` Rob Herring
  2015-02-21 11:31         ` Srinivas Kandagatla
                           ` (2 more replies)
  0 siblings, 3 replies; 153+ messages in thread
From: Rob Herring @ 2015-02-20 22:01 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

On Fri, Feb 20, 2015 at 1:25 PM, Srinivas Kandagatla
<srinivas.kandagatla@linaro.org> wrote:
>
>
> On 20/02/15 17:21, Rob Herring wrote:
>>
>> On Thu, Feb 19, 2015 at 11:08 AM, Srinivas Kandagatla
>> <srinivas.kandagatla@linaro.org> wrote:
>>>
>>> From: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>
>>> Up until now, EEPROM drivers were stored in drivers/misc, where they all
>>> had to
>>> duplicate pretty much the same code to register a sysfs file, allow
>>> in-kernel
>>> users to access the content of the devices they were driving, etc.
>>>
>>> This was also a problem as far as other in-kernel users were involved,
>>> since
>>> the solutions used were pretty much different from on driver to another,
>>> there
>>> was a rather big abstraction leak.
>>>
>>> This introduction of this framework aims at solving this. It also
>>> introduces DT
>>> representation for consumer devices to go get the data they require (MAC
>>> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
>>>
>>> Having regmap interface to this framework would give much better
>>> abstraction for eeproms on different buses.
>>>
>>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>>> [srinivas.kandagatla: Moved to regmap based and cleanedup apis]
>>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>>> ---
>>>   .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
>>>   drivers/Kconfig                                    |   2 +
>>>   drivers/Makefile                                   |   1 +
>>>   drivers/eeprom/Kconfig                             |  19 ++
>>>   drivers/eeprom/Makefile                            |   9 +
>>>   drivers/eeprom/core.c                              | 290
>>> +++++++++++++++++++++
>>>   include/linux/eeprom-consumer.h                    |  73 ++++++
>>>   include/linux/eeprom-provider.h                    |  51 ++++
>>
>>
>> Who is going to be the maintainer for this?
>
>
> Am happy to be one.

So please add a MAINTAINERS entry.

[...]

>>> += Data consumers =
>>> +
>>> +Required properties:
>>> +
>>> +eeproms: List of phandle and data cell specifier triplet, one triplet
>>> +        for each data cell the device might be interested in. The
>>> +        triplet consists of the phandle to the eeprom provider, then
>>> +        the offset in byte within that storage device, and the length
>>> +        in byte of the data we care about.
>>
>>
>> The problem with this is it assumes you know who the consumer is and
>> that it is a DT node. For example, how would you describe a serial
>> number?
>
> Correct me if I miss understood.
> Is serial number any different?
> Am hoping that the eeprom consumer would be aware of offset and size of
> serial number in the eeprom
>
> Cant the consumer do:
>
> eeprom-consumer {
>         eeproms = <&at24 0 4>;
>         eeprom-names = "device-serial-number";

Yes, but who is "eeprom-consumer"? DT nodes generally describe a h/w
block, but it this case, the consumer depends on the OS, not the h/w.
I'm not saying you can't describe where things are, but I don't think
you should imply who is the consumer and doing so is unnecessarily
complicated.

Also, the layout of EEPROM is likely very much platform specific. Some
could have a more complex structure perhaps with key ids and linked
list structure.

I would do something more simple that is just a list of keys and their
location like this:

device-serial-number = <start size>;
key1 = <start size>;
key2 = <start size>;

Rob

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-20 22:01       ` Rob Herring
@ 2015-02-21 11:31         ` Srinivas Kandagatla
  2015-02-22 14:34           ` Maxime Ripard
  2015-02-22 14:32         ` Maxime Ripard
  2015-02-23  9:15         ` Sascha Hauer
  2 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-21 11:31 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman



On 20/02/15 22:01, Rob Herring wrote:
> On Fri, Feb 20, 2015 at 1:25 PM, Srinivas Kandagatla
> <srinivas.kandagatla@linaro.org> wrote:
>>
>>
>> On 20/02/15 17:21, Rob Herring wrote:
>>>
>>> On Thu, Feb 19, 2015 at 11:08 AM, Srinivas Kandagatla
>>> <srinivas.kandagatla@linaro.org> wrote:
>>>>
>>>> From: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>>
>>>> Up until now, EEPROM drivers were stored in drivers/misc, where they all
>>>> had to
>>>> duplicate pretty much the same code to register a sysfs file, allow
>>>> in-kernel
>>>> users to access the content of the devices they were driving, etc.
>>>>
>>>> This was also a problem as far as other in-kernel users were involved,
>>>> since
>>>> the solutions used were pretty much different from on driver to another,
>>>> there
>>>> was a rather big abstraction leak.
>>>>
>>>> This introduction of this framework aims at solving this. It also
>>>> introduces DT
>>>> representation for consumer devices to go get the data they require (MAC
>>>> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
>>>>
>>>> Having regmap interface to this framework would give much better
>>>> abstraction for eeproms on different buses.
>>>>
>>>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>> [srinivas.kandagatla: Moved to regmap based and cleanedup apis]
>>>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>>>> ---
>>>>    .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
>>>>    drivers/Kconfig                                    |   2 +
>>>>    drivers/Makefile                                   |   1 +
>>>>    drivers/eeprom/Kconfig                             |  19 ++
>>>>    drivers/eeprom/Makefile                            |   9 +
>>>>    drivers/eeprom/core.c                              | 290
>>>> +++++++++++++++++++++
>>>>    include/linux/eeprom-consumer.h                    |  73 ++++++
>>>>    include/linux/eeprom-provider.h                    |  51 ++++
>>>
>>>
>>> Who is going to be the maintainer for this?
>>
>>
>> Am happy to be one.
>
> So please add a MAINTAINERS entry.
Yep, I will do that in next version.

>
> [...]
>
>>>> += Data consumers =
>>>> +
>>>> +Required properties:
>>>> +
>>>> +eeproms: List of phandle and data cell specifier triplet, one triplet
>>>> +        for each data cell the device might be interested in. The
>>>> +        triplet consists of the phandle to the eeprom provider, then
>>>> +        the offset in byte within that storage device, and the length
>>>> +        in byte of the data we care about.
>>>
>>>
>>> The problem with this is it assumes you know who the consumer is and
>>> that it is a DT node. For example, how would you describe a serial
>>> number?
>>
>> Correct me if I miss understood.
>> Is serial number any different?
>> Am hoping that the eeprom consumer would be aware of offset and size of
>> serial number in the eeprom
>>
>> Cant the consumer do:
>>
>> eeprom-consumer {
>>          eeproms = <&at24 0 4>;
>>          eeprom-names = "device-serial-number";
>
> Yes, but who is "eeprom-consumer"? DT nodes generally describe a h/w
> block, but it this case, the consumer depends on the OS, not the h/w.

Consumer could be any driver for the IP on the SOC, for example an 
ethernet driver which needs Mac Address from eeprom or an thermal sensor 
which requires cablibration values or an cpufreq driver which requires 
OPP settings. Am not sure who could be the consumer for serial number, I 
guess it should some soc specific driver.

> I'm not saying you can't describe where things are, but I don't think
> you should imply who is the consumer and doing so is unnecessarily
> complicated.
>
> Also, the layout of EEPROM is likely very much platform specific. Some
> could have a more complex structure perhaps with key ids and linked
> list structure.
I agree, the data layout is very specific to platform and could vary in 
complexity.
This simple framework is attempting to solve most common usecase where 
in the consumer drivers like thermal-sensor/network/cpufreq needs to 
read an location in the eeprom. Am sure we can find a way to accommodate 
the complex layout as well.
>
> I would do something more simple that is just a list of keys and their
> location like this:
>
> device-serial-number = <start size>;
> key1 = <start size>;
> key2 = <start size>;
>
There are pros and cons doing it as list of keys.

One reason for doing it as fixed properties("eeproms", "eemprom-names") 
is "consistency and familiarity" like interrupts, regs, dmas, clocks, 
pinctrl, reset, pwm have fixed property names, trying to get most 
subsystems to do it the same way makes it easier for people to write dts 
files.


--srini


> Rob
>

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-20 22:01       ` Rob Herring
  2015-02-21 11:31         ` Srinivas Kandagatla
@ 2015-02-22 14:32         ` Maxime Ripard
  2015-02-23  0:57           ` Rob Herring
  2015-02-23  9:15         ` Sascha Hauer
  2 siblings, 1 reply; 153+ messages in thread
From: Maxime Ripard @ 2015-02-22 14:32 UTC (permalink / raw)
  To: Rob Herring
  Cc: Srinivas Kandagatla, linux-arm-kernel, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

[-- Attachment #1: Type: text/plain, Size: 2405 bytes --]

On Fri, Feb 20, 2015 at 04:01:55PM -0600, Rob Herring wrote:
> [...]
> 
> >>> += Data consumers =
> >>> +
> >>> +Required properties:
> >>> +
> >>> +eeproms: List of phandle and data cell specifier triplet, one triplet
> >>> +        for each data cell the device might be interested in. The
> >>> +        triplet consists of the phandle to the eeprom provider, then
> >>> +        the offset in byte within that storage device, and the length
> >>> +        in byte of the data we care about.
> >>
> >>
> >> The problem with this is it assumes you know who the consumer is and
> >> that it is a DT node. For example, how would you describe a serial
> >> number?
> >
> > Correct me if I miss understood.
> > Is serial number any different?
> > Am hoping that the eeprom consumer would be aware of offset and size of
> > serial number in the eeprom
> >
> > Cant the consumer do:
> >
> > eeprom-consumer {
> >         eeproms = <&at24 0 4>;
> >         eeprom-names = "device-serial-number";
> 
> Yes, but who is "eeprom-consumer"?

Any device that should lookup values in one of the EEPROM.

> DT nodes generally describe a h/w block, but it this case, the
> consumer depends on the OS, not the h/w. 

Not really, or at least, not more than any similar binding we
currently have.

The fact that a MAC-address for the first ethernet chip is stored at a
given offset in a given eeprom has nothing to do with the OS.

> I'm not saying you can't describe where things are, but I don't
> think you should imply who is the consumer and doing so is
> unnecessarily complicated.

If you only take the case of a serial number, indeed. If you take
other usage into account, you can't really do without it.

> Also, the layout of EEPROM is likely very much platform specific.

Indeed, which is why it should be in the DT.

> Some could have a more complex structure perhaps with key ids and
> linked list structure.

Then just request the size of the whole list, and parse it afterwards
in your driver?

> I would do something more simple that is just a list of keys and their
> location like this:
> 
> device-serial-number = <start size>;
> key1 = <start size>;
> key2 = <start size>;

I'm sorry, but what's the difference?

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-21 11:31         ` Srinivas Kandagatla
@ 2015-02-22 14:34           ` Maxime Ripard
  0 siblings, 0 replies; 153+ messages in thread
From: Maxime Ripard @ 2015-02-22 14:34 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Rob Herring, linux-arm-kernel, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

[-- Attachment #1: Type: text/plain, Size: 880 bytes --]

On Sat, Feb 21, 2015 at 11:31:49AM +0000, Srinivas Kandagatla wrote:
> >I would do something more simple that is just a list of keys and their
> >location like this:
> >
> >device-serial-number = <start size>;
> >key1 = <start size>;
> >key2 = <start size>;
> >
> There are pros and cons doing it as list of keys.
> 
> One reason for doing it as fixed properties("eeproms", "eemprom-names") is
> "consistency and familiarity" like interrupts, regs, dmas, clocks, pinctrl,
> reset, pwm have fixed property names, trying to get most subsystems to do it
> the same way makes it easier for people to write dts files.

And eeprom-names was something that was asked for last time we
discussed it (I don't really remember who though, maybe Arnd?)

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-22 14:32         ` Maxime Ripard
@ 2015-02-23  0:57           ` Rob Herring
  2015-02-23 23:11             ` Stephen Boyd
  0 siblings, 1 reply; 153+ messages in thread
From: Rob Herring @ 2015-02-23  0:57 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Srinivas Kandagatla, linux-arm-kernel, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

On Sun, Feb 22, 2015 at 8:32 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Fri, Feb 20, 2015 at 04:01:55PM -0600, Rob Herring wrote:
>> [...]
>>
>> >>> += Data consumers =
>> >>> +
>> >>> +Required properties:
>> >>> +
>> >>> +eeproms: List of phandle and data cell specifier triplet, one triplet
>> >>> +        for each data cell the device might be interested in. The
>> >>> +        triplet consists of the phandle to the eeprom provider, then
>> >>> +        the offset in byte within that storage device, and the length
>> >>> +        in byte of the data we care about.
>> >>
>> >>
>> >> The problem with this is it assumes you know who the consumer is and
>> >> that it is a DT node. For example, how would you describe a serial
>> >> number?
>> >
>> > Correct me if I miss understood.
>> > Is serial number any different?
>> > Am hoping that the eeprom consumer would be aware of offset and size of
>> > serial number in the eeprom
>> >
>> > Cant the consumer do:
>> >
>> > eeprom-consumer {
>> >         eeproms = <&at24 0 4>;
>> >         eeprom-names = "device-serial-number";
>>
>> Yes, but who is "eeprom-consumer"?
>
> Any device that should lookup values in one of the EEPROM.
>
>> DT nodes generally describe a h/w block, but it this case, the
>> consumer depends on the OS, not the h/w.
>
> Not really, or at least, not more than any similar binding we
> currently have.
>
> The fact that a MAC-address for the first ethernet chip is stored at a
> given offset in a given eeprom has nothing to do with the OS.

So MAC address would be a valid use to link to a h/w device, but there
are certainly cases that don't correspond to a device.

>> I'm not saying you can't describe where things are, but I don't
>> think you should imply who is the consumer and doing so is
>> unnecessarily complicated.
>
> If you only take the case of a serial number, indeed. If you take
> other usage into account, you can't really do without it.
>
>> Also, the layout of EEPROM is likely very much platform specific.
>
> Indeed, which is why it should be in the DT.

Agreed. I'm not saying the layout should not be.

>> Some could have a more complex structure perhaps with key ids and
>> linked list structure.
>
> Then just request the size of the whole list, and parse it afterwards
> in your driver?
>
>> I would do something more simple that is just a list of keys and their
>> location like this:
>>
>> device-serial-number = <start size>;
>> key1 = <start size>;
>> key2 = <start size>;
>
> I'm sorry, but what's the difference?

It can describe the layout completely whether the fields are tied to a
h/w device or not.

What I would like to see here is the entire layout described covering
both types of fields.

Rob

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-20 22:01       ` Rob Herring
  2015-02-21 11:31         ` Srinivas Kandagatla
  2015-02-22 14:32         ` Maxime Ripard
@ 2015-02-23  9:15         ` Sascha Hauer
  2 siblings, 0 replies; 153+ messages in thread
From: Sascha Hauer @ 2015-02-23  9:15 UTC (permalink / raw)
  To: Rob Herring
  Cc: Srinivas Kandagatla, linux-arm-kernel, Maxime Ripard,
	Rob Herring, Pawel Moll, Kumar Gala, linux-api, linux-kernel,
	devicetree, Stephen Boyd, Arnd Bergmann, Mark Brown,
	Greg Kroah-Hartman

On Fri, Feb 20, 2015 at 04:01:55PM -0600, Rob Herring wrote:
> On Fri, Feb 20, 2015 at 1:25 PM, Srinivas Kandagatla
> <srinivas.kandagatla@linaro.org> wrote:
> >
> >
> > On 20/02/15 17:21, Rob Herring wrote:
> >>
> >> On Thu, Feb 19, 2015 at 11:08 AM, Srinivas Kandagatla
> >> <srinivas.kandagatla@linaro.org> wrote:
> >>>
> >>> From: Maxime Ripard <maxime.ripard@free-electrons.com>
> >>>
> >>> Up until now, EEPROM drivers were stored in drivers/misc, where they all
> >>> had to
> >>> duplicate pretty much the same code to register a sysfs file, allow
> >>> in-kernel
> >>> users to access the content of the devices they were driving, etc.
> >>>
> >>> This was also a problem as far as other in-kernel users were involved,
> >>> since
> >>> the solutions used were pretty much different from on driver to another,
> >>> there
> >>> was a rather big abstraction leak.
> >>>
> >>> This introduction of this framework aims at solving this. It also
> >>> introduces DT
> >>> representation for consumer devices to go get the data they require (MAC
> >>> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
> >>>
> >>> Having regmap interface to this framework would give much better
> >>> abstraction for eeproms on different buses.
> >>>
> >>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> >>> [srinivas.kandagatla: Moved to regmap based and cleanedup apis]
> >>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> >>> ---
> >>>   .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
> >>>   drivers/Kconfig                                    |   2 +
> >>>   drivers/Makefile                                   |   1 +
> >>>   drivers/eeprom/Kconfig                             |  19 ++
> >>>   drivers/eeprom/Makefile                            |   9 +
> >>>   drivers/eeprom/core.c                              | 290
> >>> +++++++++++++++++++++
> >>>   include/linux/eeprom-consumer.h                    |  73 ++++++
> >>>   include/linux/eeprom-provider.h                    |  51 ++++
> >>
> >>
> >> Who is going to be the maintainer for this?
> >
> >
> > Am happy to be one.
> 
> So please add a MAINTAINERS entry.
> 
> [...]
> 
> >>> += Data consumers =
> >>> +
> >>> +Required properties:
> >>> +
> >>> +eeproms: List of phandle and data cell specifier triplet, one triplet
> >>> +        for each data cell the device might be interested in. The
> >>> +        triplet consists of the phandle to the eeprom provider, then
> >>> +        the offset in byte within that storage device, and the length
> >>> +        in byte of the data we care about.
> >>
> >>
> >> The problem with this is it assumes you know who the consumer is and
> >> that it is a DT node. For example, how would you describe a serial
> >> number?
> >
> > Correct me if I miss understood.
> > Is serial number any different?
> > Am hoping that the eeprom consumer would be aware of offset and size of
> > serial number in the eeprom
> >
> > Cant the consumer do:
> >
> > eeprom-consumer {
> >         eeproms = <&at24 0 4>;
> >         eeprom-names = "device-serial-number";
> 
> Yes, but who is "eeprom-consumer"? DT nodes generally describe a h/w
> block, but it this case, the consumer depends on the OS, not the h/w.
> I'm not saying you can't describe where things are, but I don't think
> you should imply who is the consumer and doing so is unnecessarily
> complicated.
> 
> Also, the layout of EEPROM is likely very much platform specific. Some
> could have a more complex structure perhaps with key ids and linked
> list structure.
> 
> I would do something more simple that is just a list of keys and their
> location like this:
> 
> device-serial-number = <start size>;
> key1 = <start size>;
> key2 = <start size>;

Maybe better a node instead of a property. That would allow to use the
standard reg property to describe the position in the eeprom. Also it
would give consumers in dt a possibility to use a phandle to point to a
variable:

	serial_number: var@c {
		reg = <0xc 0x8>;
		name = <?>;
	};

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-19 17:08 ` [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework Srinivas Kandagatla
                     ` (3 preceding siblings ...)
  2015-02-20 17:46   ` Russell King - ARM Linux
@ 2015-02-23 15:04   ` Mark Brown
  2015-02-23 15:38     ` Srinivas Kandagatla
  4 siblings, 1 reply; 153+ messages in thread
From: Mark Brown @ 2015-02-23 15:04 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Greg Kroah-Hartman

[-- Attachment #1: Type: text/plain, Size: 2967 bytes --]

On Thu, Feb 19, 2015 at 05:08:28PM +0000, Srinivas Kandagatla wrote:

>  .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
>  drivers/Kconfig                                    |   2 +
>  drivers/Makefile                                   |   1 +
>  drivers/eeprom/Kconfig                             |  19 ++
>  drivers/eeprom/Makefile                            |   9 +
>  drivers/eeprom/core.c                              | 290 +++++++++++++++++++++
>  include/linux/eeprom-consumer.h                    |  73 ++++++
>  include/linux/eeprom-provider.h                    |  51 ++++

This seems to have a bunch of different things in it - there's some
binding, there's some framework code, there's some user code for the
framework...  splitting it up more would probably help with review.
I'd at least make sure the framework is split from the DT code, that
will cut down on the bulk and help make sure the framework isn't too DT
tied.

> +	if (read)
> +		rc = regmap_bulk_read(eeprom->regmap, offset,
> +				      buf, count/eeprom->stride);
> +	else
> +		rc = regmap_bulk_write(eeprom->regmap, offset,
> +				       buf, count/eeprom->stride);
> +
> +	if (IS_ERR_VALUE(rc))
> +		return 0;
> +
> +	return count;
> +}

> +static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
> +				    struct bin_attribute *attr,
> +				    char *buf, loff_t offset, size_t count)
> +{
> +	return bin_attr_eeprom_read_write(kobj, buf, offset, count, true);
> +}

I'm not sure the factoring out is actually helping the clarity here TBH.

> +int eeprom_unregister(struct eeprom_device *eeprom)
> +{
> +	device_del(&eeprom->edev);
> +
> +	mutex_lock(&eeprom_list_mutex);
> +	list_del(&eeprom->list);
> +	mutex_unlock(&eeprom_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(eeprom_unregister);

Here we return having dropped the lock without doing anything else with
the eeprom, meaning the caller could delete it.

> +	mutex_lock(&eeprom_list_mutex);
> +
> +	list_for_each_entry(e, &eeprom_list, list) {
> +		if (args.np == e->edev.of_node) {
> +			eeprom = e;
> +			break;
> +		}
> +	}
> +	mutex_unlock(&eeprom_list_mutex);

Here we iterate the list, find the relevant eeprom and drop the lock
while still holding a reference to the eeprom we just found.  This means
that a removal could race with us and free the eeprom underneath us.
I'm also not seeing anything stopping or even noticing a device being
removed with a cell active on it.

> +/**
> + * eeprom_cell_get(): Get eeprom cell of device form a given index.
> + *
> + * @dev: Device that will be interacted with
> + * @index: Index of the eeprom cell.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index);

Normally the kerneldoc goes with the function definition, not the
prototype.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-23 15:04   ` Mark Brown
@ 2015-02-23 15:38     ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-23 15:38 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Greg Kroah-Hartman

Thankyou for the comments.

On 23/02/15 15:04, Mark Brown wrote:
> On Thu, Feb 19, 2015 at 05:08:28PM +0000, Srinivas Kandagatla wrote:
>
>>   .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
>>   drivers/Kconfig                                    |   2 +
>>   drivers/Makefile                                   |   1 +
>>   drivers/eeprom/Kconfig                             |  19 ++
>>   drivers/eeprom/Makefile                            |   9 +
>>   drivers/eeprom/core.c                              | 290 +++++++++++++++++++++
>>   include/linux/eeprom-consumer.h                    |  73 ++++++
>>   include/linux/eeprom-provider.h                    |  51 ++++
>
> This seems to have a bunch of different things in it - there's some
> binding, there's some framework code, there's some user code for the
> framework...  splitting it up more would probably help with review.
> I'd at least make sure the framework is split from the DT code, that
> will cut down on the bulk and help make sure the framework isn't too DT
> tied.

Yes I agree, will make sure that I split it into different patches in 
next version.
>
>> +	if (read)
>> +		rc = regmap_bulk_read(eeprom->regmap, offset,
>> +				      buf, count/eeprom->stride);
>> +	else
>> +		rc = regmap_bulk_write(eeprom->regmap, offset,
>> +				       buf, count/eeprom->stride);
>> +
>> +	if (IS_ERR_VALUE(rc))
>> +		return 0;
>> +
>> +	return count;
>> +}
>
>> +static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
>> +				    struct bin_attribute *attr,
>> +				    char *buf, loff_t offset, size_t count)
>> +{
>> +	return bin_attr_eeprom_read_write(kobj, buf, offset, count, true);
>> +}
>
> I'm not sure the factoring out is actually helping the clarity here TBH.
>
ok.

>> +int eeprom_unregister(struct eeprom_device *eeprom)
>> +{
>> +	device_del(&eeprom->edev);
>> +
>> +	mutex_lock(&eeprom_list_mutex);
>> +	list_del(&eeprom->list);
>> +	mutex_unlock(&eeprom_list_mutex);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(eeprom_unregister);
>
> Here we return having dropped the lock without doing anything else with
> the eeprom, meaning the caller could delete it.
>
>> +	mutex_lock(&eeprom_list_mutex);
>> +
>> +	list_for_each_entry(e, &eeprom_list, list) {
>> +		if (args.np == e->edev.of_node) {
>> +			eeprom = e;
>> +			break;
>> +		}
>> +	}
>> +	mutex_unlock(&eeprom_list_mutex);
>
> Here we iterate the list, find the relevant eeprom and drop the lock
> while still holding a reference to the eeprom we just found.  This means
> that a removal could race with us and free the eeprom underneath us.
> I'm also not seeing anything stopping or even noticing a device being
> removed with a cell active on it.
>
As suggested by Stephen Boyd reference counting on eeprom should ensure 
safe removal of eeprom.

>> +/**
>> + * eeprom_cell_get(): Get eeprom cell of device form a given index.
>> + *
>> + * @dev: Device that will be interacted with
>> + * @index: Index of the eeprom cell.
>> + *
>> + * The return value will be an ERR_PTR() on error or a valid pointer
>> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
>> + * eeprom_cell_put().
>> + */
>> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index);
>
> Normally the kerneldoc goes with the function definition, not the
> prototype.
Thats true, will fix it in next version.
>

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-23  0:57           ` Rob Herring
@ 2015-02-23 23:11             ` Stephen Boyd
  2015-02-24  7:08               ` Srinivas Kandagatla
  2015-02-24  9:21               ` Maxime Ripard
  0 siblings, 2 replies; 153+ messages in thread
From: Stephen Boyd @ 2015-02-23 23:11 UTC (permalink / raw)
  To: Rob Herring, Maxime Ripard
  Cc: Srinivas Kandagatla, linux-arm-kernel, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Arnd Bergmann,
	Mark Brown, Greg Kroah-Hartman

On 02/22/15 16:57, Rob Herring wrote:
> On Sun, Feb 22, 2015 at 8:32 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
>> On Fri, Feb 20, 2015 at 04:01:55PM -0600, Rob Herring wrote:
>>> [...]
>>>
>>>>>> += Data consumers =
>>>>>> +
>>>>>> +Required properties:
>>>>>> +
>>>>>> +eeproms: List of phandle and data cell specifier triplet, one triplet
>>>>>> +        for each data cell the device might be interested in. The
>>>>>> +        triplet consists of the phandle to the eeprom provider, then
>>>>>> +        the offset in byte within that storage device, and the length
>>>>>> +        in byte of the data we care about.
>>>>>
>>>>> The problem with this is it assumes you know who the consumer is and
>>>>> that it is a DT node. For example, how would you describe a serial
>>>>> number?
>>>> Correct me if I miss understood.
>>>> Is serial number any different?
>>>> Am hoping that the eeprom consumer would be aware of offset and size of
>>>> serial number in the eeprom
>>>>
>>>> Cant the consumer do:
>>>>
>>>> eeprom-consumer {
>>>>         eeproms = <&at24 0 4>;
>>>>         eeprom-names = "device-serial-number";
>>> Yes, but who is "eeprom-consumer"?
>> Any device that should lookup values in one of the EEPROM.
>>
>>> DT nodes generally describe a h/w block, but it this case, the
>>> consumer depends on the OS, not the h/w.
>> Not really, or at least, not more than any similar binding we
>> currently have.
>>
>> The fact that a MAC-address for the first ethernet chip is stored at a
>> given offset in a given eeprom has nothing to do with the OS.
> So MAC address would be a valid use to link to a h/w device, but there
> are certainly cases that don't correspond to a device.
>
>>> I'm not saying you can't describe where things are, but I don't
>>> think you should imply who is the consumer and doing so is
>>> unnecessarily complicated.
>> If you only take the case of a serial number, indeed. If you take
>> other usage into account, you can't really do without it.
>>
>>> Also, the layout of EEPROM is likely very much platform specific.
>> Indeed, which is why it should be in the DT.
> Agreed. I'm not saying the layout should not be.
>
>>> Some could have a more complex structure perhaps with key ids and
>>> linked list structure.
>> Then just request the size of the whole list, and parse it afterwards
>> in your driver?
>>
>>> I would do something more simple that is just a list of keys and their
>>> location like this:
>>>
>>> device-serial-number = <start size>;
>>> key1 = <start size>;
>>> key2 = <start size>;
>> I'm sorry, but what's the difference?
> It can describe the layout completely whether the fields are tied to a
> h/w device or not.
>
> What I would like to see here is the entire layout described covering
> both types of fields.
>

I was thinking the DT might be like this on the provider side:

   qfprom@1000000 {
      reg = <0x1000000 0x1000>;
      ranges = <0 0x1000000 0x1000>;
      compatible = "qcom,qfprom-msm8960"

      pvs-data: pvs-data@40 {
            compatible = "qcom,pvs-a";
            reg = <0x40 0x20>,
	    #eeprom-cells = <0>;
      };

       tsens-data: tmdata@10 {
            compatible = "qcom,tsens-data-msm8960";
            reg = <0x10 4>, <0x16 4>;
	    #eeprom-cells = <0>;

      };

      serial-number: serial@50 {
            compatible = "qcom,serial-msm8960";
            reg = <0x50 4>, <0x60 4>;
	    #eeprom-cells = <0>;

      };
   };

and then on the consumer side:

	device {
		eeproms = <&serial-number>;
		eeprom-names = "soc-rev-id";
	};


This would solve a problem where the consumer device is some standard
off-the-shelf IP block that needs to get some SoC specific calibration
data from the eeprom. I may want to interpret the bits differently
depending on which eeprom is connected to my SoC. Sometimes that data
format may be the same across many variations of the SoC (e.g. the
qcom,pvs-a node) or it may be completely different for a given SoC (e.g.
qcom,serial-msm8960 node). I imagine for other SoCs out there it could
be different depending on which eeprom the board manufacturer decides to
wire onto their board and how they choose to program the data.

So this is where I think the eeprom-cells and offset + length starts to
fall apart. It forces us to make up a bunch of different compatible
strings for our consumer device just so that we can parse the eeprom
that we decided to use for some SoC/board specific data. Instead I'd
like to see some framework that expresses exactly which eeprom is on my
board and how to interpret the bits in a way that doesn't require me to
keep refining the compatible string for my generic IP block.

I worry that if we put all those details in DT we'll end up having to
describe individual bits like serial-number-bit-2, serial-number-bit-3,
etc. because sometimes these pieces of data are scattered all around the
eeprom and aren't contiguous or aligned on a byte boundary. It may be
easier to just have a way to express that this is an eeprom with this
specific layout and my device has data stored in there. Then the driver
can be told what layout it is (via compatible or some other string based
means if we're not using DT?) and match that up with some driver data if
it needs to know how to understand the bits it can read with the
eeprom_read() API.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-23 23:11             ` Stephen Boyd
@ 2015-02-24  7:08               ` Srinivas Kandagatla
  2015-02-24  9:21               ` Maxime Ripard
  1 sibling, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-24  7:08 UTC (permalink / raw)
  To: Stephen Boyd, Rob Herring, Maxime Ripard
  Cc: linux-arm-kernel, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Arnd Bergmann, Mark Brown,
	Greg Kroah-Hartman

Thanks Stephen for the comments.

On 23/02/15 23:11, Stephen Boyd wrote:
> On 02/22/15 16:57, Rob Herring wrote:
>> On Sun, Feb 22, 2015 at 8:32 AM, Maxime Ripard
>> <maxime.ripard@free-electrons.com> wrote:
>>> On Fri, Feb 20, 2015 at 04:01:55PM -0600, Rob Herring wrote:
>>>> [...]
>>>>
>>>>>>> += Data consumers =
>>>>>>> +
>>>>>>> +Required properties:
>>>>>>> +
>>>>>>> +eeproms: List of phandle and data cell specifier triplet, one triplet
>>>>>>> +        for each data cell the device might be interested in. The
>>>>>>> +        triplet consists of the phandle to the eeprom provider, then
>>>>>>> +        the offset in byte within that storage device, and the length
>>>>>>> +        in byte of the data we care about.
>>>>>>
>>>>>> The problem with this is it assumes you know who the consumer is and
>>>>>> that it is a DT node. For example, how would you describe a serial
>>>>>> number?
>>>>> Correct me if I miss understood.
>>>>> Is serial number any different?
>>>>> Am hoping that the eeprom consumer would be aware of offset and size of
>>>>> serial number in the eeprom
>>>>>
>>>>> Cant the consumer do:
>>>>>
>>>>> eeprom-consumer {
>>>>>          eeproms = <&at24 0 4>;
>>>>>          eeprom-names = "device-serial-number";
>>>> Yes, but who is "eeprom-consumer"?
>>> Any device that should lookup values in one of the EEPROM.
>>>
>>>> DT nodes generally describe a h/w block, but it this case, the
>>>> consumer depends on the OS, not the h/w.
>>> Not really, or at least, not more than any similar binding we
>>> currently have.
>>>
>>> The fact that a MAC-address for the first ethernet chip is stored at a
>>> given offset in a given eeprom has nothing to do with the OS.
>> So MAC address would be a valid use to link to a h/w device, but there
>> are certainly cases that don't correspond to a device.
>>
>>>> I'm not saying you can't describe where things are, but I don't
>>>> think you should imply who is the consumer and doing so is
>>>> unnecessarily complicated.
>>> If you only take the case of a serial number, indeed. If you take
>>> other usage into account, you can't really do without it.
>>>
>>>> Also, the layout of EEPROM is likely very much platform specific.
>>> Indeed, which is why it should be in the DT.
>> Agreed. I'm not saying the layout should not be.
>>
>>>> Some could have a more complex structure perhaps with key ids and
>>>> linked list structure.
>>> Then just request the size of the whole list, and parse it afterwards
>>> in your driver?
>>>
>>>> I would do something more simple that is just a list of keys and their
>>>> location like this:
>>>>
>>>> device-serial-number = <start size>;
>>>> key1 = <start size>;
>>>> key2 = <start size>;
>>> I'm sorry, but what's the difference?
>> It can describe the layout completely whether the fields are tied to a
>> h/w device or not.
>>
>> What I would like to see here is the entire layout described covering
>> both types of fields.
>>
>
> I was thinking the DT might be like this on the provider side:
>
>     qfprom@1000000 {
>        reg = <0x1000000 0x1000>;
>        ranges = <0 0x1000000 0x1000>;
>        compatible = "qcom,qfprom-msm8960"
>
>        pvs-data: pvs-data@40 {
>              compatible = "qcom,pvs-a";

These compatibles could be optional. As it might not be required for 
devices which are simple and do not require any special interpretation 
of eeprom data.

>              reg = <0x40 0x20>,
> 	    #eeprom-cells = <0>;

Do we still need eeprom-cells if we are moving to use reg property here?

>        };
>
>         tsens-data: tmdata@10 {
>              compatible = "qcom,tsens-data-msm8960";
>              reg = <0x10 4>, <0x16 4>;
> 	    #eeprom-cells = <0>;
>
>        };
>
>        serial-number: serial@50 {
>              compatible = "qcom,serial-msm8960";
>              reg = <0x50 4>, <0x60 4>;
> 	    #eeprom-cells = <0>;
>
>        };
>     };
>
> and then on the consumer side:
>
> 	device {
> 		eeproms = <&serial-number>;
> 		eeprom-names = "soc-rev-id";
> 	};
>

Yes, this looks good, and Sasha was also recommending something on these 
lines too. Also this addresses the use cases like serial number too.

>
> This would solve a problem where the consumer device is some standard
> off-the-shelf IP block that needs to get some SoC specific calibration
> data from the eeprom. I may want to interpret the bits differently
> depending on which eeprom is connected to my SoC. Sometimes that data
> format may be the same across many variations of the SoC (e.g. the
> qcom,pvs-a node) or it may be completely different for a given SoC (e.g.
> qcom,serial-msm8960 node). I imagine for other SoCs out there it could
> be different depending on which eeprom the board manufacturer decides to
> wire onto their board and how they choose to program the data.
>
> So this is where I think the eeprom-cells and offset + length starts to
> fall apart. It forces us to make up a bunch of different compatible
> strings for our consumer device just so that we can parse the eeprom
> that we decided to use for some SoC/board specific data. Instead I'd
> like to see some framework that expresses exactly which eeprom is on my
> board and how to interpret the bits in a way that doesn't require me to
> keep refining the compatible string for my generic IP block.
>
> I worry that if we put all those details in DT we'll end up having to
> describe individual bits like serial-number-bit-2, serial-number-bit-3,
> etc. because sometimes these pieces of data are scattered all around the
> eeprom and aren't contiguous or aligned on a byte boundary. It may be
> easier to just have a way to express that this is an eeprom with this
> specific layout and my device has data stored in there. Then the driver
> can be told what layout it is (via compatible or some other string based
> means if we're not using DT?) and match that up with some driver data if
> it needs to know how to understand the bits it can read with the
> eeprom_read() API.
Yes this sounds more sensible to let the consumer driver interpret the 
eeprom data than the eeprom framework itself.


--srini
>

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-23 23:11             ` Stephen Boyd
  2015-02-24  7:08               ` Srinivas Kandagatla
@ 2015-02-24  9:21               ` Maxime Ripard
  2015-02-25  1:30                 ` Stephen Boyd
  1 sibling, 1 reply; 153+ messages in thread
From: Maxime Ripard @ 2015-02-24  9:21 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Rob Herring, Srinivas Kandagatla, linux-arm-kernel, Rob Herring,
	Pawel Moll, Kumar Gala, linux-api, linux-kernel, devicetree,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

[-- Attachment #1: Type: text/plain, Size: 4924 bytes --]

On Mon, Feb 23, 2015 at 03:11:40PM -0800, Stephen Boyd wrote:
> >>> I would do something more simple that is just a list of keys and
> >>> their location like this:
> >>>
> >>> device-serial-number = <start size>;
> >>> key1 = <start size>;
> >>> key2 = <start size>;
> >> I'm sorry, but what's the difference?
> > It can describe the layout completely whether the fields are tied to a
> > h/w device or not.
> >
> > What I would like to see here is the entire layout described covering
> > both types of fields.
> >
> 
> I was thinking the DT might be like this on the provider side:
> 
>    qfprom@1000000 {
>       reg = <0x1000000 0x1000>;
>       ranges = <0 0x1000000 0x1000>;
>       compatible = "qcom,qfprom-msm8960"
> 
>       pvs-data: pvs-data@40 {
>             compatible = "qcom,pvs-a";
>             reg = <0x40 0x20>,
> 	    #eeprom-cells = <0>;
>       };
> 
>        tsens-data: tmdata@10 {
>             compatible = "qcom,tsens-data-msm8960";
>             reg = <0x10 4>, <0x16 4>;
> 	    #eeprom-cells = <0>;
> 
>       };
> 
>       serial-number: serial@50 {
>             compatible = "qcom,serial-msm8960";
>             reg = <0x50 4>, <0x60 4>;
> 	    #eeprom-cells = <0>;
> 
>       };
>    };

I'm not sure the compatible is really needed.

A label of some sort, just like the MTD partitions do would do just
fine, and wouldn't have the implicit expectation that a driver will be
probed from that node.

> and then on the consumer side:
> 
> 	device {
> 		eeproms = <&serial-number>;
> 		eeprom-names = "soc-rev-id";
> 	};
> 
> 
> This would solve a problem where the consumer device is some standard
> off-the-shelf IP block that needs to get some SoC specific calibration
> data from the eeprom. I may want to interpret the bits differently
> depending on which eeprom is connected to my SoC. Sometimes that data
> format may be the same across many variations of the SoC (e.g. the
> qcom,pvs-a node) or it may be completely different for a given SoC (e.g.
> qcom,serial-msm8960 node). I imagine for other SoCs out there it could
> be different depending on which eeprom the board manufacturer decides to
> wire onto their board and how they choose to program the data.

Oh, so you'd like to infer the data format it's stored in from the
compatible?

AFAICT, this format will be highly depending on the board itself,
rather than on the SoC, do you think it will scale enough?

> So this is where I think the eeprom-cells and offset + length starts to
> fall apart. It forces us to make up a bunch of different compatible
> strings for our consumer device just so that we can parse the eeprom
> that we decided to use for some SoC/board specific data. Instead I'd
> like to see some framework that expresses exactly which eeprom is on my
> board and how to interpret the bits in a way that doesn't require me to
> keep refining the compatible string for my generic IP block.

Hmmmm, apparently you don't :)

> I worry that if we put all those details in DT we'll end up having to
> describe individual bits like serial-number-bit-2, serial-number-bit-3,
> etc. because sometimes these pieces of data are scattered all around the
> eeprom and aren't contiguous or aligned on a byte boundary. It may be
> easier to just have a way to express that this is an eeprom with this
> specific layout and my device has data stored in there. Then the driver
> can be told what layout it is (via compatible or some other string based
> means if we're not using DT?) and match that up with some driver data if
> it needs to know how to understand the bits it can read with the
> eeprom_read() API.

I'm half convinced that the layout information will actually work for
more complex cases, like the linked list Rob described.

If such a structure is ever to be found, it would feel wrong to have
that in the EEPROM driver, but it would feel just as wrong to put that
in the client driver, that would have to handle the parsing of raw
data coming flashed by one single crazy board vendor.

Maybe we can have each cell carry a property that defines the format
it's stored in, and match that to some parsers plugins, starting with
the generic and trivial cases but still allowing for custom parsers to
be defined?

Something like

eeprom@42 {
	compatible = "atmel,at24something";
	reg = <0x42>;

	serial@0 {
		label = "board serial";
		reg = <0x0 0x10>;
		format = "packed";
	};

	opps@10 {
		label = "board serial";
		reg = <0x10 0x10>, <0x40 0x10>, <0x80 0x10>;
		format = "random-vendor,opp-linked-list";
	};
};

That would make eeprom_read always return the same format of data to
the client drivers, without cripling the generic EEPROM drivers
either.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-24  9:21               ` Maxime Ripard
@ 2015-02-25  1:30                 ` Stephen Boyd
  2015-02-26  9:16                   ` Srinivas Kandagatla
  2015-02-26 13:18                   ` Maxime Ripard
  0 siblings, 2 replies; 153+ messages in thread
From: Stephen Boyd @ 2015-02-25  1:30 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Rob Herring, Srinivas Kandagatla, linux-arm-kernel, Rob Herring,
	Pawel Moll, Kumar Gala, linux-api, linux-kernel, devicetree,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

On 02/24, Maxime Ripard wrote:
> On Mon, Feb 23, 2015 at 03:11:40PM -0800, Stephen Boyd wrote:
> > >>> I would do something more simple that is just a list of keys and
> > >>> their location like this:
> > >>>
> > >>> device-serial-number = <start size>;
> > >>> key1 = <start size>;
> > >>> key2 = <start size>;
> > >> I'm sorry, but what's the difference?
> > > It can describe the layout completely whether the fields are tied to a
> > > h/w device or not.
> > >
> > > What I would like to see here is the entire layout described covering
> > > both types of fields.
> > >
> > 
> > I was thinking the DT might be like this on the provider side:
> > 
> >    qfprom@1000000 {
> >       reg = <0x1000000 0x1000>;
> >       ranges = <0 0x1000000 0x1000>;
> >       compatible = "qcom,qfprom-msm8960"
> > 
> >       pvs-data: pvs-data@40 {
> >             compatible = "qcom,pvs-a";
> >             reg = <0x40 0x20>,
> > 	    #eeprom-cells = <0>;
> >       };
> > 
> >        tsens-data: tmdata@10 {
> >             compatible = "qcom,tsens-data-msm8960";
> >             reg = <0x10 4>, <0x16 4>;
> > 	    #eeprom-cells = <0>;
> > 
> >       };
> > 
> >       serial-number: serial@50 {
> >             compatible = "qcom,serial-msm8960";
> >             reg = <0x50 4>, <0x60 4>;
> > 	    #eeprom-cells = <0>;
> > 
> >       };
> >    };
> 
> I'm not sure the compatible is really needed.
> 
> A label of some sort, just like the MTD partitions do would do just
> fine, and wouldn't have the implicit expectation that a driver will be
> probed from that node.

I wasn't aware that compatible meant driver probe. I thought
compatible just meant some software entity can understand what
I've described within this node. For example, compatible for
reserved-memory nodes doesn't mean we're going to probe a device.

> 
> > and then on the consumer side:
> > 
> > 	device {
> > 		eeproms = <&serial-number>;
> > 		eeprom-names = "soc-rev-id";
> > 	};
> > 
> > 
> > This would solve a problem where the consumer device is some standard
> > off-the-shelf IP block that needs to get some SoC specific calibration
> > data from the eeprom. I may want to interpret the bits differently
> > depending on which eeprom is connected to my SoC. Sometimes that data
> > format may be the same across many variations of the SoC (e.g. the
> > qcom,pvs-a node) or it may be completely different for a given SoC (e.g.
> > qcom,serial-msm8960 node). I imagine for other SoCs out there it could
> > be different depending on which eeprom the board manufacturer decides to
> > wire onto their board and how they choose to program the data.
> 
> Oh, so you'd like to infer the data format it's stored in from the
> compatible?
> 
> AFAICT, this format will be highly depending on the board itself,
> rather than on the SoC, do you think it will scale enough?
> 
> > So this is where I think the eeprom-cells and offset + length starts to
> > fall apart. It forces us to make up a bunch of different compatible
> > strings for our consumer device just so that we can parse the eeprom
> > that we decided to use for some SoC/board specific data. Instead I'd
> > like to see some framework that expresses exactly which eeprom is on my
> > board and how to interpret the bits in a way that doesn't require me to
> > keep refining the compatible string for my generic IP block.
> 
> Hmmmm, apparently you don't :)
> 
> > I worry that if we put all those details in DT we'll end up having to
> > describe individual bits like serial-number-bit-2, serial-number-bit-3,
> > etc. because sometimes these pieces of data are scattered all around the
> > eeprom and aren't contiguous or aligned on a byte boundary. It may be
> > easier to just have a way to express that this is an eeprom with this
> > specific layout and my device has data stored in there. Then the driver
> > can be told what layout it is (via compatible or some other string based
> > means if we're not using DT?) and match that up with some driver data if
> > it needs to know how to understand the bits it can read with the
> > eeprom_read() API.
> 
> I'm half convinced that the layout information will actually work for
> more complex cases, like the linked list Rob described.
> 
> If such a structure is ever to be found, it would feel wrong to have
> that in the EEPROM driver, but it would feel just as wrong to put that
> in the client driver, that would have to handle the parsing of raw
> data coming flashed by one single crazy board vendor.
> 
> Maybe we can have each cell carry a property that defines the format
> it's stored in, and match that to some parsers plugins, starting with
> the generic and trivial cases but still allowing for custom parsers to
> be defined?
> 
> Something like
> 
> eeprom@42 {
> 	compatible = "atmel,at24something";
> 	reg = <0x42>;
> 
> 	serial@0 {
> 		label = "board serial";
> 		reg = <0x0 0x10>;
> 		format = "packed";
> 	};
> 
> 	opps@10 {
> 		label = "board serial";
> 		reg = <0x10 0x10>, <0x40 0x10>, <0x80 0x10>;
> 		format = "random-vendor,opp-linked-list";
> 	};
> };
> 
> That would make eeprom_read always return the same format of data to
> the client drivers, without cripling the generic EEPROM drivers
> either.
> 

Is the goal here to make eeprom_read() figure out how to return
the next byte of data and hide the parsing logic behind the
eeprom APIs? I imagine "random-vendor,opp-linked-list" would be
handled by the eeprom driver and that would return OPPs byte by
byte across the different reg properties to the eeprom consumer?

This approach concerns me because every eeprom_read() call needs
to fit the format that the client driver is expecting. How do we
validate that? What do we do if we have a random OPP client #1
that expects to get the data from eeprom_read() with OPPs in
ascending order and random OPP client #2 that expects to get the
data from eeprom_read() with OPPs in descending order?

It feels like we're making the eeprom framework too smart without
a well defined abstraction. If we were to make it so that
eeprom_get_opps() knew what to do and parsed/populated the OPPs,
it might work. But if we're just exporting raw data across a
read/write API with some implementation specific mangling it
sounds like it's going to get messy fast. And if the API is well
defined, it would start to become rather large with many
different types of data that need to be parsed and sometimes data
that's only specific to a single SoC.

I wonder how much we could get away with this approach though. If
the eeprom driver probed and populated OPPs, made a serial number
available via the soc device, and then we made up framework(s)
for things like our thermal sensor calibration data and display
panel calibration data, I would guess that covers most of my
use-cases. The client drivers would need some sort of 'wait for
eeprom to populate things' API or we'd need to work that into the
new calibration framework.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-25  1:30                 ` Stephen Boyd
@ 2015-02-26  9:16                   ` Srinivas Kandagatla
  2015-02-26 13:21                     ` Maxime Ripard
  2015-02-26 13:18                   ` Maxime Ripard
  1 sibling, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-26  9:16 UTC (permalink / raw)
  To: Stephen Boyd, Maxime Ripard
  Cc: Rob Herring, linux-arm-kernel, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Arnd Bergmann,
	Mark Brown, Greg Kroah-Hartman



On 25/02/15 01:30, Stephen Boyd wrote:
> On 02/24, Maxime Ripard wrote:
>> On Mon, Feb 23, 2015 at 03:11:40PM -0800, Stephen Boyd wrote:
>>>>>> I would do something more simple that is just a list of keys and
>>>>>> their location like this:
>>>>>>
>>>>>> device-serial-number = <start size>;
>>>>>> key1 = <start size>;
>>>>>> key2 = <start size>;
>>>>> I'm sorry, but what's the difference?
>>>> It can describe the layout completely whether the fields are tied to a
>>>> h/w device or not.
>>>>
>>>> What I would like to see here is the entire layout described covering
>>>> both types of fields.
>>>>
>>>
>>> I was thinking the DT might be like this on the provider side:
>>>
>>>     qfprom@1000000 {
>>>        reg = <0x1000000 0x1000>;
>>>        ranges = <0 0x1000000 0x1000>;
>>>        compatible = "qcom,qfprom-msm8960"
>>>
>>>        pvs-data: pvs-data@40 {
>>>              compatible = "qcom,pvs-a";
>>>              reg = <0x40 0x20>,
>>> 	    #eeprom-cells = <0>;
>>>        };
>>>
>>>         tsens-data: tmdata@10 {
>>>              compatible = "qcom,tsens-data-msm8960";
>>>              reg = <0x10 4>, <0x16 4>;
>>> 	    #eeprom-cells = <0>;
>>>
>>>        };
>>>
>>>        serial-number: serial@50 {
>>>              compatible = "qcom,serial-msm8960";
>>>              reg = <0x50 4>, <0x60 4>;
>>> 	    #eeprom-cells = <0>;
>>>
>>>        };
>>>     };
>>
>> I'm not sure the compatible is really needed.
>>
>> A label of some sort, just like the MTD partitions do would do just
>> fine, and wouldn't have the implicit expectation that a driver will be
>> probed from that node.
>
> I wasn't aware that compatible meant driver probe. I thought
> compatible just meant some software entity can understand what
> I've described within this node. For example, compatible for
> reserved-memory nodes doesn't mean we're going to probe a device.
>
>>
>>> and then on the consumer side:
>>>
>>> 	device {
>>> 		eeproms = <&serial-number>;
>>> 		eeprom-names = "soc-rev-id";
>>> 	};
>>>
>>>
>>> This would solve a problem where the consumer device is some standard
>>> off-the-shelf IP block that needs to get some SoC specific calibration
>>> data from the eeprom. I may want to interpret the bits differently
>>> depending on which eeprom is connected to my SoC. Sometimes that data
>>> format may be the same across many variations of the SoC (e.g. the
>>> qcom,pvs-a node) or it may be completely different for a given SoC (e.g.
>>> qcom,serial-msm8960 node). I imagine for other SoCs out there it could
>>> be different depending on which eeprom the board manufacturer decides to
>>> wire onto their board and how they choose to program the data.
>>
>> Oh, so you'd like to infer the data format it's stored in from the
>> compatible?
>>
>> AFAICT, this format will be highly depending on the board itself,
>> rather than on the SoC, do you think it will scale enough?
>>
>>> So this is where I think the eeprom-cells and offset + length starts to
>>> fall apart. It forces us to make up a bunch of different compatible
>>> strings for our consumer device just so that we can parse the eeprom
>>> that we decided to use for some SoC/board specific data. Instead I'd
>>> like to see some framework that expresses exactly which eeprom is on my
>>> board and how to interpret the bits in a way that doesn't require me to
>>> keep refining the compatible string for my generic IP block.
>>
>> Hmmmm, apparently you don't :)
>>
>>> I worry that if we put all those details in DT we'll end up having to
>>> describe individual bits like serial-number-bit-2, serial-number-bit-3,
>>> etc. because sometimes these pieces of data are scattered all around the
>>> eeprom and aren't contiguous or aligned on a byte boundary. It may be
>>> easier to just have a way to express that this is an eeprom with this
>>> specific layout and my device has data stored in there. Then the driver
>>> can be told what layout it is (via compatible or some other string based
>>> means if we're not using DT?) and match that up with some driver data if
>>> it needs to know how to understand the bits it can read with the
>>> eeprom_read() API.
>>
>> I'm half convinced that the layout information will actually work for
>> more complex cases, like the linked list Rob described.
>>
>> If such a structure is ever to be found, it would feel wrong to have
>> that in the EEPROM driver, but it would feel just as wrong to put that
>> in the client driver, that would have to handle the parsing of raw
>> data coming flashed by one single crazy board vendor.
>>
>> Maybe we can have each cell carry a property that defines the format
>> it's stored in, and match that to some parsers plugins, starting with
>> the generic and trivial cases but still allowing for custom parsers to
>> be defined?
>>
>> Something like
>>
>> eeprom@42 {
>> 	compatible = "atmel,at24something";
>> 	reg = <0x42>;
>>
>> 	serial@0 {
>> 		label = "board serial";
>> 		reg = <0x0 0x10>;
>> 		format = "packed";
>> 	};
>>
>> 	opps@10 {
>> 		label = "board serial";
>> 		reg = <0x10 0x10>, <0x40 0x10>, <0x80 0x10>;
>> 		format = "random-vendor,opp-linked-list";
>> 	};
>> };
>>
>> That would make eeprom_read always return the same format of data to
>> the client drivers, without cripling the generic EEPROM drivers
>> either.
>>
>
> Is the goal here to make eeprom_read() figure out how to return
> the next byte of data and hide the parsing logic behind the
> eeprom APIs? I imagine "random-vendor,opp-linked-list" would be
> handled by the eeprom driver and that would return OPPs byte by
> byte across the different reg properties to the eeprom consumer?
>
> This approach concerns me because every eeprom_read() call needs
> to fit the format that the client driver is expecting. How do we
> validate that? What do we do if we have a random OPP client #1
> that expects to get the data from eeprom_read() with OPPs in
> ascending order and random OPP client #2 that expects to get the
> data from eeprom_read() with OPPs in descending order?
>
> It feels like we're making the eeprom framework too smart without
> a well defined abstraction. If we were to make it so that
> eeprom_get_opps() knew what to do and parsed/populated the OPPs,
> it might work. But if we're just exporting raw data across a
> read/write API with some implementation specific mangling it
> sounds like it's going to get messy fast. And if the API is well
> defined, it would start to become rather large with many
> different types of data that need to be parsed and sometimes data
> that's only specific to a single SoC.
>
> I wonder how much we could get away with this approach though. If
> the eeprom driver probed and populated OPPs, made a serial number
> available via the soc device, and then we made up framework(s)
> for things like our thermal sensor calibration data and display
> panel calibration data, I would guess that covers most of my
> use-cases. The client drivers would need some sort of 'wait for
> eeprom to populate things' API or we'd need to work that into the
> new calibration framework.
>
I think we are making simple eeprom framework too smart which will break 
in future.

IMHO, Anything on top of eeprom interface that interprets the data 
should not go into the eeprom framework itself, it can either live some 
parsers/SOC specific drivers/interfaces.

As Stephen pointed out earlier lets start with something like this, 
which would provide a better abstraction to the discussed use cases like 
serial-number and packed data in eeprom.

    qfprom@1000000 {
       reg = <0x1000000 0x1000>;
       ranges = <0 0x1000000 0x1000>;
       compatible = "qcom,qfprom-msm8960"

       pvs-data: pvs-data@40 {
             compatible = "qcom,pvs-a";
             reg = <0x40 0x20>,
       };

        tsens-data: tmdata@10 {
             reg = <0x10 40>;
       };

       serial-number: serial@50 {
             compatible = "qcom,serial-msm8960";
             reg = <0x50 4>, <0x60 4>;
       };

    };

and then on the consumer side:

	device {
		eeproms = <&serial-number>;
		eeprom-names = "soc-rev-id";
	};
	
driver side:

	eeprom_get_cell()
	eeprom_read();



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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-25  1:30                 ` Stephen Boyd
  2015-02-26  9:16                   ` Srinivas Kandagatla
@ 2015-02-26 13:18                   ` Maxime Ripard
  1 sibling, 0 replies; 153+ messages in thread
From: Maxime Ripard @ 2015-02-26 13:18 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Rob Herring, Srinivas Kandagatla, linux-arm-kernel, Rob Herring,
	Pawel Moll, Kumar Gala, linux-api, linux-kernel, devicetree,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

[-- Attachment #1: Type: text/plain, Size: 8091 bytes --]

On Tue, Feb 24, 2015 at 05:30:49PM -0800, Stephen Boyd wrote:
> On 02/24, Maxime Ripard wrote:
> > On Mon, Feb 23, 2015 at 03:11:40PM -0800, Stephen Boyd wrote:
> > > >>> I would do something more simple that is just a list of keys and
> > > >>> their location like this:
> > > >>>
> > > >>> device-serial-number = <start size>;
> > > >>> key1 = <start size>;
> > > >>> key2 = <start size>;
> > > >> I'm sorry, but what's the difference?
> > > > It can describe the layout completely whether the fields are tied to a
> > > > h/w device or not.
> > > >
> > > > What I would like to see here is the entire layout described covering
> > > > both types of fields.
> > > >
> > > 
> > > I was thinking the DT might be like this on the provider side:
> > > 
> > >    qfprom@1000000 {
> > >       reg = <0x1000000 0x1000>;
> > >       ranges = <0 0x1000000 0x1000>;
> > >       compatible = "qcom,qfprom-msm8960"
> > > 
> > >       pvs-data: pvs-data@40 {
> > >             compatible = "qcom,pvs-a";
> > >             reg = <0x40 0x20>,
> > > 	    #eeprom-cells = <0>;
> > >       };
> > > 
> > >        tsens-data: tmdata@10 {
> > >             compatible = "qcom,tsens-data-msm8960";
> > >             reg = <0x10 4>, <0x16 4>;
> > > 	    #eeprom-cells = <0>;
> > > 
> > >       };
> > > 
> > >       serial-number: serial@50 {
> > >             compatible = "qcom,serial-msm8960";
> > >             reg = <0x50 4>, <0x60 4>;
> > > 	    #eeprom-cells = <0>;
> > > 
> > >       };
> > >    };
> > 
> > I'm not sure the compatible is really needed.
> > 
> > A label of some sort, just like the MTD partitions do would do just
> > fine, and wouldn't have the implicit expectation that a driver will be
> > probed from that node.
> 
> I wasn't aware that compatible meant driver probe. I thought
> compatible just meant some software entity can understand what
> I've described within this node. For example, compatible for
> reserved-memory nodes doesn't mean we're going to probe a device.

Maybe it's just me then :)

> > > and then on the consumer side:
> > > 
> > > 	device {
> > > 		eeproms = <&serial-number>;
> > > 		eeprom-names = "soc-rev-id";
> > > 	};
> > > 
> > > 
> > > This would solve a problem where the consumer device is some standard
> > > off-the-shelf IP block that needs to get some SoC specific calibration
> > > data from the eeprom. I may want to interpret the bits differently
> > > depending on which eeprom is connected to my SoC. Sometimes that data
> > > format may be the same across many variations of the SoC (e.g. the
> > > qcom,pvs-a node) or it may be completely different for a given SoC (e.g.
> > > qcom,serial-msm8960 node). I imagine for other SoCs out there it could
> > > be different depending on which eeprom the board manufacturer decides to
> > > wire onto their board and how they choose to program the data.
> > 
> > Oh, so you'd like to infer the data format it's stored in from the
> > compatible?
> > 
> > AFAICT, this format will be highly depending on the board itself,
> > rather than on the SoC, do you think it will scale enough?
> > 
> > > So this is where I think the eeprom-cells and offset + length starts to
> > > fall apart. It forces us to make up a bunch of different compatible
> > > strings for our consumer device just so that we can parse the eeprom
> > > that we decided to use for some SoC/board specific data. Instead I'd
> > > like to see some framework that expresses exactly which eeprom is on my
> > > board and how to interpret the bits in a way that doesn't require me to
> > > keep refining the compatible string for my generic IP block.
> > 
> > Hmmmm, apparently you don't :)
> > 
> > > I worry that if we put all those details in DT we'll end up having to
> > > describe individual bits like serial-number-bit-2, serial-number-bit-3,
> > > etc. because sometimes these pieces of data are scattered all around the
> > > eeprom and aren't contiguous or aligned on a byte boundary. It may be
> > > easier to just have a way to express that this is an eeprom with this
> > > specific layout and my device has data stored in there. Then the driver
> > > can be told what layout it is (via compatible or some other string based
> > > means if we're not using DT?) and match that up with some driver data if
> > > it needs to know how to understand the bits it can read with the
> > > eeprom_read() API.
> > 
> > I'm half convinced that the layout information will actually work for
> > more complex cases, like the linked list Rob described.
> > 
> > If such a structure is ever to be found, it would feel wrong to have
> > that in the EEPROM driver, but it would feel just as wrong to put that
> > in the client driver, that would have to handle the parsing of raw
> > data coming flashed by one single crazy board vendor.
> > 
> > Maybe we can have each cell carry a property that defines the format
> > it's stored in, and match that to some parsers plugins, starting with
> > the generic and trivial cases but still allowing for custom parsers to
> > be defined?
> > 
> > Something like
> > 
> > eeprom@42 {
> > 	compatible = "atmel,at24something";
> > 	reg = <0x42>;
> > 
> > 	serial@0 {
> > 		label = "board serial";
> > 		reg = <0x0 0x10>;
> > 		format = "packed";
> > 	};
> > 
> > 	opps@10 {
> > 		label = "board serial";
> > 		reg = <0x10 0x10>, <0x40 0x10>, <0x80 0x10>;
> > 		format = "random-vendor,opp-linked-list";
> > 	};
> > };
> > 
> > That would make eeprom_read always return the same format of data to
> > the client drivers, without cripling the generic EEPROM drivers
> > either.
> > 
> 
> Is the goal here to make eeprom_read() figure out how to return
> the next byte of data and hide the parsing logic behind the
> eeprom APIs? I imagine "random-vendor,opp-linked-list" would be
> handled by the eeprom driver and that would return OPPs byte by
> byte across the different reg properties to the eeprom consumer?
> 
> This approach concerns me because every eeprom_read() call needs
> to fit the format that the client driver is expecting. How do we
> validate that? What do we do if we have a random OPP client #1
> that expects to get the data from eeprom_read() with OPPs in
> ascending order and random OPP client #2 that expects to get the
> data from eeprom_read() with OPPs in descending order?

Without going that far, we could have the little/big endian topic here
as well.

But I guess it all boils down to wether we should support only the
trivial cases, or not. Generally speaking, and not just about the OPPs
above, we could really well end up with a "generic" (not necessarily a
really generic driver, but also IPs used across several SoCs, like the
Mentor/Synopsis ones) driver, requiring to read some data from an
EEPROM for some reason.

Where would you fit the raw data parsing code? In that generic
driver. It would end up being just as messy, if not more.

So yeah, it really depends on wether we just want to support reading a
contiguous block of data, or if we want to cover all cases. And in
that case, we should indeed support the cases you mentioned above.

> It feels like we're making the eeprom framework too smart without
> a well defined abstraction. If we were to make it so that
> eeprom_get_opps() knew what to do and parsed/populated the OPPs,
> it might work. But if we're just exporting raw data across a
> read/write API with some implementation specific mangling it
> sounds like it's going to get messy fast. And if the API is well
> defined, it would start to become rather large with many
> different types of data that need to be parsed and sometimes data
> that's only specific to a single SoC.

Or even a single board. Most of the drivers are in that case. That
doesn't mean that the frameworks should just ignore them entirely
because of that fact.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-26  9:16                   ` Srinivas Kandagatla
@ 2015-02-26 13:21                     ` Maxime Ripard
  2015-02-26 14:56                       ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Maxime Ripard @ 2015-02-26 13:21 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Stephen Boyd, Rob Herring, linux-arm-kernel, Rob Herring,
	Pawel Moll, Kumar Gala, linux-api, linux-kernel, devicetree,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

[-- Attachment #1: Type: text/plain, Size: 1576 bytes --]

On Thu, Feb 26, 2015 at 09:16:27AM +0000, Srinivas Kandagatla wrote:
> I think we are making simple eeprom framework too smart which will
> break in future.
> 
> IMHO, Anything on top of eeprom interface that interprets the data should
> not go into the eeprom framework itself, it can either live some parsers/SOC
> specific drivers/interfaces.

True, but that doesn't mean that this parser support can't be built
within the framework itself.

> As Stephen pointed out earlier lets start with something like this, which
> would provide a better abstraction to the discussed use cases like
> serial-number and packed data in eeprom.
> 
>    qfprom@1000000 {
>       reg = <0x1000000 0x1000>;
>       ranges = <0 0x1000000 0x1000>;
>       compatible = "qcom,qfprom-msm8960"
> 
>       pvs-data: pvs-data@40 {
>             compatible = "qcom,pvs-a";
>             reg = <0x40 0x20>,
>       };
> 
>        tsens-data: tmdata@10 {
>             reg = <0x10 40>;
>       };
> 
>       serial-number: serial@50 {
>             compatible = "qcom,serial-msm8960";
>             reg = <0x50 4>, <0x60 4>;
>       };
> 
>    };

And I'm sorry, but I still don't get why the compatibles are needed
here.

> and then on the consumer side:
> 
> 	device {
> 		eeproms = <&serial-number>;
> 		eeprom-names = "soc-rev-id";
> 	};
> 	
> driver side:
> 
> 	eeprom_get_cell()
> 	eeprom_read();

Looks good otherwise.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
  2015-02-26 13:21                     ` Maxime Ripard
@ 2015-02-26 14:56                       ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-02-26 14:56 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Stephen Boyd, Rob Herring, linux-arm-kernel, Rob Herring,
	Pawel Moll, Kumar Gala, linux-api, linux-kernel, devicetree,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman



On 26/02/15 13:21, Maxime Ripard wrote:
> On Thu, Feb 26, 2015 at 09:16:27AM +0000, Srinivas Kandagatla wrote:
>> I think we are making simple eeprom framework too smart which will
>> break in future.
>>
>> IMHO, Anything on top of eeprom interface that interprets the data should
>> not go into the eeprom framework itself, it can either live some parsers/SOC
>> specific drivers/interfaces.
>
> True, but that doesn't mean that this parser support can't be built
> within the framework itself.
I was more of thinking parsers/interpreters as a layer on top of this 
framework. Allowing the simplest users direct access to framework. Also 
just eeprom_read() apis would not cater for all the parsers and I think 
it would be very difficult to come up with abstracted consumer apis for 
all the parsers which could be iterator or link-lists parsers or 
something very different.

>
>> As Stephen pointed out earlier lets start with something like this, which
>> would provide a better abstraction to the discussed use cases like
>> serial-number and packed data in eeprom.
>>
>>     qfprom@1000000 {
>>        reg = <0x1000000 0x1000>;
>>        ranges = <0 0x1000000 0x1000>;
>>        compatible = "qcom,qfprom-msm8960"
>>
>>        pvs-data: pvs-data@40 {
>>              compatible = "qcom,pvs-a";
>>              reg = <0x40 0x20>,
>>        };
>>
>>         tsens-data: tmdata@10 {
>>              reg = <0x10 40>;
>>        };
>>
>>        serial-number: serial@50 {
>>              compatible = "qcom,serial-msm8960";
>>              reg = <0x50 4>, <0x60 4>;
>>        };
>>
>>     };
>
> And I'm sorry, but I still don't get why the compatibles are needed
> here.
This is an optional property, only purpose of this would be to serve as 
parser/soc-specific identifier.

>
>> and then on the consumer side:
>>
>> 	device {
>> 		eeproms = <&serial-number>;
>> 		eeprom-names = "soc-rev-id";
>> 	};
>> 	
>> driver side:
>>
>> 	eeprom_get_cell()
>> 	eeprom_read();
>
> Looks good otherwise.
thanks
--srini
>
> Maxime
>

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

* [PATCH v1 0/6] Add simple EEPROM Framework via regmap.
  2015-02-19 17:07 [RFC PATCH 0/3] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                   ` (2 preceding siblings ...)
  2015-02-19 17:08 ` [RFC PATCH 3/3] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
@ 2015-03-05  9:44 ` Srinivas Kandagatla
  2015-03-05  9:45   ` [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
                     ` (6 more replies)
  3 siblings, 7 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-05  9:44 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, andrew, Srinivas Kandagatla

Thankyou all for providing inputs and comments on RFC patchset.
Here is the v1 of the patchset addressing all the issues raised as
part of RFC review.

This patchset adds a new simple EEPROM framework to kernel.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.
    
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
    
This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
    
Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

patch 1-4 Introduces the EEPROM framework.
Patch 5 migrates an existing driver to eeprom framework.
Patch 6 Adds Qualcomm specific qfprom driver.

Its also possible to migrate other eeprom drivers to this framework.
Patch 6 can also be made a generic mmio-eeprom driver.

Providers APIs:
	eeprom_register/unregister();

Consumers APIs:
	eeprom_cell_get()/of_eeprom_cell_get()/of_eeprom_cell_get_byname();
	eeprom_cell_read()/eeprom_cell_write();

Device Tree:

	/* Provider */
	qfprom: qfprom@00700000 {
		compatible 	= "qcom,qfprom";
		reg		= <0x00700000 0x1000>;
		...

		/* Data cells */
		tsens_calibration: calib@404 {
			reg = <0x404 0x10>;
		};

		serial_number: sn {
			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;

		};
		...
	};
	
	/* Consumer node */
	tsens: tsens {
		...
		eeproms = <&tsens_calibration>;
		eeprom-names = "calib";
		...
	};

userspace interface:

hexdump /sys/class/eeprom/qfprom0/eeprom
                                                                                                                                                                                                                  
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
0000000 0000 0000 0000 0000 0000 0000 0000 0000
...
*
0001000


Changes since RFC(https://lkml.org/lkml/2015/2/19/307)
 * Fix documentation and error checks in read/write spotted by Andrew Lunn
 * Kconfig fix suggested by Stephen Boyd.
 * Add module owner suggested by Stephen Boyd and others.
 * Fix unsafe handling of eeprom in unregister spotted by Russell and Mark Brown.
 * seperate bindings patch as suggested by Rob.
 * Add MAINTAINERS as suggested by Rob.
 * Added support to allow reading eeprom for things like serial number which
 * canbe scatters across.
 * Added eeprom data using reg property suggested by Sascha and Stephen.
 * Added non-DT support.
 * Move kerneldoc to the src files spotted by Mark Brown.
 * Remove local list and do eeprom lookup by using class_find_device()


Thanks,
srini


Maxime Ripard (1):
  eeprom: sunxi: Move the SID driver to the eeprom framework

Srinivas Kandagatla (5):
  eeprom: Add a simple EEPROM framework for eeprom providers
  eeprom: Add a simple EEPROM framework for eeprom consumers
  eeprom: Add bindings for simple eeprom framework
  eeprom: qfprom: Add Qualcomm QFPROM support.
  eeprom: Add to MAINTAINERS for eeprom framework

 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 -
 .../devicetree/bindings/eeprom/eeprom.txt          |  70 +++
 MAINTAINERS                                        |   9 +
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/eeprom/Kconfig                             |  38 ++
 drivers/eeprom/Makefile                            |  11 +
 drivers/eeprom/core.c                              | 506 +++++++++++++++++++++
 drivers/eeprom/eeprom-sunxi-sid.c                  | 129 ++++++
 drivers/eeprom/qfprom.c                            |  74 +++
 drivers/misc/eeprom/Kconfig                        |  13 -
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 -------
 include/linux/eeprom-consumer.h                    |  67 +++
 include/linux/eeprom-provider.h                    |  47 ++
 15 files changed, 954 insertions(+), 192 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
 create mode 100644 drivers/eeprom/Kconfig
 create mode 100644 drivers/eeprom/Makefile
 create mode 100644 drivers/eeprom/core.c
 create mode 100644 drivers/eeprom/eeprom-sunxi-sid.c
 create mode 100644 drivers/eeprom/qfprom.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
 create mode 100644 include/linux/eeprom-consumer.h
 create mode 100644 include/linux/eeprom-provider.h

-- 
1.9.1


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

* [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-05  9:44 ` [PATCH v1 0/6] Add simple EEPROM Framework via regmap Srinivas Kandagatla
@ 2015-03-05  9:45   ` Srinivas Kandagatla
  2015-03-05 10:23     ` Paul Bolle
  2015-03-07 15:00     ` Mark Brown
  2015-03-05  9:45   ` [PATCH v1 2/6] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
                     ` (5 subsequent siblings)
  6 siblings, 2 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-05  9:45 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, andrew, Arnd Bergmann,
	broonie, Greg Kroah-Hartman, Srinivas Kandagatla

This patch adds just providers part of the framework just to enable easy
review.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.

Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/Kconfig                 |   2 +
 drivers/Makefile                |   1 +
 drivers/eeprom/Kconfig          |  20 ++++
 drivers/eeprom/Makefile         |   9 ++
 drivers/eeprom/core.c           | 208 ++++++++++++++++++++++++++++++++++++++++
 include/linux/eeprom-provider.h |  47 +++++++++
 6 files changed, 287 insertions(+)
 create mode 100644 drivers/eeprom/Kconfig
 create mode 100644 drivers/eeprom/Makefile
 create mode 100644 drivers/eeprom/core.c
 create mode 100644 include/linux/eeprom-provider.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index c70d6e4..d7afc82 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
 
 source "drivers/android/Kconfig"
 
+source "drivers/eeprom/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 527a6da..57eb5b0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= coresight/
 obj-$(CONFIG_ANDROID)		+= android/
+obj-$(CONFIG_EEPROM)		+= eeprom/
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
new file mode 100644
index 0000000..d00f7d2
--- /dev/null
+++ b/drivers/eeprom/Kconfig
@@ -0,0 +1,20 @@
+menuconfig EEPROM
+	bool "EEPROM Support"
+	depends on OF
+	select REGMAP
+	help
+	  Support for EEPROM alike devices.
+
+	  This framework is designed to provide a generic interface to EEPROM
+	  from both the Linux Kernel and the userspace.
+
+	  If unsure, say no.
+
+if EEPROM
+
+config EEPROM_DEBUG
+	bool "EEPROM debug support"
+	help
+	  Say yes here to enable debugging support.
+
+endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
new file mode 100644
index 0000000..e130079
--- /dev/null
+++ b/drivers/eeprom/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for eeprom drivers.
+#
+
+ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
+
+obj-$(CONFIG_EEPROM)		+= core.o
+
+# Devices
diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
new file mode 100644
index 0000000..243e466
--- /dev/null
+++ b/drivers/eeprom/core.c
@@ -0,0 +1,208 @@
+/*
+ * EEPROM framework core.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+struct eeprom_device {
+	struct regmap		*regmap;
+	int			stride;
+	size_t			size;
+
+	struct module		*owner;
+	struct device		dev;
+	int			id;
+	atomic_t		users;
+};
+
+static DEFINE_MUTEX(eeprom_mutex);
+static DEFINE_IDA(eeprom_ida);
+
+#define to_eeprom(d) container_of(d, struct eeprom_device, dev)
+
+static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
+				    struct bin_attribute *attr,
+				    char *buf, loff_t offset, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct eeprom_device *eeprom = to_eeprom(dev);
+	int rc;
+
+	if (offset > eeprom->size)
+		return -EINVAL;
+
+	if (offset + count > eeprom->size)
+		count = eeprom->size - offset;
+
+	rc = regmap_bulk_read(eeprom->regmap, offset,
+			      buf, count/eeprom->stride);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count - count % eeprom->stride;
+}
+
+static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *attr,
+				     char *buf, loff_t offset, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct eeprom_device *eeprom = to_eeprom(dev);
+	int rc;
+
+	if (offset > eeprom->size)
+		return -EINVAL;
+
+	if (offset + count > eeprom->size)
+		count = eeprom->size - offset;
+
+	rc = regmap_bulk_write(eeprom->regmap, offset,
+			       buf, count/eeprom->stride);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count - count % eeprom->stride;
+}
+
+static struct bin_attribute bin_attr_eeprom = {
+	.attr	= {
+		.name	= "eeprom",
+		.mode	= S_IWUSR | S_IRUGO,
+	},
+	.read	= bin_attr_eeprom_read,
+	.write	= bin_attr_eeprom_write,
+};
+
+static struct bin_attribute *eeprom_bin_attributes[] = {
+	&bin_attr_eeprom,
+	NULL,
+};
+
+static const struct attribute_group eeprom_bin_group = {
+	.bin_attrs	= eeprom_bin_attributes,
+};
+
+static const struct attribute_group *eeprom_dev_groups[] = {
+	&eeprom_bin_group,
+	NULL,
+};
+
+static void eeprom_release(struct device *dev)
+{
+	kfree(to_eeprom(dev));
+}
+
+static struct class eeprom_class = {
+	.name		= "eeprom",
+	.dev_groups	= eeprom_dev_groups,
+	.dev_release	= eeprom_release,
+};
+
+/**
+ * eeprom_register(): Register a eeprom device for given eeprom.
+ * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
+ *
+ * @eeprom: eeprom device that needs to be created
+ *
+ * The return value will be an error code on error or a zero on success.
+ * The eeprom_device and sysfs entery will be freed by the eeprom_unregister().
+ */
+
+struct eeprom_device *eeprom_register(struct eeprom_config *config)
+{
+	struct eeprom_device *eeprom;
+	int rval;
+
+	if (!config->regmap || !config->size) {
+		dev_err(config->dev, "Regmap not found\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL);
+	if (!eeprom)
+		return ERR_PTR(-ENOMEM);
+
+	eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
+	if (eeprom->id < 0)
+		return ERR_PTR(eeprom->id);
+
+	eeprom->owner = config->owner;
+	eeprom->regmap = config->regmap;
+	eeprom->stride = config->stride;
+	eeprom->size = config->size;
+	eeprom->dev.class = &eeprom_class;
+	eeprom->dev.parent = config->dev;
+	eeprom->dev.of_node = config->dev ? config->dev->of_node : NULL;
+	dev_set_name(&eeprom->dev, "%s%d",
+		     config->name ? : "eeprom", config->id);
+
+	device_initialize(&eeprom->dev);
+
+	dev_dbg(&eeprom->dev, "Registering eeprom device %s\n",
+		dev_name(&eeprom->dev));
+
+	rval = device_add(&eeprom->dev);
+	if (rval)
+		return ERR_PTR(rval);
+
+	return eeprom;
+}
+EXPORT_SYMBOL(eeprom_register);
+
+/**
+ * eeprom_unregister(): Unregister previously registered eeprom device
+ *
+ * @eeprom: Pointer to previously registered eeprom device.
+ *
+ * The return value will be an non zero on error or a zero on success.
+ */
+int eeprom_unregister(struct eeprom_device *eeprom)
+{
+	mutex_lock(&eeprom_mutex);
+	if (atomic_read(&eeprom->users)) {
+		mutex_unlock(&eeprom_mutex);
+		return -EBUSY;
+	}
+
+	device_del(&eeprom->dev);
+	mutex_unlock(&eeprom_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(eeprom_unregister);
+
+static int eeprom_init(void)
+{
+	return class_register(&eeprom_class);
+}
+
+static void eeprom_exit(void)
+{
+	class_unregister(&eeprom_class);
+}
+
+subsys_initcall(eeprom_init);
+module_exit(eeprom_exit);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("EEPROM Driver Core");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
new file mode 100644
index 0000000..51dc654
--- /dev/null
+++ b/include/linux/eeprom-provider.h
@@ -0,0 +1,47 @@
+/*
+ * EEPROM framework provider.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_PROVIDER_H
+#define _LINUX_EEPROM_PROVIDER_H
+
+#include <linux/regmap.h>
+
+struct eeprom_device;
+
+struct eeprom_config {
+	struct device		*dev;
+	struct regmap		*regmap;
+	const char		*name;
+	int			id;
+	int			stride;
+	size_t			size;
+	struct module		*owner;
+};
+
+#ifdef CONFIG_EEPROM
+
+struct eeprom_device *eeprom_register(struct eeprom_config *cfg);
+int eeprom_unregister(struct eeprom_device *eeprom);
+
+#else
+
+static inline struct eeprom_device *eeprom_register(struct eeprom_config *cfg)
+{
+	return NULL;
+}
+static inline int eeprom_unregister(struct eeprom_device *eeprom)
+{
+	return -ENOSYS;
+}
+
+#endif /* CONFIG_EEPROM */
+
+#endif  /* ifndef _LINUX_EEPROM_PROVIDER_H */
-- 
1.9.1


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

* [PATCH v1 2/6] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-03-05  9:44 ` [PATCH v1 0/6] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  2015-03-05  9:45   ` [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
@ 2015-03-05  9:45   ` Srinivas Kandagatla
  2015-03-05  9:46   ` [PATCH v1 3/6] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-05  9:45 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, andrew, Arnd Bergmann,
	broonie, Greg Kroah-Hartman, Srinivas Kandagatla

This patch adds just consumers part of the framework just to enable easy
review.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.

Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of the framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/core.c           | 298 ++++++++++++++++++++++++++++++++++++++++
 include/linux/eeprom-consumer.h |  67 +++++++++
 2 files changed, 365 insertions(+)
 create mode 100644 include/linux/eeprom-consumer.h

diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
index 243e466..75ae39c 100644
--- a/drivers/eeprom/core.c
+++ b/drivers/eeprom/core.c
@@ -11,6 +11,7 @@
 
 #include <linux/device.h>
 #include <linux/eeprom-provider.h>
+#include <linux/eeprom-consumer.h>
 #include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/idr.h>
@@ -31,6 +32,13 @@ struct eeprom_device {
 	atomic_t		users;
 };
 
+struct eeprom_cell {
+	struct eeprom_device *eeprom;
+	int nblocks;
+	int size;
+	struct eeprom_block blocks[0];
+};
+
 static DEFINE_MUTEX(eeprom_mutex);
 static DEFINE_IDA(eeprom_ida);
 
@@ -116,6 +124,37 @@ static struct class eeprom_class = {
 	.dev_release	= eeprom_release,
 };
 
+static int of_eeprom_match(struct device *dev, const void *eeprom_np)
+{
+	return dev->of_node == eeprom_np;
+}
+
+static struct eeprom_device *of_eeprom_find(struct device_node *eeprom_np)
+{
+	struct device *d;
+
+	if (!eeprom_np)
+		return NULL;
+
+	d = class_find_device(&eeprom_class, NULL, eeprom_np, of_eeprom_match);
+
+	return d ? to_eeprom(d) : NULL;
+}
+
+static int eeprom_match(struct device *dev, const void *data)
+{
+	return !strcmp(dev_name(dev), (const char *)data);
+}
+
+static struct eeprom_device *eeprom_find(const char *name)
+{
+	struct device *d;
+
+	d = class_find_device(&eeprom_class, NULL, (void *)name, eeprom_match);
+
+	return d ? to_eeprom(d) : NULL;
+}
+
 /**
  * eeprom_register(): Register a eeprom device for given eeprom.
  * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
@@ -189,6 +228,265 @@ int eeprom_unregister(struct eeprom_device *eeprom)
 }
 EXPORT_SYMBOL(eeprom_unregister);
 
+static struct eeprom_cell *eeprom_cell_sanity_check(struct eeprom_cell *cell)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	int i;
+
+	/* byte aligned, no need to check for stride sanity */
+	if (eeprom->stride == 1)
+		return cell;
+
+	for (i = 0; i < cell->nblocks; i++) {
+		if (!IS_ALIGNED(cell->blocks[i].offset, eeprom->stride) ||
+		    !IS_ALIGNED(cell->blocks[i].count, eeprom->stride)) {
+			dev_err(&eeprom->dev,
+				"cell unaligned to eeprom stride %d\n",
+				eeprom->stride);
+			atomic_dec(&eeprom->users);
+			module_put(eeprom->owner);
+			kfree(cell);
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
+	return cell;
+}
+
+/**
+ * eeprom_cell_get(): Get eeprom cell of device form a given eeprom name
+ * and blocks.
+ *
+ * @ename: eeprom device name that needs to be looked-up.
+ * @blocks: eeprom blocks containing offset and length information.
+ * @nblocks: number of eeprom blocks.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks)
+{
+	struct eeprom_cell *cell;
+	struct eeprom_device *eeprom = NULL;
+	int i;
+
+	mutex_lock(&eeprom_mutex);
+	eeprom = eeprom_find(ename);
+	if (!eeprom) {
+		mutex_unlock(&eeprom_mutex);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+	atomic_inc(&eeprom->users);
+
+	if (!try_module_get(eeprom->owner)) {
+		dev_err(&eeprom->dev,
+			"could not increase module refcount for cell %s\n",
+			ename);
+			mutex_unlock(&eeprom_mutex);
+		return ERR_PTR(-EINVAL);
+	}
+	mutex_unlock(&eeprom_mutex);
+
+	cell = kzalloc(sizeof(*cell) + nblocks * sizeof(*blocks), GFP_KERNEL);
+	if (!cell)
+		return ERR_PTR(-ENOMEM);
+
+	memcpy(cell->blocks, blocks, nblocks * sizeof(*blocks));
+	cell->nblocks = nblocks;
+	cell->eeprom = eeprom;
+	cell->size = 0;
+
+	for (i = 0; i < nblocks; i++)
+		cell->size += blocks[i].count;
+
+	return eeprom_cell_sanity_check(cell);
+}
+EXPORT_SYMBOL(eeprom_cell_get);
+
+/**
+ * of_eeprom_cell_get(): Get eeprom cell of device form a given index
+ *
+ * @dev: Device that will be interacted with
+ * @index: eeprom index in eeproms property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *of_eeprom_cell_get(struct device *dev, int index)
+{
+	struct device_node *cell_np;
+	struct eeprom_cell *cell;
+	struct eeprom_device *eeprom = NULL;
+	int i, nblocks;
+	struct property *prop;
+	const __be32 *vp;
+	u32 pv;
+
+	if (!dev || !dev->of_node)
+		return ERR_PTR(-EINVAL);
+
+	cell_np = of_parse_phandle(dev->of_node, "eeproms", index);
+	if (!cell_np)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	mutex_lock(&eeprom_mutex);
+	eeprom = of_eeprom_find(cell_np->parent);
+	if (!eeprom) {
+		mutex_unlock(&eeprom_mutex);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	atomic_inc(&eeprom->users);
+
+	if (!try_module_get(eeprom->owner)) {
+		dev_err(&eeprom->dev,
+			"could not increase module refcount for cell %d\n",
+			index);
+			mutex_unlock(&eeprom_mutex);
+		return ERR_PTR(-EINVAL);
+	}
+	mutex_unlock(&eeprom_mutex);
+
+	nblocks = of_property_count_u32_elems(cell_np, "reg") / 2;
+
+	cell = kzalloc(sizeof(*cell) + nblocks * sizeof(struct eeprom_block),
+		       GFP_KERNEL);
+	cell->nblocks = nblocks;
+	cell->eeprom = eeprom;
+	cell->size = 0;
+	i = 0;
+
+	of_property_for_each_u32(cell_np, "reg", prop, vp, pv) {
+		cell->blocks[i].offset = pv;
+		vp = of_prop_next_u32(prop, vp, &pv);
+		cell->blocks[i].count = pv;
+		cell->size += pv;
+		i++;
+	}
+
+	return eeprom_cell_sanity_check(cell);
+}
+EXPORT_SYMBOL(of_eeprom_cell_get);
+
+/**
+ * of_eeprom_cell_get_byname(): Get eeprom cell of device form a given name
+ *
+ * @dev: Device that will be interacted with
+ * @name: eeprom name in eeprom-names property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+					      const char *id)
+{
+	int index = 0;
+
+	if (!dev || !dev->of_node)
+		return ERR_PTR(-EINVAL);
+
+	if (id)
+		index = of_property_match_string(dev->of_node,
+						 "eeprom-names",
+						 id);
+	return of_eeprom_cell_get(dev, index);
+
+}
+EXPORT_SYMBOL(of_eeprom_cell_get_byname);
+
+/**
+ * eeprom_cell_put(): Release previously allocated eeprom cell.
+ *
+ * @cell: Previously allocated eeprom cell by eeprom_cell_get()
+ * or of_eeprom_cell_get() or of_eeprom_cell_get_byname().
+ */
+void eeprom_cell_put(struct eeprom_cell *cell)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+
+	atomic_dec(&eeprom->users);
+	module_put(eeprom->owner);
+	kfree(cell);
+}
+EXPORT_SYMBOL(eeprom_cell_put);
+
+/**
+ * eeprom_cell_read(): Read a given eeprom cell
+ *
+ * @cell: eeprom cell to be read.
+ * @len: pointer to length of cell which will be populated on successful read.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a char * bufffer.  The buffer should be freed by the consumer with a
+ * kfree().
+ */
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	char *buf;
+	int rc, i, offset = 0;
+
+	if (!eeprom || !eeprom->regmap)
+		return ERR_PTR(-EINVAL);
+
+	buf = kzalloc(cell->size, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < cell->nblocks; i++) {
+		rc = regmap_bulk_read(eeprom->regmap, cell->blocks[i].offset,
+				      buf + offset,
+				      cell->blocks[i].count);
+
+		if (IS_ERR_VALUE(rc)) {
+			kfree(buf);
+			return ERR_PTR(rc);
+		}
+		offset += cell->blocks[i].count;
+	}
+
+	*len = cell->size;
+
+	return buf;
+}
+EXPORT_SYMBOL(eeprom_cell_read);
+
+/**
+ * eeprom_cell_write(): Write to a given eeprom cell
+ *
+ * @cell: eeprom cell to be written.
+ * @buf: Buffer to be written.
+ * @len: length of buffer to be written to eeprom cell.
+ *
+ * The return value will be an non zero on error or a zero on successful write.
+ */
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	int i, rc, offset = 0;
+
+	if (!eeprom || !eeprom->regmap || len != cell->size)
+		return -EINVAL;
+
+	for (i = 0; i < cell->nblocks; i++) {
+		rc = regmap_bulk_write(eeprom->regmap, cell->blocks[i].offset,
+				 buf + offset,
+				 cell->blocks[i].count);
+
+		if (IS_ERR_VALUE(rc))
+			return rc;
+
+		offset += cell->blocks[i].count;
+	}
+
+	return len;
+}
+EXPORT_SYMBOL(eeprom_cell_write);
+
 static int eeprom_init(void)
 {
 	return class_register(&eeprom_class);
diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
new file mode 100644
index 0000000..e06f5e5
--- /dev/null
+++ b/include/linux/eeprom-consumer.h
@@ -0,0 +1,67 @@
+/*
+ * EEPROM framework consumer.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_CONSUMER_H
+#define _LINUX_EEPROM_CONSUMER_H
+
+struct eeprom_cell;
+
+struct eeprom_block {
+	loff_t offset;
+	size_t count;
+};
+#ifdef CONFIG_EEPROM
+struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks);
+void eeprom_cell_put(struct eeprom_cell *cell);
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
+#else
+
+static inline struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks)
+{
+	return NULL;
+}
+
+static inline void eeprom_cell_put(struct eeprom_cell *cell)
+{
+}
+
+static inline char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+	return NULL;
+}
+
+static inline int eeprom_cell_write(struct eeprom_cell *cell,
+				    const char *buf, ssize_t len)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_EEPROM */
+
+#if defined(CONFIG_EEPROM) && defined(CONFIG_OF)
+struct eeprom_cell *of_eeprom_cell_get(struct device *dev, int index);
+struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+					      const char *name);
+#else
+static inline struct eeprom_cell *of_eeprom_cell_get(
+					struct device *dev, int index)
+{
+	return NULL;
+}
+static inline struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+							    const char *name)
+{
+	return NULL;
+}
+#endif
+#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */
-- 
1.9.1


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

* [PATCH v1 3/6] eeprom: Add bindings for simple eeprom framework
  2015-03-05  9:44 ` [PATCH v1 0/6] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  2015-03-05  9:45   ` [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
  2015-03-05  9:45   ` [PATCH v1 2/6] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
@ 2015-03-05  9:46   ` Srinivas Kandagatla
  2015-03-05 20:11     ` Rob Herring
  2015-03-05  9:46   ` [PATCH v1 4/6] eeprom: sunxi: Move the SID driver to the " Srinivas Kandagatla
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-05  9:46 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, andrew, Arnd Bergmann,
	broonie, Greg Kroah-Hartman, Srinivas Kandagatla

This patch adds bindings for simple eeprom framework which allows eeprom
consumers to talk to eeprom providers to get access to eeprom cell data.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/eeprom/eeprom.txt          | 70 ++++++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt

diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
new file mode 100644
index 0000000..dbfb95c
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
@@ -0,0 +1,70 @@
+= EEPROM Data Device Tree Bindings =
+
+This binding is intended to represent the location of hardware
+configuration data stored in EEPROMs.
+
+On a significant proportion of boards, the manufacturer has stored
+some data on an EEPROM-like device, for the OS to be able to retrieve
+these information and act upon it. Obviously, the OS has to know
+about where to retrieve these data from, and where they are stored on
+the storage device.
+
+This document is here to document this.
+
+= Data providers =
+Contains bindings specific to provider drivers and data cells as children
+to this node.
+
+= Data cells =
+These are the child nodes of the provider which contain data cell
+information like offset and size in eeprom provider.
+
+Required properties:
+reg:	specifies the offset in byte within that storage device, and the length
+	in bytes of the data we care about.
+	There could be more then one offset-length pairs in this property.
+
+Optional properties:
+As required by specific data parsers/interpreters.
+
+For example:
+
+	/* Provider */
+	qfprom: qfprom@00700000 {
+		compatible 	= "qcom,qfprom";
+		reg		= <0x00700000 0x1000>;
+		...
+
+		/* Data cells */
+		tsens_calibration: calib@404 {
+			reg = <0x404 0x10>;
+		};
+
+		serial_number: sn {
+			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
+
+		};
+		...
+	};
+
+= Data consumers =
+Are drivers which consume eeprom data cells.
+
+Required properties:
+
+eeproms: List of phandle and data cell the device might be interested in.
+
+Optional properties:
+
+eeprom-names: List of data cell name strings sorted in the same order
+ 	      as the resets property. Consumers drivers will use
+ 	      eeprom-names to differentiate between multiple cells,
+ 	      and hence being able to know what these cells are for.
+
+For example:
+
+	tsens {
+		...
+		eeproms = <&tsens_calibration>;
+		eeprom-names = "calibration";
+	};
-- 
1.9.1


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

* [PATCH v1 4/6] eeprom: sunxi: Move the SID driver to the eeprom framework
  2015-03-05  9:44 ` [PATCH v1 0/6] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                     ` (2 preceding siblings ...)
  2015-03-05  9:46   ` [PATCH v1 3/6] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
@ 2015-03-05  9:46   ` Srinivas Kandagatla
  2015-03-05 10:15     ` Paul Bolle
  2015-03-05  9:46   ` [PATCH v1 5/6] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
                     ` (2 subsequent siblings)
  6 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-05  9:46 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, andrew, Arnd Bergmann,
	broonie, Greg Kroah-Hartman, Srinivas Kandagatla

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

Now that we have the EEPROM framework, we can consolidate the common driver
code. Move the driver to the framework, and hopefully, it will fix the sysfs
file creation race.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[srinivas.kandagatla: Moved to regmap based EEPROM framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/ABI/testing/sysfs-driver-sunxi-sid |  22 ----
 drivers/eeprom/Kconfig                           |  11 ++
 drivers/eeprom/Makefile                          |   1 +
 drivers/eeprom/eeprom-sunxi-sid.c                | 129 +++++++++++++++++++
 drivers/misc/eeprom/Kconfig                      |  13 --
 drivers/misc/eeprom/Makefile                     |   1 -
 drivers/misc/eeprom/sunxi_sid.c                  | 156 -----------------------
 7 files changed, 141 insertions(+), 192 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 drivers/eeprom/eeprom-sunxi-sid.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid
deleted file mode 100644
index ffb9536..0000000
--- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid
+++ /dev/null
@@ -1,22 +0,0 @@
-What:		/sys/devices/*/<our-device>/eeprom
-Date:		August 2013
-Contact:	Oliver Schinagl <oliver@schinagl.nl>
-Description:	read-only access to the SID (Security-ID) on current
-		A-series SoC's from Allwinner. Currently supports A10, A10s, A13
-		and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes,
-		whereas the newer A20 SoC exposes 512 bytes split into sections.
-		Besides the 16 bytes of SID, there's also an SJTAG area,
-		HDMI-HDCP key and some custom keys. Below a quick overview, for
-		details see the user manual:
-		0x000  128 bit root-key (sun[457]i)
-		0x010  128 bit boot-key (sun7i)
-		0x020   64 bit security-jtag-key (sun7i)
-		0x028   16 bit key configuration (sun7i)
-		0x02b   16 bit custom-vendor-key (sun7i)
-		0x02c  320 bit low general key (sun7i)
-		0x040   32 bit read-control access (sun7i)
-		0x064  224 bit low general key (sun7i)
-		0x080 2304 bit HDCP-key (sun7i)
-		0x1a0  768 bit high general key (sun7i)
-Users:		any user space application which wants to read the SID on
-		Allwinner's A-series of CPU's.
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index d00f7d2..bff8ecb 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -17,4 +17,15 @@ config EEPROM_DEBUG
 	help
 	  Say yes here to enable debugging support.
 
+config EEPROM_SUNXI_SID
+	depends on ARCH_SUNXI
+	tristate "Allwinner SoCs SID support"
+	select REGMAP_MMIO
+	help
+	  This is a driver for the 'security ID' available on various Allwinner
+	  devices.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called sunxi_sid.
+
 endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index e130079..661422c 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -7,3 +7,4 @@ ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
 obj-$(CONFIG_EEPROM)		+= core.o
 
 # Devices
+obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
diff --git a/drivers/eeprom/eeprom-sunxi-sid.c b/drivers/eeprom/eeprom-sunxi-sid.c
new file mode 100644
index 0000000..eb32afb
--- /dev/null
+++ b/drivers/eeprom/eeprom-sunxi-sid.c
@@ -0,0 +1,129 @@
+/*
+ * Allwinner sunXi SoCs Security ID support.
+ *
+ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct eeprom_sid {
+	void __iomem	*membase;
+	struct eeprom_device *eeprom;
+};
+
+static struct eeprom_config econfig = {
+	.stride = 1,
+	.name = "sunix-sid",
+};
+
+/* We read the entire key, due to a 32 bit read alignment requirement. Since we
+ * want to return the requested byte, this results in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarely probed, this is not really an issue.
+ */
+static int sunxi_sid_reg_read(void *context,
+			      unsigned int offset, unsigned int *val)
+{
+	struct eeprom_sid *sid  = context;
+	u32 sid_key;
+
+	sid_key = ioread32be(sid->membase + round_down(offset, 4));
+	sid_key >>= (offset % 4) * 8;
+
+	*val = sid_key;
+
+	return 0;
+}
+
+static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
+	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static struct regmap_config sunxi_sid_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+	.reg_read = sunxi_sid_reg_read,
+	.writeable_reg = sunxi_sid_writeable_reg,
+};
+
+static int sunxi_sid_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *device;
+	struct eeprom_sid *sid;
+	struct resource *res;
+	struct eeprom_device *eeprom;
+	struct device *dev = &pdev->dev;
+
+	sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL);
+	if (!sid)
+		return -ENOMEM;
+
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid->membase = devm_ioremap_resource(dev, res);
+	if (IS_ERR(sid->membase))
+		return PTR_ERR(sid->membase);
+
+	device = of_match_device(sunxi_sid_of_match, dev);
+	if (!device)
+		return -ENODEV;
+
+	sunxi_sid_regmap_config.max_register = (unsigned int)device->data - 1;
+
+	econfig.regmap = devm_regmap_init(dev, NULL,
+					  sid, &sunxi_sid_regmap_config);
+	if (IS_ERR(econfig.regmap))
+		return PTR_ERR(econfig.regmap);
+
+	econfig.dev = dev;
+	econfig.owner = THIS_MODULE;
+	econfig.size = sunxi_sid_regmap_config.max_register;
+
+	eeprom = eeprom_register(&econfig);
+	if (IS_ERR(eeprom))
+		return PTR_ERR(eeprom);
+
+	platform_set_drvdata(pdev, eeprom);
+
+	return 0;
+}
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = "sunxi-sid",
+		.of_match_table = sunxi_sid_of_match,
+	},
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 9536852f..04f2e1f 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG
 
 	  If unsure, say N.
 
-config EEPROM_SUNXI_SID
-	tristate "Allwinner sunxi security ID support"
-	depends on ARCH_SUNXI && SYSFS
-	help
-	  This is a driver for the 'security ID' available on various Allwinner
-	  devices.
-
-	  Due to the potential risks involved with changing e-fuses,
-	  this driver is read-only.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called sunxi_sid.
-
 endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 9507aec..fc1e81d 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY)	+= eeprom.o
 obj-$(CONFIG_EEPROM_MAX6875)	+= max6875.o
 obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
 obj-$(CONFIG_EEPROM_93XX46)	+= eeprom_93xx46.o
-obj-$(CONFIG_EEPROM_SUNXI_SID)	+= sunxi_sid.o
 obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
deleted file mode 100644
index 8385177..0000000
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
- * http://www.linux-sunxi.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * This driver exposes the Allwinner security ID, efuses exported in byte-
- * sized chunks.
- */
-
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#define DRV_NAME "sunxi-sid"
-
-struct sunxi_sid_data {
-	void __iomem *reg_base;
-	unsigned int keysize;
-};
-
-/* We read the entire key, due to a 32 bit read alignment requirement. Since we
- * want to return the requested byte, this results in somewhat slower code and
- * uses 4 times more reads as needed but keeps code simpler. Since the SID is
- * only very rarely probed, this is not really an issue.
- */
-static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data,
-			      const unsigned int offset)
-{
-	u32 sid_key;
-
-	if (offset >= sid_data->keysize)
-		return 0;
-
-	sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4));
-	sid_key >>= (offset % 4) * 8;
-
-	return sid_key; /* Only return the last byte */
-}
-
-static ssize_t sid_read(struct file *fd, struct kobject *kobj,
-			struct bin_attribute *attr, char *buf,
-			loff_t pos, size_t size)
-{
-	struct platform_device *pdev;
-	struct sunxi_sid_data *sid_data;
-	int i;
-
-	pdev = to_platform_device(kobj_to_dev(kobj));
-	sid_data = platform_get_drvdata(pdev);
-
-	if (pos < 0 || pos >= sid_data->keysize)
-		return 0;
-	if (size > sid_data->keysize - pos)
-		size = sid_data->keysize - pos;
-
-	for (i = 0; i < size; i++)
-		buf[i] = sunxi_sid_read_byte(sid_data, pos + i);
-
-	return i;
-}
-
-static struct bin_attribute sid_bin_attr = {
-	.attr = { .name = "eeprom", .mode = S_IRUGO, },
-	.read = sid_read,
-};
-
-static int sunxi_sid_remove(struct platform_device *pdev)
-{
-	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
-	dev_dbg(&pdev->dev, "driver unloaded\n");
-
-	return 0;
-}
-
-static const struct of_device_id sunxi_sid_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
-	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
-	{/* sentinel */},
-};
-MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-
-static int sunxi_sid_probe(struct platform_device *pdev)
-{
-	struct sunxi_sid_data *sid_data;
-	struct resource *res;
-	const struct of_device_id *of_dev_id;
-	u8 *entropy;
-	unsigned int i;
-
-	sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data),
-				GFP_KERNEL);
-	if (!sid_data)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(sid_data->reg_base))
-		return PTR_ERR(sid_data->reg_base);
-
-	of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev);
-	if (!of_dev_id)
-		return -ENODEV;
-	sid_data->keysize = (int)of_dev_id->data;
-
-	platform_set_drvdata(pdev, sid_data);
-
-	sid_bin_attr.size = sid_data->keysize;
-	if (device_create_bin_file(&pdev->dev, &sid_bin_attr))
-		return -ENODEV;
-
-	entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL);
-	for (i = 0; i < sid_data->keysize; i++)
-		entropy[i] = sunxi_sid_read_byte(sid_data, i);
-	add_device_randomness(entropy, sid_data->keysize);
-	kfree(entropy);
-
-	dev_dbg(&pdev->dev, "loaded\n");
-
-	return 0;
-}
-
-static struct platform_driver sunxi_sid_driver = {
-	.probe = sunxi_sid_probe,
-	.remove = sunxi_sid_remove,
-	.driver = {
-		.name = DRV_NAME,
-		.of_match_table = sunxi_sid_of_match,
-	},
-};
-module_platform_driver(sunxi_sid_driver);
-
-MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
-MODULE_DESCRIPTION("Allwinner sunxi security id driver");
-MODULE_LICENSE("GPL");
-- 
1.9.1


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

* [PATCH v1 5/6] eeprom: qfprom: Add Qualcomm QFPROM support.
  2015-03-05  9:44 ` [PATCH v1 0/6] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                     ` (3 preceding siblings ...)
  2015-03-05  9:46   ` [PATCH v1 4/6] eeprom: sunxi: Move the SID driver to the " Srinivas Kandagatla
@ 2015-03-05  9:46   ` Srinivas Kandagatla
  2015-03-05 10:02     ` Paul Bolle
  2015-03-05  9:46   ` [PATCH v1 6/6] eeprom: Add to MAINTAINERS for eeprom framework Srinivas Kandagatla
  2015-03-13  9:49   ` [PATCH v2 0/7] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  6 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-05  9:46 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, andrew, Arnd Bergmann,
	broonie, Greg Kroah-Hartman, Srinivas Kandagatla

This patch adds QFPROM support driver which is used by other drivers
like thermal sensor and cpufreq.

On MSM parts there are some efuses (called qfprom) these fuses store things like
calibration data, speed bins.. etc. Drivers like cpufreq, thermal sensors would
read out this data for configuring the driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/Kconfig  |  7 +++++
 drivers/eeprom/Makefile |  1 +
 drivers/eeprom/qfprom.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)
 create mode 100644 drivers/eeprom/qfprom.c

diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index bff8ecb..65325c7 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -28,4 +28,11 @@ config EEPROM_SUNXI_SID
 	  This driver can also be built as a module. If so, the module
 	  will be called sunxi_sid.
 
+config QCOM_QFPROM
+	tristate "QCOM QFPROM Support"
+        depends on EEPROM
+	select REGMAP_MMIO
+	help
+          Say y here to enable QFPROM support. The QFPROM provides access
+          functions for QFPROM data to rest of the drivers via eeprom interface.
 endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 661422c..f99c824 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_EEPROM)		+= core.o
 
 # Devices
 obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
+obj-$(CONFIG_QCOM_QFPROM)	+= qfprom.o
diff --git a/drivers/eeprom/qfprom.c b/drivers/eeprom/qfprom.c
new file mode 100644
index 0000000..371a8c0
--- /dev/null
+++ b/drivers/eeprom/qfprom.c
@@ -0,0 +1,74 @@
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/eeprom-provider.h>
+
+static struct regmap_config qfprom_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+};
+
+static struct eeprom_config econfig = {
+	.stride = 1,
+	.name = "qfprom",
+};
+
+static int qfprom_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+
+static int qfprom_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	void __iomem *base;
+	struct device *dev = &pdev->dev;
+	struct eeprom_device *eeprom;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	qfprom_regmap_config.max_register = resource_size(res) - 1;
+
+	econfig.regmap = devm_regmap_init_mmio(dev, base,
+					       &qfprom_regmap_config);
+	if (IS_ERR(econfig.regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(econfig.regmap);
+	}
+	econfig.owner = THIS_MODULE;
+	econfig.dev = dev;
+	econfig.size = resource_size(res) - 1;
+	eeprom = eeprom_register(&econfig);
+	if (IS_ERR(eeprom))
+		return PTR_ERR(eeprom);
+
+	platform_set_drvdata(pdev, eeprom);
+	return 0;
+}
+
+static const struct of_device_id qfprom_of_match[] = {
+	{ .compatible = "qcom,qfprom"},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, qfprom_of_match);
+
+static struct platform_driver qfprom_driver = {
+	.probe = qfprom_probe,
+	.remove = qfprom_remove,
+	.driver = {
+		.name = "qcom,qfprom",
+		.of_match_table = qfprom_of_match,
+	},
+};
+module_platform_driver(qfprom_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm QFPROM driver");
+MODULE_LICENSE("GPL2");
-- 
1.9.1


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

* [PATCH v1 6/6] eeprom: Add to MAINTAINERS for eeprom framework
  2015-03-05  9:44 ` [PATCH v1 0/6] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                     ` (4 preceding siblings ...)
  2015-03-05  9:46   ` [PATCH v1 5/6] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
@ 2015-03-05  9:46   ` Srinivas Kandagatla
  2015-03-13  9:49   ` [PATCH v2 0/7] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  6 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-05  9:46 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, andrew, Arnd Bergmann,
	broonie, Greg Kroah-Hartman, Srinivas Kandagatla

This patch adds MAINTAINERS to eeprom framework.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index d66a97d..ee7ba92 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3657,6 +3657,15 @@ T:	git git://git.alsa-project.org/alsa-kernel.git
 S:	Maintained
 F:	sound/usb/misc/ua101.c
 
+EEPROM FRAMEWORK
+M:	Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+M:	Maxime Ripard <maxime.ripard@free-electrons.com>
+S:	Maintained
+F:	drivers/eeprom/
+F:	Documentation/devicetree/bindings/eeprom/
+F:	include/linux/eeprom-provider.h
+F:	include/linux/eeprom-consumer.h
+
 EXTENSIBLE FIRMWARE INTERFACE (EFI)
 M:	Matt Fleming <matt.fleming@intel.com>
 L:	linux-efi@vger.kernel.org
-- 
1.9.1


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

* Re: [PATCH v1 5/6] eeprom: qfprom: Add Qualcomm QFPROM support.
  2015-03-05  9:46   ` [PATCH v1 5/6] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
@ 2015-03-05 10:02     ` Paul Bolle
  2015-03-05 10:10       ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Paul Bolle @ 2015-03-05 10:02 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	andrew, Arnd Bergmann, broonie, Greg Kroah-Hartman

On Thu, 2015-03-05 at 09:46 +0000, Srinivas Kandagatla wrote:
> diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
> index bff8ecb..65325c7 100644
> --- a/drivers/eeprom/Kconfig
> +++ b/drivers/eeprom/Kconfig
> @@ -28,4 +28,11 @@ config EEPROM_SUNXI_SID
>  	  This driver can also be built as a module. If so, the module
>  	  will be called sunxi_sid.
>  
> +config QCOM_QFPROM
> +	tristate "QCOM QFPROM Support"
> +        depends on EEPROM

Make this one tab, please.

> +	select REGMAP_MMIO
> +	help
> +          Say y here to enable QFPROM support. The QFPROM provides access
> +          functions for QFPROM data to rest of the drivers via eeprom interface.

And this one tab and two spaces, please.

All utterly trivial, of course, but I found a less trivial problem with
this patch, so I included these two comments anyway.

>  endif
> diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
> index 661422c..f99c824 100644
> --- a/drivers/eeprom/Makefile
> +++ b/drivers/eeprom/Makefile
> @@ -8,3 +8,4 @@ obj-$(CONFIG_EEPROM)		+= core.o
>  
>  # Devices
>  obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
> +obj-$(CONFIG_QCOM_QFPROM)	+= qfprom.o
> diff --git a/drivers/eeprom/qfprom.c b/drivers/eeprom/qfprom.c
> new file mode 100644
> index 0000000..371a8c0
> --- /dev/null
> +++ b/drivers/eeprom/qfprom.c
> @@ -0,0 +1,74 @@
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/eeprom-provider.h>

[...]

> +MODULE_LICENSE("GPL2");

This will taint the kernel on module load. I guess you meant
    MODULE_LICENSE("GPL v2");

but there's no comment with some lines about the license at the top of
this file, so I can't be sure.


Paul Bolle

(Chances are that by the end of this week everybody is so tired of
messages like this that people actually check this stuff before
submitting, and there's no need to review this anymore for the rest of
this year. That would be mission accomplished, I guess.)


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

* Re: [PATCH v1 5/6] eeprom: qfprom: Add Qualcomm QFPROM support.
  2015-03-05 10:02     ` Paul Bolle
@ 2015-03-05 10:10       ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-05 10:10 UTC (permalink / raw)
  To: Paul Bolle
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	andrew, Arnd Bergmann, broonie, Greg Kroah-Hartman

Thankyou for the comments,

On 05/03/15 10:02, Paul Bolle wrote:
> On Thu, 2015-03-05 at 09:46 +0000, Srinivas Kandagatla wrote:
>> diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
>> index bff8ecb..65325c7 100644
>> --- a/drivers/eeprom/Kconfig
>> +++ b/drivers/eeprom/Kconfig
>> @@ -28,4 +28,11 @@ config EEPROM_SUNXI_SID
>>   	  This driver can also be built as a module. If so, the module
>>   	  will be called sunxi_sid.
>>
>> +config QCOM_QFPROM
>> +	tristate "QCOM QFPROM Support"
>> +        depends on EEPROM
>
> Make this one tab, please.
>
>> +	select REGMAP_MMIO
>> +	help
>> +          Say y here to enable QFPROM support. The QFPROM provides access
>> +          functions for QFPROM data to rest of the drivers via eeprom interface.
>
> And this one tab and two spaces, please.
>
> All utterly trivial, of course, but I found a less trivial problem with
> this patch, so I included these two comments anyway.
>
Will fix it in next version.
>>   endif
>> diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
>> index 661422c..f99c824 100644
>> --- a/drivers/eeprom/Makefile
>> +++ b/drivers/eeprom/Makefile
>> @@ -8,3 +8,4 @@ obj-$(CONFIG_EEPROM)		+= core.o
>>
>>   # Devices
>>   obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
>> +obj-$(CONFIG_QCOM_QFPROM)	+= qfprom.o
>> diff --git a/drivers/eeprom/qfprom.c b/drivers/eeprom/qfprom.c
>> new file mode 100644
>> index 0000000..371a8c0
>> --- /dev/null
>> +++ b/drivers/eeprom/qfprom.c
>> @@ -0,0 +1,74 @@
>> +#include <linux/device.h>
>> +#include <linux/module.h>
>> +#include <linux/err.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/eeprom-provider.h>
>
> [...]
>
>> +MODULE_LICENSE("GPL2");
>
> This will taint the kernel on module load. I guess you meant
>      MODULE_LICENSE("GPL v2");
>
> but there's no comment with some lines about the license at the top of
> this file, so I can't be sure.
>
Yes, I meant GPL v2, and will fix the license header too in next version.

--srini

>
> Paul Bolle
>
> (Chances are that by the end of this week everybody is so tired of
> messages like this that people actually check this stuff before
> submitting, and there's no need to review this anymore for the rest of
> this year. That would be mission accomplished, I guess.)
>

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

* Re: [PATCH v1 4/6] eeprom: sunxi: Move the SID driver to the eeprom framework
  2015-03-05  9:46   ` [PATCH v1 4/6] eeprom: sunxi: Move the SID driver to the " Srinivas Kandagatla
@ 2015-03-05 10:15     ` Paul Bolle
  2015-03-05 18:36       ` Maxime Ripard
  0 siblings, 1 reply; 153+ messages in thread
From: Paul Bolle @ 2015-03-05 10:15 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	andrew, Arnd Bergmann, broonie, Greg Kroah-Hartman

On Thu, 2015-03-05 at 09:46 +0000, Srinivas Kandagatla wrote:
> --- a/drivers/eeprom/Kconfig
> +++ b/drivers/eeprom/Kconfig
> @@ -17,4 +17,15 @@ config EEPROM_DEBUG
>  	help
>  	  Say yes here to enable debugging support.
>  
> +config EEPROM_SUNXI_SID
> +	depends on ARCH_SUNXI
> +	tristate "Allwinner SoCs SID support"

Nit: make this the first option, please.

> +	select REGMAP_MMIO
> +	help
> +	  This is a driver for the 'security ID' available on various Allwinner
> +	  devices.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called sunxi_sid.

I think it will be called "eeprom-sunxi-sid". Am I right?

(There must be thousands of lines like this in the various Kconfig
files. Has anyone ever tried to autogenerate this info for the make
*config tools? Probably rather complicated...)

> +
>  endif
> diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
> index e130079..661422c 100644
> --- a/drivers/eeprom/Makefile
> +++ b/drivers/eeprom/Makefile
> @@ -7,3 +7,4 @@ ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
>  obj-$(CONFIG_EEPROM)		+= core.o
>  
>  # Devices
> +obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
> diff --git a/drivers/eeprom/eeprom-sunxi-sid.c b/drivers/eeprom/eeprom-sunxi-sid.c
> new file mode 100644
> index 0000000..eb32afb
> --- /dev/null
> +++ b/drivers/eeprom/eeprom-sunxi-sid.c
> @@ -0,0 +1,129 @@
> +/*
> + * Allwinner sunXi SoCs Security ID support.
> + *
> + * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
> + * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */

So the license is GPL v2.

> +MODULE_LICENSE("GPL");

Which means you probably want
    MODULE_LICENSE("GPL v2");

> --- a/drivers/misc/eeprom/sunxi_sid.c
> +++ /dev/null
> @@ -1,156 +0,0 @@
> -/*
> - * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
> - * http://www.linux-sunxi.org
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.

But the previous driver was GPL v2 or later.

> -MODULE_LICENSE("GPL");

And this matches that.

Was it intended to re-license this, or is the code basically new? (I
haven't compared the before and after code, to be honest.)


Paul Bolle


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

* Re: [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-05  9:45   ` [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
@ 2015-03-05 10:23     ` Paul Bolle
  2015-03-05 10:35       ` Srinivas Kandagatla
  2015-03-07 15:00     ` Mark Brown
  1 sibling, 1 reply; 153+ messages in thread
From: Paul Bolle @ 2015-03-05 10:23 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	andrew, Arnd Bergmann, broonie, Greg Kroah-Hartman

On Thu, 2015-03-05 at 09:45 +0000, Srinivas Kandagatla wrote:
> --- /dev/null
> +++ b/drivers/eeprom/Kconfig
> @@ -0,0 +1,20 @@
> +menuconfig EEPROM
> +	bool "EEPROM Support"

EEPROM is a bool symbol.

> +	depends on OF
> +	select REGMAP
> +	help
> +	  Support for EEPROM alike devices.
> +
> +	  This framework is designed to provide a generic interface to EEPROM
> +	  from both the Linux Kernel and the userspace.
> +
> +	  If unsure, say no.
> +
> +if EEPROM
> +
> +config EEPROM_DEBUG
> +	bool "EEPROM debug support"
> +	help
> +	  Say yes here to enable debugging support.
> +
> +endif
> diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
> new file mode 100644
> index 0000000..e130079
> --- /dev/null
> +++ b/drivers/eeprom/Makefile
> @@ -0,0 +1,9 @@
> +#
> +# Makefile for eeprom drivers.
> +#
> +
> +ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
> +
> +obj-$(CONFIG_EEPROM)		+= core.o

So core.o will be built-in (or not built at all, of course).

> +# Devices
> diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
> new file mode 100644
> index 0000000..243e466
> --- /dev/null
> +++ b/drivers/eeprom/core.c
> @@ -0,0 +1,208 @@
> +/*
> + * EEPROM framework core.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/eeprom-provider.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/idr.h>
> +#include <linux/init.h>
> +#include <linux/module.h>

So I guess this header is not needed.

> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>

> +module_exit(eeprom_exit);

And this will never be called.

> +MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
> +MODULE_DESCRIPTION("EEPROM Driver Core");
> +MODULE_LICENSE("GPL");

And those four macros will basically be preprocessed away. But if you
actually want this code to be built modular too, and change EEPROM to
tristate, you probably want to use
    MODULE_LICENSE("GPL v2");

here.


Paul Bolle


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

* Re: [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-05 10:23     ` Paul Bolle
@ 2015-03-05 10:35       ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-05 10:35 UTC (permalink / raw)
  To: Paul Bolle
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	andrew, Arnd Bergmann, broonie, Greg Kroah-Hartman



On 05/03/15 10:23, Paul Bolle wrote:
> On Thu, 2015-03-05 at 09:45 +0000, Srinivas Kandagatla wrote:
>> --- /dev/null
>> +++ b/drivers/eeprom/Kconfig
>> @@ -0,0 +1,20 @@
>> +menuconfig EEPROM
>> +	bool "EEPROM Support"
>
> EEPROM is a bool symbol.
>
>> +	depends on OF
>> +	select REGMAP
>> +	help
>> +	  Support for EEPROM alike devices.
>> +
>> +	  This framework is designed to provide a generic interface to EEPROM
>> +	  from both the Linux Kernel and the userspace.
>> +
>> +	  If unsure, say no.
>> +
>> +if EEPROM
>> +
>> +config EEPROM_DEBUG
>> +	bool "EEPROM debug support"
>> +	help
>> +	  Say yes here to enable debugging support.
>> +
>> +endif
>> diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
>> new file mode 100644
>> index 0000000..e130079
>> --- /dev/null
>> +++ b/drivers/eeprom/Makefile
>> @@ -0,0 +1,9 @@
>> +#
>> +# Makefile for eeprom drivers.
>> +#
>> +
>> +ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
>> +
>> +obj-$(CONFIG_EEPROM)		+= core.o
>
> So core.o will be built-in (or not built at all, of course).
>
>> +# Devices
>> diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
>> new file mode 100644
>> index 0000000..243e466
>> --- /dev/null
>> +++ b/drivers/eeprom/core.c
>> @@ -0,0 +1,208 @@
>> +/*
>> + * EEPROM framework core.
>> + *
>> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2.  This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#include <linux/device.h>
>> +#include <linux/eeprom-provider.h>
>> +#include <linux/export.h>
>> +#include <linux/fs.h>
>> +#include <linux/idr.h>
>> +#include <linux/init.h>
>> +#include <linux/module.h>
>
> So I guess this header is not needed.
>
>> +#include <linux/of.h>
>> +#include <linux/slab.h>
>> +#include <linux/uaccess.h>
>
>> +module_exit(eeprom_exit);
>
> And this will never be called.
>
>> +MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
>> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
>> +MODULE_DESCRIPTION("EEPROM Driver Core");
>> +MODULE_LICENSE("GPL");
>
> And those four macros will basically be preprocessed away. But if you
> actually want this code to be built modular too, and change EEPROM to
> tristate, you probably want to use
>      MODULE_LICENSE("GPL v2");
>
> here.

Thanks, Thats a good catch,
There is no reason why this driver can't be a module, I will change the 
Kconfig and License in next version.


>
>
> Paul Bolle
>

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

* Re: [PATCH v1 4/6] eeprom: sunxi: Move the SID driver to the eeprom framework
  2015-03-05 10:15     ` Paul Bolle
@ 2015-03-05 18:36       ` Maxime Ripard
  0 siblings, 0 replies; 153+ messages in thread
From: Maxime Ripard @ 2015-03-05 18:36 UTC (permalink / raw)
  To: Paul Bolle
  Cc: Srinivas Kandagatla, linux-arm-kernel, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	andrew, Arnd Bergmann, broonie, Greg Kroah-Hartman

[-- Attachment #1: Type: text/plain, Size: 2251 bytes --]

Hi Paul,

On Thu, Mar 05, 2015 at 11:15:15AM +0100, Paul Bolle wrote:
> >  endif
> > diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
> > index e130079..661422c 100644
> > --- a/drivers/eeprom/Makefile
> > +++ b/drivers/eeprom/Makefile
> > @@ -7,3 +7,4 @@ ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
> >  obj-$(CONFIG_EEPROM)		+= core.o
> >  
> >  # Devices
> > +obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
> > diff --git a/drivers/eeprom/eeprom-sunxi-sid.c b/drivers/eeprom/eeprom-sunxi-sid.c
> > new file mode 100644
> > index 0000000..eb32afb
> > --- /dev/null
> > +++ b/drivers/eeprom/eeprom-sunxi-sid.c
> > @@ -0,0 +1,129 @@
> > +/*
> > + * Allwinner sunXi SoCs Security ID support.
> > + *
> > + * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
> > + * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
> > + *
> > + * This file is licensed under the terms of the GNU General Public
> > + * License version 2.  This program is licensed "as is" without any
> > + * warranty of any kind, whether express or implied.
> > + */
> 
> So the license is GPL v2.
> 
> > +MODULE_LICENSE("GPL");
> 
> Which means you probably want
>     MODULE_LICENSE("GPL v2");
> 
> > --- a/drivers/misc/eeprom/sunxi_sid.c
> > +++ /dev/null
> > @@ -1,156 +0,0 @@
> > -/*
> > - * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
> > - * http://www.linux-sunxi.org
> > - *
> > - * This program is free software; you can redistribute it and/or modify
> > - * it under the terms of the GNU General Public License as published by
> > - * the Free Software Foundation; either version 2 of the License, or
> > - * (at your option) any later version.
> 
> But the previous driver was GPL v2 or later.
> 
> > -MODULE_LICENSE("GPL");
> 
> And this matches that.
> 
> Was it intended to re-license this, or is the code basically new? (I
> haven't compared the before and after code, to be honest.)

That was unintentional, especially since this driver is not new at
all, and is barely a conversion to that framework.

Thanks for catching this!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v1 3/6] eeprom: Add bindings for simple eeprom framework
  2015-03-05  9:46   ` [PATCH v1 3/6] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
@ 2015-03-05 20:11     ` Rob Herring
  2015-03-05 22:34       ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Rob Herring @ 2015-03-05 20:11 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Andrew Lunn, Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

On Thu, Mar 5, 2015 at 3:46 AM, Srinivas Kandagatla
<srinivas.kandagatla@linaro.org> wrote:
> This patch adds bindings for simple eeprom framework which allows eeprom
> consumers to talk to eeprom providers to get access to eeprom cell data.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> [Maxime Ripard: intial version of eeprom framework]
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  .../devicetree/bindings/eeprom/eeprom.txt          | 70 ++++++++++++++++++++++
>  1 file changed, 70 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
>
> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> new file mode 100644
> index 0000000..dbfb95c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> @@ -0,0 +1,70 @@
> += EEPROM Data Device Tree Bindings =
> +
> +This binding is intended to represent the location of hardware
> +configuration data stored in EEPROMs.
> +
> +On a significant proportion of boards, the manufacturer has stored
> +some data on an EEPROM-like device, for the OS to be able to retrieve
> +these information and act upon it. Obviously, the OS has to know
> +about where to retrieve these data from, and where they are stored on
> +the storage device.
> +
> +This document is here to document this.
> +
> += Data providers =
> +Contains bindings specific to provider drivers and data cells as children
> +to this node.
> +
> += Data cells =
> +These are the child nodes of the provider which contain data cell
> +information like offset and size in eeprom provider.
> +
> +Required properties:
> +reg:   specifies the offset in byte within that storage device, and the length
> +       in bytes of the data we care about.
> +       There could be more then one offset-length pairs in this property.
> +
> +Optional properties:
> +As required by specific data parsers/interpreters.
> +
> +For example:
> +
> +       /* Provider */
> +       qfprom: qfprom@00700000 {
> +               compatible      = "qcom,qfprom";
> +               reg             = <0x00700000 0x1000>;
> +               ...
> +
> +               /* Data cells */
> +               tsens_calibration: calib@404 {
> +                       reg = <0x404 0x10>;
> +               };
> +
> +               serial_number: sn {
> +                       reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
> +
> +               };
> +               ...
> +       };
> +
> += Data consumers =
> +Are drivers which consume eeprom data cells.

s/drivers/device nodes/

> +
> +Required properties:
> +
> +eeproms: List of phandle and data cell the device might be interested in.
> +
> +Optional properties:
> +
> +eeprom-names: List of data cell name strings sorted in the same order
> +             as the resets property. Consumers drivers will use

resets?

> +             eeprom-names to differentiate between multiple cells,
> +             and hence being able to know what these cells are for.

Is this still needed? The sub-node name defines the name. Or you can
use reg-names with-in the sub-node.

Rob

> +
> +For example:
> +
> +       tsens {
> +               ...
> +               eeproms = <&tsens_calibration>;
> +               eeprom-names = "calibration";
> +       };
> --
> 1.9.1
>

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

* Re: [PATCH v1 3/6] eeprom: Add bindings for simple eeprom framework
  2015-03-05 20:11     ` Rob Herring
@ 2015-03-05 22:34       ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-05 22:34 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Andrew Lunn, Arnd Bergmann, Mark Brown, Greg Kroah-Hartman

>> +
>> +For example:
>> +
>> +       /* Provider */
>> +       qfprom: qfprom@00700000 {
>> +               compatible      = "qcom,qfprom";
>> +               reg             = <0x00700000 0x1000>;
>> +               ...
>> +
>> +               /* Data cells */
>> +               tsens_calibration: calib@404 {
>> +                       reg = <0x404 0x10>;
>> +               };
>> +
>> +               serial_number: sn {
>> +                       reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
>> +
>> +               };
>> +               ...
>> +       };
>> +
>> += Data consumers =
>> +Are drivers which consume eeprom data cells.
>
> s/drivers/device nodes/
>
Thats true, "device nodes" makes sense.
>> +
>> +Required properties:
>> +
>> +eeproms: List of phandle and data cell the device might be interested in.
>> +
>> +Optional properties:
>> +
>> +eeprom-names: List of data cell name strings sorted in the same order
>> +             as the resets property. Consumers drivers will use
>
> resets?
Opps..
I remember fixing this, I will take care of it in next version.
>
>> +             eeprom-names to differentiate between multiple cells,
>> +             and hence being able to know what these cells are for.
>
> Is this still needed? The sub-node name defines the name. Or you can
> use reg-names with-in the sub-node.
Yes, eeprom-names is needed in the consumer nodes, where there are 
multiple eeproms cells, its easy to lookup by name rather than 
index,which depends on the order of the entries.

reg-names inside the "data cells" is ok, but I can't think of its use 
immediately. May be useful for debug?

--srini
 >
>
> Rob
>
>> +
>> +For example:
>> +
>> +       tsens {
>> +               ...
>> +               eeproms = <&tsens_calibration>;
>> +               eeprom-names = "calibration";
>> +       };
>> --
>> 1.9.1
>>

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

* Re: [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-05  9:45   ` [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
  2015-03-05 10:23     ` Paul Bolle
@ 2015-03-07 15:00     ` Mark Brown
  2015-03-09  7:13       ` Srinivas Kandagatla
  1 sibling, 1 reply; 153+ messages in thread
From: Mark Brown @ 2015-03-07 15:00 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	andrew, Arnd Bergmann, Greg Kroah-Hartman

[-- Attachment #1: Type: text/plain, Size: 526 bytes --]

On Thu, Mar 05, 2015 at 09:45:41AM +0000, Srinivas Kandagatla wrote:

> +
> +	return eeprom;
> +}
> +EXPORT_SYMBOL(eeprom_register);

This framework uses regmap but regmap is EXPORT_SYMBOL_GPL() and this is
using EXPORT_SYMBOL().

> +int eeprom_unregister(struct eeprom_device *eeprom)
> +{
> +	mutex_lock(&eeprom_mutex);
> +	if (atomic_read(&eeprom->users)) {
> +		mutex_unlock(&eeprom_mutex);

Atomic reads and a mutex - isn't the mutex enough?  Atomics are
generally a recipie for bugs due to the complexity in using them.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v1 1/6] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-07 15:00     ` Mark Brown
@ 2015-03-09  7:13       ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-09  7:13 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	andrew, Arnd Bergmann, Greg Kroah-Hartman



On 07/03/15 15:00, Mark Brown wrote:
> On Thu, Mar 05, 2015 at 09:45:41AM +0000, Srinivas Kandagatla wrote:
>
>> +
>> +	return eeprom;
>> +}
>> +EXPORT_SYMBOL(eeprom_register);
>
> This framework uses regmap but regmap is EXPORT_SYMBOL_GPL() and this is
> using EXPORT_SYMBOL().
>
Thanks for spotting this, I will fix this in next version.

>> +int eeprom_unregister(struct eeprom_device *eeprom)
>> +{
>> +	mutex_lock(&eeprom_mutex);
>> +	if (atomic_read(&eeprom->users)) {
>> +		mutex_unlock(&eeprom_mutex);
>
> Atomic reads and a mutex - isn't the mutex enough?  Atomics are
> generally a recipie for bugs due to the complexity in using them.
Yes, you are right as long as we protect users variable with mutex, 
using atomic is really redundant, will fix it in next version.
>


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

* [PATCH v2 0/7] Add simple EEPROM Framework via regmap.
  2015-03-05  9:44 ` [PATCH v1 0/6] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                     ` (5 preceding siblings ...)
  2015-03-05  9:46   ` [PATCH v1 6/6] eeprom: Add to MAINTAINERS for eeprom framework Srinivas Kandagatla
@ 2015-03-13  9:49   ` Srinivas Kandagatla
  2015-03-13  9:50     ` [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
                       ` (7 more replies)
  6 siblings, 8 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-13  9:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, linux-arm-msm, Srinivas Kandagatla

Thankyou all for providing inputs and comments on previous versions of this
patchset. Here is the v2 of the patchset addressing all the issues raised as
part of previous versions review.

This patchset adds a new simple EEPROM framework to kernel.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.
    
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
    
This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
    
Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

patch 1-3 Introduces the EEPROM framework.
Patch 4 migrates an existing driver to eeprom framework.
Patch 5-6 Adds Qualcomm specific qfprom driver.
Patch 7 adds entry in MAINTAINERS.

Its also possible to migrate other eeprom drivers to this framework.
Patch 6 can also be made a generic mmio-eeprom driver.

Providers APIs:
	eeprom_register/unregister();

Consumers APIs:
	eeprom_cell_get()/of_eeprom_cell_get()/of_eeprom_cell_get_byname();
	eeprom_cell_read()/eeprom_cell_write();

Device Tree:

	/* Provider */
	qfprom: qfprom@00700000 {
		compatible 	= "qcom,qfprom";
		reg		= <0x00700000 0x1000>;
		...

		/* Data cells */
		tsens_calibration: calib@404 {
			reg = <0x404 0x10>;
		};

		serial_number: sn {
			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;

		};
		...
	};
	
	/* Consumer node */
	tsens: tsens {
		...
		eeproms = <&tsens_calibration>;
		eeprom-names = "calib";
		...
	};

userspace interface:

hexdump /sys/class/eeprom/qfprom0/eeprom
                                                                                                                                                                                                                  
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
0000000 0000 0000 0000 0000 0000 0000 0000 0000
...
*
0001000


Changes since v1(https://lkml.org/lkml/2015/3/5/153)
 * Fix various Licencing issues spotted by Paul Bolle and Mark Brown
 * Allow eeprom core to build as module spotted by Paul Bolle.
 * Fix various kconfig issues spotted by Paul Bolle.
 * remove unessary atomic varible spotted by Mark Brown.
 * Few cleanups and common up some of the code in core.
 * Add qfprom bindings.

Changes since RFC(https://lkml.org/lkml/2015/2/19/307)
 * Fix documentation and error checks in read/write spotted by Andrew Lunn
 * Kconfig fix suggested by Stephen Boyd.
 * Add module owner suggested by Stephen Boyd and others.
 * Fix unsafe handling of eeprom in unregister spotted by Russell and Mark Brown.
 * seperate bindings patch as suggested by Rob.
 * Add MAINTAINERS as suggested by Rob.
 * Added support to allow reading eeprom for things like serial number which
  can be scatters across.
 * Added eeprom data using reg property suggested by Sascha and Stephen.
 * Added non-DT support.
 * Move kerneldoc to the src files spotted by Mark Brown.
 * Remove local list and do eeprom lookup by using class_find_device()


Thanks,
srini


Maxime Ripard (1):
  eeprom: sunxi: Move the SID driver to the eeprom framework

Srinivas Kandagatla (6):
  eeprom: Add a simple EEPROM framework for eeprom providers
  eeprom: Add a simple EEPROM framework for eeprom consumers
  eeprom: Add bindings for simple eeprom framework
  eeprom: qfprom: Add Qualcomm QFPROM support.
  eeprom: qfprom: Add bindings for qfprom
  eeprom: Add to MAINTAINERS for eeprom framework

 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 -
 .../bindings/eeprom/allwinner,sunxi-sid.txt        |  21 +
 .../devicetree/bindings/eeprom/eeprom.txt          |  70 +++
 .../devicetree/bindings/eeprom/qfprom.txt          |  23 +
 .../bindings/misc/allwinner,sunxi-sid.txt          |  17 -
 MAINTAINERS                                        |   9 +
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/eeprom/Kconfig                             |  33 ++
 drivers/eeprom/Makefile                            |   9 +
 drivers/eeprom/core.c                              | 517 +++++++++++++++++++++
 drivers/eeprom/eeprom-sunxi-sid.c                  | 136 ++++++
 drivers/eeprom/qfprom.c                            |  87 ++++
 drivers/misc/eeprom/Kconfig                        |  13 -
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 -------
 include/linux/eeprom-consumer.h                    |  67 +++
 include/linux/eeprom-provider.h                    |  47 ++
 18 files changed, 1022 insertions(+), 209 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
 create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
 create mode 100644 Documentation/devicetree/bindings/eeprom/qfprom.txt
 delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 drivers/eeprom/Kconfig
 create mode 100644 drivers/eeprom/Makefile
 create mode 100644 drivers/eeprom/core.c
 create mode 100644 drivers/eeprom/eeprom-sunxi-sid.c
 create mode 100644 drivers/eeprom/qfprom.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
 create mode 100644 include/linux/eeprom-consumer.h
 create mode 100644 include/linux/eeprom-provider.h

-- 
1.9.1


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

* [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-13  9:49   ` [PATCH v2 0/7] Add simple EEPROM Framework via regmap Srinivas Kandagatla
@ 2015-03-13  9:50     ` Srinivas Kandagatla
  2015-03-23 21:09       ` Mark Brown
  2015-03-13  9:50     ` [PATCH v2 2/7] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
                       ` (6 subsequent siblings)
  7 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-13  9:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, linux-arm-msm, Srinivas Kandagatla

This patch adds just providers part of the framework just to enable easy
review.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.

Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/Kconfig                 |   2 +
 drivers/Makefile                |   1 +
 drivers/eeprom/Kconfig          |  11 +++
 drivers/eeprom/Makefile         |   5 +
 drivers/eeprom/core.c           | 213 ++++++++++++++++++++++++++++++++++++++++
 include/linux/eeprom-provider.h |  47 +++++++++
 6 files changed, 279 insertions(+)
 create mode 100644 drivers/eeprom/Kconfig
 create mode 100644 drivers/eeprom/Makefile
 create mode 100644 drivers/eeprom/core.c
 create mode 100644 include/linux/eeprom-provider.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index c70d6e4..d7afc82 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
 
 source "drivers/android/Kconfig"
 
+source "drivers/eeprom/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 527a6da..57eb5b0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= coresight/
 obj-$(CONFIG_ANDROID)		+= android/
+obj-$(CONFIG_EEPROM)		+= eeprom/
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
new file mode 100644
index 0000000..21e1847
--- /dev/null
+++ b/drivers/eeprom/Kconfig
@@ -0,0 +1,11 @@
+menuconfig EEPROM
+	tristate "EEPROM Support"
+	depends on OF
+	select REGMAP
+	help
+	  Support for EEPROM alike devices.
+
+	  This framework is designed to provide a generic interface to EEPROM
+	  from both the Linux Kernel and the userspace.
+
+	  If unsure, say no.
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
new file mode 100644
index 0000000..250c95a
--- /dev/null
+++ b/drivers/eeprom/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for eeprom drivers.
+#
+
+obj-$(CONFIG_EEPROM)		+= core.o
diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
new file mode 100644
index 0000000..a9839de
--- /dev/null
+++ b/drivers/eeprom/core.c
@@ -0,0 +1,213 @@
+/*
+ * EEPROM framework core.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+struct eeprom_device {
+	struct regmap		*regmap;
+	int			stride;
+	size_t			size;
+
+	struct module		*owner;
+	struct device		dev;
+	int			id;
+	int			users;
+};
+
+static DEFINE_MUTEX(eeprom_mutex);
+static DEFINE_IDA(eeprom_ida);
+
+#define to_eeprom(d) container_of(d, struct eeprom_device, dev)
+
+static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
+				    struct bin_attribute *attr,
+				    char *buf, loff_t offset, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct eeprom_device *eeprom = to_eeprom(dev);
+	int rc;
+
+	if (offset > eeprom->size)
+		return -EINVAL;
+
+	if (offset + count > eeprom->size)
+		count = eeprom->size - offset;
+
+	rc = regmap_bulk_read(eeprom->regmap, offset,
+			      buf, count/eeprom->stride);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count - count % eeprom->stride;
+}
+
+static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *attr,
+				     char *buf, loff_t offset, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct eeprom_device *eeprom = to_eeprom(dev);
+	int rc;
+
+	if (offset > eeprom->size)
+		return -EINVAL;
+
+	if (offset + count > eeprom->size)
+		count = eeprom->size - offset;
+
+	rc = regmap_bulk_write(eeprom->regmap, offset,
+			       buf, count/eeprom->stride);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count - count % eeprom->stride;
+}
+
+static struct bin_attribute bin_attr_eeprom = {
+	.attr	= {
+		.name	= "eeprom",
+		.mode	= S_IWUSR | S_IRUGO,
+	},
+	.read	= bin_attr_eeprom_read,
+	.write	= bin_attr_eeprom_write,
+};
+
+static struct bin_attribute *eeprom_bin_attributes[] = {
+	&bin_attr_eeprom,
+	NULL,
+};
+
+static const struct attribute_group eeprom_bin_group = {
+	.bin_attrs	= eeprom_bin_attributes,
+};
+
+static const struct attribute_group *eeprom_dev_groups[] = {
+	&eeprom_bin_group,
+	NULL,
+};
+
+static void eeprom_release(struct device *dev)
+{
+	kfree(to_eeprom(dev));
+}
+
+static struct class eeprom_class = {
+	.name		= "eeprom",
+	.dev_groups	= eeprom_dev_groups,
+	.dev_release	= eeprom_release,
+};
+
+/**
+ * eeprom_register(): Register a eeprom device for given eeprom.
+ * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
+ *
+ * @eeprom: eeprom device that needs to be created
+ *
+ * The return value will be an error code on error or a zero on success.
+ * The eeprom_device and sysfs entery will be freed by the eeprom_unregister().
+ */
+
+struct eeprom_device *eeprom_register(struct eeprom_config *config)
+{
+	struct eeprom_device *eeprom;
+	int rval;
+
+	if (!config->regmap || !config->size) {
+		dev_err(config->dev, "Regmap not found\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL);
+	if (!eeprom)
+		return ERR_PTR(-ENOMEM);
+
+	eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
+	if (eeprom->id < 0)
+		return ERR_PTR(eeprom->id);
+
+	eeprom->owner = config->owner;
+	eeprom->regmap = config->regmap;
+	eeprom->stride = config->stride;
+	eeprom->size = config->size;
+	eeprom->dev.class = &eeprom_class;
+	eeprom->dev.parent = config->dev;
+	eeprom->dev.of_node = config->dev ? config->dev->of_node : NULL;
+	dev_set_name(&eeprom->dev, "%s%d",
+		     config->name ? : "eeprom", config->id);
+
+	device_initialize(&eeprom->dev);
+
+	dev_dbg(&eeprom->dev, "Registering eeprom device %s\n",
+		dev_name(&eeprom->dev));
+
+	rval = device_add(&eeprom->dev);
+	if (rval)
+		return ERR_PTR(rval);
+
+	return eeprom;
+}
+EXPORT_SYMBOL_GPL(eeprom_register);
+
+/**
+ * eeprom_unregister(): Unregister previously registered eeprom device
+ *
+ * @eeprom: Pointer to previously registered eeprom device.
+ *
+ * The return value will be an non zero on error or a zero on success.
+ */
+int eeprom_unregister(struct eeprom_device *eeprom)
+{
+	mutex_lock(&eeprom_mutex);
+	if (eeprom->users) {
+		mutex_unlock(&eeprom_mutex);
+		return -EBUSY;
+	}
+	mutex_unlock(&eeprom_mutex);
+
+	device_del(&eeprom->dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(eeprom_unregister);
+
+static int eeprom_init(void)
+{
+	return class_register(&eeprom_class);
+}
+
+static void eeprom_exit(void)
+{
+	class_unregister(&eeprom_class);
+}
+
+subsys_initcall(eeprom_init);
+module_exit(eeprom_exit);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("EEPROM Driver Core");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
new file mode 100644
index 0000000..21afdaa
--- /dev/null
+++ b/include/linux/eeprom-provider.h
@@ -0,0 +1,47 @@
+/*
+ * EEPROM framework provider.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_PROVIDER_H
+#define _LINUX_EEPROM_PROVIDER_H
+
+#include <linux/regmap.h>
+
+struct eeprom_device;
+
+struct eeprom_config {
+	struct device		*dev;
+	struct regmap		*regmap;
+	const char		*name;
+	int			id;
+	int			stride;
+	size_t			size;
+	struct module		*owner;
+};
+
+#if IS_ENABLED(CONFIG_EEPROM)
+
+struct eeprom_device *eeprom_register(struct eeprom_config *cfg);
+int eeprom_unregister(struct eeprom_device *eeprom);
+
+#else
+
+static inline struct eeprom_device *eeprom_register(struct eeprom_config *cfg)
+{
+	return NULL;
+}
+static inline int eeprom_unregister(struct eeprom_device *eeprom)
+{
+	return -ENOSYS;
+}
+
+#endif /* CONFIG_EEPROM */
+
+#endif  /* ifndef _LINUX_EEPROM_PROVIDER_H */
-- 
1.9.1


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

* [PATCH v2 2/7] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-03-13  9:49   ` [PATCH v2 0/7] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  2015-03-13  9:50     ` [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
@ 2015-03-13  9:50     ` Srinivas Kandagatla
  2015-03-13  9:50     ` [PATCH v2 3/7] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
                       ` (5 subsequent siblings)
  7 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-13  9:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, linux-arm-msm, Srinivas Kandagatla

This patch adds just consumers part of the framework just to enable easy
review.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.

Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of the framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/core.c           | 304 ++++++++++++++++++++++++++++++++++++++++
 include/linux/eeprom-consumer.h |  67 +++++++++
 2 files changed, 371 insertions(+)
 create mode 100644 include/linux/eeprom-consumer.h

diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
index a9839de..b87e136 100644
--- a/drivers/eeprom/core.c
+++ b/drivers/eeprom/core.c
@@ -16,6 +16,7 @@
 
 #include <linux/device.h>
 #include <linux/eeprom-provider.h>
+#include <linux/eeprom-consumer.h>
 #include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/idr.h>
@@ -36,6 +37,13 @@ struct eeprom_device {
 	int			users;
 };
 
+struct eeprom_cell {
+	struct eeprom_device	*eeprom;
+	int			nblocks;
+	int			size;
+	struct eeprom_block	blocks[0];
+};
+
 static DEFINE_MUTEX(eeprom_mutex);
 static DEFINE_IDA(eeprom_ida);
 
@@ -121,6 +129,37 @@ static struct class eeprom_class = {
 	.dev_release	= eeprom_release,
 };
 
+static int of_eeprom_match(struct device *dev, const void *eeprom_np)
+{
+	return dev->of_node == eeprom_np;
+}
+
+static struct eeprom_device *of_eeprom_find(struct device_node *eeprom_np)
+{
+	struct device *d;
+
+	if (!eeprom_np)
+		return NULL;
+
+	d = class_find_device(&eeprom_class, NULL, eeprom_np, of_eeprom_match);
+
+	return d ? to_eeprom(d) : NULL;
+}
+
+static int eeprom_match(struct device *dev, const void *data)
+{
+	return !strcmp(dev_name(dev), (const char *)data);
+}
+
+static struct eeprom_device *eeprom_find(const char *name)
+{
+	struct device *d;
+
+	d = class_find_device(&eeprom_class, NULL, (void *)name, eeprom_match);
+
+	return d ? to_eeprom(d) : NULL;
+}
+
 /**
  * eeprom_register(): Register a eeprom device for given eeprom.
  * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
@@ -194,6 +233,271 @@ int eeprom_unregister(struct eeprom_device *eeprom)
 }
 EXPORT_SYMBOL_GPL(eeprom_unregister);
 
+static int eeprom_cell_sanity_check(struct eeprom_cell *cell)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	int i;
+
+	/* byte aligned, no need to check for stride sanity */
+	if (eeprom->stride == 1)
+		return 0;
+
+	for (i = 0; i < cell->nblocks; i++) {
+		if (!IS_ALIGNED(cell->blocks[i].offset, eeprom->stride) ||
+		    !IS_ALIGNED(cell->blocks[i].count, eeprom->stride)) {
+			dev_err(&eeprom->dev,
+				"cell unaligned to eeprom stride %d\n",
+				eeprom->stride);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static struct eeprom_cell *__eeprom_cell_get(struct device_node *cell_np,
+					     const char *ename,
+					     struct eeprom_block *blocks,
+					     int nblocks)
+{
+	struct eeprom_cell *cell;
+	struct eeprom_device *eeprom = NULL;
+	struct property *prop;
+	const __be32 *vp;
+	u32 pv;
+	int i, rval;
+
+	mutex_lock(&eeprom_mutex);
+
+	eeprom = cell_np ? of_eeprom_find(cell_np->parent) : eeprom_find(ename);
+	if (!eeprom) {
+		mutex_unlock(&eeprom_mutex);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	eeprom->users++;
+	mutex_unlock(&eeprom_mutex);
+
+	if (!try_module_get(eeprom->owner)) {
+		dev_err(&eeprom->dev,
+			"could not increase module refcount for cell %s\n",
+			ename);
+		rval = -EINVAL;
+		goto err_mod;
+	}
+
+	if (cell_np)
+		nblocks = of_property_count_u32_elems(cell_np, "reg") / 2;
+
+	cell = kzalloc(sizeof(*cell) + nblocks * sizeof(*blocks), GFP_KERNEL);
+	if (!cell) {
+		rval = -ENOMEM;
+		goto err_mem;
+	}
+
+	cell->nblocks = nblocks;
+	cell->eeprom = eeprom;
+	cell->size = 0;
+	i = 0;
+
+	if (cell_np) {
+		of_property_for_each_u32(cell_np, "reg", prop, vp, pv) {
+			cell->blocks[i].offset = pv;
+			vp = of_prop_next_u32(prop, vp, &pv);
+			cell->blocks[i].count = pv;
+			cell->size += pv;
+			i++;
+		}
+	} else {
+		memcpy(cell->blocks, blocks, nblocks * sizeof(*blocks));
+		for (; i < nblocks; i++)
+			cell->size += blocks[i].count;
+	}
+
+	if (IS_ERR_VALUE(eeprom_cell_sanity_check(cell))) {
+		rval  = -EINVAL;
+		goto err_sanity;
+	}
+
+	return cell;
+
+err_sanity:
+	kfree(cell);
+
+err_mem:
+	module_put(eeprom->owner);
+
+err_mod:
+	mutex_lock(&eeprom_mutex);
+	eeprom->users--;
+	mutex_unlock(&eeprom_mutex);
+
+	return ERR_PTR(rval);
+
+}
+
+/**
+ * eeprom_cell_get(): Get eeprom cell of device form a given eeprom name
+ * and blocks.
+ *
+ * @ename: eeprom device name that needs to be looked-up.
+ * @blocks: eeprom blocks containing offset and length information.
+ * @nblocks: number of eeprom blocks.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks)
+{
+	return __eeprom_cell_get(NULL, ename, blocks, nblocks);
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_get);
+
+/**
+ * of_eeprom_cell_get(): Get eeprom cell of device form a given index
+ *
+ * @dev: Device that will be interacted with
+ * @index: eeprom index in eeproms property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *of_eeprom_cell_get(struct device *dev, int index)
+{
+	struct device_node *cell_np;
+
+	if (!dev || !dev->of_node)
+		return ERR_PTR(-EINVAL);
+
+	cell_np = of_parse_phandle(dev->of_node, "eeproms", index);
+	if (!cell_np)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	return __eeprom_cell_get(cell_np, NULL, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(of_eeprom_cell_get);
+
+/**
+ * of_eeprom_cell_get_byname(): Get eeprom cell of device form a given name
+ *
+ * @dev: Device that will be interacted with
+ * @name: eeprom name in eeprom-names property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+					      const char *id)
+{
+	int index = 0;
+
+	if (!dev || !dev->of_node)
+		return ERR_PTR(-EINVAL);
+
+	if (id)
+		index = of_property_match_string(dev->of_node,
+						 "eeprom-names",
+						 id);
+	return of_eeprom_cell_get(dev, index);
+
+}
+EXPORT_SYMBOL_GPL(of_eeprom_cell_get_byname);
+
+/**
+ * eeprom_cell_put(): Release previously allocated eeprom cell.
+ *
+ * @cell: Previously allocated eeprom cell by eeprom_cell_get()
+ * or of_eeprom_cell_get() or of_eeprom_cell_get_byname().
+ */
+void eeprom_cell_put(struct eeprom_cell *cell)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+
+	mutex_lock(&eeprom_mutex);
+	eeprom->users--;
+	mutex_unlock(&eeprom_mutex);
+	module_put(eeprom->owner);
+	kfree(cell);
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_put);
+
+/**
+ * eeprom_cell_read(): Read a given eeprom cell
+ *
+ * @cell: eeprom cell to be read.
+ * @len: pointer to length of cell which will be populated on successful read.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a char * bufffer.  The buffer should be freed by the consumer with a
+ * kfree().
+ */
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	char *buf;
+	int rc, i, offset = 0;
+
+	if (!eeprom || !eeprom->regmap)
+		return ERR_PTR(-EINVAL);
+
+	buf = kzalloc(cell->size, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < cell->nblocks; i++) {
+		rc = regmap_bulk_read(eeprom->regmap, cell->blocks[i].offset,
+				      buf + offset,
+				      cell->blocks[i].count);
+
+		if (IS_ERR_VALUE(rc)) {
+			kfree(buf);
+			return ERR_PTR(rc);
+		}
+		offset += cell->blocks[i].count;
+	}
+
+	*len = cell->size;
+
+	return buf;
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_read);
+
+/**
+ * eeprom_cell_write(): Write to a given eeprom cell
+ *
+ * @cell: eeprom cell to be written.
+ * @buf: Buffer to be written.
+ * @len: length of buffer to be written to eeprom cell.
+ *
+ * The return value will be an non zero on error or a zero on successful write.
+ */
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	int i, rc, offset = 0;
+
+	if (!eeprom || !eeprom->regmap || len != cell->size)
+		return -EINVAL;
+
+	for (i = 0; i < cell->nblocks; i++) {
+		rc = regmap_bulk_write(eeprom->regmap, cell->blocks[i].offset,
+				 buf + offset,
+				 cell->blocks[i].count);
+
+		if (IS_ERR_VALUE(rc))
+			return rc;
+
+		offset += cell->blocks[i].count;
+	}
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_write);
+
 static int eeprom_init(void)
 {
 	return class_register(&eeprom_class);
diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
new file mode 100644
index 0000000..6d9d075
--- /dev/null
+++ b/include/linux/eeprom-consumer.h
@@ -0,0 +1,67 @@
+/*
+ * EEPROM framework consumer.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_CONSUMER_H
+#define _LINUX_EEPROM_CONSUMER_H
+
+struct eeprom_cell;
+
+struct eeprom_block {
+	loff_t offset;
+	size_t count;
+};
+#if IS_ENABLED(CONFIG_EEPROM)
+struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks);
+void eeprom_cell_put(struct eeprom_cell *cell);
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
+#else
+
+static inline struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks)
+{
+	return NULL;
+}
+
+static inline void eeprom_cell_put(struct eeprom_cell *cell)
+{
+}
+
+static inline char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+	return NULL;
+}
+
+static inline int eeprom_cell_write(struct eeprom_cell *cell,
+				    const char *buf, ssize_t len)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_EEPROM */
+
+#if IS_ENABLED(CONFIG_EEPROM) && IS_ENABLED(CONFIG_OF)
+struct eeprom_cell *of_eeprom_cell_get(struct device *dev, int index);
+struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+					      const char *name);
+#else
+static inline struct eeprom_cell *of_eeprom_cell_get(
+					struct device *dev, int index)
+{
+	return NULL;
+}
+static inline struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+							    const char *name)
+{
+	return NULL;
+}
+#endif
+#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */
-- 
1.9.1


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

* [PATCH v2 3/7] eeprom: Add bindings for simple eeprom framework
  2015-03-13  9:49   ` [PATCH v2 0/7] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  2015-03-13  9:50     ` [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
  2015-03-13  9:50     ` [PATCH v2 2/7] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
@ 2015-03-13  9:50     ` Srinivas Kandagatla
  2015-03-13  9:50     ` [PATCH v2 4/7] eeprom: sunxi: Move the SID driver to the " Srinivas Kandagatla
                       ` (4 subsequent siblings)
  7 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-13  9:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, linux-arm-msm, Srinivas Kandagatla

This patch adds bindings for simple eeprom framework which allows eeprom
consumers to talk to eeprom providers to get access to eeprom cell data.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/eeprom/eeprom.txt          | 70 ++++++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt

diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
new file mode 100644
index 0000000..8348d18
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
@@ -0,0 +1,70 @@
+= EEPROM Data Device Tree Bindings =
+
+This binding is intended to represent the location of hardware
+configuration data stored in EEPROMs.
+
+On a significant proportion of boards, the manufacturer has stored
+some data on an EEPROM-like device, for the OS to be able to retrieve
+these information and act upon it. Obviously, the OS has to know
+about where to retrieve these data from, and where they are stored on
+the storage device.
+
+This document is here to document this.
+
+= Data providers =
+Contains bindings specific to provider drivers and data cells as children
+to this node.
+
+= Data cells =
+These are the child nodes of the provider which contain data cell
+information like offset and size in eeprom provider.
+
+Required properties:
+reg:	specifies the offset in byte within that storage device, and the length
+	in bytes of the data we care about.
+	There could be more then one offset-length pairs in this property.
+
+Optional properties:
+As required by specific data parsers/interpreters.
+
+For example:
+
+	/* Provider */
+	qfprom: qfprom@00700000 {
+		compatible 	= "qcom,qfprom";
+		reg		= <0x00700000 0x1000>;
+		...
+
+		/* Data cells */
+		tsens_calibration: calib@404 {
+			reg = <0x404 0x10>;
+		};
+
+		serial_number: sn {
+			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
+
+		};
+		...
+	};
+
+= Data consumers =
+Are device nodes which consume eeprom data cells.
+
+Required properties:
+
+eeproms: List of phandle and data cell the device might be interested in.
+
+Optional properties:
+
+eeprom-names: List of data cell name strings sorted in the same order
+	      as the eeproms property. Consumers drivers will use
+	      eeprom-names to differentiate between multiple cells,
+	      and hence being able to know what these cells are for.
+
+For example:
+
+	tsens {
+		...
+		eeproms = <&tsens_calibration>;
+		eeprom-names = "calibration";
+	};
-- 
1.9.1


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

* [PATCH v2 4/7] eeprom: sunxi: Move the SID driver to the eeprom framework
  2015-03-13  9:49   ` [PATCH v2 0/7] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                       ` (2 preceding siblings ...)
  2015-03-13  9:50     ` [PATCH v2 3/7] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
@ 2015-03-13  9:50     ` Srinivas Kandagatla
  2015-03-13  9:50     ` [PATCH v2 5/7] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
                       ` (3 subsequent siblings)
  7 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-13  9:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, linux-arm-msm, Srinivas Kandagatla

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

Now that we have the EEPROM framework, we can consolidate the common driver
code. Move the driver to the framework, and hopefully, it will fix the sysfs
file creation race.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[srinivas.kandagatla: Moved to regmap based EEPROM framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 ---
 .../bindings/eeprom/allwinner,sunxi-sid.txt        |  21 +++
 .../bindings/misc/allwinner,sunxi-sid.txt          |  17 ---
 drivers/eeprom/Kconfig                             |  15 ++
 drivers/eeprom/Makefile                            |   3 +
 drivers/eeprom/eeprom-sunxi-sid.c                  | 136 ++++++++++++++++++
 drivers/misc/eeprom/Kconfig                        |  13 --
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 ---------------------
 9 files changed, 175 insertions(+), 209 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
 delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 drivers/eeprom/eeprom-sunxi-sid.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid
deleted file mode 100644
index ffb9536..0000000
--- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid
+++ /dev/null
@@ -1,22 +0,0 @@
-What:		/sys/devices/*/<our-device>/eeprom
-Date:		August 2013
-Contact:	Oliver Schinagl <oliver@schinagl.nl>
-Description:	read-only access to the SID (Security-ID) on current
-		A-series SoC's from Allwinner. Currently supports A10, A10s, A13
-		and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes,
-		whereas the newer A20 SoC exposes 512 bytes split into sections.
-		Besides the 16 bytes of SID, there's also an SJTAG area,
-		HDMI-HDCP key and some custom keys. Below a quick overview, for
-		details see the user manual:
-		0x000  128 bit root-key (sun[457]i)
-		0x010  128 bit boot-key (sun7i)
-		0x020   64 bit security-jtag-key (sun7i)
-		0x028   16 bit key configuration (sun7i)
-		0x02b   16 bit custom-vendor-key (sun7i)
-		0x02c  320 bit low general key (sun7i)
-		0x040   32 bit read-control access (sun7i)
-		0x064  224 bit low general key (sun7i)
-		0x080 2304 bit HDCP-key (sun7i)
-		0x1a0  768 bit high general key (sun7i)
-Users:		any user space application which wants to read the SID on
-		Allwinner's A-series of CPU's.
diff --git a/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
new file mode 100644
index 0000000..cceaaf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
@@ -0,0 +1,21 @@
+Allwinner sunxi-sid
+
+Required properties:
+- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/eeprom/eeprom.txt
+
+Example for sun4i:
+	sid@01c23800 {
+		compatible = "allwinner,sun4i-a10-sid";
+		reg = <0x01c23800 0x10>
+	};
+
+Example for sun7i:
+	sid@01c23800 {
+		compatible = "allwinner,sun7i-a20-sid";
+		reg = <0x01c23800 0x200>
+	};
diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
deleted file mode 100644
index fabdf64..0000000
--- a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Allwinner sunxi-sid
-
-Required properties:
-- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
-- reg: Should contain registers location and length
-
-Example for sun4i:
-	sid@01c23800 {
-		compatible = "allwinner,sun4i-a10-sid";
-		reg = <0x01c23800 0x10>
-	};
-
-Example for sun7i:
-	sid@01c23800 {
-		compatible = "allwinner,sun7i-a20-sid";
-		reg = <0x01c23800 0x200>
-	};
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index 21e1847..fd4fa2f 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -9,3 +9,18 @@ menuconfig EEPROM
 	  from both the Linux Kernel and the userspace.
 
 	  If unsure, say no.
+
+if EEPROM
+
+config EEPROM_SUNXI_SID
+	tristate "Allwinner SoCs SID support"
+	depends on ARCH_SUNXI
+	select REGMAP_MMIO
+	help
+	  This is a driver for the 'security ID' available on various Allwinner
+	  devices.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called eprom-sunxi-sid.
+
+endif
\ No newline at end of file
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 250c95a..546a27c 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -3,3 +3,6 @@
 #
 
 obj-$(CONFIG_EEPROM)		+= core.o
+
+# Devices
+obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
diff --git a/drivers/eeprom/eeprom-sunxi-sid.c b/drivers/eeprom/eeprom-sunxi-sid.c
new file mode 100644
index 0000000..58f7d24
--- /dev/null
+++ b/drivers/eeprom/eeprom-sunxi-sid.c
@@ -0,0 +1,136 @@
+/*
+ * Allwinner sunXi SoCs Security ID support.
+ *
+ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct eeprom_sid {
+	void __iomem	*membase;
+	struct eeprom_device *eeprom;
+};
+
+static struct eeprom_config econfig = {
+	.stride = 1,
+	.name = "sunix-sid",
+};
+
+/* We read the entire key, due to a 32 bit read alignment requirement. Since we
+ * want to return the requested byte, this results in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarely probed, this is not really an issue.
+ */
+static int sunxi_sid_reg_read(void *context,
+			      unsigned int offset, unsigned int *val)
+{
+	struct eeprom_sid *sid  = context;
+	u32 sid_key;
+
+	sid_key = ioread32be(sid->membase + round_down(offset, 4));
+	sid_key >>= (offset % 4) * 8;
+
+	*val = sid_key;
+
+	return 0;
+}
+
+static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
+	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static struct regmap_config sunxi_sid_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+	.reg_read = sunxi_sid_reg_read,
+	.writeable_reg = sunxi_sid_writeable_reg,
+};
+
+static int sunxi_sid_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *device;
+	struct eeprom_sid *sid;
+	struct resource *res;
+	struct eeprom_device *eeprom;
+	struct device *dev = &pdev->dev;
+
+	sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL);
+	if (!sid)
+		return -ENOMEM;
+
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid->membase = devm_ioremap_resource(dev, res);
+	if (IS_ERR(sid->membase))
+		return PTR_ERR(sid->membase);
+
+	device = of_match_device(sunxi_sid_of_match, dev);
+	if (!device)
+		return -ENODEV;
+
+	sunxi_sid_regmap_config.max_register = (unsigned int)device->data - 1;
+
+	econfig.regmap = devm_regmap_init(dev, NULL,
+					  sid, &sunxi_sid_regmap_config);
+	if (IS_ERR(econfig.regmap))
+		return PTR_ERR(econfig.regmap);
+
+	econfig.dev = dev;
+	econfig.owner = THIS_MODULE;
+	econfig.size = sunxi_sid_regmap_config.max_register;
+
+	eeprom = eeprom_register(&econfig);
+	if (IS_ERR(eeprom))
+		return PTR_ERR(eeprom);
+
+	platform_set_drvdata(pdev, eeprom);
+
+	return 0;
+}
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = "eeprom-sunxi-sid",
+		.of_match_table = sunxi_sid_of_match,
+	},
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 9536852f..04f2e1f 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG
 
 	  If unsure, say N.
 
-config EEPROM_SUNXI_SID
-	tristate "Allwinner sunxi security ID support"
-	depends on ARCH_SUNXI && SYSFS
-	help
-	  This is a driver for the 'security ID' available on various Allwinner
-	  devices.
-
-	  Due to the potential risks involved with changing e-fuses,
-	  this driver is read-only.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called sunxi_sid.
-
 endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 9507aec..fc1e81d 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY)	+= eeprom.o
 obj-$(CONFIG_EEPROM_MAX6875)	+= max6875.o
 obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
 obj-$(CONFIG_EEPROM_93XX46)	+= eeprom_93xx46.o
-obj-$(CONFIG_EEPROM_SUNXI_SID)	+= sunxi_sid.o
 obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
deleted file mode 100644
index 8385177..0000000
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
- * http://www.linux-sunxi.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * This driver exposes the Allwinner security ID, efuses exported in byte-
- * sized chunks.
- */
-
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#define DRV_NAME "sunxi-sid"
-
-struct sunxi_sid_data {
-	void __iomem *reg_base;
-	unsigned int keysize;
-};
-
-/* We read the entire key, due to a 32 bit read alignment requirement. Since we
- * want to return the requested byte, this results in somewhat slower code and
- * uses 4 times more reads as needed but keeps code simpler. Since the SID is
- * only very rarely probed, this is not really an issue.
- */
-static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data,
-			      const unsigned int offset)
-{
-	u32 sid_key;
-
-	if (offset >= sid_data->keysize)
-		return 0;
-
-	sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4));
-	sid_key >>= (offset % 4) * 8;
-
-	return sid_key; /* Only return the last byte */
-}
-
-static ssize_t sid_read(struct file *fd, struct kobject *kobj,
-			struct bin_attribute *attr, char *buf,
-			loff_t pos, size_t size)
-{
-	struct platform_device *pdev;
-	struct sunxi_sid_data *sid_data;
-	int i;
-
-	pdev = to_platform_device(kobj_to_dev(kobj));
-	sid_data = platform_get_drvdata(pdev);
-
-	if (pos < 0 || pos >= sid_data->keysize)
-		return 0;
-	if (size > sid_data->keysize - pos)
-		size = sid_data->keysize - pos;
-
-	for (i = 0; i < size; i++)
-		buf[i] = sunxi_sid_read_byte(sid_data, pos + i);
-
-	return i;
-}
-
-static struct bin_attribute sid_bin_attr = {
-	.attr = { .name = "eeprom", .mode = S_IRUGO, },
-	.read = sid_read,
-};
-
-static int sunxi_sid_remove(struct platform_device *pdev)
-{
-	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
-	dev_dbg(&pdev->dev, "driver unloaded\n");
-
-	return 0;
-}
-
-static const struct of_device_id sunxi_sid_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
-	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
-	{/* sentinel */},
-};
-MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-
-static int sunxi_sid_probe(struct platform_device *pdev)
-{
-	struct sunxi_sid_data *sid_data;
-	struct resource *res;
-	const struct of_device_id *of_dev_id;
-	u8 *entropy;
-	unsigned int i;
-
-	sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data),
-				GFP_KERNEL);
-	if (!sid_data)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(sid_data->reg_base))
-		return PTR_ERR(sid_data->reg_base);
-
-	of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev);
-	if (!of_dev_id)
-		return -ENODEV;
-	sid_data->keysize = (int)of_dev_id->data;
-
-	platform_set_drvdata(pdev, sid_data);
-
-	sid_bin_attr.size = sid_data->keysize;
-	if (device_create_bin_file(&pdev->dev, &sid_bin_attr))
-		return -ENODEV;
-
-	entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL);
-	for (i = 0; i < sid_data->keysize; i++)
-		entropy[i] = sunxi_sid_read_byte(sid_data, i);
-	add_device_randomness(entropy, sid_data->keysize);
-	kfree(entropy);
-
-	dev_dbg(&pdev->dev, "loaded\n");
-
-	return 0;
-}
-
-static struct platform_driver sunxi_sid_driver = {
-	.probe = sunxi_sid_probe,
-	.remove = sunxi_sid_remove,
-	.driver = {
-		.name = DRV_NAME,
-		.of_match_table = sunxi_sid_of_match,
-	},
-};
-module_platform_driver(sunxi_sid_driver);
-
-MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
-MODULE_DESCRIPTION("Allwinner sunxi security id driver");
-MODULE_LICENSE("GPL");
-- 
1.9.1


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

* [PATCH v2 5/7] eeprom: qfprom: Add Qualcomm QFPROM support.
  2015-03-13  9:49   ` [PATCH v2 0/7] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                       ` (3 preceding siblings ...)
  2015-03-13  9:50     ` [PATCH v2 4/7] eeprom: sunxi: Move the SID driver to the " Srinivas Kandagatla
@ 2015-03-13  9:50     ` Srinivas Kandagatla
  2015-03-13  9:50     ` [PATCH v2 6/7] eeprom: qfprom: Add bindings for qfprom Srinivas Kandagatla
                       ` (2 subsequent siblings)
  7 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-13  9:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, linux-arm-msm, Srinivas Kandagatla

This patch adds QFPROM support driver which is used by other drivers
like thermal sensor and cpufreq.

On MSM parts there are some efuses (called qfprom) these fuses store things like
calibration data, speed bins.. etc. Drivers like cpufreq, thermal sensors would
read out this data for configuring the driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/Kconfig  |  9 ++++-
 drivers/eeprom/Makefile |  1 +
 drivers/eeprom/qfprom.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 1 deletion(-)
 create mode 100644 drivers/eeprom/qfprom.c

diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index fd4fa2f..b77828b 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -23,4 +23,11 @@ config EEPROM_SUNXI_SID
 	  This driver can also be built as a module. If so, the module
 	  will be called eprom-sunxi-sid.
 
-endif
\ No newline at end of file
+config QCOM_QFPROM
+	tristate "QCOM QFPROM Support"
+	depends on EEPROM
+	select REGMAP_MMIO
+	help
+	  Say y here to enable QFPROM support. The QFPROM provides access
+	  functions for QFPROM data to rest of the drivers via eeprom interface.
+endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 546a27c..9c1bb03 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_EEPROM)		+= core.o
 
 # Devices
 obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
+obj-$(CONFIG_QCOM_QFPROM)	+= qfprom.o
diff --git a/drivers/eeprom/qfprom.c b/drivers/eeprom/qfprom.c
new file mode 100644
index 0000000..7d9e5e9
--- /dev/null
+++ b/drivers/eeprom/qfprom.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/eeprom-provider.h>
+
+static struct regmap_config qfprom_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+};
+
+static struct eeprom_config econfig = {
+	.stride = 1,
+	.name = "qfprom",
+};
+
+static int qfprom_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+
+static int qfprom_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	void __iomem *base;
+	struct device *dev = &pdev->dev;
+	struct eeprom_device *eeprom;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	qfprom_regmap_config.max_register = resource_size(res) - 1;
+
+	econfig.regmap = devm_regmap_init_mmio(dev, base,
+					       &qfprom_regmap_config);
+	if (IS_ERR(econfig.regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(econfig.regmap);
+	}
+	econfig.owner = THIS_MODULE;
+	econfig.dev = dev;
+	econfig.size = resource_size(res) - 1;
+	eeprom = eeprom_register(&econfig);
+	if (IS_ERR(eeprom))
+		return PTR_ERR(eeprom);
+
+	platform_set_drvdata(pdev, eeprom);
+	return 0;
+}
+
+static const struct of_device_id qfprom_of_match[] = {
+	{ .compatible = "qcom,qfprom"},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, qfprom_of_match);
+
+static struct platform_driver qfprom_driver = {
+	.probe = qfprom_probe,
+	.remove = qfprom_remove,
+	.driver = {
+		.name = "qcom,qfprom",
+		.of_match_table = qfprom_of_match,
+	},
+};
+module_platform_driver(qfprom_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm QFPROM driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


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

* [PATCH v2 6/7] eeprom: qfprom: Add bindings for qfprom
  2015-03-13  9:49   ` [PATCH v2 0/7] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                       ` (4 preceding siblings ...)
  2015-03-13  9:50     ` [PATCH v2 5/7] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
@ 2015-03-13  9:50     ` Srinivas Kandagatla
  2015-03-13  9:51     ` [PATCH v2 7/7] eeprom: Add to MAINTAINERS for eeprom framework Srinivas Kandagatla
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  7 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-13  9:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, linux-arm-msm, Srinivas Kandagatla

This patch adds bindings for qfprom found in QCOM SOCs. QFPROM driver
is based on simple eeprom framework.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/eeprom/qfprom.txt          | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/eeprom/qfprom.txt

diff --git a/Documentation/devicetree/bindings/eeprom/qfprom.txt b/Documentation/devicetree/bindings/eeprom/qfprom.txt
new file mode 100644
index 0000000..d5baed6
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/qfprom.txt
@@ -0,0 +1,23 @@
+= Qualcomm QFPROM device tree bindings =
+
+This binding is intended to represent QFPROM which is found in most QCOM SOCs.
+
+Required properties:
+- compatible: should be "qcom,qfprom"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/eeprom/eeprom.txt
+
+Example:
+
+	qfprom: qfprom@00700000 {
+		compatible 	= "qcom,qfprom";
+		reg		= <0x00700000 0x1000>;
+		...
+		/* Data cells */
+		tsens_calibration: calib@404 {
+			reg = <0x404 0x10>;
+		};
+	};
-- 
1.9.1


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

* [PATCH v2 7/7] eeprom: Add to MAINTAINERS for eeprom framework
  2015-03-13  9:49   ` [PATCH v2 0/7] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                       ` (5 preceding siblings ...)
  2015-03-13  9:50     ` [PATCH v2 6/7] eeprom: qfprom: Add bindings for qfprom Srinivas Kandagatla
@ 2015-03-13  9:51     ` Srinivas Kandagatla
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  7 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-13  9:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, linux-arm-msm, Srinivas Kandagatla

This patch adds MAINTAINERS to eeprom framework.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index d66a97d..ee7ba92 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3657,6 +3657,15 @@ T:	git git://git.alsa-project.org/alsa-kernel.git
 S:	Maintained
 F:	sound/usb/misc/ua101.c
 
+EEPROM FRAMEWORK
+M:	Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+M:	Maxime Ripard <maxime.ripard@free-electrons.com>
+S:	Maintained
+F:	drivers/eeprom/
+F:	Documentation/devicetree/bindings/eeprom/
+F:	include/linux/eeprom-provider.h
+F:	include/linux/eeprom-consumer.h
+
 EXTENSIBLE FIRMWARE INTERFACE (EFI)
 M:	Matt Fleming <matt.fleming@intel.com>
 L:	linux-efi@vger.kernel.org
-- 
1.9.1


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

* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-13  9:50     ` [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
@ 2015-03-23 21:09       ` Mark Brown
  2015-03-23 22:05         ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Mark Brown @ 2015-03-23 21:09 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 856 bytes --]

On Fri, Mar 13, 2015 at 09:50:14AM +0000, Srinivas Kandagatla wrote:

A couple of *very* minor points below, otherwise this looks OK to me.

> +struct eeprom_device *eeprom_register(struct eeprom_config *config)
> +{
> +	struct eeprom_device *eeprom;
> +	int rval;
> +
> +	if (!config->regmap || !config->size) {
> +		dev_err(config->dev, "Regmap not found\n");
> +		return ERR_PTR(-EINVAL);
> +	}

You have a struct device in the config and the regmap API has
dev_get_regmap() which for most devices that don't have multiple regmaps
will give the right regmap.  It would be nice to support this as a
convenience for users.

> +	eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL);
> +	if (!eeprom)
> +		return ERR_PTR(-ENOMEM);

...

> +	rval = device_add(&eeprom->dev);
> +	if (rval)
> +		return ERR_PTR(rval);

Don't you need a kfree() if device_add() fails?

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-23 21:09       ` Mark Brown
@ 2015-03-23 22:05         ` Srinivas Kandagatla
  2015-03-24  9:18           ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-23 22:05 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm



On 23/03/15 21:09, Mark Brown wrote:
> On Fri, Mar 13, 2015 at 09:50:14AM +0000, Srinivas Kandagatla wrote:
>
> A couple of *very* minor points below, otherwise this looks OK to me.
>
Thankyou for the review.

>> +struct eeprom_device *eeprom_register(struct eeprom_config *config)
>> +{
>> +	struct eeprom_device *eeprom;
>> +	int rval;
>> +
>> +	if (!config->regmap || !config->size) {
>> +		dev_err(config->dev, "Regmap not found\n");
>> +		return ERR_PTR(-EINVAL);
>> +	}
>
> You have a struct device in the config and the regmap API has
> dev_get_regmap() which for most devices that don't have multiple regmaps
> will give the right regmap.  It would be nice to support this as a
> convenience for users.
Yes, sure that makes sense, I will give it a try.

>
>> +	eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL);
>> +	if (!eeprom)
>> +		return ERR_PTR(-ENOMEM);
>
> ...
>
>> +	rval = device_add(&eeprom->dev);
>> +	if (rval)
>> +		return ERR_PTR(rval);
>
> Don't you need a kfree() if device_add() fails?
I will fix it in next version.

--srini
>

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

* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-23 22:05         ` Srinivas Kandagatla
@ 2015-03-24  9:18           ` Srinivas Kandagatla
  2015-03-24 17:23             ` Mark Brown
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24  9:18 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm



On 23/03/15 22:05, Srinivas Kandagatla wrote:
>
>
> On 23/03/15 21:09, Mark Brown wrote:
>> On Fri, Mar 13, 2015 at 09:50:14AM +0000, Srinivas Kandagatla wrote:
>>
>> A couple of *very* minor points below, otherwise this looks OK to me.
>>
> Thankyou for the review.
>
>>> +struct eeprom_device *eeprom_register(struct eeprom_config *config)
>>> +{
>>> +    struct eeprom_device *eeprom;
>>> +    int rval;
>>> +
>>> +    if (!config->regmap || !config->size) {
>>> +        dev_err(config->dev, "Regmap not found\n");
>>> +        return ERR_PTR(-EINVAL);
>>> +    }
>>
>> You have a struct device in the config and the regmap API has
>> dev_get_regmap() which for most devices that don't have multiple regmaps
>> will give the right regmap.  It would be nice to support this as a
>> convenience for users.
> Yes, sure that makes sense, I will give it a try.
>
I did try your suggestion, by which I could remove the regmap from 
config. One thing I did not like was eeprom-core getting size/stride 
info directly from providers and regmap from regmap apis. I was 
wondering if we could take a step further and introduce new regmap 
helpers like

regmap_get_size(regmap)
regmap_get_stride(regmap)

Which would be give eeprom-core the size and stride info, doing this way 
would cut down regmap related things from eeprom_config structure to 
minimal and also the source of information would come from just regmap apis.


--srini

>>
>>> +    eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL);
>>> +    if (!eeprom)
>>> +        return ERR_PTR(-ENOMEM);
>>
>> ...
>>
>>> +    rval = device_add(&eeprom->dev);
>>> +    if (rval)
>>> +        return ERR_PTR(rval);
>>
>> Don't you need a kfree() if device_add() fails?
> I will fix it in next version.
>
> --srini
>>

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

* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-24  9:18           ` Srinivas Kandagatla
@ 2015-03-24 17:23             ` Mark Brown
  2015-03-24 18:34               ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Mark Brown @ 2015-03-24 17:23 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 700 bytes --]

On Tue, Mar 24, 2015 at 09:18:14AM +0000, Srinivas Kandagatla wrote:

> I did try your suggestion, by which I could remove the regmap from config.
> One thing I did not like was eeprom-core getting size/stride info directly
> from providers and regmap from regmap apis. I was wondering if we could take
> a step further and introduce new regmap helpers like

> regmap_get_size(regmap)

This is already there.

> regmap_get_stride(regmap)

> Which would be give eeprom-core the size and stride info, doing this way
> would cut down regmap related things from eeprom_config structure to minimal
> and also the source of information would come from just regmap apis.

Documentation/SubmittingPatches...

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-24 17:23             ` Mark Brown
@ 2015-03-24 18:34               ` Srinivas Kandagatla
  2015-03-24 19:02                 ` Mark Brown
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 18:34 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm



On 24/03/15 17:23, Mark Brown wrote:
> On Tue, Mar 24, 2015 at 09:18:14AM +0000, Srinivas Kandagatla wrote:
>
>> I did try your suggestion, by which I could remove the regmap from config.
>> One thing I did not like was eeprom-core getting size/stride info directly
>> from providers and regmap from regmap apis. I was wondering if we could take
>> a step further and introduce new regmap helpers like
>
>> regmap_get_size(regmap)
>
> This is already there.
Sorry, I can't see any such api atleast in v4.0-rc5 and linux-next? Are 
you referring to another api which does the same job?

>
>> regmap_get_stride(regmap)
>
>> Which would be give eeprom-core the size and stride info, doing this way
>> would cut down regmap related things from eeprom_config structure to minimal
>> and also the source of information would come from just regmap apis.
>
> Documentation/SubmittingPatches...
>
Am not sure what you meant here, Am guessing that you asked me to keep 
the respective maintainers in the loop and follow the guide, when I 
resend the patch?

--srini

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

* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-24 18:34               ` Srinivas Kandagatla
@ 2015-03-24 19:02                 ` Mark Brown
  2015-03-24 19:26                   ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Mark Brown @ 2015-03-24 19:02 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 824 bytes --]

On Tue, Mar 24, 2015 at 06:34:32PM +0000, Srinivas Kandagatla wrote:
> On 24/03/15 17:23, Mark Brown wrote:

> >>regmap_get_size(regmap)

> >This is already there.

> Sorry, I can't see any such api atleast in v4.0-rc5 and linux-next? Are you
> referring to another api which does the same job?

regmap_get_val_bytes()

> >>Which would be give eeprom-core the size and stride info, doing this way
> >>would cut down regmap related things from eeprom_config structure to minimal
> >>and also the source of information would come from just regmap apis.

> >Documentation/SubmittingPatches...

> Am not sure what you meant here, Am guessing that you asked me to keep the
> respective maintainers in the loop and follow the guide, when I resend the
> patch?

I'm saying that you should send patches if you want to add features.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-24 19:02                 ` Mark Brown
@ 2015-03-24 19:26                   ` Srinivas Kandagatla
  2015-03-24 20:55                     ` Mark Brown
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 19:26 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm



On 24/03/15 19:02, Mark Brown wrote:
> On Tue, Mar 24, 2015 at 06:34:32PM +0000, Srinivas Kandagatla wrote:
>> >On 24/03/15 17:23, Mark Brown wrote:
>>>> > >>regmap_get_size(regmap)
>>> > >This is already there.
>> >Sorry, I can't see any such api atleast in v4.0-rc5 and linux-next? Are you
>> >referring to another api which does the same job?
> regmap_get_val_bytes()
>
This would return value bytes, but I wanted is the regmap->max_register 
value which would be used for sanity checks in eeprom-core.

--srini


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

* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-24 19:26                   ` Srinivas Kandagatla
@ 2015-03-24 20:55                     ` Mark Brown
  0 siblings, 0 replies; 153+ messages in thread
From: Mark Brown @ 2015-03-24 20:55 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
	Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 804 bytes --]

On Tue, Mar 24, 2015 at 07:26:45PM +0000, Srinivas Kandagatla wrote:
> On 24/03/15 19:02, Mark Brown wrote:
> >On Tue, Mar 24, 2015 at 06:34:32PM +0000, Srinivas Kandagatla wrote:
> >>>On 24/03/15 17:23, Mark Brown wrote:

> >>>>> >>regmap_get_size(regmap)

> >>>> >This is already there.

> >>>Sorry, I can't see any such api atleast in v4.0-rc5 and linux-next? Are you
> >>>referring to another api which does the same job?

> >regmap_get_val_bytes()

> This would return value bytes, but I wanted is the regmap->max_register
> value which would be used for sanity checks in eeprom-core.

Then you *really* want to pick a better name then, I'd never have
inferred that meaning from "size" (consider sparse register maps for
example).  Like I said, send patches (preferrably showing the users as
well).

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* [PATCH v3 0/9]  Add simple EEPROM Framework via regmap.
  2015-03-13  9:49   ` [PATCH v2 0/7] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                       ` (6 preceding siblings ...)
  2015-03-13  9:51     ` [PATCH v2 7/7] eeprom: Add to MAINTAINERS for eeprom framework Srinivas Kandagatla
@ 2015-03-24 22:28     ` Srinivas Kandagatla
  2015-03-24 22:29       ` [PATCH v3 1/9] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
                         ` (9 more replies)
  7 siblings, 10 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 22:28 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

Thankyou all for providing inputs and comments on previous versions of this patchset.
Here is the v3 of the patchset addressing all the issues raised as
part of previous versions review.

This patchset adds a new simple EEPROM framework to kernel.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.
    
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
    
This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
    
Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

patch 1-2 Introduces two regmap helper functions.
patch 3-5 Introduces the EEPROM framework.
Patch 6 migrates an existing driver to eeprom framework.
Patch 7-8 Adds Qualcomm specific qfprom driver.
Patch 9 adds entry in MAINTAINERS.

Its also possible to migrate other eeprom drivers to this framework.
Patch 6 can also be made a generic mmio-eeprom driver.

Providers APIs:
	eeprom_register/unregister();

Consumers APIs:
	eeprom_cell_get()/of_eeprom_cell_get()/of_eeprom_cell_get_byname();
	eeprom_cell_put();
	eeprom_cell_read()/eeprom_cell_write();

Device Tree:

	/* Provider */
	qfprom: qfprom@00700000 {
		compatible 	= "qcom,qfprom";
		reg		= <0x00700000 0x1000>;
		...

		/* Data cells */
		tsens_calibration: calib@404 {
			reg = <0x404 0x10>;
		};

		serial_number: sn {
			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;

		};
		...
	};
	
	/* Consumer node */
	tsens: tsens {
		...
		eeproms = <&tsens_calibration>;
		eeprom-names = "calib";
		...
	};

userspace interface:

hexdump /sys/class/eeprom/qfprom0/eeprom
                                                                                                                                                                                                                  
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
0000000 0000 0000 0000 0000 0000 0000 0000 0000
...
*
0001000

Changes since v2(https://lkml.org/lkml/2015/3/13/168)
 * Fixed error handling in eeprom_register spotted by Mark Brown
 * Added new regmap_get_max_register() and regmap_get_reg_stride().
 * Fixed module build errors reported by kbuild robot.
 * recycle the ids when eeprom provider is released.

Changes since v1(https://lkml.org/lkml/2015/3/5/153)
 * Fix various Licencing issues spotted by Paul Bolle and Mark Brown
 * Allow eeprom core to build as module spotted by Paul Bolle.
 * Fix various kconfig issues spotted by Paul Bolle.
 * remove unessary atomic varible spotted by Mark Brown.
 * Few cleanups and common up some of the code in core.
 * Add qfprom bindings.

Changes since RFC(https://lkml.org/lkml/2015/2/19/307)
 * Fix documentation and error checks in read/write spotted by Andrew Lunn
 * Kconfig fix suggested by Stephen Boyd.
 * Add module owner suggested by Stephen Boyd and others.
 * Fix unsafe handling of eeprom in unregister spotted by Russell and Mark Brown.
 * seperate bindings patch as suggested by Rob.
 * Add MAINTAINERS as suggested by Rob.
 * Added support to allow reading eeprom for things like serial number which
 * canbe scatters across.
 * Added eeprom data using reg property suggested by Sascha and Stephen.
 * Added non-DT support.
 * Move kerneldoc to the src files spotted by Mark Brown.
 * Remove local list and do eeprom lookup by using class_find_device()


Thanks,
srini

Maxime Ripard (1):
  eeprom: sunxi: Move the SID driver to the eeprom framework

Srinivas Kandagatla (8):
  regmap: Introduce regmap_get_max_register.
  regmap: Introduce regmap_get_reg_stride.
  eeprom: Add a simple EEPROM framework for eeprom providers
  eeprom: Add a simple EEPROM framework for eeprom consumers
  eeprom: Add bindings for simple eeprom framework
  eeprom: qfprom: Add Qualcomm QFPROM support.
  eeprom: qfprom: Add bindings for qfprom
  eeprom: Add to MAINTAINERS for eeprom framework

 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 -
 .../bindings/eeprom/allwinner,sunxi-sid.txt        |  21 +
 .../devicetree/bindings/eeprom/eeprom.txt          |  70 +++
 .../devicetree/bindings/eeprom/qfprom.txt          |  23 +
 .../bindings/misc/allwinner,sunxi-sid.txt          |  17 -
 MAINTAINERS                                        |   9 +
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/base/regmap/regmap.c                       |  23 +
 drivers/eeprom/Kconfig                             |  37 ++
 drivers/eeprom/Makefile                            |  12 +
 drivers/eeprom/core.c                              | 531 +++++++++++++++++++++
 drivers/eeprom/qfprom.c                            |  87 ++++
 drivers/eeprom/sunxi-sid.c                         | 136 ++++++
 drivers/misc/eeprom/Kconfig                        |  13 -
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 ------
 include/linux/eeprom-consumer.h                    |  67 +++
 include/linux/eeprom-provider.h                    |  42 ++
 include/linux/regmap.h                             |  14 +
 20 files changed, 1075 insertions(+), 209 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
 create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
 create mode 100644 Documentation/devicetree/bindings/eeprom/qfprom.txt
 delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 drivers/eeprom/Kconfig
 create mode 100644 drivers/eeprom/Makefile
 create mode 100644 drivers/eeprom/core.c
 create mode 100644 drivers/eeprom/qfprom.c
 create mode 100644 drivers/eeprom/sunxi-sid.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
 create mode 100644 include/linux/eeprom-consumer.h
 create mode 100644 include/linux/eeprom-provider.h

-- 
1.9.1


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

* [PATCH v3 1/9] regmap: Introduce regmap_get_max_register.
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
@ 2015-03-24 22:29       ` Srinivas Kandagatla
  2015-03-24 22:36         ` Mark Brown
  2015-03-24 22:30       ` [PATCH v3 2/9] regmap: Introduce regmap_get_reg_stride Srinivas Kandagatla
                         ` (8 subsequent siblings)
  9 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 22:29 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch introduces regmap_get_max_register() function which would be
used by the infrastructures like eeprom framework built on top of
regmap.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/base/regmap/regmap.c | 12 ++++++++++++
 include/linux/regmap.h       |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index d2f8a81..6fd234b 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2616,6 +2616,18 @@ int regmap_get_val_bytes(struct regmap *map)
 }
 EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
 
+/*
+ * regmap_get_max_register(): Report the max register value
+ *
+ * Report the max register value, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_max_register(struct regmap *map)
+{
+	return map->max_register ? : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regmap_get_max_register);
+
 int regmap_parse_val(struct regmap *map, const void *buf,
 			unsigned int *val)
 {
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 4419b99..c46dbf3 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -433,6 +433,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
 				   unsigned int mask, unsigned int val,
 				   bool *change);
 int regmap_get_val_bytes(struct regmap *map);
+int regmap_get_max_register(struct regmap *map);
 int regmap_async_complete(struct regmap *map);
 bool regmap_can_raw_write(struct regmap *map);
 
@@ -676,6 +677,12 @@ static inline int regmap_get_val_bytes(struct regmap *map)
 	return -EINVAL;
 }
 
+static inline int regmap_get_max_register(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline int regcache_sync(struct regmap *map)
 {
 	WARN_ONCE(1, "regmap API is disabled");
-- 
1.9.1


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

* [PATCH v3 2/9] regmap: Introduce regmap_get_reg_stride.
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  2015-03-24 22:29       ` [PATCH v3 1/9] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
@ 2015-03-24 22:30       ` Srinivas Kandagatla
  2015-03-24 22:37         ` Mark Brown
  2015-03-24 22:30       ` [PATCH v3 3/9] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
                         ` (7 subsequent siblings)
  9 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch introduces regmap_get_reg_stride() function which would
be used by the infrastructures like eeprom framework built on top of
regmap. Mostly this function would be used for sanity checks on inputs
within such infrastructure.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/base/regmap/regmap.c | 11 +++++++++++
 include/linux/regmap.h       |  7 +++++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6fd234b..44d3d94 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2628,6 +2628,17 @@ int regmap_get_max_register(struct regmap *map)
 }
 EXPORT_SYMBOL_GPL(regmap_get_max_register);
 
+ /* regmap_get_reg_stride(): Report the register address stride
+ *
+ * Report the register address stride, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_reg_stride(struct regmap *map)
+{
+	return map->reg_stride;
+}
+EXPORT_SYMBOL_GPL(regmap_get_reg_stride);
+
 int regmap_parse_val(struct regmap *map, const void *buf,
 			unsigned int *val)
 {
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index c46dbf3..b58067c 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -434,6 +434,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
 				   bool *change);
 int regmap_get_val_bytes(struct regmap *map);
 int regmap_get_max_register(struct regmap *map);
+int regmap_get_reg_stride(struct regmap *map);
 int regmap_async_complete(struct regmap *map);
 bool regmap_can_raw_write(struct regmap *map);
 
@@ -683,6 +684,12 @@ static inline int regmap_get_max_register(struct regmap *map)
 	return -EINVAL;
 }
 
+static inline int regmap_get_reg_stride(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline int regcache_sync(struct regmap *map)
 {
 	WARN_ONCE(1, "regmap API is disabled");
-- 
1.9.1


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

* [PATCH v3 3/9] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  2015-03-24 22:29       ` [PATCH v3 1/9] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
  2015-03-24 22:30       ` [PATCH v3 2/9] regmap: Introduce regmap_get_reg_stride Srinivas Kandagatla
@ 2015-03-24 22:30       ` Srinivas Kandagatla
  2015-03-24 22:53         ` Mark Brown
  2015-03-24 22:30       ` [PATCH v3 4/9] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
                         ` (6 subsequent siblings)
  9 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds just providers part of the framework just to enable easy
review.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.

Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/Kconfig                 |   2 +
 drivers/Makefile                |   1 +
 drivers/eeprom/Kconfig          |  11 ++
 drivers/eeprom/Makefile         |   6 ++
 drivers/eeprom/core.c           | 227 ++++++++++++++++++++++++++++++++++++++++
 include/linux/eeprom-provider.h |  42 ++++++++
 6 files changed, 289 insertions(+)
 create mode 100644 drivers/eeprom/Kconfig
 create mode 100644 drivers/eeprom/Makefile
 create mode 100644 drivers/eeprom/core.c
 create mode 100644 include/linux/eeprom-provider.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index c70d6e4..d7afc82 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
 
 source "drivers/android/Kconfig"
 
+source "drivers/eeprom/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 527a6da..57eb5b0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= coresight/
 obj-$(CONFIG_ANDROID)		+= android/
+obj-$(CONFIG_EEPROM)		+= eeprom/
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
new file mode 100644
index 0000000..21e1847
--- /dev/null
+++ b/drivers/eeprom/Kconfig
@@ -0,0 +1,11 @@
+menuconfig EEPROM
+	tristate "EEPROM Support"
+	depends on OF
+	select REGMAP
+	help
+	  Support for EEPROM alike devices.
+
+	  This framework is designed to provide a generic interface to EEPROM
+	  from both the Linux Kernel and the userspace.
+
+	  If unsure, say no.
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
new file mode 100644
index 0000000..51a727f
--- /dev/null
+++ b/drivers/eeprom/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for eeprom drivers.
+#
+
+obj-$(CONFIG_EEPROM)		+= eeprom_core.o
+eeprom_core-y			:= core.o
diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
new file mode 100644
index 0000000..9fd556c
--- /dev/null
+++ b/drivers/eeprom/core.c
@@ -0,0 +1,227 @@
+/*
+ * EEPROM framework core.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+struct eeprom_device {
+	struct regmap		*regmap;
+	int			stride;
+	size_t			size;
+
+	struct module		*owner;
+	struct device		dev;
+	int			id;
+	int			users;
+};
+
+static DEFINE_MUTEX(eeprom_mutex);
+static DEFINE_IDA(eeprom_ida);
+
+#define to_eeprom(d) container_of(d, struct eeprom_device, dev)
+
+static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
+				    struct bin_attribute *attr,
+				    char *buf, loff_t offset, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct eeprom_device *eeprom = to_eeprom(dev);
+	int rc;
+
+	if (offset > eeprom->size)
+		return -EINVAL;
+
+	if (offset + count > eeprom->size)
+		count = eeprom->size - offset;
+
+	rc = regmap_bulk_read(eeprom->regmap, offset,
+			      buf, count/eeprom->stride);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count - count % eeprom->stride;
+}
+
+static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *attr,
+				     char *buf, loff_t offset, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct eeprom_device *eeprom = to_eeprom(dev);
+	int rc;
+
+	if (offset > eeprom->size)
+		return -EINVAL;
+
+	if (offset + count > eeprom->size)
+		count = eeprom->size - offset;
+
+	rc = regmap_bulk_write(eeprom->regmap, offset,
+			       buf, count/eeprom->stride);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count - count % eeprom->stride;
+}
+
+static struct bin_attribute bin_attr_eeprom = {
+	.attr	= {
+		.name	= "eeprom",
+		.mode	= S_IWUSR | S_IRUGO,
+	},
+	.read	= bin_attr_eeprom_read,
+	.write	= bin_attr_eeprom_write,
+};
+
+static struct bin_attribute *eeprom_bin_attributes[] = {
+	&bin_attr_eeprom,
+	NULL,
+};
+
+static const struct attribute_group eeprom_bin_group = {
+	.bin_attrs	= eeprom_bin_attributes,
+};
+
+static const struct attribute_group *eeprom_dev_groups[] = {
+	&eeprom_bin_group,
+	NULL,
+};
+
+static void eeprom_release(struct device *dev)
+{
+	struct eeprom_device *eeprom = to_eeprom(dev);
+
+	ida_simple_remove(&eeprom_ida, eeprom->id);
+	kfree(eeprom);
+}
+
+static struct class eeprom_class = {
+	.name		= "eeprom",
+	.dev_groups	= eeprom_dev_groups,
+	.dev_release	= eeprom_release,
+};
+
+/**
+ * eeprom_register(): Register a eeprom device for given eeprom.
+ * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
+ *
+ * @eeprom: eeprom device that needs to be created
+ *
+ * The return value will be an error code on error or a zero on success.
+ * The eeprom_device and sysfs entery will be freed by the eeprom_unregister().
+ */
+
+struct eeprom_device *eeprom_register(struct eeprom_config *config)
+{
+	struct eeprom_device *eeprom;
+	struct regmap *rm;
+	int rval;
+
+	if (!config->dev)
+		return ERR_PTR(-EINVAL);
+
+	rm = dev_get_regmap(config->dev, NULL);
+	if (!rm) {
+		dev_err(config->dev, "Regmap not found\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL);
+	if (!eeprom)
+		return ERR_PTR(-ENOMEM);
+
+	eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
+	if (eeprom->id < 0) {
+		kfree(eeprom);
+		return ERR_PTR(eeprom->id);
+	}
+
+	eeprom->regmap = rm;
+	eeprom->owner = config->owner;
+	eeprom->stride = regmap_get_reg_stride(rm);
+	eeprom->size = regmap_get_max_register(rm);
+	eeprom->dev.class = &eeprom_class;
+	eeprom->dev.parent = config->dev;
+	eeprom->dev.of_node = config->dev ? config->dev->of_node : NULL;
+	dev_set_name(&eeprom->dev, "%s%d",
+		     config->name ? : "eeprom", config->id);
+
+	device_initialize(&eeprom->dev);
+
+	dev_dbg(&eeprom->dev, "Registering eeprom device %s\n",
+		dev_name(&eeprom->dev));
+
+	rval = device_add(&eeprom->dev);
+	if (rval) {
+		ida_simple_remove(&eeprom_ida, eeprom->id);
+		kfree(eeprom);
+		return ERR_PTR(rval);
+	}
+
+	return eeprom;
+}
+EXPORT_SYMBOL_GPL(eeprom_register);
+
+/**
+ * eeprom_unregister(): Unregister previously registered eeprom device
+ *
+ * @eeprom: Pointer to previously registered eeprom device.
+ *
+ * The return value will be an non zero on error or a zero on success.
+ */
+int eeprom_unregister(struct eeprom_device *eeprom)
+{
+	mutex_lock(&eeprom_mutex);
+	if (eeprom->users) {
+		mutex_unlock(&eeprom_mutex);
+		return -EBUSY;
+	}
+	mutex_unlock(&eeprom_mutex);
+
+	device_del(&eeprom->dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(eeprom_unregister);
+
+static int eeprom_init(void)
+{
+	return class_register(&eeprom_class);
+}
+
+static void eeprom_exit(void)
+{
+	class_unregister(&eeprom_class);
+}
+
+subsys_initcall(eeprom_init);
+module_exit(eeprom_exit);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("EEPROM Driver Core");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
new file mode 100644
index 0000000..f2efa07
--- /dev/null
+++ b/include/linux/eeprom-provider.h
@@ -0,0 +1,42 @@
+/*
+ * EEPROM framework provider.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_PROVIDER_H
+#define _LINUX_EEPROM_PROVIDER_H
+
+struct eeprom_device;
+
+struct eeprom_config {
+	struct device		*dev;
+	const char		*name;
+	int			id;
+	struct module		*owner;
+};
+
+#if IS_ENABLED(CONFIG_EEPROM)
+
+struct eeprom_device *eeprom_register(struct eeprom_config *cfg);
+int eeprom_unregister(struct eeprom_device *eeprom);
+
+#else
+
+static inline struct eeprom_device *eeprom_register(struct eeprom_config *cfg)
+{
+	return NULL;
+}
+static inline int eeprom_unregister(struct eeprom_device *eeprom)
+{
+	return -ENOSYS;
+}
+
+#endif /* CONFIG_EEPROM */
+
+#endif  /* ifndef _LINUX_EEPROM_PROVIDER_H */
-- 
1.9.1


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

* [PATCH v3 4/9] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                         ` (2 preceding siblings ...)
  2015-03-24 22:30       ` [PATCH v3 3/9] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
@ 2015-03-24 22:30       ` Srinivas Kandagatla
  2015-03-25  7:16         ` Sascha Hauer
  2015-03-24 22:30       ` [PATCH v3 5/9] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
                         ` (5 subsequent siblings)
  9 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds just consumers part of the framework just to enable easy
review.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.

Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of the framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/core.c           | 304 ++++++++++++++++++++++++++++++++++++++++
 include/linux/eeprom-consumer.h |  67 +++++++++
 2 files changed, 371 insertions(+)
 create mode 100644 include/linux/eeprom-consumer.h

diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
index 9fd556c..43d03ef 100644
--- a/drivers/eeprom/core.c
+++ b/drivers/eeprom/core.c
@@ -16,6 +16,7 @@
 
 #include <linux/device.h>
 #include <linux/eeprom-provider.h>
+#include <linux/eeprom-consumer.h>
 #include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/idr.h>
@@ -37,6 +38,13 @@ struct eeprom_device {
 	int			users;
 };
 
+struct eeprom_cell {
+	struct eeprom_device	*eeprom;
+	int			nblocks;
+	int			size;
+	struct eeprom_block	blocks[0];
+};
+
 static DEFINE_MUTEX(eeprom_mutex);
 static DEFINE_IDA(eeprom_ida);
 
@@ -125,6 +133,37 @@ static struct class eeprom_class = {
 	.dev_release	= eeprom_release,
 };
 
+static int of_eeprom_match(struct device *dev, const void *eeprom_np)
+{
+	return dev->of_node == eeprom_np;
+}
+
+static struct eeprom_device *of_eeprom_find(struct device_node *eeprom_np)
+{
+	struct device *d;
+
+	if (!eeprom_np)
+		return NULL;
+
+	d = class_find_device(&eeprom_class, NULL, eeprom_np, of_eeprom_match);
+
+	return d ? to_eeprom(d) : NULL;
+}
+
+static int eeprom_match(struct device *dev, const void *data)
+{
+	return !strcmp(dev_name(dev), (const char *)data);
+}
+
+static struct eeprom_device *eeprom_find(const char *name)
+{
+	struct device *d;
+
+	d = class_find_device(&eeprom_class, NULL, (void *)name, eeprom_match);
+
+	return d ? to_eeprom(d) : NULL;
+}
+
 /**
  * eeprom_register(): Register a eeprom device for given eeprom.
  * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
@@ -208,6 +247,271 @@ int eeprom_unregister(struct eeprom_device *eeprom)
 }
 EXPORT_SYMBOL_GPL(eeprom_unregister);
 
+static int eeprom_cell_sanity_check(struct eeprom_cell *cell)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	int i;
+
+	/* byte aligned, no need to check for stride sanity */
+	if (eeprom->stride == 1)
+		return 0;
+
+	for (i = 0; i < cell->nblocks; i++) {
+		if (!IS_ALIGNED(cell->blocks[i].offset, eeprom->stride) ||
+		    !IS_ALIGNED(cell->blocks[i].count, eeprom->stride)) {
+			dev_err(&eeprom->dev,
+				"cell unaligned to eeprom stride %d\n",
+				eeprom->stride);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static struct eeprom_cell *__eeprom_cell_get(struct device_node *cell_np,
+					     const char *ename,
+					     struct eeprom_block *blocks,
+					     int nblocks)
+{
+	struct eeprom_cell *cell;
+	struct eeprom_device *eeprom = NULL;
+	struct property *prop;
+	const __be32 *vp;
+	u32 pv;
+	int i, rval;
+
+	mutex_lock(&eeprom_mutex);
+
+	eeprom = cell_np ? of_eeprom_find(cell_np->parent) : eeprom_find(ename);
+	if (!eeprom) {
+		mutex_unlock(&eeprom_mutex);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	eeprom->users++;
+	mutex_unlock(&eeprom_mutex);
+
+	if (!try_module_get(eeprom->owner)) {
+		dev_err(&eeprom->dev,
+			"could not increase module refcount for cell %s\n",
+			ename);
+		rval = -EINVAL;
+		goto err_mod;
+	}
+
+	if (cell_np)
+		nblocks = of_property_count_u32_elems(cell_np, "reg") / 2;
+
+	cell = kzalloc(sizeof(*cell) + nblocks * sizeof(*blocks), GFP_KERNEL);
+	if (!cell) {
+		rval = -ENOMEM;
+		goto err_mem;
+	}
+
+	cell->nblocks = nblocks;
+	cell->eeprom = eeprom;
+	cell->size = 0;
+	i = 0;
+
+	if (cell_np) {
+		of_property_for_each_u32(cell_np, "reg", prop, vp, pv) {
+			cell->blocks[i].offset = pv;
+			vp = of_prop_next_u32(prop, vp, &pv);
+			cell->blocks[i].count = pv;
+			cell->size += pv;
+			i++;
+		}
+	} else {
+		memcpy(cell->blocks, blocks, nblocks * sizeof(*blocks));
+		for (; i < nblocks; i++)
+			cell->size += blocks[i].count;
+	}
+
+	if (IS_ERR_VALUE(eeprom_cell_sanity_check(cell))) {
+		rval  = -EINVAL;
+		goto err_sanity;
+	}
+
+	return cell;
+
+err_sanity:
+	kfree(cell);
+
+err_mem:
+	module_put(eeprom->owner);
+
+err_mod:
+	mutex_lock(&eeprom_mutex);
+	eeprom->users--;
+	mutex_unlock(&eeprom_mutex);
+
+	return ERR_PTR(rval);
+
+}
+
+/**
+ * eeprom_cell_get(): Get eeprom cell of device form a given eeprom name
+ * and blocks.
+ *
+ * @ename: eeprom device name that needs to be looked-up.
+ * @blocks: eeprom blocks containing offset and length information.
+ * @nblocks: number of eeprom blocks.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks)
+{
+	return __eeprom_cell_get(NULL, ename, blocks, nblocks);
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_get);
+
+/**
+ * of_eeprom_cell_get(): Get eeprom cell of device form a given index
+ *
+ * @dev: Device that will be interacted with
+ * @index: eeprom index in eeproms property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *of_eeprom_cell_get(struct device *dev, int index)
+{
+	struct device_node *cell_np;
+
+	if (!dev || !dev->of_node)
+		return ERR_PTR(-EINVAL);
+
+	cell_np = of_parse_phandle(dev->of_node, "eeproms", index);
+	if (!cell_np)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	return __eeprom_cell_get(cell_np, NULL, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(of_eeprom_cell_get);
+
+/**
+ * of_eeprom_cell_get_byname(): Get eeprom cell of device form a given name
+ *
+ * @dev: Device that will be interacted with
+ * @name: eeprom name in eeprom-names property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+					      const char *id)
+{
+	int index = 0;
+
+	if (!dev || !dev->of_node)
+		return ERR_PTR(-EINVAL);
+
+	if (id)
+		index = of_property_match_string(dev->of_node,
+						 "eeprom-names",
+						 id);
+	return of_eeprom_cell_get(dev, index);
+
+}
+EXPORT_SYMBOL_GPL(of_eeprom_cell_get_byname);
+
+/**
+ * eeprom_cell_put(): Release previously allocated eeprom cell.
+ *
+ * @cell: Previously allocated eeprom cell by eeprom_cell_get()
+ * or of_eeprom_cell_get() or of_eeprom_cell_get_byname().
+ */
+void eeprom_cell_put(struct eeprom_cell *cell)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+
+	mutex_lock(&eeprom_mutex);
+	eeprom->users--;
+	mutex_unlock(&eeprom_mutex);
+	module_put(eeprom->owner);
+	kfree(cell);
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_put);
+
+/**
+ * eeprom_cell_read(): Read a given eeprom cell
+ *
+ * @cell: eeprom cell to be read.
+ * @len: pointer to length of cell which will be populated on successful read.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a char * bufffer.  The buffer should be freed by the consumer with a
+ * kfree().
+ */
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	char *buf;
+	int rc, i, offset = 0;
+
+	if (!eeprom || !eeprom->regmap)
+		return ERR_PTR(-EINVAL);
+
+	buf = kzalloc(cell->size, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < cell->nblocks; i++) {
+		rc = regmap_bulk_read(eeprom->regmap, cell->blocks[i].offset,
+				      buf + offset,
+				      cell->blocks[i].count);
+
+		if (IS_ERR_VALUE(rc)) {
+			kfree(buf);
+			return ERR_PTR(rc);
+		}
+		offset += cell->blocks[i].count;
+	}
+
+	*len = cell->size;
+
+	return buf;
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_read);
+
+/**
+ * eeprom_cell_write(): Write to a given eeprom cell
+ *
+ * @cell: eeprom cell to be written.
+ * @buf: Buffer to be written.
+ * @len: length of buffer to be written to eeprom cell.
+ *
+ * The return value will be an non zero on error or a zero on successful write.
+ */
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	int i, rc, offset = 0;
+
+	if (!eeprom || !eeprom->regmap || len != cell->size)
+		return -EINVAL;
+
+	for (i = 0; i < cell->nblocks; i++) {
+		rc = regmap_bulk_write(eeprom->regmap, cell->blocks[i].offset,
+				 buf + offset,
+				 cell->blocks[i].count);
+
+		if (IS_ERR_VALUE(rc))
+			return rc;
+
+		offset += cell->blocks[i].count;
+	}
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_write);
+
 static int eeprom_init(void)
 {
 	return class_register(&eeprom_class);
diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
new file mode 100644
index 0000000..6d9d075
--- /dev/null
+++ b/include/linux/eeprom-consumer.h
@@ -0,0 +1,67 @@
+/*
+ * EEPROM framework consumer.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_CONSUMER_H
+#define _LINUX_EEPROM_CONSUMER_H
+
+struct eeprom_cell;
+
+struct eeprom_block {
+	loff_t offset;
+	size_t count;
+};
+#if IS_ENABLED(CONFIG_EEPROM)
+struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks);
+void eeprom_cell_put(struct eeprom_cell *cell);
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
+#else
+
+static inline struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks)
+{
+	return NULL;
+}
+
+static inline void eeprom_cell_put(struct eeprom_cell *cell)
+{
+}
+
+static inline char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+	return NULL;
+}
+
+static inline int eeprom_cell_write(struct eeprom_cell *cell,
+				    const char *buf, ssize_t len)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_EEPROM */
+
+#if IS_ENABLED(CONFIG_EEPROM) && IS_ENABLED(CONFIG_OF)
+struct eeprom_cell *of_eeprom_cell_get(struct device *dev, int index);
+struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+					      const char *name);
+#else
+static inline struct eeprom_cell *of_eeprom_cell_get(
+					struct device *dev, int index)
+{
+	return NULL;
+}
+static inline struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+							    const char *name)
+{
+	return NULL;
+}
+#endif
+#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */
-- 
1.9.1


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

* [PATCH v3 5/9] eeprom: Add bindings for simple eeprom framework
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                         ` (3 preceding siblings ...)
  2015-03-24 22:30       ` [PATCH v3 4/9] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
@ 2015-03-24 22:30       ` Srinivas Kandagatla
  2015-03-25  7:10         ` Sascha Hauer
  2015-03-24 22:30       ` [PATCH v3 6/9] eeprom: sunxi: Move the SID driver to the " Srinivas Kandagatla
                         ` (4 subsequent siblings)
  9 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds bindings for simple eeprom framework which allows eeprom
consumers to talk to eeprom providers to get access to eeprom cell data.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/eeprom/eeprom.txt          | 70 ++++++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt

diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
new file mode 100644
index 0000000..8348d18
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
@@ -0,0 +1,70 @@
+= EEPROM Data Device Tree Bindings =
+
+This binding is intended to represent the location of hardware
+configuration data stored in EEPROMs.
+
+On a significant proportion of boards, the manufacturer has stored
+some data on an EEPROM-like device, for the OS to be able to retrieve
+these information and act upon it. Obviously, the OS has to know
+about where to retrieve these data from, and where they are stored on
+the storage device.
+
+This document is here to document this.
+
+= Data providers =
+Contains bindings specific to provider drivers and data cells as children
+to this node.
+
+= Data cells =
+These are the child nodes of the provider which contain data cell
+information like offset and size in eeprom provider.
+
+Required properties:
+reg:	specifies the offset in byte within that storage device, and the length
+	in bytes of the data we care about.
+	There could be more then one offset-length pairs in this property.
+
+Optional properties:
+As required by specific data parsers/interpreters.
+
+For example:
+
+	/* Provider */
+	qfprom: qfprom@00700000 {
+		compatible 	= "qcom,qfprom";
+		reg		= <0x00700000 0x1000>;
+		...
+
+		/* Data cells */
+		tsens_calibration: calib@404 {
+			reg = <0x404 0x10>;
+		};
+
+		serial_number: sn {
+			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
+
+		};
+		...
+	};
+
+= Data consumers =
+Are device nodes which consume eeprom data cells.
+
+Required properties:
+
+eeproms: List of phandle and data cell the device might be interested in.
+
+Optional properties:
+
+eeprom-names: List of data cell name strings sorted in the same order
+	      as the eeproms property. Consumers drivers will use
+	      eeprom-names to differentiate between multiple cells,
+	      and hence being able to know what these cells are for.
+
+For example:
+
+	tsens {
+		...
+		eeproms = <&tsens_calibration>;
+		eeprom-names = "calibration";
+	};
-- 
1.9.1


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

* [PATCH v3 6/9] eeprom: sunxi: Move the SID driver to the eeprom framework
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                         ` (4 preceding siblings ...)
  2015-03-24 22:30       ` [PATCH v3 5/9] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
@ 2015-03-24 22:30       ` Srinivas Kandagatla
  2015-03-24 22:30       ` [PATCH v3 7/9] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
                         ` (3 subsequent siblings)
  9 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

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

Now that we have the EEPROM framework, we can consolidate the common driver
code. Move the driver to the framework, and hopefully, it will fix the sysfs
file creation race.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[srinivas.kandagatla: Moved to regmap based EEPROM framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 ---
 .../bindings/eeprom/allwinner,sunxi-sid.txt        |  21 +++
 .../bindings/misc/allwinner,sunxi-sid.txt          |  17 ---
 drivers/eeprom/Kconfig                             |  15 ++
 drivers/eeprom/Makefile                            |   4 +
 drivers/eeprom/sunxi-sid.c                         | 136 ++++++++++++++++++
 drivers/misc/eeprom/Kconfig                        |  13 --
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 ---------------------
 9 files changed, 176 insertions(+), 209 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
 delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 drivers/eeprom/sunxi-sid.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid
deleted file mode 100644
index ffb9536..0000000
--- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid
+++ /dev/null
@@ -1,22 +0,0 @@
-What:		/sys/devices/*/<our-device>/eeprom
-Date:		August 2013
-Contact:	Oliver Schinagl <oliver@schinagl.nl>
-Description:	read-only access to the SID (Security-ID) on current
-		A-series SoC's from Allwinner. Currently supports A10, A10s, A13
-		and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes,
-		whereas the newer A20 SoC exposes 512 bytes split into sections.
-		Besides the 16 bytes of SID, there's also an SJTAG area,
-		HDMI-HDCP key and some custom keys. Below a quick overview, for
-		details see the user manual:
-		0x000  128 bit root-key (sun[457]i)
-		0x010  128 bit boot-key (sun7i)
-		0x020   64 bit security-jtag-key (sun7i)
-		0x028   16 bit key configuration (sun7i)
-		0x02b   16 bit custom-vendor-key (sun7i)
-		0x02c  320 bit low general key (sun7i)
-		0x040   32 bit read-control access (sun7i)
-		0x064  224 bit low general key (sun7i)
-		0x080 2304 bit HDCP-key (sun7i)
-		0x1a0  768 bit high general key (sun7i)
-Users:		any user space application which wants to read the SID on
-		Allwinner's A-series of CPU's.
diff --git a/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
new file mode 100644
index 0000000..cceaaf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
@@ -0,0 +1,21 @@
+Allwinner sunxi-sid
+
+Required properties:
+- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/eeprom/eeprom.txt
+
+Example for sun4i:
+	sid@01c23800 {
+		compatible = "allwinner,sun4i-a10-sid";
+		reg = <0x01c23800 0x10>
+	};
+
+Example for sun7i:
+	sid@01c23800 {
+		compatible = "allwinner,sun7i-a20-sid";
+		reg = <0x01c23800 0x200>
+	};
diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
deleted file mode 100644
index fabdf64..0000000
--- a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Allwinner sunxi-sid
-
-Required properties:
-- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
-- reg: Should contain registers location and length
-
-Example for sun4i:
-	sid@01c23800 {
-		compatible = "allwinner,sun4i-a10-sid";
-		reg = <0x01c23800 0x10>
-	};
-
-Example for sun7i:
-	sid@01c23800 {
-		compatible = "allwinner,sun7i-a20-sid";
-		reg = <0x01c23800 0x200>
-	};
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index 21e1847..ad396c1 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -9,3 +9,18 @@ menuconfig EEPROM
 	  from both the Linux Kernel and the userspace.
 
 	  If unsure, say no.
+
+if EEPROM
+
+config EEPROM_SUNXI_SID
+	tristate "Allwinner SoCs SID support"
+	depends on ARCH_SUNXI
+	select REGMAP_MMIO
+	help
+	  This is a driver for the 'security ID' available on various Allwinner
+	  devices.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called eeprom-sunxi-sid.
+
+endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 51a727f..184aa53 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -4,3 +4,7 @@
 
 obj-$(CONFIG_EEPROM)		+= eeprom_core.o
 eeprom_core-y			:= core.o
+
+# Devices
+obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
+eeprom-sunxi-sid-y		:= sunxi-sid.o
diff --git a/drivers/eeprom/sunxi-sid.c b/drivers/eeprom/sunxi-sid.c
new file mode 100644
index 0000000..dd7238d
--- /dev/null
+++ b/drivers/eeprom/sunxi-sid.c
@@ -0,0 +1,136 @@
+/*
+ * Allwinner sunXi SoCs Security ID support.
+ *
+ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct eeprom_sid {
+	void __iomem	*membase;
+	struct eeprom_device *eeprom;
+};
+
+static struct eeprom_config econfig = {
+	.name = "sunix-sid",
+};
+
+/* We read the entire key, due to a 32 bit read alignment requirement. Since we
+ * want to return the requested byte, this results in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarely probed, this is not really an issue.
+ */
+static int sunxi_sid_reg_read(void *context,
+			      unsigned int offset, unsigned int *val)
+{
+	struct eeprom_sid *sid  = context;
+	u32 sid_key;
+
+	sid_key = ioread32be(sid->membase + round_down(offset, 4));
+	sid_key >>= (offset % 4) * 8;
+
+	*val = sid_key;
+
+	return 0;
+}
+
+static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
+	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static struct regmap_config sunxi_sid_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+	.reg_read = sunxi_sid_reg_read,
+	.writeable_reg = sunxi_sid_writeable_reg,
+};
+
+static int sunxi_sid_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *device;
+	struct eeprom_sid *sid;
+	struct resource *res;
+	struct eeprom_device *eeprom;
+	struct device *dev = &pdev->dev;
+	struct regmap *regmap;
+
+	sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL);
+	if (!sid)
+		return -ENOMEM;
+
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid->membase = devm_ioremap_resource(dev, res);
+	if (IS_ERR(sid->membase))
+		return PTR_ERR(sid->membase);
+
+	device = of_match_device(sunxi_sid_of_match, dev);
+	if (!device)
+		return -ENODEV;
+
+	sunxi_sid_regmap_config.max_register = (unsigned int)device->data - 1;
+
+	regmap = devm_regmap_init(dev, NULL,
+					  sid, &sunxi_sid_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	econfig.dev = dev;
+	econfig.owner = THIS_MODULE;
+
+	eeprom = eeprom_register(&econfig);
+	if (IS_ERR(eeprom))
+		return PTR_ERR(eeprom);
+
+	platform_set_drvdata(pdev, eeprom);
+
+	return 0;
+}
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = "eeprom-sunxi-sid",
+		.of_match_table = sunxi_sid_of_match,
+	},
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 9536852f..04f2e1f 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG
 
 	  If unsure, say N.
 
-config EEPROM_SUNXI_SID
-	tristate "Allwinner sunxi security ID support"
-	depends on ARCH_SUNXI && SYSFS
-	help
-	  This is a driver for the 'security ID' available on various Allwinner
-	  devices.
-
-	  Due to the potential risks involved with changing e-fuses,
-	  this driver is read-only.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called sunxi_sid.
-
 endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 9507aec..fc1e81d 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY)	+= eeprom.o
 obj-$(CONFIG_EEPROM_MAX6875)	+= max6875.o
 obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
 obj-$(CONFIG_EEPROM_93XX46)	+= eeprom_93xx46.o
-obj-$(CONFIG_EEPROM_SUNXI_SID)	+= sunxi_sid.o
 obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
deleted file mode 100644
index 8385177..0000000
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
- * http://www.linux-sunxi.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * This driver exposes the Allwinner security ID, efuses exported in byte-
- * sized chunks.
- */
-
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#define DRV_NAME "sunxi-sid"
-
-struct sunxi_sid_data {
-	void __iomem *reg_base;
-	unsigned int keysize;
-};
-
-/* We read the entire key, due to a 32 bit read alignment requirement. Since we
- * want to return the requested byte, this results in somewhat slower code and
- * uses 4 times more reads as needed but keeps code simpler. Since the SID is
- * only very rarely probed, this is not really an issue.
- */
-static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data,
-			      const unsigned int offset)
-{
-	u32 sid_key;
-
-	if (offset >= sid_data->keysize)
-		return 0;
-
-	sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4));
-	sid_key >>= (offset % 4) * 8;
-
-	return sid_key; /* Only return the last byte */
-}
-
-static ssize_t sid_read(struct file *fd, struct kobject *kobj,
-			struct bin_attribute *attr, char *buf,
-			loff_t pos, size_t size)
-{
-	struct platform_device *pdev;
-	struct sunxi_sid_data *sid_data;
-	int i;
-
-	pdev = to_platform_device(kobj_to_dev(kobj));
-	sid_data = platform_get_drvdata(pdev);
-
-	if (pos < 0 || pos >= sid_data->keysize)
-		return 0;
-	if (size > sid_data->keysize - pos)
-		size = sid_data->keysize - pos;
-
-	for (i = 0; i < size; i++)
-		buf[i] = sunxi_sid_read_byte(sid_data, pos + i);
-
-	return i;
-}
-
-static struct bin_attribute sid_bin_attr = {
-	.attr = { .name = "eeprom", .mode = S_IRUGO, },
-	.read = sid_read,
-};
-
-static int sunxi_sid_remove(struct platform_device *pdev)
-{
-	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
-	dev_dbg(&pdev->dev, "driver unloaded\n");
-
-	return 0;
-}
-
-static const struct of_device_id sunxi_sid_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
-	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
-	{/* sentinel */},
-};
-MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-
-static int sunxi_sid_probe(struct platform_device *pdev)
-{
-	struct sunxi_sid_data *sid_data;
-	struct resource *res;
-	const struct of_device_id *of_dev_id;
-	u8 *entropy;
-	unsigned int i;
-
-	sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data),
-				GFP_KERNEL);
-	if (!sid_data)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(sid_data->reg_base))
-		return PTR_ERR(sid_data->reg_base);
-
-	of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev);
-	if (!of_dev_id)
-		return -ENODEV;
-	sid_data->keysize = (int)of_dev_id->data;
-
-	platform_set_drvdata(pdev, sid_data);
-
-	sid_bin_attr.size = sid_data->keysize;
-	if (device_create_bin_file(&pdev->dev, &sid_bin_attr))
-		return -ENODEV;
-
-	entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL);
-	for (i = 0; i < sid_data->keysize; i++)
-		entropy[i] = sunxi_sid_read_byte(sid_data, i);
-	add_device_randomness(entropy, sid_data->keysize);
-	kfree(entropy);
-
-	dev_dbg(&pdev->dev, "loaded\n");
-
-	return 0;
-}
-
-static struct platform_driver sunxi_sid_driver = {
-	.probe = sunxi_sid_probe,
-	.remove = sunxi_sid_remove,
-	.driver = {
-		.name = DRV_NAME,
-		.of_match_table = sunxi_sid_of_match,
-	},
-};
-module_platform_driver(sunxi_sid_driver);
-
-MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
-MODULE_DESCRIPTION("Allwinner sunxi security id driver");
-MODULE_LICENSE("GPL");
-- 
1.9.1


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

* [PATCH v3 7/9] eeprom: qfprom: Add Qualcomm QFPROM support.
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                         ` (5 preceding siblings ...)
  2015-03-24 22:30       ` [PATCH v3 6/9] eeprom: sunxi: Move the SID driver to the " Srinivas Kandagatla
@ 2015-03-24 22:30       ` Srinivas Kandagatla
  2015-03-24 22:31       ` [PATCH v3 8/9] eeprom: qfprom: Add bindings for qfprom Srinivas Kandagatla
                         ` (2 subsequent siblings)
  9 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds QFPROM support driver which is used by other drivers
like thermal sensor and cpufreq.

On MSM parts there are some efuses (called qfprom) these fuses store things like
calibration data, speed bins.. etc. Drivers like cpufreq, thermal sensors would
read out this data for configuring the driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/Kconfig  | 11 +++++++
 drivers/eeprom/Makefile |  2 ++
 drivers/eeprom/qfprom.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+)
 create mode 100644 drivers/eeprom/qfprom.c

diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index ad396c1..8fc14d3 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -23,4 +23,15 @@ config EEPROM_SUNXI_SID
 	  This driver can also be built as a module. If so, the module
 	  will be called eeprom-sunxi-sid.
 
+config QCOM_QFPROM
+	tristate "QCOM QFPROM Support"
+	depends on ARCH_QCOM
+	select REGMAP_MMIO
+	help
+	  Say y here to enable QFPROM support. The QFPROM provides access
+	  functions for QFPROM data to rest of the drivers via eeprom interface.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called eeprom-qfprom.
+
 endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 184aa53..4ac437e 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -8,3 +8,5 @@ eeprom_core-y			:= core.o
 # Devices
 obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
 eeprom-sunxi-sid-y		:= sunxi-sid.o
+obj-$(CONFIG_QCOM_QFPROM)	+= eeprom_qfprom.o
+eeprom_qfprom-y			:= qfprom.o
diff --git a/drivers/eeprom/qfprom.c b/drivers/eeprom/qfprom.c
new file mode 100644
index 0000000..8d5d4d8
--- /dev/null
+++ b/drivers/eeprom/qfprom.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/eeprom-provider.h>
+
+static struct regmap_config qfprom_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+};
+
+static struct eeprom_config econfig = {
+	.name = "qfprom",
+};
+
+static int qfprom_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+
+static int qfprom_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	void __iomem *base;
+	struct device *dev = &pdev->dev;
+	struct eeprom_device *eeprom;
+	struct regmap *regmap;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	qfprom_regmap_config.max_register = resource_size(res) - 1;
+
+	regmap = devm_regmap_init_mmio(dev, base,
+					       &qfprom_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(regmap);
+	}
+	econfig.owner = THIS_MODULE;
+	econfig.dev = dev;
+	eeprom = eeprom_register(&econfig);
+	if (IS_ERR(eeprom))
+		return PTR_ERR(eeprom);
+
+	platform_set_drvdata(pdev, eeprom);
+	return 0;
+}
+
+static const struct of_device_id qfprom_of_match[] = {
+	{ .compatible = "qcom,qfprom"},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, qfprom_of_match);
+
+static struct platform_driver qfprom_driver = {
+	.probe = qfprom_probe,
+	.remove = qfprom_remove,
+	.driver = {
+		.name = "qcom,qfprom",
+		.of_match_table = qfprom_of_match,
+	},
+};
+module_platform_driver(qfprom_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm QFPROM driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


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

* [PATCH v3 8/9] eeprom: qfprom: Add bindings for qfprom
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                         ` (6 preceding siblings ...)
  2015-03-24 22:30       ` [PATCH v3 7/9] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
@ 2015-03-24 22:31       ` Srinivas Kandagatla
  2015-03-25  0:28         ` Bjorn Andersson
  2015-03-24 22:31       ` [PATCH v3 9/9] eeprom: Add to MAINTAINERS for eeprom framework Srinivas Kandagatla
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  9 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 22:31 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds bindings for qfprom found in QCOM SOCs. QFPROM driver
is based on simple eeprom framework.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/eeprom/qfprom.txt          | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/eeprom/qfprom.txt

diff --git a/Documentation/devicetree/bindings/eeprom/qfprom.txt b/Documentation/devicetree/bindings/eeprom/qfprom.txt
new file mode 100644
index 0000000..d5baed6
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/qfprom.txt
@@ -0,0 +1,23 @@
+= Qualcomm QFPROM device tree bindings =
+
+This binding is intended to represent QFPROM which is found in most QCOM SOCs.
+
+Required properties:
+- compatible: should be "qcom,qfprom"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/eeprom/eeprom.txt
+
+Example:
+
+	qfprom: qfprom@00700000 {
+		compatible 	= "qcom,qfprom";
+		reg		= <0x00700000 0x1000>;
+		...
+		/* Data cells */
+		tsens_calibration: calib@404 {
+			reg = <0x404 0x10>;
+		};
+	};
-- 
1.9.1


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

* [PATCH v3 9/9] eeprom: Add to MAINTAINERS for eeprom framework
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                         ` (7 preceding siblings ...)
  2015-03-24 22:31       ` [PATCH v3 8/9] eeprom: qfprom: Add bindings for qfprom Srinivas Kandagatla
@ 2015-03-24 22:31       ` Srinivas Kandagatla
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  9 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 22:31 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds MAINTAINERS to eeprom framework.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index d66a97d..ee7ba92 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3657,6 +3657,15 @@ T:	git git://git.alsa-project.org/alsa-kernel.git
 S:	Maintained
 F:	sound/usb/misc/ua101.c
 
+EEPROM FRAMEWORK
+M:	Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+M:	Maxime Ripard <maxime.ripard@free-electrons.com>
+S:	Maintained
+F:	drivers/eeprom/
+F:	Documentation/devicetree/bindings/eeprom/
+F:	include/linux/eeprom-provider.h
+F:	include/linux/eeprom-consumer.h
+
 EXTENSIBLE FIRMWARE INTERFACE (EFI)
 M:	Matt Fleming <matt.fleming@intel.com>
 L:	linux-efi@vger.kernel.org
-- 
1.9.1


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

* Re: [PATCH v3 1/9] regmap: Introduce regmap_get_max_register.
  2015-03-24 22:29       ` [PATCH v3 1/9] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
@ 2015-03-24 22:36         ` Mark Brown
  2015-03-24 23:05           ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Mark Brown @ 2015-03-24 22:36 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd

[-- Attachment #1: Type: text/plain, Size: 429 bytes --]

On Tue, Mar 24, 2015 at 10:29:39PM +0000, Srinivas Kandagatla wrote:

> This patch introduces regmap_get_max_register() function which would be
> used by the infrastructures like eeprom framework built on top of
> regmap.

In what way would it be used?

> +int regmap_get_max_register(struct regmap *map)
> +{
> +	return map->max_register ? : -EINVAL;
> +}

Please write the logic out properly, don't abuse the ternery operator.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v3 2/9] regmap: Introduce regmap_get_reg_stride.
  2015-03-24 22:30       ` [PATCH v3 2/9] regmap: Introduce regmap_get_reg_stride Srinivas Kandagatla
@ 2015-03-24 22:37         ` Mark Brown
  2015-03-24 23:07           ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Mark Brown @ 2015-03-24 22:37 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd

[-- Attachment #1: Type: text/plain, Size: 472 bytes --]

On Tue, Mar 24, 2015 at 10:30:00PM +0000, Srinivas Kandagatla wrote:

> + /* regmap_get_reg_stride(): Report the register address stride
> + *
> + * Report the register address stride, mainly intended to for use by
> + * generic infrastructure built on top of regmap.
> + */
> +int regmap_get_reg_stride(struct regmap *map)

Please fix the indentation for the comment block and add kerneldoc for
the argument.  This is an exported function so it should also be /** not
/*

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v3 3/9] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-24 22:30       ` [PATCH v3 3/9] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
@ 2015-03-24 22:53         ` Mark Brown
  2015-03-26 16:23           ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Mark Brown @ 2015-03-24 22:53 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd

[-- Attachment #1: Type: text/plain, Size: 1463 bytes --]

On Tue, Mar 24, 2015 at 10:30:08PM +0000, Srinivas Kandagatla wrote:

> +static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
> +				     struct bin_attribute *attr,
> +				     char *buf, loff_t offset, size_t count)
> +{
> +	struct device *dev = container_of(kobj, struct device, kobj);
> +	struct eeprom_device *eeprom = to_eeprom(dev);
> +	int rc;
> +
> +	if (offset > eeprom->size)
> +		return -EINVAL;
> +
> +	if (offset + count > eeprom->size)
> +		count = eeprom->size - offset;
> +
> +	rc = regmap_bulk_write(eeprom->regmap, offset,
> +			       buf, count/eeprom->stride);

Are you sure that this and the read interface should be using the bulk
interface and not the raw interface - do we want the byte swapping that
the bulk interface provides?

I'm also not entirely able to convince myself that the above error
checks and code line up with what I'd expect the userspace ABI to be, we
seem to be treating offset as both a byte offset into the data (which is
what I'd expect the userspace ABI to do) and a word based index into the
data (which is what the regmap API is doing).  For example with 16 bit
words offset 2 will start at the 5th byte of data but if userspace seeks
to offset 5 it will get the 11th byte and onwards.

The stride and the word size are separate, they will frequently line up
for memory mapped devices but typically won't for other devices.  I
think you need more data mangling to handle this robustly.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v3 1/9] regmap: Introduce regmap_get_max_register.
  2015-03-24 22:36         ` Mark Brown
@ 2015-03-24 23:05           ` Srinivas Kandagatla
  2015-03-24 23:23             ` Joe Perches
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 23:05 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd



On 24/03/15 22:36, Mark Brown wrote:
> On Tue, Mar 24, 2015 at 10:29:39PM +0000, Srinivas Kandagatla wrote:
>
>> This patch introduces regmap_get_max_register() function which would be
>> used by the infrastructures like eeprom framework built on top of
>> regmap.
>
> In what way would it be used?
Its used in 2 purposes
1> It is used for sanity check purposes of the register ranges provided 
via DT/non-DT eeprom data cells.

2> To stop user reading when eeprom binary from /sys/class/eeprom/*/eeprom

>
>> +int regmap_get_max_register(struct regmap *map)
>> +{
>> +	return map->max_register ? : -EINVAL;
>> +}
>
> Please write the logic out properly, don't abuse the ternery operator.
Am happy to change it to your preference in next version, but this GNU 
extensions widely used in the kernel

$  grep -rR "return.*? :" ./linux | wc -l

115


>

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

* Re: [PATCH v3 2/9] regmap: Introduce regmap_get_reg_stride.
  2015-03-24 22:37         ` Mark Brown
@ 2015-03-24 23:07           ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-24 23:07 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd



On 24/03/15 22:37, Mark Brown wrote:
> On Tue, Mar 24, 2015 at 10:30:00PM +0000, Srinivas Kandagatla wrote:
>
>> + /* regmap_get_reg_stride(): Report the register address stride
>> + *
>> + * Report the register address stride, mainly intended to for use by
>> + * generic infrastructure built on top of regmap.
>> + */
>> +int regmap_get_reg_stride(struct regmap *map)
>
> Please fix the indentation for the comment block and add kerneldoc for
> the argument.  This is an exported function so it should also be /** not
> /*
>
My bad.. I will fix it in next version.

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

* Re: [PATCH v3 1/9] regmap: Introduce regmap_get_max_register.
  2015-03-24 23:05           ` Srinivas Kandagatla
@ 2015-03-24 23:23             ` Joe Perches
  0 siblings, 0 replies; 153+ messages in thread
From: Joe Perches @ 2015-03-24 23:23 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Mark Brown, linux-arm-kernel, Maxime Ripard, Rob Herring,
	Kumar Gala, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, arnd, sboyd

On Tue, 2015-03-24 at 23:05 +0000, Srinivas Kandagatla wrote:
> On 24/03/15 22:36, Mark Brown wrote:
> >> +int regmap_get_max_register(struct regmap *map)
> >> +{
> >> +	return map->max_register ? : -EINVAL;
> >> +}
> >
> > Please write the logic out properly, don't abuse the ternery operator.
> Am happy to change it to your preference in next version, but this GNU 
> extensions widely used in the kernel
> 
> $  grep -rR "return.*? :" ./linux | wc -l
> 115

Double that when you add the ?: variants

$ git grep -E "return.*\?\s*:" | wc -l
253

There are ~530 uses like:

	return <foo> ? <foo> :


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

* Re: [PATCH v3 8/9] eeprom: qfprom: Add bindings for qfprom
  2015-03-24 22:31       ` [PATCH v3 8/9] eeprom: qfprom: Add bindings for qfprom Srinivas Kandagatla
@ 2015-03-25  0:28         ` Bjorn Andersson
  0 siblings, 0 replies; 153+ messages in thread
From: Bjorn Andersson @ 2015-03-25  0:28 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, Arnd Bergmann, Stephen Boyd

On Tue, Mar 24, 2015 at 11:31 PM, Srinivas Kandagatla
<srinivas.kandagatla@linaro.org> wrote:
> This patch adds bindings for qfprom found in QCOM SOCs. QFPROM driver
> is based on simple eeprom framework.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  .../devicetree/bindings/eeprom/qfprom.txt          | 23 ++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/eeprom/qfprom.txt
>
> diff --git a/Documentation/devicetree/bindings/eeprom/qfprom.txt b/Documentation/devicetree/bindings/eeprom/qfprom.txt
> new file mode 100644
> index 0000000..d5baed6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/eeprom/qfprom.txt
> @@ -0,0 +1,23 @@
> += Qualcomm QFPROM device tree bindings =
> +
> +This binding is intended to represent QFPROM which is found in most QCOM SOCs.
> +
> +Required properties:
> +- compatible: should be "qcom,qfprom"
> +- reg: Should contain registers location and length
> +
> += Data cells =
> +Are child nodes of qfprom, bindings of which as described in
> +bindings/eeprom/eeprom.txt
> +
> +Example:
> +
> +       qfprom: qfprom@00700000 {
> +               compatible      = "qcom,qfprom";
> +               reg             = <0x00700000 0x1000>;

The qfprom block starts at 0x700000 and is 0x8000 long.

The registers at the beginning of this block are raw R/W fuse bits and
should not be read directly. Instead there is an ecc corrected shadow
copy of these registers at 0x4000.

> +               ...
> +               /* Data cells */
> +               tsens_calibration: calib@404 {
> +                       reg = <0x404 0x10>;
> +               };
> +       };

Regards,
Bjorn

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

* Re: [PATCH v3 5/9] eeprom: Add bindings for simple eeprom framework
  2015-03-24 22:30       ` [PATCH v3 5/9] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
@ 2015-03-25  7:10         ` Sascha Hauer
  2015-03-25 16:40           ` Maxime Ripard
  0 siblings, 1 reply; 153+ messages in thread
From: Sascha Hauer @ 2015-03-25  7:10 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, arnd, sboyd

On Tue, Mar 24, 2015 at 10:30:30PM +0000, Srinivas Kandagatla wrote:
> This patch adds bindings for simple eeprom framework which allows eeprom
> consumers to talk to eeprom providers to get access to eeprom cell data.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> [Maxime Ripard: intial version of eeprom framework]
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  .../devicetree/bindings/eeprom/eeprom.txt          | 70 ++++++++++++++++++++++
>  1 file changed, 70 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
> 
> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> new file mode 100644
> index 0000000..8348d18
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> @@ -0,0 +1,70 @@
> += EEPROM Data Device Tree Bindings =
> +
> +This binding is intended to represent the location of hardware
> +configuration data stored in EEPROMs.
> +
> +On a significant proportion of boards, the manufacturer has stored
> +some data on an EEPROM-like device, for the OS to be able to retrieve
> +these information and act upon it. Obviously, the OS has to know
> +about where to retrieve these data from, and where they are stored on
> +the storage device.
> +
> +This document is here to document this.
> +
> += Data providers =
> +Contains bindings specific to provider drivers and data cells as children
> +to this node.
> +
> += Data cells =
> +These are the child nodes of the provider which contain data cell
> +information like offset and size in eeprom provider.
> +
> +Required properties:
> +reg:	specifies the offset in byte within that storage device, and the length
> +	in bytes of the data we care about.
> +	There could be more then one offset-length pairs in this property.
> +
> +Optional properties:
> +As required by specific data parsers/interpreters.
> +
> +For example:
> +
> +	/* Provider */
> +	qfprom: qfprom@00700000 {
> +		compatible 	= "qcom,qfprom";
> +		reg		= <0x00700000 0x1000>;
> +		...
> +
> +		/* Data cells */
> +		tsens_calibration: calib@404 {
> +			reg = <0x404 0x10>;
> +		};
> +
> +		serial_number: sn {
> +			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
> +
> +		};
> +		...
> +	};
> +
> += Data consumers =
> +Are device nodes which consume eeprom data cells.
> +
> +Required properties:
> +
> +eeproms: List of phandle and data cell the device might be interested in.
> +
> +Optional properties:
> +
> +eeprom-names: List of data cell name strings sorted in the same order
> +	      as the eeproms property. Consumers drivers will use
> +	      eeprom-names to differentiate between multiple cells,
> +	      and hence being able to know what these cells are for.
> +
> +For example:
> +
> +	tsens {
> +		...
> +		eeproms = <&tsens_calibration>;
> +		eeprom-names = "calibration";
> +	};

This is somewhat complicated. Also having 'eeprom' in the binding is not
nice since it could be FRAM or something else. How about:

	tsens {
		calibration = <&tsens_calibration>;
	};


Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v3 4/9] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-03-24 22:30       ` [PATCH v3 4/9] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
@ 2015-03-25  7:16         ` Sascha Hauer
  2015-03-25 12:29           ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Sascha Hauer @ 2015-03-25  7:16 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, arnd, sboyd

On Tue, Mar 24, 2015 at 10:30:19PM +0000, Srinivas Kandagatla wrote:
> This patch adds just consumers part of the framework just to enable easy
> review.
> 
> Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
> duplicate pretty much the same code to register a sysfs file, allow in-kernel
> users to access the content of the devices they were driving, etc.
> 
> This was also a problem as far as other in-kernel users were involved, since
> the solutions used were pretty much different from on driver to another, there
> was a rather big abstraction leak.
> 
> This introduction of this framework aims at solving this. It also introduces DT
> representation for consumer devices to go get the data they require (MAC
> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
> 
> Having regmap interface to this framework would give much better
> abstraction for eeproms on different buses.

Thanks for working on this. This is something that is missing in the
kernel, it looks very promising to me.

Some comments inline

> +static struct eeprom_cell *__eeprom_cell_get(struct device_node *cell_np,
> +					     const char *ename,
> +					     struct eeprom_block *blocks,
> +					     int nblocks)
> +{
> +	struct eeprom_cell *cell;
> +	struct eeprom_device *eeprom = NULL;

No need to initialize.

> +	struct property *prop;
> +	const __be32 *vp;
> +	u32 pv;
> +	int i, rval;
> +
> +	mutex_lock(&eeprom_mutex);
> +
> +	eeprom = cell_np ? of_eeprom_find(cell_np->parent) : eeprom_find(ename);
> +	if (!eeprom) {
> +		mutex_unlock(&eeprom_mutex);
> +		return ERR_PTR(-EPROBE_DEFER);
> +	}
> +

> +/**
> + * of_eeprom_cell_get(): Get eeprom cell of device form a given index
> + *
> + * @dev: Device that will be interacted with
> + * @index: eeprom index in eeproms property.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *of_eeprom_cell_get(struct device *dev, int index)
> +{

I think the consumer API could be improved. The dev pointer is only used
to get the struct device_node out of it, so the device_node could be
passed in directly. As written in my other mail I think the binding
would be better like "calibration = <&tsens_calibration>;", so this
function could be:

of_eeprom_cell_get(struct device_node *np, const char *name)

With this we could also get eeprom cells from subnodes which do not have
a struct device bound to them.

> +	struct device_node *cell_np;
> +
> +	if (!dev || !dev->of_node)
> +		return ERR_PTR(-EINVAL);
> +
> +	cell_np = of_parse_phandle(dev->of_node, "eeproms", index);
> +	if (!cell_np)
> +		return ERR_PTR(-EPROBE_DEFER);

-EPROBE_DEFER is not appropriate here. If of_parse_phandle fails it
won't work next time.

> +
> +	return __eeprom_cell_get(cell_np, NULL, NULL, 0);
> +}
> +EXPORT_SYMBOL_GPL(of_eeprom_cell_get);
> +
> +/**
> + * eeprom_cell_write(): Write to a given eeprom cell
> + *
> + * @cell: eeprom cell to be written.
> + * @buf: Buffer to be written.
> + * @len: length of buffer to be written to eeprom cell.
> + *
> + * The return value will be an non zero on error or a zero on successful write.

No, it returns the length.

> + */
> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
> +{
> +	struct eeprom_device *eeprom = cell->eeprom;
> +	int i, rc, offset = 0;
> +
> +	if (!eeprom || !eeprom->regmap || len != cell->size)
> +		return -EINVAL;
> +
> +	for (i = 0; i < cell->nblocks; i++) {
> +		rc = regmap_bulk_write(eeprom->regmap, cell->blocks[i].offset,
> +				 buf + offset,
> +				 cell->blocks[i].count);
> +
> +		if (IS_ERR_VALUE(rc))
> +			return rc;
> +
> +		offset += cell->blocks[i].count;
> +	}
> +
> +	return len;
> +}
> +EXPORT_SYMBOL_GPL(eeprom_cell_write);
> +

> +static inline char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
> +{
> +	return NULL;
> +}

The documentation above the real function states that this function
either returns an ERR_PTR() or a valid pointer. The wrapper should then
do the same.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v3 4/9] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-03-25  7:16         ` Sascha Hauer
@ 2015-03-25 12:29           ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-25 12:29 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, arnd, sboyd



On 25/03/15 07:16, Sascha Hauer wrote:
> On Tue, Mar 24, 2015 at 10:30:19PM +0000, Srinivas Kandagatla wrote:
>> This patch adds just consumers part of the framework just to enable easy
>> review.
>>
>> Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
>> duplicate pretty much the same code to register a sysfs file, allow in-kernel
>> users to access the content of the devices they were driving, etc.
>>
>> This was also a problem as far as other in-kernel users were involved, since
>> the solutions used were pretty much different from on driver to another, there
>> was a rather big abstraction leak.
>>
>> This introduction of this framework aims at solving this. It also introduces DT
>> representation for consumer devices to go get the data they require (MAC
>> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
>>
>> Having regmap interface to this framework would give much better
>> abstraction for eeproms on different buses.
>
> Thanks for working on this. This is something that is missing in the
> kernel, it looks very promising to me.
>
> Some comments inline
>
>> +static struct eeprom_cell *__eeprom_cell_get(struct device_node *cell_np,
>> +					     const char *ename,
>> +					     struct eeprom_block *blocks,
>> +					     int nblocks)
>> +{
>> +	struct eeprom_cell *cell;
>> +	struct eeprom_device *eeprom = NULL;
>
> No need to initialize.
Sure.. Will fix it.

>
>> +	struct property *prop;
>> +	const __be32 *vp;
>> +	u32 pv;
>> +	int i, rval;
>> +
>> +	mutex_lock(&eeprom_mutex);
>> +
>> +	eeprom = cell_np ? of_eeprom_find(cell_np->parent) : eeprom_find(ename);
>> +	if (!eeprom) {
>> +		mutex_unlock(&eeprom_mutex);
>> +		return ERR_PTR(-EPROBE_DEFER);
>> +	}
>> +
>
>> +/**
>> + * of_eeprom_cell_get(): Get eeprom cell of device form a given index
>> + *
>> + * @dev: Device that will be interacted with
>> + * @index: eeprom index in eeproms property.
>> + *
>> + * The return value will be an ERR_PTR() on error or a valid pointer
>> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
>> + * eeprom_cell_put().
>> + */
>> +struct eeprom_cell *of_eeprom_cell_get(struct device *dev, int index)
>> +{
>
> I think the consumer API could be improved. The dev pointer is only used
> to get the struct device_node out of it, so the device_node could be
> passed in directly. As written in my other mail I think the binding
> would be better like "calibration = <&tsens_calibration>;", so this
> function could be:
>
> of_eeprom_cell_get(struct device_node *np, const char *name)
>
> With this we could also get eeprom cells from subnodes which do not have
> a struct device bound to them.
>
Its a good point, I will give it a try and see.

>> +	struct device_node *cell_np;
>> +
>> +	if (!dev || !dev->of_node)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	cell_np = of_parse_phandle(dev->of_node, "eeproms", index);
>> +	if (!cell_np)
>> +		return ERR_PTR(-EPROBE_DEFER);
>
> -EPROBE_DEFER is not appropriate here. If of_parse_phandle fails it
> won't work next time.
>
That's right, if it cant parse it now, it would also fail next time too.
Will fix it in next version.

>> +
>> +	return __eeprom_cell_get(cell_np, NULL, NULL, 0);
>> +}
>> +EXPORT_SYMBOL_GPL(of_eeprom_cell_get);
>> +
>> +/**
>> + * eeprom_cell_write(): Write to a given eeprom cell
>> + *
>> + * @cell: eeprom cell to be written.
>> + * @buf: Buffer to be written.
>> + * @len: length of buffer to be written to eeprom cell.
>> + *
>> + * The return value will be an non zero on error or a zero on successful write.
>
> No, it returns the length.
>
Yes, thats true, will fix it in next version.

>> + */
>> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
>> +{
>> +	struct eeprom_device *eeprom = cell->eeprom;
>> +	int i, rc, offset = 0;
>> +
>> +	if (!eeprom || !eeprom->regmap || len != cell->size)
>> +		return -EINVAL;
>> +
>> +	for (i = 0; i < cell->nblocks; i++) {
>> +		rc = regmap_bulk_write(eeprom->regmap, cell->blocks[i].offset,
>> +				 buf + offset,
>> +				 cell->blocks[i].count);
>> +
>> +		if (IS_ERR_VALUE(rc))
>> +			return rc;
>> +
>> +		offset += cell->blocks[i].count;
>> +	}
>> +
>> +	return len;
>> +}
>> +EXPORT_SYMBOL_GPL(eeprom_cell_write);
>> +
>
>> +static inline char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
>> +{
>> +	return NULL;
>> +}
>
> The documentation above the real function states that this function
> either returns an ERR_PTR() or a valid pointer. The wrapper should then
> do the same.
>
Will fix this in next version.

> Sascha
>
>

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

* Re: [PATCH v3 5/9] eeprom: Add bindings for simple eeprom framework
  2015-03-25  7:10         ` Sascha Hauer
@ 2015-03-25 16:40           ` Maxime Ripard
  0 siblings, 0 replies; 153+ messages in thread
From: Maxime Ripard @ 2015-03-25 16:40 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Srinivas Kandagatla, linux-arm-kernel, Rob Herring, Kumar Gala,
	Mark Brown, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, arnd, sboyd

[-- Attachment #1: Type: text/plain, Size: 3807 bytes --]

On Wed, Mar 25, 2015 at 08:10:06AM +0100, Sascha Hauer wrote:
> On Tue, Mar 24, 2015 at 10:30:30PM +0000, Srinivas Kandagatla wrote:
> > This patch adds bindings for simple eeprom framework which allows eeprom
> > consumers to talk to eeprom providers to get access to eeprom cell data.
> > 
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > [Maxime Ripard: intial version of eeprom framework]
> > Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> > ---
> >  .../devicetree/bindings/eeprom/eeprom.txt          | 70 ++++++++++++++++++++++
> >  1 file changed, 70 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> > new file mode 100644
> > index 0000000..8348d18
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> > @@ -0,0 +1,70 @@
> > += EEPROM Data Device Tree Bindings =
> > +
> > +This binding is intended to represent the location of hardware
> > +configuration data stored in EEPROMs.
> > +
> > +On a significant proportion of boards, the manufacturer has stored
> > +some data on an EEPROM-like device, for the OS to be able to retrieve
> > +these information and act upon it. Obviously, the OS has to know
> > +about where to retrieve these data from, and where they are stored on
> > +the storage device.
> > +
> > +This document is here to document this.
> > +
> > += Data providers =
> > +Contains bindings specific to provider drivers and data cells as children
> > +to this node.
> > +
> > += Data cells =
> > +These are the child nodes of the provider which contain data cell
> > +information like offset and size in eeprom provider.
> > +
> > +Required properties:
> > +reg:	specifies the offset in byte within that storage device, and the length
> > +	in bytes of the data we care about.
> > +	There could be more then one offset-length pairs in this property.
> > +
> > +Optional properties:
> > +As required by specific data parsers/interpreters.
> > +
> > +For example:
> > +
> > +	/* Provider */
> > +	qfprom: qfprom@00700000 {
> > +		compatible 	= "qcom,qfprom";
> > +		reg		= <0x00700000 0x1000>;
> > +		...
> > +
> > +		/* Data cells */
> > +		tsens_calibration: calib@404 {
> > +			reg = <0x404 0x10>;
> > +		};
> > +
> > +		serial_number: sn {
> > +			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
> > +
> > +		};
> > +		...
> > +	};
> > +
> > += Data consumers =
> > +Are device nodes which consume eeprom data cells.
> > +
> > +Required properties:
> > +
> > +eeproms: List of phandle and data cell the device might be interested in.
> > +
> > +Optional properties:
> > +
> > +eeprom-names: List of data cell name strings sorted in the same order
> > +	      as the eeproms property. Consumers drivers will use
> > +	      eeprom-names to differentiate between multiple cells,
> > +	      and hence being able to know what these cells are for.
> > +
> > +For example:
> > +
> > +	tsens {
> > +		...
> > +		eeproms = <&tsens_calibration>;
> > +		eeprom-names = "calibration";
> > +	};
> 
> This is somewhat complicated. Also having 'eeprom' in the binding is not
> nice since it could be FRAM or something else. How about:
> 
> 	tsens {
> 		calibration = <&tsens_calibration>;
> 	};

A similar property was suggested the first time we discussed it, and
it turned out eventually that the construct you commented about was
actually preferred.

I guess we can always change the property name to something more
generic though.

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v3 3/9] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-24 22:53         ` Mark Brown
@ 2015-03-26 16:23           ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-26 16:23 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd



On 24/03/15 22:53, Mark Brown wrote:
> On Tue, Mar 24, 2015 at 10:30:08PM +0000, Srinivas Kandagatla wrote:
>
>> +static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
>> +				     struct bin_attribute *attr,
>> +				     char *buf, loff_t offset, size_t count)
>> +{
>> +	struct device *dev = container_of(kobj, struct device, kobj);
>> +	struct eeprom_device *eeprom = to_eeprom(dev);
>> +	int rc;
>> +
>> +	if (offset > eeprom->size)
>> +		return -EINVAL;
>> +
>> +	if (offset + count > eeprom->size)
>> +		count = eeprom->size - offset;
>> +
>> +	rc = regmap_bulk_write(eeprom->regmap, offset,
>> +			       buf, count/eeprom->stride);
>
> Are you sure that this and the read interface should be using the bulk
> interface and not the raw interface - do we want the byte swapping that
> the bulk interface provides?
>
You are correct, byte swapping is not really needed in this cases.
It should read/write data as it is.

I will fix it in next version.

> I'm also not entirely able to convince myself that the above error
> checks and code line up with what I'd expect the userspace ABI to be, we
> seem to be treating offset as both a byte offset into the data (which is
> what I'd expect the userspace ABI to do) and a word based index into the
> data (which is what the regmap API is doing).  For example with 16 bit
> words offset 2 will start at the 5th byte of data but if userspace seeks
> to offset 5 it will get the 11th byte and onwards.

Thanks for spotting this, Yes, the offset from userspace should be 
treated as byte oriented and the offset to regmap as word based index 
into the data.
Yes, logic here needs a fix to handle data correctly.

>
> The stride and the word size are separate, they will frequently line up
> for memory mapped devices but typically won't for other devices.  I
> think you need more data mangling to handle this robustly.
Yes, I agree I will address this too in next version.

thanks,
srini

>

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

* [PATCH v4 00/10] Add simple EEPROM Framework via regmap.
  2015-03-24 22:28     ` [PATCH v3 0/9] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                         ` (8 preceding siblings ...)
  2015-03-24 22:31       ` [PATCH v3 9/9] eeprom: Add to MAINTAINERS for eeprom framework Srinivas Kandagatla
@ 2015-03-30 21:54       ` Srinivas Kandagatla
  2015-03-30 21:56         ` [PATCH v4 01/10] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
                           ` (10 more replies)
  9 siblings, 11 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:54 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

Thankyou all for providing inputs and comments on previous versions of this patchset.
Here is the v4 of the patchset addressing all the issues raised as
part of previous versions review.

This patchset adds a new simple EEPROM framework to kernel.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.
    
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
    
This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
    
Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

patch 1-2 Introduces two regmap helper functions.
patch 3-5 Introduces the EEPROM framework.
Patch 6 Adds helper functions for eeproms based on mmio.
Patch 7 migrates an existing driver to eeprom framework.
Patch 8-9 Adds Qualcomm specific qfprom driver.
Patch 10 adds entry in MAINTAINERS.

Its also possible to migrate other eeprom drivers to this framework.

Providers APIs:
	eeprom_register/unregister();

Consumers APIs:
	eeprom_cell_get()/of_eeprom_cell_get();
	eeprom_cell_put();
	eeprom_cell_read()/eeprom_cell_write();

Device Tree:

	/* Provider */
	qfprom: qfprom@00700000 {
		compatible 	= "qcom,qfprom";
		reg		= <0x00700000 0x1000>;
		...

		/* Data cells */
		tsens_calibration: calib@404 {
			reg = <0x404 0x10>;
		};

		serial_number: sn {
			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;

		};
		...
	};
	
	/* Consumer node */
	tsens: tsens {
		...
		calibration = <&tsens_calibration>;
		...
	};

userspace interface: binary file in /sys/class/eeprom/*/eeprom

ex:
hexdump /sys/class/eeprom/qfprom0/eeprom
                                                                                                                                                                                                                  
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
0000000 0000 0000 0000 0000 0000 0000 0000 0000
...
*
0001000


Changes since v3(https://lkml.org/lkml/2015/3/24/1066)
 * simplified logic in bin_attr_eeprom_read/write spotted by Mark Brown.
 * moved from using regmap_bulk_read/write to regmap_raw_read/write
 spotted by Mark Brown
 * Fixed return error codes for the dummy wrappers spotted by Sascha Hauer
 * Fixed various error code checks in core spotted by Sascha Hauer.
 * Simplified consumer bindings suggested by Sascha Hauer.
 * Added eeprom-mmio helper functions.

Changes since v2(https://lkml.org/lkml/2015/3/13/168)
 * Fixed error handling in eeprom_register spotted by Mark Brown
 * Added new regmap_get_max_register() and regmap_get_reg_stride().
 * Fixed module build errors reported by kbuild robot.
 * recycle the ids when eeprom provider is released.

Changes since v1(https://lkml.org/lkml/2015/3/5/153)
 * Fix various Licencing issues spotted by Paul Bolle and Mark Brown
 * Allow eeprom core to build as module spotted by Paul Bolle.
 * Fix various kconfig issues spotted by Paul Bolle.
 * remove unessary atomic varible spotted by Mark Brown.
 * Few cleanups and common up some of the code in core.
 * Add qfprom bindings.

Changes since RFC(https://lkml.org/lkml/2015/2/19/307)
 * Fix documentation and error checks in read/write spotted by Andrew Lunn
 * Kconfig fix suggested by Stephen Boyd.
 * Add module owner suggested by Stephen Boyd and others.
 * Fix unsafe handling of eeprom in unregister spotted by Russell and Mark Brown.
 * seperate bindings patch as suggested by Rob.
 * Add MAINTAINERS as suggested by Rob.
 * Added support to allow reading eeprom for things like serial number which
 * canbe scatters across.
 * Added eeprom data using reg property suggested by Sascha and Stephen.
 * Added non-DT support.
 * Move kerneldoc to the src files spotted by Mark Brown.
 * Remove local list and do eeprom lookup by using class_find_device()


Thanks,
srini


Maxime Ripard (1):
  eeprom: sunxi: Move the SID driver to the eeprom framework

Srinivas Kandagatla (9):
  regmap: Introduce regmap_get_max_register.
  regmap: Introduce regmap_get_reg_stride.
  eeprom: Add a simple EEPROM framework for eeprom providers
  eeprom: Add a simple EEPROM framework for eeprom consumers
  eeprom: Add bindings for simple eeprom framework
  eeprom: Add simple eeprom-mmio consumer helper functions.
  eeprom: qfprom: Add Qualcomm QFPROM support.
  eeprom: qfprom: Add bindings for qfprom
  eeprom: Add to MAINTAINERS for eeprom framework

 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 -
 .../bindings/eeprom/allwinner,sunxi-sid.txt        |  21 +
 .../devicetree/bindings/eeprom/eeprom.txt          |  58 +++
 .../devicetree/bindings/eeprom/qfprom.txt          |  34 ++
 .../bindings/misc/allwinner,sunxi-sid.txt          |  17 -
 MAINTAINERS                                        |   9 +
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/base/regmap/regmap.c                       |  24 +
 drivers/eeprom/Kconfig                             |  36 ++
 drivers/eeprom/Makefile                            |  13 +
 drivers/eeprom/core.c                              | 504 +++++++++++++++++++++
 drivers/eeprom/eeprom-mmio.c                       |  69 +++
 drivers/eeprom/eeprom-mmio.h                       |  41 ++
 drivers/eeprom/qfprom.c                            |  51 +++
 drivers/eeprom/sunxi-sid.c                         |  64 +++
 drivers/misc/eeprom/Kconfig                        |  13 -
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 -------
 include/linux/eeprom-consumer.h                    |  61 +++
 include/linux/eeprom-provider.h                    |  43 ++
 include/linux/regmap.h                             |  14 +
 22 files changed, 1045 insertions(+), 209 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
 create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
 create mode 100644 Documentation/devicetree/bindings/eeprom/qfprom.txt
 delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 drivers/eeprom/Kconfig
 create mode 100644 drivers/eeprom/Makefile
 create mode 100644 drivers/eeprom/core.c
 create mode 100644 drivers/eeprom/eeprom-mmio.c
 create mode 100644 drivers/eeprom/eeprom-mmio.h
 create mode 100644 drivers/eeprom/qfprom.c
 create mode 100644 drivers/eeprom/sunxi-sid.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
 create mode 100644 include/linux/eeprom-consumer.h
 create mode 100644 include/linux/eeprom-provider.h

-- 
1.9.1


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

* [PATCH v4 01/10] regmap: Introduce regmap_get_max_register.
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
@ 2015-03-30 21:56         ` Srinivas Kandagatla
  2015-05-04 12:05           ` Mark Brown
  2015-03-30 21:57         ` [PATCH v4 02/10] regmap: Introduce regmap_get_reg_stride Srinivas Kandagatla
                           ` (9 subsequent siblings)
  10 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:56 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch introduces regmap_get_max_register() function which would be
used by the infrastructures like eeprom framework built on top of
regmap.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/base/regmap/regmap.c | 12 ++++++++++++
 include/linux/regmap.h       |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index f99b098..d703921 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2617,6 +2617,18 @@ int regmap_get_val_bytes(struct regmap *map)
 }
 EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
 
+/**
+ * regmap_get_max_register(): Report the max register value
+ *
+ * Report the max register value, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_max_register(struct regmap *map)
+{
+	return map->max_register ? : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regmap_get_max_register);
+
 int regmap_parse_val(struct regmap *map, const void *buf,
 			unsigned int *val)
 {
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 116655d..2d87ded 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -433,6 +433,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
 				   unsigned int mask, unsigned int val,
 				   bool *change);
 int regmap_get_val_bytes(struct regmap *map);
+int regmap_get_max_register(struct regmap *map);
 int regmap_async_complete(struct regmap *map);
 bool regmap_can_raw_write(struct regmap *map);
 
@@ -676,6 +677,12 @@ static inline int regmap_get_val_bytes(struct regmap *map)
 	return -EINVAL;
 }
 
+static inline int regmap_get_max_register(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline int regcache_sync(struct regmap *map)
 {
 	WARN_ONCE(1, "regmap API is disabled");
-- 
1.9.1


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

* [PATCH v4 02/10] regmap: Introduce regmap_get_reg_stride.
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  2015-03-30 21:56         ` [PATCH v4 01/10] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
@ 2015-03-30 21:57         ` Srinivas Kandagatla
  2015-03-30 21:57         ` [PATCH v4 03/10] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
                           ` (8 subsequent siblings)
  10 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:57 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch introduces regmap_get_reg_stride() function which would
be used by the infrastructures like eeprom framework built on top of
regmap. Mostly this function would be used for sanity checks on inputs
within such infrastructure.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/base/regmap/regmap.c | 12 ++++++++++++
 include/linux/regmap.h       |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index d703921..ac44d43 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2629,6 +2629,18 @@ int regmap_get_max_register(struct regmap *map)
 }
 EXPORT_SYMBOL_GPL(regmap_get_max_register);
 
+/**
+ * regmap_get_reg_stride(): Report the register address stride
+ *
+ * Report the register address stride, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_reg_stride(struct regmap *map)
+{
+	return map->reg_stride;
+}
+EXPORT_SYMBOL_GPL(regmap_get_reg_stride);
+
 int regmap_parse_val(struct regmap *map, const void *buf,
 			unsigned int *val)
 {
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 2d87ded..59c55ea 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -434,6 +434,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
 				   bool *change);
 int regmap_get_val_bytes(struct regmap *map);
 int regmap_get_max_register(struct regmap *map);
+int regmap_get_reg_stride(struct regmap *map);
 int regmap_async_complete(struct regmap *map);
 bool regmap_can_raw_write(struct regmap *map);
 
@@ -683,6 +684,12 @@ static inline int regmap_get_max_register(struct regmap *map)
 	return -EINVAL;
 }
 
+static inline int regmap_get_reg_stride(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline int regcache_sync(struct regmap *map)
 {
 	WARN_ONCE(1, "regmap API is disabled");
-- 
1.9.1


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

* [PATCH v4 03/10] eeprom: Add a simple EEPROM framework for eeprom providers
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
  2015-03-30 21:56         ` [PATCH v4 01/10] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
  2015-03-30 21:57         ` [PATCH v4 02/10] regmap: Introduce regmap_get_reg_stride Srinivas Kandagatla
@ 2015-03-30 21:57         ` Srinivas Kandagatla
  2015-03-30 21:57         ` [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
                           ` (7 subsequent siblings)
  10 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:57 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds just providers part of the framework just to enable easy
review.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.

Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/Kconfig                 |   2 +
 drivers/Makefile                |   1 +
 drivers/eeprom/Kconfig          |  10 ++
 drivers/eeprom/Makefile         |   6 ++
 drivers/eeprom/core.c           | 233 ++++++++++++++++++++++++++++++++++++++++
 include/linux/eeprom-provider.h |  43 ++++++++
 6 files changed, 295 insertions(+)
 create mode 100644 drivers/eeprom/Kconfig
 create mode 100644 drivers/eeprom/Makefile
 create mode 100644 drivers/eeprom/core.c
 create mode 100644 include/linux/eeprom-provider.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 7d233c1..6767a2f 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
 
 source "drivers/android/Kconfig"
 
+source "drivers/eeprom/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 527a6da..57eb5b0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= coresight/
 obj-$(CONFIG_ANDROID)		+= android/
+obj-$(CONFIG_EEPROM)		+= eeprom/
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
new file mode 100644
index 0000000..15985e1
--- /dev/null
+++ b/drivers/eeprom/Kconfig
@@ -0,0 +1,10 @@
+menuconfig EEPROM
+	tristate "EEPROM Support"
+	select REGMAP
+	help
+	  Support for EEPROM alike devices.
+
+	  This framework is designed to provide a generic interface to EEPROM
+	  from both the Linux Kernel and the userspace.
+
+	  If unsure, say no.
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
new file mode 100644
index 0000000..51a727f
--- /dev/null
+++ b/drivers/eeprom/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for eeprom drivers.
+#
+
+obj-$(CONFIG_EEPROM)		+= eeprom_core.o
+eeprom_core-y			:= core.o
diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
new file mode 100644
index 0000000..a2c7e6c
--- /dev/null
+++ b/drivers/eeprom/core.c
@@ -0,0 +1,233 @@
+/*
+ * EEPROM framework core.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+struct eeprom_device {
+	struct regmap		*regmap;
+	int			stride;
+	int			word_size;
+	size_t			size;
+
+	struct module		*owner;
+	struct device		dev;
+	int			id;
+	int			users;
+};
+
+static DEFINE_MUTEX(eeprom_mutex);
+static DEFINE_IDA(eeprom_ida);
+
+#define to_eeprom(d) container_of(d, struct eeprom_device, dev)
+
+static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
+				    struct bin_attribute *attr,
+				    char *buf, loff_t pos, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct eeprom_device *eeprom = to_eeprom(dev);
+	int rc;
+
+	/* Stop the user from reading */
+	if (pos > eeprom->size)
+		return 0;
+
+	if (pos + count > eeprom->size)
+		count = eeprom->size - pos;
+
+	count = count/eeprom->word_size * eeprom->word_size;
+
+	rc = regmap_raw_read(eeprom->regmap, pos, buf, count);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count;
+}
+
+static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *attr,
+				     char *buf, loff_t pos, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct eeprom_device *eeprom = to_eeprom(dev);
+	int rc;
+
+	/* Stop the user from writing */
+	if (pos > eeprom->size)
+		return 0;
+
+	if (pos + count > eeprom->size)
+		count = eeprom->size - pos;
+
+	count = count/eeprom->word_size * eeprom->word_size;
+
+	rc = regmap_raw_write(eeprom->regmap, pos, buf, count);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count;
+}
+
+static struct bin_attribute bin_attr_eeprom = {
+	.attr	= {
+		.name	= "eeprom",
+		.mode	= S_IWUSR | S_IRUGO,
+	},
+	.read	= bin_attr_eeprom_read,
+	.write	= bin_attr_eeprom_write,
+};
+
+static struct bin_attribute *eeprom_bin_attributes[] = {
+	&bin_attr_eeprom,
+	NULL,
+};
+
+static const struct attribute_group eeprom_bin_group = {
+	.bin_attrs	= eeprom_bin_attributes,
+};
+
+static const struct attribute_group *eeprom_dev_groups[] = {
+	&eeprom_bin_group,
+	NULL,
+};
+
+static void eeprom_release(struct device *dev)
+{
+	struct eeprom_device *eeprom = to_eeprom(dev);
+
+	ida_simple_remove(&eeprom_ida, eeprom->id);
+	kfree(eeprom);
+}
+
+static struct class eeprom_class = {
+	.name		= "eeprom",
+	.dev_groups	= eeprom_dev_groups,
+	.dev_release	= eeprom_release,
+};
+
+/**
+ * eeprom_register(): Register a eeprom device for given eeprom.
+ * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
+ *
+ * @eeprom: eeprom device that needs to be created
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to eeprom_device.
+ */
+
+struct eeprom_device *eeprom_register(struct eeprom_config *config)
+{
+	struct eeprom_device *eeprom;
+	struct regmap *rm;
+	int rval;
+
+	if (!config->dev)
+		return ERR_PTR(-EINVAL);
+
+	rm = dev_get_regmap(config->dev, NULL);
+	if (!rm) {
+		dev_err(config->dev, "Regmap not found\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL);
+	if (!eeprom)
+		return ERR_PTR(-ENOMEM);
+
+	eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
+	if (eeprom->id < 0) {
+		kfree(eeprom);
+		return ERR_PTR(eeprom->id);
+	}
+
+	eeprom->regmap = rm;
+	eeprom->owner = config->owner;
+	eeprom->stride = regmap_get_reg_stride(rm);
+	eeprom->word_size = regmap_get_val_bytes(rm);
+	eeprom->size = regmap_get_max_register(rm) + eeprom->stride;
+	eeprom->dev.class = &eeprom_class;
+	eeprom->dev.parent = config->dev;
+	eeprom->dev.of_node = config->dev ? config->dev->of_node : NULL;
+	dev_set_name(&eeprom->dev, "%s%d",
+		     config->name ? : "eeprom", config->id);
+
+	device_initialize(&eeprom->dev);
+
+	dev_dbg(&eeprom->dev, "Registering eeprom device %s\n",
+		dev_name(&eeprom->dev));
+
+	rval = device_add(&eeprom->dev);
+	if (rval) {
+		ida_simple_remove(&eeprom_ida, eeprom->id);
+		kfree(eeprom);
+		return ERR_PTR(rval);
+	}
+
+	return eeprom;
+}
+EXPORT_SYMBOL_GPL(eeprom_register);
+
+/**
+ * eeprom_unregister(): Unregister previously registered eeprom device
+ *
+ * @eeprom: Pointer to previously registered eeprom device.
+ *
+ * The return value will be an non zero on error or a zero on success.
+ */
+int eeprom_unregister(struct eeprom_device *eeprom)
+{
+	mutex_lock(&eeprom_mutex);
+	if (eeprom->users) {
+		mutex_unlock(&eeprom_mutex);
+		return -EBUSY;
+	}
+	mutex_unlock(&eeprom_mutex);
+
+	device_del(&eeprom->dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(eeprom_unregister);
+
+static int eeprom_init(void)
+{
+	return class_register(&eeprom_class);
+}
+
+static void eeprom_exit(void)
+{
+	class_unregister(&eeprom_class);
+}
+
+subsys_initcall(eeprom_init);
+module_exit(eeprom_exit);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("EEPROM Driver Core");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
new file mode 100644
index 0000000..1892897
--- /dev/null
+++ b/include/linux/eeprom-provider.h
@@ -0,0 +1,43 @@
+/*
+ * EEPROM framework provider.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_PROVIDER_H
+#define _LINUX_EEPROM_PROVIDER_H
+
+struct eeprom_device;
+
+struct eeprom_config {
+	struct device		*dev;
+	const char		*name;
+	int			id;
+	struct module		*owner;
+};
+
+#if IS_ENABLED(CONFIG_EEPROM)
+
+struct eeprom_device *eeprom_register(struct eeprom_config *cfg);
+int eeprom_unregister(struct eeprom_device *eeprom);
+
+#else
+
+static inline struct eeprom_device *eeprom_register(struct eeprom_config *cfg)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline int eeprom_unregister(struct eeprom_device *eeprom)
+{
+	return -ENOSYS;
+}
+
+#endif /* CONFIG_EEPROM */
+
+#endif  /* ifndef _LINUX_EEPROM_PROVIDER_H */
-- 
1.9.1


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

* [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                           ` (2 preceding siblings ...)
  2015-03-30 21:57         ` [PATCH v4 03/10] eeprom: Add a simple EEPROM framework for eeprom providers Srinivas Kandagatla
@ 2015-03-30 21:57         ` Srinivas Kandagatla
  2015-04-07 18:45           ` Stephen Boyd
  2015-05-06 17:28           ` Mark Brown
  2015-03-30 21:57         ` [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
                           ` (6 subsequent siblings)
  10 siblings, 2 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:57 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds just consumers part of the framework just to enable easy
review.

Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.

Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of the framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/core.c           | 271 ++++++++++++++++++++++++++++++++++++++++
 include/linux/eeprom-consumer.h |  61 +++++++++
 2 files changed, 332 insertions(+)
 create mode 100644 include/linux/eeprom-consumer.h

diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
index a2c7e6c..7065275 100644
--- a/drivers/eeprom/core.c
+++ b/drivers/eeprom/core.c
@@ -16,6 +16,7 @@
 
 #include <linux/device.h>
 #include <linux/eeprom-provider.h>
+#include <linux/eeprom-consumer.h>
 #include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/idr.h>
@@ -38,6 +39,13 @@ struct eeprom_device {
 	int			users;
 };
 
+struct eeprom_cell {
+	struct eeprom_device	*eeprom;
+	int			nblocks;
+	int			size;
+	struct eeprom_block	blocks[0];
+};
+
 static DEFINE_MUTEX(eeprom_mutex);
 static DEFINE_IDA(eeprom_ida);
 
@@ -130,6 +138,37 @@ static struct class eeprom_class = {
 	.dev_release	= eeprom_release,
 };
 
+static int of_eeprom_match(struct device *dev, const void *eeprom_np)
+{
+	return dev->of_node == eeprom_np;
+}
+
+static struct eeprom_device *of_eeprom_find(struct device_node *eeprom_np)
+{
+	struct device *d;
+
+	if (!eeprom_np)
+		return NULL;
+
+	d = class_find_device(&eeprom_class, NULL, eeprom_np, of_eeprom_match);
+
+	return d ? to_eeprom(d) : NULL;
+}
+
+static int eeprom_match(struct device *dev, const void *data)
+{
+	return !strcmp(dev_name(dev), (const char *)data);
+}
+
+static struct eeprom_device *eeprom_find(const char *name)
+{
+	struct device *d;
+
+	d = class_find_device(&eeprom_class, NULL, (void *)name, eeprom_match);
+
+	return d ? to_eeprom(d) : NULL;
+}
+
 /**
  * eeprom_register(): Register a eeprom device for given eeprom.
  * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
@@ -214,6 +253,238 @@ int eeprom_unregister(struct eeprom_device *eeprom)
 }
 EXPORT_SYMBOL_GPL(eeprom_unregister);
 
+static int eeprom_cell_sanity_check(struct eeprom_cell *cell)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	int i;
+
+	/* byte aligned, no need to check for stride sanity */
+	if (eeprom->stride == 1)
+		return 0;
+
+	for (i = 0; i < cell->nblocks; i++) {
+		if (!IS_ALIGNED(cell->blocks[i].offset, eeprom->stride)) {
+			dev_err(&eeprom->dev,
+				"cell unaligned to eeprom stride %d\n",
+				eeprom->stride);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static struct eeprom_cell *__eeprom_cell_get(struct device_node *cell_np,
+					     const char *ename,
+					     struct eeprom_block *blocks,
+					     int nblocks)
+{
+	struct eeprom_cell *cell;
+	struct eeprom_device *eeprom;
+	struct property *prop;
+	const __be32 *vp;
+	u32 pv;
+	int i, rval;
+
+	mutex_lock(&eeprom_mutex);
+
+	eeprom = cell_np ? of_eeprom_find(cell_np->parent) : eeprom_find(ename);
+	if (!eeprom) {
+		mutex_unlock(&eeprom_mutex);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	eeprom->users++;
+	mutex_unlock(&eeprom_mutex);
+
+	if (!try_module_get(eeprom->owner)) {
+		dev_err(&eeprom->dev,
+			"could not increase module refcount for cell %s\n",
+			ename);
+		rval = -EINVAL;
+		goto err_mod;
+	}
+
+	if (cell_np)
+		nblocks = of_property_count_u32_elems(cell_np, "reg") / 2;
+
+	cell = kzalloc(sizeof(*cell) + nblocks * sizeof(*blocks), GFP_KERNEL);
+	if (!cell) {
+		rval = -ENOMEM;
+		goto err_mem;
+	}
+
+	cell->nblocks = nblocks;
+	cell->eeprom = eeprom;
+	cell->size = 0;
+	i = 0;
+
+	if (cell_np) {
+		of_property_for_each_u32(cell_np, "reg", prop, vp, pv) {
+			cell->blocks[i].offset = pv;
+			vp = of_prop_next_u32(prop, vp, &pv);
+			cell->blocks[i].count = pv;
+			cell->size += pv;
+			i++;
+		}
+	} else {
+		memcpy(cell->blocks, blocks, nblocks * sizeof(*blocks));
+		for (; i < nblocks; i++)
+			cell->size += blocks[i].count;
+	}
+
+	if (IS_ERR_VALUE(eeprom_cell_sanity_check(cell))) {
+		rval  = -EINVAL;
+		goto err_sanity;
+	}
+
+	return cell;
+
+err_sanity:
+	kfree(cell);
+
+err_mem:
+	module_put(eeprom->owner);
+
+err_mod:
+	mutex_lock(&eeprom_mutex);
+	eeprom->users--;
+	mutex_unlock(&eeprom_mutex);
+
+	return ERR_PTR(rval);
+
+}
+
+/**
+ * eeprom_cell_get(): Get eeprom cell of device form a given eeprom name
+ * and blocks.
+ *
+ * @ename: eeprom device name that needs to be looked-up.
+ * @blocks: eeprom blocks containing offset and length information.
+ * @nblocks: number of eeprom blocks.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks)
+{
+	return __eeprom_cell_get(NULL, ename, blocks, nblocks);
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_get);
+
+/**
+ * of_eeprom_cell_get(): Get eeprom cell of device form a given index
+ *
+ * @dev node: Device tree node that uses the eeprom cell
+ * @index: eeprom index in eeproms property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell.  The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *of_eeprom_cell_get(struct device_node *np, const char *name)
+{
+	struct device_node *cell_np;
+
+	cell_np = of_parse_phandle(np, name, 0);
+	if (!cell_np)
+		return ERR_PTR(-EINVAL);
+
+	return __eeprom_cell_get(cell_np, NULL, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(of_eeprom_cell_get);
+
+/**
+ * eeprom_cell_put(): Release previously allocated eeprom cell.
+ *
+ * @cell: Previously allocated eeprom cell by eeprom_cell_get()
+ * or of_eeprom_cell_get().
+ */
+void eeprom_cell_put(struct eeprom_cell *cell)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+
+	mutex_lock(&eeprom_mutex);
+	eeprom->users--;
+	mutex_unlock(&eeprom_mutex);
+	module_put(eeprom->owner);
+	kfree(cell);
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_put);
+
+/**
+ * eeprom_cell_read(): Read a given eeprom cell
+ *
+ * @cell: eeprom cell to be read.
+ * @len: pointer to length of cell which will be populated on successful read.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a char * bufffer.  The buffer should be freed by the consumer with a
+ * kfree().
+ */
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	char *buf;
+	int rc, i, offset = 0;
+
+	if (!eeprom || !eeprom->regmap)
+		return ERR_PTR(-EINVAL);
+
+	buf = kzalloc(cell->size, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < cell->nblocks; i++) {
+		rc = regmap_raw_read(eeprom->regmap, cell->blocks[i].offset,
+				      buf + offset, cell->blocks[i].count);
+
+		if (IS_ERR_VALUE(rc)) {
+			kfree(buf);
+			return ERR_PTR(rc);
+		}
+		offset += cell->blocks[i].count;
+	}
+
+	*len = cell->size;
+
+	return buf;
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_read);
+
+/**
+ * eeprom_cell_write(): Write to a given eeprom cell
+ *
+ * @cell: eeprom cell to be written.
+ * @buf: Buffer to be written.
+ * @len: length of buffer to be written to eeprom cell.
+ *
+ * The return value will be an length of bytes written or non zero on failure.
+ */
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
+{
+	struct eeprom_device *eeprom = cell->eeprom;
+	int i, rc, offset = 0;
+
+	if (!eeprom || !eeprom->regmap || len != cell->size)
+		return -EINVAL;
+
+	for (i = 0; i < cell->nblocks; i++) {
+		rc = regmap_raw_write(eeprom->regmap, cell->blocks[i].offset,
+				       buf + offset, cell->blocks[i].count);
+
+		if (IS_ERR_VALUE(rc))
+			return rc;
+
+		offset += cell->blocks[i].count;
+	}
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_write);
+
 static int eeprom_init(void)
 {
 	return class_register(&eeprom_class);
diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
new file mode 100644
index 0000000..effa417
--- /dev/null
+++ b/include/linux/eeprom-consumer.h
@@ -0,0 +1,61 @@
+/*
+ * EEPROM framework consumer.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_CONSUMER_H
+#define _LINUX_EEPROM_CONSUMER_H
+
+struct eeprom_cell;
+
+struct eeprom_block {
+	loff_t offset;
+	size_t count;
+};
+#if IS_ENABLED(CONFIG_EEPROM)
+struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks);
+void eeprom_cell_put(struct eeprom_cell *cell);
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
+#else
+
+static inline struct eeprom_cell *eeprom_cell_get(const char *ename,
+				    struct eeprom_block *blocks, int nblocks)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline void eeprom_cell_put(struct eeprom_cell *cell)
+{
+}
+
+static inline char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline int eeprom_cell_write(struct eeprom_cell *cell,
+				    const char *buf, ssize_t len)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_EEPROM */
+
+#if IS_ENABLED(CONFIG_EEPROM) && IS_ENABLED(CONFIG_OF)
+struct eeprom_cell *of_eeprom_cell_get(struct device_node *dev,
+				       const char *property);
+#else
+static inline struct eeprom_cell *of_eeprom_cell_get(struct device_node *np,
+						     const char *property)
+{
+	return ERR_PTR(-ENOSYS);
+}
+#endif
+#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */
-- 
1.9.1


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

* [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                           ` (3 preceding siblings ...)
  2015-03-30 21:57         ` [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
@ 2015-03-30 21:57         ` Srinivas Kandagatla
  2015-04-06 13:32           ` Matt Porter
  2015-03-30 21:58         ` [PATCH v4 06/10] eeprom: Add simple eeprom-mmio consumer helper functions Srinivas Kandagatla
                           ` (5 subsequent siblings)
  10 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:57 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds bindings for simple eeprom framework which allows eeprom
consumers to talk to eeprom providers to get access to eeprom cell data.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/eeprom/eeprom.txt          | 58 ++++++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt

diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
new file mode 100644
index 0000000..fb71d46
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
@@ -0,0 +1,58 @@
+= EEPROM Data Device Tree Bindings =
+
+This binding is intended to represent the location of hardware
+configuration data stored in EEPROMs.
+
+On a significant proportion of boards, the manufacturer has stored
+some data on an EEPROM-like device, for the OS to be able to retrieve
+these information and act upon it. Obviously, the OS has to know
+about where to retrieve these data from, and where they are stored on
+the storage device.
+
+This document is here to document this.
+
+= Data providers =
+Contains bindings specific to provider drivers and data cells as children
+to this node.
+
+= Data cells =
+These are the child nodes of the provider which contain data cell
+information like offset and size in eeprom provider.
+
+Required properties:
+reg:	specifies the offset in byte within that storage device, and the length
+	in bytes of the data we care about.
+	There could be more then one offset-length pairs in this property.
+
+Optional properties:
+As required by specific data parsers/interpreters.
+
+For example:
+
+	/* Provider */
+	qfprom: qfprom@00700000 {
+		compatible 	= "qcom,qfprom";
+		reg		= <0x00700000 0x8000>;
+		...
+
+		/* Data cells */
+		tsens_calibration: calib@4404 {
+			reg = <0x4404 0x10>;
+		};
+
+		serial_number: sn {
+			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
+
+		};
+		...
+	};
+
+= Data consumers =
+Are device nodes which consume eeprom data cells.
+
+For example:
+
+	tsens {
+		...
+		calibration = <&tsens_calibration>;
+	};
-- 
1.9.1


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

* [PATCH v4 06/10] eeprom: Add simple eeprom-mmio consumer helper functions.
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                           ` (4 preceding siblings ...)
  2015-03-30 21:57         ` [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
@ 2015-03-30 21:58         ` Srinivas Kandagatla
  2015-03-30 21:58         ` [PATCH v4 07/10] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
                           ` (4 subsequent siblings)
  10 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:58 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds probe and remove helper functions for eeproms which are
mmio based, With these helper function new eeprom consumer drivers need
very little code add its driver.

This code is currently used for qfprom and sunxi-sid eeprom consumer drivers.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/Makefile      |  1 +
 drivers/eeprom/eeprom-mmio.c | 69 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/eeprom/eeprom-mmio.h | 41 ++++++++++++++++++++++++++
 3 files changed, 111 insertions(+)
 create mode 100644 drivers/eeprom/eeprom-mmio.c
 create mode 100644 drivers/eeprom/eeprom-mmio.h

diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 51a727f..6812bbe 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_EEPROM)		+= eeprom_core.o
 eeprom_core-y			:= core.o
+eeprom_core-y			+= eeprom-mmio.o
diff --git a/drivers/eeprom/eeprom-mmio.c b/drivers/eeprom/eeprom-mmio.c
new file mode 100644
index 0000000..55b8913
--- /dev/null
+++ b/drivers/eeprom/eeprom-mmio.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include "eeprom-mmio.h"
+
+int eeprom_mmio_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+EXPORT_SYMBOL_GPL(eeprom_mmio_remove);
+
+int eeprom_mmio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	const struct eeprom_mmio_data *data;
+	struct eeprom_device *eeprom;
+	struct regmap *regmap;
+	const struct of_device_id *match;
+	void __iomem *base;
+
+	if (!dev || !dev->driver)
+		return -ENODEV;
+
+	match = of_match_device(dev->driver->of_match_table, dev);
+	if (!match || !match->data)
+		return -EINVAL;
+
+	data = match->data;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	data->regmap_config->max_register = resource_size(res) - 1;
+
+	regmap = devm_regmap_init_mmio(dev, base, data->regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(regmap);
+	}
+	data->eeprom_config->dev = dev;
+	eeprom = eeprom_register(data->eeprom_config);
+	if (IS_ERR(eeprom))
+		return PTR_ERR(eeprom);
+
+	platform_set_drvdata(pdev, eeprom);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(eeprom_mmio_probe);
diff --git a/drivers/eeprom/eeprom-mmio.h b/drivers/eeprom/eeprom-mmio.h
new file mode 100644
index 0000000..e58bcc8
--- /dev/null
+++ b/drivers/eeprom/eeprom-mmio.h
@@ -0,0 +1,41 @@
+/*
+ * MMIO based EEPROM providers.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_MMIO_H
+#define _LINUX_EEPROM_MMIO_H
+
+#include <linux/platform_device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/regmap.h>
+
+struct eeprom_mmio_data {
+	struct regmap_config *regmap_config;
+	struct eeprom_config *eeprom_config;
+};
+
+#if IS_ENABLED(CONFIG_EEPROM)
+
+int eeprom_mmio_probe(struct platform_device *pdev);
+int eeprom_mmio_remove(struct platform_device *pdev);
+
+#else
+
+static inline int eeprom_mmio_probe(struct platform_device *pdev)
+{
+	return -ENOSYS;
+}
+
+static inline int eeprom_mmio_remove(struct platform_device *pdev)
+{
+	return -ENOSYS;
+}
+#endif
+
+#endif  /* ifndef _LINUX_EEPROM_MMIO_H */
-- 
1.9.1


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

* [PATCH v4 07/10] eeprom: qfprom: Add Qualcomm QFPROM support.
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                           ` (5 preceding siblings ...)
  2015-03-30 21:58         ` [PATCH v4 06/10] eeprom: Add simple eeprom-mmio consumer helper functions Srinivas Kandagatla
@ 2015-03-30 21:58         ` Srinivas Kandagatla
  2015-03-30 21:58         ` [PATCH v4 08/10] eeprom: qfprom: Add bindings for qfprom Srinivas Kandagatla
                           ` (3 subsequent siblings)
  10 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:58 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds QFPROM support driver which is used by other drivers
like thermal sensor and cpufreq.

On MSM parts there are some efuses (called qfprom) these fuses store things like
calibration data, speed bins.. etc. Drivers like cpufreq, thermal sensors would
read out this data for configuring the driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/Kconfig  | 15 +++++++++++++++
 drivers/eeprom/Makefile |  4 ++++
 drivers/eeprom/qfprom.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 70 insertions(+)
 create mode 100644 drivers/eeprom/qfprom.c

diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index 15985e1..8fcde9b 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -8,3 +8,18 @@ menuconfig EEPROM
 	  from both the Linux Kernel and the userspace.
 
 	  If unsure, say no.
+
+if EEPROM
+
+config QCOM_QFPROM
+	tristate "QCOM QFPROM Support"
+	depends on ARCH_QCOM
+	select REGMAP_MMIO
+	help
+	  Say y here to enable QFPROM support. The QFPROM provides access
+	  functions for QFPROM data to rest of the drivers via eeprom interface.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called eeprom-qfprom.
+
+endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 6812bbe..819476c 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -5,3 +5,7 @@
 obj-$(CONFIG_EEPROM)		+= eeprom_core.o
 eeprom_core-y			:= core.o
 eeprom_core-y			+= eeprom-mmio.o
+
+# Devices
+obj-$(CONFIG_QCOM_QFPROM)	+= eeprom_qfprom.o
+eeprom_qfprom-y			:= qfprom.o
diff --git a/drivers/eeprom/qfprom.c b/drivers/eeprom/qfprom.c
new file mode 100644
index 0000000..011bdf1
--- /dev/null
+++ b/drivers/eeprom/qfprom.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include "eeprom-mmio.h"
+
+static struct regmap_config qfprom_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+};
+
+static struct eeprom_config econfig = {
+	.name = "qfprom",
+	.owner = THIS_MODULE,
+};
+
+static struct eeprom_mmio_data qfprom_data = {
+	.eeprom_config = &econfig,
+	.regmap_config = &qfprom_regmap_config,
+};
+
+static const struct of_device_id qfprom_of_match[] = {
+	{ .compatible = "qcom,qfprom", .data = &qfprom_data},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, qfprom_of_match);
+
+static struct platform_driver qfprom_driver = {
+	.probe = eeprom_mmio_probe,
+	.remove = eeprom_mmio_remove,
+	.driver = {
+		.name = "qcom,qfprom",
+		.of_match_table = qfprom_of_match,
+	},
+};
+module_platform_driver(qfprom_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm QFPROM driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


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

* [PATCH v4 08/10] eeprom: qfprom: Add bindings for qfprom
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                           ` (6 preceding siblings ...)
  2015-03-30 21:58         ` [PATCH v4 07/10] eeprom: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
@ 2015-03-30 21:58         ` Srinivas Kandagatla
  2015-03-30 21:58         ` [PATCH v4 09/10] eeprom: sunxi: Move the SID driver to the eeprom framework Srinivas Kandagatla
                           ` (2 subsequent siblings)
  10 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:58 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds bindings for qfprom found in QCOM SOCs. QFPROM driver
is based on simple eeprom framework.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/eeprom/qfprom.txt          | 34 ++++++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/eeprom/qfprom.txt

diff --git a/Documentation/devicetree/bindings/eeprom/qfprom.txt b/Documentation/devicetree/bindings/eeprom/qfprom.txt
new file mode 100644
index 0000000..21a7104
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/qfprom.txt
@@ -0,0 +1,34 @@
+= Qualcomm QFPROM device tree bindings =
+
+This binding is intended to represent QFPROM which is found in most QCOM SOCs.
+
+Required properties:
+- compatible: should be "qcom,qfprom"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/eeprom/eeprom.txt
+
+Example:
+
+	qfprom: qfprom@00700000 {
+		compatible 	= "qcom,qfprom";
+		reg		= <0x00700000 0x8000>;
+		...
+		/* Data cells */
+		tsens_calibration: calib@404 {
+			reg = <0x4404 0x10>;
+		};
+	};
+
+
+= Data consumers =
+Are device nodes which consume eeprom data cells.
+
+For example:
+
+	tsens {
+		...
+		calibration = <&tsens_calibration>;
+	};
-- 
1.9.1


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

* [PATCH v4 09/10] eeprom: sunxi: Move the SID driver to the eeprom framework
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                           ` (7 preceding siblings ...)
  2015-03-30 21:58         ` [PATCH v4 08/10] eeprom: qfprom: Add bindings for qfprom Srinivas Kandagatla
@ 2015-03-30 21:58         ` Srinivas Kandagatla
  2015-03-30 21:58         ` [PATCH v4 10/10] eeprom: Add to MAINTAINERS for " Srinivas Kandagatla
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
  10 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:58 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

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

Now that we have the EEPROM framework, we can consolidate the common driver
code. Move the driver to the framework, and hopefully, it will fix the sysfs
file creation race.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[srinivas.kandagatla: Moved to regmap based EEPROM framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 ---
 .../bindings/eeprom/allwinner,sunxi-sid.txt        |  21 +++
 .../bindings/misc/allwinner,sunxi-sid.txt          |  17 ---
 drivers/eeprom/Kconfig                             |  11 ++
 drivers/eeprom/Makefile                            |   2 +
 drivers/eeprom/sunxi-sid.c                         |  64 +++++++++
 drivers/misc/eeprom/Kconfig                        |  13 --
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 ---------------------
 9 files changed, 98 insertions(+), 209 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
 delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 drivers/eeprom/sunxi-sid.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid
deleted file mode 100644
index ffb9536..0000000
--- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid
+++ /dev/null
@@ -1,22 +0,0 @@
-What:		/sys/devices/*/<our-device>/eeprom
-Date:		August 2013
-Contact:	Oliver Schinagl <oliver@schinagl.nl>
-Description:	read-only access to the SID (Security-ID) on current
-		A-series SoC's from Allwinner. Currently supports A10, A10s, A13
-		and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes,
-		whereas the newer A20 SoC exposes 512 bytes split into sections.
-		Besides the 16 bytes of SID, there's also an SJTAG area,
-		HDMI-HDCP key and some custom keys. Below a quick overview, for
-		details see the user manual:
-		0x000  128 bit root-key (sun[457]i)
-		0x010  128 bit boot-key (sun7i)
-		0x020   64 bit security-jtag-key (sun7i)
-		0x028   16 bit key configuration (sun7i)
-		0x02b   16 bit custom-vendor-key (sun7i)
-		0x02c  320 bit low general key (sun7i)
-		0x040   32 bit read-control access (sun7i)
-		0x064  224 bit low general key (sun7i)
-		0x080 2304 bit HDCP-key (sun7i)
-		0x1a0  768 bit high general key (sun7i)
-Users:		any user space application which wants to read the SID on
-		Allwinner's A-series of CPU's.
diff --git a/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
new file mode 100644
index 0000000..cceaaf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
@@ -0,0 +1,21 @@
+Allwinner sunxi-sid
+
+Required properties:
+- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/eeprom/eeprom.txt
+
+Example for sun4i:
+	sid@01c23800 {
+		compatible = "allwinner,sun4i-a10-sid";
+		reg = <0x01c23800 0x10>
+	};
+
+Example for sun7i:
+	sid@01c23800 {
+		compatible = "allwinner,sun7i-a20-sid";
+		reg = <0x01c23800 0x200>
+	};
diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
deleted file mode 100644
index fabdf64..0000000
--- a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Allwinner sunxi-sid
-
-Required properties:
-- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
-- reg: Should contain registers location and length
-
-Example for sun4i:
-	sid@01c23800 {
-		compatible = "allwinner,sun4i-a10-sid";
-		reg = <0x01c23800 0x10>
-	};
-
-Example for sun7i:
-	sid@01c23800 {
-		compatible = "allwinner,sun7i-a20-sid";
-		reg = <0x01c23800 0x200>
-	};
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index 8fcde9b..f931fcb 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -22,4 +22,15 @@ config QCOM_QFPROM
 	  This driver can also be built as a module. If so, the module
 	  will be called eeprom-qfprom.
 
+config EEPROM_SUNXI_SID
+	tristate "Allwinner SoCs SID support"
+	depends on ARCH_SUNXI
+	select REGMAP_MMIO
+	help
+	  This is a driver for the 'security ID' available on various Allwinner
+	  devices.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called eeprom-sunxi-sid.
+
 endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 819476c..8bd9450 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -9,3 +9,5 @@ eeprom_core-y			+= eeprom-mmio.o
 # Devices
 obj-$(CONFIG_QCOM_QFPROM)	+= eeprom_qfprom.o
 eeprom_qfprom-y			:= qfprom.o
+obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
+eeprom-sunxi-sid-y		:= sunxi-sid.o
diff --git a/drivers/eeprom/sunxi-sid.c b/drivers/eeprom/sunxi-sid.c
new file mode 100644
index 0000000..b963463
--- /dev/null
+++ b/drivers/eeprom/sunxi-sid.c
@@ -0,0 +1,64 @@
+/*
+ * Allwinner sunXi SoCs Security ID support.
+ *
+ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include "eeprom-mmio.h"
+
+static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static struct eeprom_config econfig = {
+	.name = "sunix-sid",
+	.owner = THIS_MODULE,
+};
+
+static struct regmap_config sunxi_sid_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.writeable_reg = sunxi_sid_writeable_reg,
+};
+
+static struct eeprom_mmio_data sunxi_data = {
+	.eeprom_config = &econfig,
+	.regmap_config = &sunxi_sid_regmap_config,
+};
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-sid", .data = &sunxi_data},
+	{ .compatible = "allwinner,sun7i-a20-sid", .data = &sunxi_data},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = eeprom_mmio_probe,
+	.remove = eeprom_mmio_remove,
+	.driver = {
+		.name = "eeprom-sunxi-sid",
+		.of_match_table = sunxi_sid_of_match,
+	},
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 9536852f..04f2e1f 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG
 
 	  If unsure, say N.
 
-config EEPROM_SUNXI_SID
-	tristate "Allwinner sunxi security ID support"
-	depends on ARCH_SUNXI && SYSFS
-	help
-	  This is a driver for the 'security ID' available on various Allwinner
-	  devices.
-
-	  Due to the potential risks involved with changing e-fuses,
-	  this driver is read-only.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called sunxi_sid.
-
 endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 9507aec..fc1e81d 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY)	+= eeprom.o
 obj-$(CONFIG_EEPROM_MAX6875)	+= max6875.o
 obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
 obj-$(CONFIG_EEPROM_93XX46)	+= eeprom_93xx46.o
-obj-$(CONFIG_EEPROM_SUNXI_SID)	+= sunxi_sid.o
 obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
deleted file mode 100644
index 8385177..0000000
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
- * http://www.linux-sunxi.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * This driver exposes the Allwinner security ID, efuses exported in byte-
- * sized chunks.
- */
-
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#define DRV_NAME "sunxi-sid"
-
-struct sunxi_sid_data {
-	void __iomem *reg_base;
-	unsigned int keysize;
-};
-
-/* We read the entire key, due to a 32 bit read alignment requirement. Since we
- * want to return the requested byte, this results in somewhat slower code and
- * uses 4 times more reads as needed but keeps code simpler. Since the SID is
- * only very rarely probed, this is not really an issue.
- */
-static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data,
-			      const unsigned int offset)
-{
-	u32 sid_key;
-
-	if (offset >= sid_data->keysize)
-		return 0;
-
-	sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4));
-	sid_key >>= (offset % 4) * 8;
-
-	return sid_key; /* Only return the last byte */
-}
-
-static ssize_t sid_read(struct file *fd, struct kobject *kobj,
-			struct bin_attribute *attr, char *buf,
-			loff_t pos, size_t size)
-{
-	struct platform_device *pdev;
-	struct sunxi_sid_data *sid_data;
-	int i;
-
-	pdev = to_platform_device(kobj_to_dev(kobj));
-	sid_data = platform_get_drvdata(pdev);
-
-	if (pos < 0 || pos >= sid_data->keysize)
-		return 0;
-	if (size > sid_data->keysize - pos)
-		size = sid_data->keysize - pos;
-
-	for (i = 0; i < size; i++)
-		buf[i] = sunxi_sid_read_byte(sid_data, pos + i);
-
-	return i;
-}
-
-static struct bin_attribute sid_bin_attr = {
-	.attr = { .name = "eeprom", .mode = S_IRUGO, },
-	.read = sid_read,
-};
-
-static int sunxi_sid_remove(struct platform_device *pdev)
-{
-	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
-	dev_dbg(&pdev->dev, "driver unloaded\n");
-
-	return 0;
-}
-
-static const struct of_device_id sunxi_sid_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
-	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
-	{/* sentinel */},
-};
-MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-
-static int sunxi_sid_probe(struct platform_device *pdev)
-{
-	struct sunxi_sid_data *sid_data;
-	struct resource *res;
-	const struct of_device_id *of_dev_id;
-	u8 *entropy;
-	unsigned int i;
-
-	sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data),
-				GFP_KERNEL);
-	if (!sid_data)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(sid_data->reg_base))
-		return PTR_ERR(sid_data->reg_base);
-
-	of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev);
-	if (!of_dev_id)
-		return -ENODEV;
-	sid_data->keysize = (int)of_dev_id->data;
-
-	platform_set_drvdata(pdev, sid_data);
-
-	sid_bin_attr.size = sid_data->keysize;
-	if (device_create_bin_file(&pdev->dev, &sid_bin_attr))
-		return -ENODEV;
-
-	entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL);
-	for (i = 0; i < sid_data->keysize; i++)
-		entropy[i] = sunxi_sid_read_byte(sid_data, i);
-	add_device_randomness(entropy, sid_data->keysize);
-	kfree(entropy);
-
-	dev_dbg(&pdev->dev, "loaded\n");
-
-	return 0;
-}
-
-static struct platform_driver sunxi_sid_driver = {
-	.probe = sunxi_sid_probe,
-	.remove = sunxi_sid_remove,
-	.driver = {
-		.name = DRV_NAME,
-		.of_match_table = sunxi_sid_of_match,
-	},
-};
-module_platform_driver(sunxi_sid_driver);
-
-MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
-MODULE_DESCRIPTION("Allwinner sunxi security id driver");
-MODULE_LICENSE("GPL");
-- 
1.9.1


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

* [PATCH v4 10/10] eeprom: Add to MAINTAINERS for eeprom framework
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                           ` (8 preceding siblings ...)
  2015-03-30 21:58         ` [PATCH v4 09/10] eeprom: sunxi: Move the SID driver to the eeprom framework Srinivas Kandagatla
@ 2015-03-30 21:58         ` Srinivas Kandagatla
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
  10 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-03-30 21:58 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla

This patch adds MAINTAINERS to eeprom framework.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 358eb01..7094bb0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3721,6 +3721,15 @@ T:	git git://git.alsa-project.org/alsa-kernel.git
 S:	Maintained
 F:	sound/usb/misc/ua101.c
 
+EEPROM FRAMEWORK
+M:	Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+M:	Maxime Ripard <maxime.ripard@free-electrons.com>
+S:	Maintained
+F:	drivers/eeprom/
+F:	Documentation/devicetree/bindings/eeprom/
+F:	include/linux/eeprom-provider.h
+F:	include/linux/eeprom-consumer.h
+
 EXTENSIBLE FIRMWARE INTERFACE (EFI)
 M:	Matt Fleming <matt.fleming@intel.com>
 L:	linux-efi@vger.kernel.org
-- 
1.9.1


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

* Re: [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework
  2015-03-30 21:57         ` [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework Srinivas Kandagatla
@ 2015-04-06 13:32           ` Matt Porter
  2015-04-06 14:11             ` Rob Herring
  0 siblings, 1 reply; 153+ messages in thread
From: Matt Porter @ 2015-04-06 13:32 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, devicetree, arnd, Greg Kroah-Hartman, s.hauer,
	sboyd, linux-kernel, Rob Herring, Mark Brown, Kumar Gala,
	Maxime Ripard, linux-api, linux-arm-msm

On Mon, Mar 30, 2015 at 10:57:59PM +0100, Srinivas Kandagatla wrote:
> This patch adds bindings for simple eeprom framework which allows eeprom
> consumers to talk to eeprom providers to get access to eeprom cell data.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> [Maxime Ripard: intial version of eeprom framework]
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  .../devicetree/bindings/eeprom/eeprom.txt          | 58 ++++++++++++++++++++++
>  1 file changed, 58 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
> 
> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> new file mode 100644
> index 0000000..fb71d46
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> @@ -0,0 +1,58 @@
> += EEPROM Data Device Tree Bindings =
> +
> +This binding is intended to represent the location of hardware
> +configuration data stored in EEPROMs.
> +
> +On a significant proportion of boards, the manufacturer has stored
> +some data on an EEPROM-like device, for the OS to be able to retrieve
> +these information and act upon it. Obviously, the OS has to know
> +about where to retrieve these data from, and where they are stored on
> +the storage device.

Since this binding (and the kernel framework supporting it) describes
non-volatile memory devices other than EEPROMs (e.g. EFuses) it should
be named more generically like "nvmem".

> +
> +This document is here to document this.
> +
> += Data providers =
> +Contains bindings specific to provider drivers and data cells as children
> +to this node.
> +
> += Data cells =
> +These are the child nodes of the provider which contain data cell
> +information like offset and size in eeprom provider.
> +
> +Required properties:
> +reg:	specifies the offset in byte within that storage device, and the length
> +	in bytes of the data we care about.
> +	There could be more then one offset-length pairs in this property.
> +
> +Optional properties:
> +As required by specific data parsers/interpreters.

The generic binding could really use a "read-only" property here as this
is a common hardware attribute for many nvmem devices. A serial EEPROM
commonly has a write protect pin which may be hard-wired such that the
hardware description should reflect that. An EFuse is typically blown with
the required information at manufacturing time (for an end product case)
and would be marked with the "read-only" flag.

Having this optional flag in the generic binding would allow the
framework to hint to consumers about the inability to write to the
provided region.

The framework sysfs attributes provide a userspace EEPROM consumer where
it would be useful information to know that a data provider region is
read only rather than having the exported writeable attribute simply
fail a write cycle. This would allow the consumer to be aware that a
failed write (if even attempted) is expected if the data provider
advertised itself as read-only.

-Matt

> +
> +For example:
> +
> +	/* Provider */
> +	qfprom: qfprom@00700000 {
> +		compatible 	= "qcom,qfprom";
> +		reg		= <0x00700000 0x8000>;
> +		...
> +
> +		/* Data cells */
> +		tsens_calibration: calib@4404 {
> +			reg = <0x4404 0x10>;
> +		};
> +
> +		serial_number: sn {
> +			reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
> +
> +		};
> +		...
> +	};
> +
> += Data consumers =
> +Are device nodes which consume eeprom data cells.
> +
> +For example:
> +
> +	tsens {
> +		...
> +		calibration = <&tsens_calibration>;
> +	};
> -- 
> 1.9.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework
  2015-04-06 13:32           ` Matt Porter
@ 2015-04-06 14:11             ` Rob Herring
  2015-04-06 15:04               ` Matt Porter
  0 siblings, 1 reply; 153+ messages in thread
From: Rob Herring @ 2015-04-06 14:11 UTC (permalink / raw)
  To: Matt Porter
  Cc: Srinivas Kandagatla, linux-arm-kernel, devicetree, Arnd Bergmann,
	Greg Kroah-Hartman, Sascha Hauer, Stephen Boyd, linux-kernel,
	Rob Herring, Mark Brown, Kumar Gala, Maxime Ripard, linux-api,
	linux-arm-msm

On Mon, Apr 6, 2015 at 8:32 AM, Matt Porter <mporter@konsulko.com> wrote:
> On Mon, Mar 30, 2015 at 10:57:59PM +0100, Srinivas Kandagatla wrote:
>> This patch adds bindings for simple eeprom framework which allows eeprom
>> consumers to talk to eeprom providers to get access to eeprom cell data.
>>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> [Maxime Ripard: intial version of eeprom framework]
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> ---
>>  .../devicetree/bindings/eeprom/eeprom.txt          | 58 ++++++++++++++++++++++
>>  1 file changed, 58 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
>>
>> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
>> new file mode 100644
>> index 0000000..fb71d46
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
>> @@ -0,0 +1,58 @@
>> += EEPROM Data Device Tree Bindings =
>> +
>> +This binding is intended to represent the location of hardware
>> +configuration data stored in EEPROMs.
>> +
>> +On a significant proportion of boards, the manufacturer has stored
>> +some data on an EEPROM-like device, for the OS to be able to retrieve
>> +these information and act upon it. Obviously, the OS has to know
>> +about where to retrieve these data from, and where they are stored on
>> +the storage device.
>
> Since this binding (and the kernel framework supporting it) describes
> non-volatile memory devices other than EEPROMs (e.g. EFuses) it should
> be named more generically like "nvmem".
>
>> +
>> +This document is here to document this.
>> +
>> += Data providers =
>> +Contains bindings specific to provider drivers and data cells as children
>> +to this node.
>> +
>> += Data cells =
>> +These are the child nodes of the provider which contain data cell
>> +information like offset and size in eeprom provider.
>> +
>> +Required properties:
>> +reg: specifies the offset in byte within that storage device, and the length
>> +     in bytes of the data we care about.
>> +     There could be more then one offset-length pairs in this property.
>> +
>> +Optional properties:
>> +As required by specific data parsers/interpreters.
>
> The generic binding could really use a "read-only" property here as this
> is a common hardware attribute for many nvmem devices. A serial EEPROM
> commonly has a write protect pin which may be hard-wired such that the
> hardware description should reflect that. An EFuse is typically blown with
> the required information at manufacturing time (for an end product case)
> and would be marked with the "read-only" flag.
>
> Having this optional flag in the generic binding would allow the
> framework to hint to consumers about the inability to write to the
> provided region.

This could get fairly complex if you wanted to describe grouping of WP
regions which could have different layout than the fields here. This
may be better left as a device property listing addr & size pairs.
However, there is the notion of s/w "read-only" which means the OS
should not allow write access. The MTD partition binding supports this
with the "read-only" property.

> The framework sysfs attributes provide a userspace EEPROM consumer where
> it would be useful information to know that a data provider region is
> read only rather than having the exported writeable attribute simply
> fail a write cycle. This would allow the consumer to be aware that a
> failed write (if even attempted) is expected if the data provider
> advertised itself as read-only.

You could distinguish with RW versus RO file attributes.

Rob

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

* Re: [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework
  2015-04-06 14:11             ` Rob Herring
@ 2015-04-06 15:04               ` Matt Porter
  2015-04-07 17:35                 ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Matt Porter @ 2015-04-06 15:04 UTC (permalink / raw)
  To: Rob Herring
  Cc: Srinivas Kandagatla, linux-arm-kernel, devicetree, Arnd Bergmann,
	Greg Kroah-Hartman, Sascha Hauer, Stephen Boyd, linux-kernel,
	Rob Herring, Mark Brown, Kumar Gala, Maxime Ripard, linux-api,
	linux-arm-msm

On Mon, Apr 06, 2015 at 09:11:05AM -0500, Rob Herring wrote:
> On Mon, Apr 6, 2015 at 8:32 AM, Matt Porter <mporter@konsulko.com> wrote:
> > On Mon, Mar 30, 2015 at 10:57:59PM +0100, Srinivas Kandagatla wrote:
> >> This patch adds bindings for simple eeprom framework which allows eeprom
> >> consumers to talk to eeprom providers to get access to eeprom cell data.
> >>
> >> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> >> [Maxime Ripard: intial version of eeprom framework]
> >> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> >> ---
> >>  .../devicetree/bindings/eeprom/eeprom.txt          | 58 ++++++++++++++++++++++
> >>  1 file changed, 58 insertions(+)
> >>  create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
> >>
> >> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> >> new file mode 100644
> >> index 0000000..fb71d46
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> >> @@ -0,0 +1,58 @@
> >> += EEPROM Data Device Tree Bindings =
> >> +
> >> +This binding is intended to represent the location of hardware
> >> +configuration data stored in EEPROMs.
> >> +
> >> +On a significant proportion of boards, the manufacturer has stored
> >> +some data on an EEPROM-like device, for the OS to be able to retrieve
> >> +these information and act upon it. Obviously, the OS has to know
> >> +about where to retrieve these data from, and where they are stored on
> >> +the storage device.
> >
> > Since this binding (and the kernel framework supporting it) describes
> > non-volatile memory devices other than EEPROMs (e.g. EFuses) it should
> > be named more generically like "nvmem".
> >
> >> +
> >> +This document is here to document this.
> >> +
> >> += Data providers =
> >> +Contains bindings specific to provider drivers and data cells as children
> >> +to this node.
> >> +
> >> += Data cells =
> >> +These are the child nodes of the provider which contain data cell
> >> +information like offset and size in eeprom provider.
> >> +
> >> +Required properties:
> >> +reg: specifies the offset in byte within that storage device, and the length
> >> +     in bytes of the data we care about.
> >> +     There could be more then one offset-length pairs in this property.
> >> +
> >> +Optional properties:
> >> +As required by specific data parsers/interpreters.
> >
> > The generic binding could really use a "read-only" property here as this
> > is a common hardware attribute for many nvmem devices. A serial EEPROM
> > commonly has a write protect pin which may be hard-wired such that the
> > hardware description should reflect that. An EFuse is typically blown with
> > the required information at manufacturing time (for an end product case)
> > and would be marked with the "read-only" flag.
> >
> > Having this optional flag in the generic binding would allow the
> > framework to hint to consumers about the inability to write to the
> > provided region.
> 
> This could get fairly complex if you wanted to describe grouping of WP
> regions which could have different layout than the fields here. This
> may be better left as a device property listing addr & size pairs.
> However, there is the notion of s/w "read-only" which means the OS
> should not allow write access. The MTD partition binding supports this
> with the "read-only" property.

Yes, if the backing device has the capability to hw write protect
regions the exported fields overlap those then it does get ugly.
The MTD partition property was the inspiration here so perhaps it's
best to term this as a property indicating how the data region is
used in an implementation.

If it's left as a device property, then a binding with this property
would need to be defined for the Efuse, etc. cases..or a simple-nvmem
binding to handle the various OTP technologies.

> > The framework sysfs attributes provide a userspace EEPROM consumer where
> > it would be useful information to know that a data provider region is
> > read only rather than having the exported writeable attribute simply
> > fail a write cycle. This would allow the consumer to be aware that a
> > failed write (if even attempted) is expected if the data provider
> > advertised itself as read-only.
> 
> You could distinguish with RW versus RO file attributes.

Right, that would be preferred, based on the what the data provider
advertises.

-Matt

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

* Re: [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework
  2015-04-06 15:04               ` Matt Porter
@ 2015-04-07 17:35                 ` Srinivas Kandagatla
  2015-04-07 17:46                   ` Mark Brown
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-04-07 17:35 UTC (permalink / raw)
  To: Matt Porter, Rob Herring
  Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Greg Kroah-Hartman,
	Sascha Hauer, Stephen Boyd, linux-kernel, Rob Herring,
	Mark Brown, Kumar Gala, Maxime Ripard, linux-api, linux-arm-msm

Thanks Matt and Rob for review,

On 06/04/15 16:04, Matt Porter wrote:
> On Mon, Apr 06, 2015 at 09:11:05AM -0500, Rob Herring wrote:
>> On Mon, Apr 6, 2015 at 8:32 AM, Matt Porter <mporter@konsulko.com> wrote:
>>> On Mon, Mar 30, 2015 at 10:57:59PM +0100, Srinivas Kandagatla wrote:
>>>> This patch adds bindings for simple eeprom framework which allows eeprom
>>>> consumers to talk to eeprom providers to get access to eeprom cell data.
>>>>
>>>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>> [Maxime Ripard: intial version of eeprom framework]
>>>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>>>> ---
>>>>   .../devicetree/bindings/eeprom/eeprom.txt          | 58 ++++++++++++++++++++++
>>>>   1 file changed, 58 insertions(+)
>>>>   create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
>>>> new file mode 100644
>>>> index 0000000..fb71d46
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
>>>> @@ -0,0 +1,58 @@
>>>> += EEPROM Data Device Tree Bindings =
>>>> +
>>>> +This binding is intended to represent the location of hardware
>>>> +configuration data stored in EEPROMs.
>>>> +
>>>> +On a significant proportion of boards, the manufacturer has stored
>>>> +some data on an EEPROM-like device, for the OS to be able to retrieve
>>>> +these information and act upon it. Obviously, the OS has to know
>>>> +about where to retrieve these data from, and where they are stored on
>>>> +the storage device.
>>>
>>> Since this binding (and the kernel framework supporting it) describes
>>> non-volatile memory devices other than EEPROMs (e.g. EFuses) it should
>>> be named more generically like "nvmem".
>>>


nvmem sounds sensible name, I will rename framework to nvmem in next 
version.


>>>> +
>>>> +This document is here to document this.
>>>> +
>>>> += Data providers =
>>>> +Contains bindings specific to provider drivers and data cells as children
>>>> +to this node.
>>>> +
>>>> += Data cells =
>>>> +These are the child nodes of the provider which contain data cell
>>>> +information like offset and size in eeprom provider.
>>>> +
>>>> +Required properties:
>>>> +reg: specifies the offset in byte within that storage device, and the length
>>>> +     in bytes of the data we care about.
>>>> +     There could be more then one offset-length pairs in this property.
>>>> +
>>>> +Optional properties:
>>>> +As required by specific data parsers/interpreters.
>>>
>>> The generic binding could really use a "read-only" property here as this
>>> is a common hardware attribute for many nvmem devices. A serial EEPROM
>>> commonly has a write protect pin which may be hard-wired such that the
>>> hardware description should reflect that. An EFuse is typically blown with
>>> the required information at manufacturing time (for an end product case)
>>> and would be marked with the "read-only" flag.
>>>
>>> Having this optional flag in the generic binding would allow the
>>> framework to hint to consumers about the inability to write to the
>>> provided region.
>>
>> This could get fairly complex if you wanted to describe grouping of WP
>> regions which could have different layout than the fields here. This
>> may be better left as a device property listing addr & size pairs.
>> However, there is the notion of s/w "read-only" which means the OS
>> should not allow write access. The MTD partition binding supports this
>> with the "read-only" property.
>
> Yes, if the backing device has the capability to hw write protect
> regions the exported fields overlap those then it does get ugly.
> The MTD partition property was the inspiration here so perhaps it's
> best to term this as a property indicating how the data region is
> used in an implementation.
>
Correct me If am wrong.

Regarding write protection/read-only, regmap already has provisions to 
support this feature. regmap would bail out with errors if any attempt 
to write to non-writable regions. It all depends on the data providers 
how they setup the regmap and the bindings for those are specific 
individual data providers I think.

This would protect the user space side and kernel side consumers as well.

This should address your original query, I guess :-)


Thanks,
srini

> If it's left as a device property, then a binding with this property
> would need to be defined for the Efuse, etc. cases..or a simple-nvmem
> binding to handle the various OTP technologies.
>
>>> The framework sysfs attributes provide a userspace EEPROM consumer where
>>> it would be useful information to know that a data provider region is
>>> read only rather than having the exported writeable attribute simply
>>> fail a write cycle. This would allow the consumer to be aware that a
>>> failed write (if even attempted) is expected if the data provider
>>> advertised itself as read-only.
>>
>> You could distinguish with RW versus RO file attributes.
>
> Right, that would be preferred, based on the what the data provider
> advertises.

>
> -Matt
>

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

* Re: [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework
  2015-04-07 17:35                 ` Srinivas Kandagatla
@ 2015-04-07 17:46                   ` Mark Brown
  2015-04-07 18:03                     ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Mark Brown @ 2015-04-07 17:46 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Matt Porter, Rob Herring, linux-arm-kernel, devicetree,
	Arnd Bergmann, Greg Kroah-Hartman, Sascha Hauer, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard, linux-api,
	linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 918 bytes --]

On Tue, Apr 07, 2015 at 06:35:49PM +0100, Srinivas Kandagatla wrote:
> On 06/04/15 16:04, Matt Porter wrote:
> >On Mon, Apr 06, 2015 at 09:11:05AM -0500, Rob Herring wrote:

> >>>The generic binding could really use a "read-only" property here as this
> >>>is a common hardware attribute for many nvmem devices. A serial EEPROM

> Correct me If am wrong.

> Regarding write protection/read-only, regmap already has provisions to
> support this feature. regmap would bail out with errors if any attempt to
> write to non-writable regions. It all depends on the data providers how they
> setup the regmap and the bindings for those are specific individual data
> providers I think.

There is the ability to flag read/write permissions in regmap but I
think there's some suggestion that this should be exposed to userspace
so that it's easier for it to handle things rather than just writing
then coping with any errors.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework
  2015-04-07 17:46                   ` Mark Brown
@ 2015-04-07 18:03                     ` Srinivas Kandagatla
  2015-04-07 19:46                       ` Matt Porter
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-04-07 18:03 UTC (permalink / raw)
  To: Mark Brown
  Cc: Matt Porter, Rob Herring, linux-arm-kernel, devicetree,
	Arnd Bergmann, Greg Kroah-Hartman, Sascha Hauer, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard, linux-api,
	linux-arm-msm



On 07/04/15 18:46, Mark Brown wrote:
> On Tue, Apr 07, 2015 at 06:35:49PM +0100, Srinivas Kandagatla wrote:
>> On 06/04/15 16:04, Matt Porter wrote:
>>> On Mon, Apr 06, 2015 at 09:11:05AM -0500, Rob Herring wrote:
>
>>>>> The generic binding could really use a "read-only" property here as this
>>>>> is a common hardware attribute for many nvmem devices. A serial EEPROM
>
>> Correct me If am wrong.
>
>> Regarding write protection/read-only, regmap already has provisions to
>> support this feature. regmap would bail out with errors if any attempt to
>> write to non-writable regions. It all depends on the data providers how they
>> setup the regmap and the bindings for those are specific individual data
>> providers I think.
>
> There is the ability to flag read/write permissions in regmap but I
> think there's some suggestion that this should be exposed to userspace
> so that it's easier for it to handle things rather than just writing
> then coping with any errors.

Yes, That's possible if the data provider use the "read-only" generic 
binding like MTD partitions which the eeprom framwork could use to set 
the binary file mode appropriately.

"read-only" property seems to be more generic for all types of data 
providers.

I will give it a try and document this in the bindings too in next version.

--srini
>

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

* Re: [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-03-30 21:57         ` [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
@ 2015-04-07 18:45           ` Stephen Boyd
  2015-04-07 20:09             ` Srinivas Kandagatla
  2015-05-06 17:28           ` Mark Brown
  1 sibling, 1 reply; 153+ messages in thread
From: Stephen Boyd @ 2015-04-07 18:45 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, s.hauer, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, arnd

On 03/30, Srinivas Kandagatla wrote:
> @@ -130,6 +138,37 @@ static struct class eeprom_class = {
>  	.dev_release	= eeprom_release,
>  };
>  
> +static int of_eeprom_match(struct device *dev, const void *eeprom_np)
> +{
> +	return dev->of_node == eeprom_np;
> +}
> +
> +static struct eeprom_device *of_eeprom_find(struct device_node *eeprom_np)
> +{
> +	struct device *d;
> +
> +	if (!eeprom_np)
> +		return NULL;
> +
> +	d = class_find_device(&eeprom_class, NULL, eeprom_np, of_eeprom_match);
> +
> +	return d ? to_eeprom(d) : NULL;
> +}
> +
> +static int eeprom_match(struct device *dev, const void *data)
> +{
> +	return !strcmp(dev_name(dev), (const char *)data);

Is this cast necessary?

> +}
> +
> +static struct eeprom_device *eeprom_find(const char *name)
> +{
> +	struct device *d;
> +
> +	d = class_find_device(&eeprom_class, NULL, (void *)name, eeprom_match);

Is this cast necessary?

> +
> +	return d ? to_eeprom(d) : NULL;
> +}
> +
>  /**
>   * eeprom_register(): Register a eeprom device for given eeprom.
>   * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
> +
> +/**
> + * eeprom_cell_get(): Get eeprom cell of device form a given eeprom name

s/form/from/

> + * and blocks.
> + *
> + * @ename: eeprom device name that needs to be looked-up.
> + * @blocks: eeprom blocks containing offset and length information.
> + * @nblocks: number of eeprom blocks.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *eeprom_cell_get(const char *ename,
> +				    struct eeprom_block *blocks, int nblocks)
> +{
> +	return __eeprom_cell_get(NULL, ename, blocks, nblocks);
> +}
> +EXPORT_SYMBOL_GPL(eeprom_cell_get);
> +
> +/**
> + * of_eeprom_cell_get(): Get eeprom cell of device form a given index

s/form/from/

> + *
> + * @dev node: Device tree node that uses the eeprom cell
> + * @index: eeprom index in eeproms property.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *of_eeprom_cell_get(struct device_node *np, const char *name)
> +{
> +	struct device_node *cell_np;
> +
> +	cell_np = of_parse_phandle(np, name, 0);
> +	if (!cell_np)
> +		return ERR_PTR(-EINVAL);
> +
> +	return __eeprom_cell_get(cell_np, NULL, NULL, 0);
> +}
> +EXPORT_SYMBOL_GPL(of_eeprom_cell_get);
> +
> diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
> new file mode 100644
> index 0000000..effa417
> --- /dev/null
> +++ b/include/linux/eeprom-consumer.h
> @@ -0,0 +1,61 @@
> +/*
> + * EEPROM framework consumer.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_CONSUMER_H
> +#define _LINUX_EEPROM_CONSUMER_H
> +
> +struct eeprom_cell;
> +
> +struct eeprom_block {
> +	loff_t offset;
> +	size_t count;
> +};
> +#if IS_ENABLED(CONFIG_EEPROM)
> +struct eeprom_cell *eeprom_cell_get(const char *ename,
> +				    struct eeprom_block *blocks, int nblocks);
> +void eeprom_cell_put(struct eeprom_cell *cell);
> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
[...]
> +
> +#if IS_ENABLED(CONFIG_EEPROM) && IS_ENABLED(CONFIG_OF)
> +struct eeprom_cell *of_eeprom_cell_get(struct device_node *dev,
> +				       const char *property);
> +#else
> +static inline struct eeprom_cell *of_eeprom_cell_get(struct device_node *np,
> +						     const char *property)
> +{
> +	return ERR_PTR(-ENOSYS);
> +}
> +#endif
> +#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */

Do you have an overview of how to use these APIs? Maybe some
Documentation/ is in order? I'm mostly interested in how the
blocks array is supposed to work and how this hooks up to drivers
that are using DT.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework
  2015-04-07 18:03                     ` Srinivas Kandagatla
@ 2015-04-07 19:46                       ` Matt Porter
  2015-04-08  9:24                         ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Matt Porter @ 2015-04-07 19:46 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Mark Brown, Rob Herring, linux-arm-kernel, devicetree,
	Arnd Bergmann, Greg Kroah-Hartman, Sascha Hauer, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard, linux-api,
	linux-arm-msm

On Tue, Apr 07, 2015 at 07:03:30PM +0100, Srinivas Kandagatla wrote:
> 
> 
> On 07/04/15 18:46, Mark Brown wrote:
> >On Tue, Apr 07, 2015 at 06:35:49PM +0100, Srinivas Kandagatla wrote:
> >>On 06/04/15 16:04, Matt Porter wrote:
> >>>On Mon, Apr 06, 2015 at 09:11:05AM -0500, Rob Herring wrote:
> >
> >>>>>The generic binding could really use a "read-only" property here as this
> >>>>>is a common hardware attribute for many nvmem devices. A serial EEPROM
> >
> >>Correct me If am wrong.
> >
> >>Regarding write protection/read-only, regmap already has provisions to
> >>support this feature. regmap would bail out with errors if any attempt to
> >>write to non-writable regions. It all depends on the data providers how they
> >>setup the regmap and the bindings for those are specific individual data
> >>providers I think.
> >
> >There is the ability to flag read/write permissions in regmap but I
> >think there's some suggestion that this should be exposed to userspace
> >so that it's easier for it to handle things rather than just writing
> >then coping with any errors.
> 
> Yes, That's possible if the data provider use the "read-only" generic
> binding like MTD partitions which the eeprom framwork could use to set the
> binary file mode appropriately.

Right, that's what Rob suggested as to how it should be exposed to
userspace. I think Mark is suggesting that it can also be done by
returning appropriately fine-grained error codes from a writeable
attribute.

Just to clarify here, I brought this up because if we only allow
the writes to fail, there's not necessarily not enough information
available to know if they failed due to a real error (perhaps write
cycles for the underlying nvmem device have been exhausted) or is
it simply that the underlying device has been hardware write protected
(such as as the write protect pin hardwired that way or it's an OTP
device). The client, whether userspace or otherwise is going to need
to know this information to make informed policy decisions.

-Matt

> "read-only" property seems to be more generic for all types of data
> providers.
> 
> I will give it a try and document this in the bindings too in next version.
> 
> --srini
> >

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

* Re: [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-04-07 18:45           ` Stephen Boyd
@ 2015-04-07 20:09             ` Srinivas Kandagatla
  2015-04-09 14:45               ` Stephen Boyd
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-04-07 20:09 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, s.hauer, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, arnd

Thanks Stephen for review,

On 07/04/15 19:45, Stephen Boyd wrote:
> On 03/30, Srinivas Kandagatla wrote:
>> @@ -130,6 +138,37 @@ static struct class eeprom_class = {
>>   	.dev_release	= eeprom_release,
>>   };
>>
>> +static int of_eeprom_match(struct device *dev, const void *eeprom_np)
>> +{
>> +	return dev->of_node == eeprom_np;
>> +}
>> +
>> +static struct eeprom_device *of_eeprom_find(struct device_node *eeprom_np)
>> +{
>> +	struct device *d;
>> +
>> +	if (!eeprom_np)
>> +		return NULL;
>> +
>> +	d = class_find_device(&eeprom_class, NULL, eeprom_np, of_eeprom_match);
>> +
>> +	return d ? to_eeprom(d) : NULL;
>> +}
>> +
>> +static int eeprom_match(struct device *dev, const void *data)
>> +{
>> +	return !strcmp(dev_name(dev), (const char *)data);
>
> Is this cast necessary?
May be an over do here, I will fix it.
>
>> +}
>> +
>> +static struct eeprom_device *eeprom_find(const char *name)
>> +{
>> +	struct device *d;
>> +
>> +	d = class_find_device(&eeprom_class, NULL, (void *)name, eeprom_match);
>
> Is this cast necessary?

I Will fix it in next version.
>
>> +
>> +	return d ? to_eeprom(d) : NULL;
>> +}
>> +
>>   /**
>>    * eeprom_register(): Register a eeprom device for given eeprom.
>>    * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
>> +
>> +/**
>> + * eeprom_cell_get(): Get eeprom cell of device form a given eeprom name
>
> s/form/from/

Will fix this in next version.
>
>> + * and blocks.
>> + *
>> + * @ename: eeprom device name that needs to be looked-up.
>> + * @blocks: eeprom blocks containing offset and length information.
>> + * @nblocks: number of eeprom blocks.
>> + *
>> + * The return value will be an ERR_PTR() on error or a valid pointer
>> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
>> + * eeprom_cell_put().
>> + */
>> +struct eeprom_cell *eeprom_cell_get(const char *ename,
>> +				    struct eeprom_block *blocks, int nblocks)
>> +{
>> +	return __eeprom_cell_get(NULL, ename, blocks, nblocks);
>> +}
>> +EXPORT_SYMBOL_GPL(eeprom_cell_get);
>> +
>> +/**
>> + * of_eeprom_cell_get(): Get eeprom cell of device form a given index
>
> s/form/from/
>
Ok,
>> + *
>> + * @dev node: Device tree node that uses the eeprom cell
>> +
>> +#ifndef _LINUX_EEPROM_CONSUMER_H
>> +#define _LINUX_EEPROM_CONSUMER_H
>> +
>> +struct eeprom_cell;
>> +
>> +struct eeprom_block {
>> +	loff_t offset;
>> +	size_t count;
>> +};
>> +#if IS_ENABLED(CONFIG_EEPROM)
>> +struct eeprom_cell *eeprom_cell_get(const char *ename,
>> +				    struct eeprom_block *blocks, int nblocks);
>> +void eeprom_cell_put(struct eeprom_cell *cell);
>> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
>> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
> [...]
>> +
>> +#if IS_ENABLED(CONFIG_EEPROM) && IS_ENABLED(CONFIG_OF)
>> +struct eeprom_cell *of_eeprom_cell_get(struct device_node *dev,
>> +				       const char *property);
>> +#else
>> +static inline struct eeprom_cell *of_eeprom_cell_get(struct device_node *np,
>> +						     const char *property)
>> +{
>> +	return ERR_PTR(-ENOSYS);
>> +}
>> +#endif
>> +#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */
>
> Do you have an overview of how to use these APIs? Maybe some
> Documentation/ is in order? I'm mostly interested in how the
> blocks array is supposed to work and how this hooks up to drivers
> that are using DT.

Only doc ATM is function level kernel doc in c file.
May be I can explain you for now and I will try to add some 
documentation with some usage examples in next version.

eeprom block array is just another way intended to get hold of eeprom 
content for non-DT providers/consumers, but DT consumers/providers can 
also use it. As of today SOC/mach level code could use it as well.

In eeprom_cell_get() case the lookup of provider is done based on 
provider name, this provider name is generally supplied by all the 
providers (both DT/non DT).

for example in qfprom case,
provider is registered from DT with eeprom config containing a unique name:
static struct eeprom_config econfig = {
	.name = "qfprom",
	.id = 0,
};

In the consumer case, the tsens driver could do some like in non DT way:

	struct eeprom_block blocks[4] ={
		{
		.offset = 0x404,
		.count = 0x4,
		},
		{
		.offset = 0x408,
		.count = 0x4,
		},
		{
		.offset = 0x40c,
		.count = 0x4,
		},
		{
		.offset = 0x410,
		.count = 0x4,
		},
	};
	calib_cell = eeprom_cell_get("qfprom0", blocks, 4);


Or in DT way
calib_cell  = of_eeprom_cell_get(np, "calib");


--srini
>

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

* Re: [PATCH v4 05/10] eeprom: Add bindings for simple eeprom framework
  2015-04-07 19:46                       ` Matt Porter
@ 2015-04-08  9:24                         ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-04-08  9:24 UTC (permalink / raw)
  To: Matt Porter
  Cc: Mark Brown, Rob Herring, linux-arm-kernel, devicetree,
	Arnd Bergmann, Greg Kroah-Hartman, Sascha Hauer, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard, linux-api,
	linux-arm-msm



On 07/04/15 20:46, Matt Porter wrote:
> On Tue, Apr 07, 2015 at 07:03:30PM +0100, Srinivas Kandagatla wrote:
>>
>>
>> On 07/04/15 18:46, Mark Brown wrote:
>>> On Tue, Apr 07, 2015 at 06:35:49PM +0100, Srinivas Kandagatla wrote:
>>>> On 06/04/15 16:04, Matt Porter wrote:
>>>>> On Mon, Apr 06, 2015 at 09:11:05AM -0500, Rob Herring wrote:
>>>
>>>>>>> The generic binding could really use a "read-only" property here as this
>>>>>>> is a common hardware attribute for many nvmem devices. A serial EEPROM
>>>
>>>> Correct me If am wrong.
>>>
>>>> Regarding write protection/read-only, regmap already has provisions to
>>>> support this feature. regmap would bail out with errors if any attempt to
>>>> write to non-writable regions. It all depends on the data providers how they
>>>> setup the regmap and the bindings for those are specific individual data
>>>> providers I think.
>>>
>>> There is the ability to flag read/write permissions in regmap but I
>>> think there's some suggestion that this should be exposed to userspace
>>> so that it's easier for it to handle things rather than just writing
>>> then coping with any errors.
>>
>> Yes, That's possible if the data provider use the "read-only" generic
>> binding like MTD partitions which the eeprom framwork could use to set the
>> binary file mode appropriately.
>
> Right, that's what Rob suggested as to how it should be exposed to
> userspace. I think Mark is suggesting that it can also be done by
> returning appropriately fine-grained error codes from a writeable
> attribute.
>


We are taking about two things here.

1: "Setting the correct mode for the user space binary file."
	This is only possible if the entire eeprom/nvmem has write protection. 
We could get that info from 2 places. One having a new DT property 
bindings like "read-only" as Rob suggested.
	or
	Second, scan the regmap for writeable attributes and the correct file 
mode. For this option AFAIK, with existing regmap code we can only do 
this by scanning the entire range, which is bad I guess.

2: "Returning appropriate error codes to user space."
	This is already addressed in the existing code, regmap would return an 
(-EIO) I/O error Or error codes from providers in cases where an write 
attempt to non writable register/or something wrong is made and the 
*same error* code is passed back to user too. All the error codes from 
regmap/provider layer are always passed back to the user space. These 
error code, I supposed are fine grained originating from the low layer.


I think with "read-only" property and returning same error codes from 
regmap/provider layer to user-space would address the points raised by Matt.


> Just to clarify here, I brought this up because if we only allow
> the writes to fail, there's not necessarily not enough information
> available to know if they failed due to a real error (perhaps write
> cycles for the underlying nvmem device have been exhausted) or is
> it simply that the underlying device has been hardware write protected
> (such as as the write protect pin hardwired that way or it's an OTP
> device). The client, whether userspace or otherwise is going to need
> to know this information to make informed policy decisions.
>


Thanks for the inputs.


The exiting regmap writeable_register api will only return true or 
false. But if the provider implements its own read/writes functions, the 
error-codes from these apis would be passed back to user anyway, so the 
user can make informed policy decisions. This logic already present in 
with the exiting eeprom/regmap code.



--srini
> -Matt
>
>> "read-only" property seems to be more generic for all types of data
>> providers.
>>
>> I will give it a try and document this in the bindings too in next version.
>>
>> --srini
>>>

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

* Re: [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-04-07 20:09             ` Srinivas Kandagatla
@ 2015-04-09 14:45               ` Stephen Boyd
  2015-04-10 11:45                 ` Maxime Ripard
  2015-05-05 11:46                 ` Srinivas Kandagatla
  0 siblings, 2 replies; 153+ messages in thread
From: Stephen Boyd @ 2015-04-09 14:45 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, s.hauer, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, arnd

On 04/07, Srinivas Kandagatla wrote:
> On 07/04/15 19:45, Stephen Boyd wrote:
> >On 03/30, Srinivas Kandagatla wrote:
> >
> >Do you have an overview of how to use these APIs? Maybe some
> >Documentation/ is in order? I'm mostly interested in how the
> >blocks array is supposed to work and how this hooks up to drivers
> >that are using DT.
> 
> Only doc ATM is function level kernel doc in c file.
> May be I can explain you for now and I will try to add some
> documentation with some usage examples in next version.

Thanks.

> 
> eeprom block array is just another way intended to get hold of
> eeprom content for non-DT providers/consumers, but DT
> consumers/providers can also use it. As of today SOC/mach level code
> could use it as well.
> 
> In eeprom_cell_get() case the lookup of provider is done based on
> provider name, this provider name is generally supplied by all the
> providers (both DT/non DT).
> 
> for example in qfprom case,
> provider is registered from DT with eeprom config containing a unique name:
> static struct eeprom_config econfig = {
> 	.name = "qfprom",
> 	.id = 0,
> };
> 
> In the consumer case, the tsens driver could do some like in non DT way:
> 
> 	struct eeprom_block blocks[4] ={
> 		{
> 		.offset = 0x404,
> 		.count = 0x4,
> 		},
> 		{
> 		.offset = 0x408,
> 		.count = 0x4,
> 		},
> 		{
> 		.offset = 0x40c,
> 		.count = 0x4,
> 		},
> 		{
> 		.offset = 0x410,
> 		.count = 0x4,
> 		},
> 	};
> 	calib_cell = eeprom_cell_get("qfprom0", blocks, 4);
> 
> 
> Or in DT way
> calib_cell  = of_eeprom_cell_get(np, "calib");
> 

Ok. I guess I was hoping for a more device centric approach like
we have for clks/regulators/etc. That way a driver doesn't need
to know it's using DT or not to figure out which API to call.
Also the global namespace is sort of worrying (qfprom0 part). How
do we know it's qfprom0? What if it's qfprom1 sometimes?

Also, how are we supposed to encode certain bits inside the
stream of bytes (blocks)? In some situations (e.g. the qcom CPR
stuff) we have quite a few fuse bits we need to read that are
packed into different bytes and may cross byte boundaries (i.e.
bits 6 to 10 of a 32-bit word). The current API looks to be byte
focused when I have bit based/non-byte aligned data.

My current feeling is that I don't want to use any of the block
stuff at all. I just want a simple byte-based API that allows me
to read a number of contiguous bytes from the fuses. Then I'll
need to shift that data down by a few bits and mask it with the
width of the data I want to read to extract the data needed.

The only thing after that where I have a problem is figuring out
which eeprom is present in the consumer driver. I think I may
need to open-code it and look at the phandle for the eeprom and
do a compatible check to figure out which bits I want to read.

The DT would be like this (note I left eeprom-cells/eeproms here
because that allows us to generically find eeproms used by a
device and find eeprom providers):

	qfprom: eeprom@58000 {
		compatible = "qcom,qfprom-msm8916";
		reg = <0x58000 0x7000>;
		#eeprom-cells = <0>;
	};
	
	cpr@b018000 {
		compatible = "qcom,cpr";
		reg = <0xb018000 0x1000>;
		interrupts = <0 15 1>, <0 16 1>, <0 17 1>;
		eeproms = <&qfprom>;
		...
	};

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-04-09 14:45               ` Stephen Boyd
@ 2015-04-10 11:45                 ` Maxime Ripard
  2015-05-05 11:46                 ` Srinivas Kandagatla
  1 sibling, 0 replies; 153+ messages in thread
From: Maxime Ripard @ 2015-04-10 11:45 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Srinivas Kandagatla, linux-arm-kernel, Rob Herring, Kumar Gala,
	Mark Brown, s.hauer, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, arnd

[-- Attachment #1: Type: text/plain, Size: 3373 bytes --]

Hi Stephen,

On Thu, Apr 09, 2015 at 07:45:22AM -0700, Stephen Boyd wrote:
> > eeprom block array is just another way intended to get hold of
> > eeprom content for non-DT providers/consumers, but DT
> > consumers/providers can also use it. As of today SOC/mach level code
> > could use it as well.
> > 
> > In eeprom_cell_get() case the lookup of provider is done based on
> > provider name, this provider name is generally supplied by all the
> > providers (both DT/non DT).
> > 
> > for example in qfprom case,
> > provider is registered from DT with eeprom config containing a unique name:
> > static struct eeprom_config econfig = {
> > 	.name = "qfprom",
> > 	.id = 0,
> > };
> > 
> > In the consumer case, the tsens driver could do some like in non DT way:
> > 
> > 	struct eeprom_block blocks[4] ={
> > 		{
> > 		.offset = 0x404,
> > 		.count = 0x4,
> > 		},
> > 		{
> > 		.offset = 0x408,
> > 		.count = 0x4,
> > 		},
> > 		{
> > 		.offset = 0x40c,
> > 		.count = 0x4,
> > 		},
> > 		{
> > 		.offset = 0x410,
> > 		.count = 0x4,
> > 		},
> > 	};
> > 	calib_cell = eeprom_cell_get("qfprom0", blocks, 4);
> > 
> > 
> > Or in DT way
> > calib_cell  = of_eeprom_cell_get(np, "calib");
> > 
> 
> Ok. I guess I was hoping for a more device centric approach like
> we have for clks/regulators/etc. That way a driver doesn't need
> to know it's using DT or not to figure out which API to call.
> Also the global namespace is sort of worrying (qfprom0 part). How
> do we know it's qfprom0? What if it's qfprom1 sometimes?

Through platform_data?

Or maybe that could be done using a function that would attach a cell
to a struct device?

I'm not sure that would cover all cases though.

> Also, how are we supposed to encode certain bits inside the
> stream of bytes (blocks)? In some situations (e.g. the qcom CPR
> stuff) we have quite a few fuse bits we need to read that are
> packed into different bytes and may cross byte boundaries (i.e.
> bits 6 to 10 of a 32-bit word). The current API looks to be byte
> focused when I have bit based/non-byte aligned data.
> 
> My current feeling is that I don't want to use any of the block
> stuff at all. I just want a simple byte-based API that allows me
> to read a number of contiguous bytes from the fuses. Then I'll
> need to shift that data down by a few bits and mask it with the
> width of the data I want to read to extract the data needed.

Except that this is highly dependent on the usage you're making of
this API.

It could be fine to expect that if your writing machine code, that for
one given SoC will always be true.

If you're writing driver code, that will just have to lookup one value
from an EEPROM, the exact offset, size and device being completely
board dependant, it's not really practical.

> The only thing after that where I have a problem is figuring out
> which eeprom is present in the consumer driver.

Is that really necessary? I mean, the point of having an abstraction
layer is precisely to *not* care about the provider when you are the
consumer.

If we can't, then the abstraction layer is not good enough and we
should improve it, but we shouldn't need to hack around it.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v4 01/10] regmap: Introduce regmap_get_max_register.
  2015-03-30 21:56         ` [PATCH v4 01/10] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
@ 2015-05-04 12:05           ` Mark Brown
  0 siblings, 0 replies; 153+ messages in thread
From: Mark Brown @ 2015-05-04 12:05 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	s.hauer, Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd

[-- Attachment #1: Type: text/plain, Size: 275 bytes --]

On Mon, Mar 30, 2015 at 10:56:27PM +0100, Srinivas Kandagatla wrote:

> +int regmap_get_max_register(struct regmap *map)
> +{
> +	return map->max_register ? : -EINVAL;
> +}

Please don't abuse the ternery operator like this, write a proper if
statement that people can read.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-04-09 14:45               ` Stephen Boyd
  2015-04-10 11:45                 ` Maxime Ripard
@ 2015-05-05 11:46                 ` Srinivas Kandagatla
  2015-05-08  5:23                   ` Sascha Hauer
  1 sibling, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-05 11:46 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, s.hauer, Greg Kroah-Hartman, linux-api, linux-kernel,
	devicetree, linux-arm-msm, arnd

Hi Stephen,

Sorry I took so long to reply.


On 09/04/15 15:45, Stephen Boyd wrote:
> On 04/07, Srinivas Kandagatla wrote:
>> On 07/04/15 19:45, Stephen Boyd wrote:
>>> On 03/30, Srinivas Kandagatla wrote:
>>>
>>> Do you have an overview of how to use these APIs? Maybe some
>>> Documentation/ is in order? I'm mostly interested in how the
>>> blocks array is supposed to work and how this hooks up to drivers
>>> that are using DT.
>>
>> Only doc ATM is function level kernel doc in c file.
>> May be I can explain you for now and I will try to add some
>> documentation with some usage examples in next version.
>
> Thanks.
>
>>
>> eeprom block array is just another way intended to get hold of
>> eeprom content for non-DT providers/consumers, but DT
>> consumers/providers can also use it. As of today SOC/mach level code
>> could use it as well.
>>
>> In eeprom_cell_get() case the lookup of provider is done based on
>> provider name, this provider name is generally supplied by all the
>> providers (both DT/non DT).
>>
>> for example in qfprom case,
>> provider is registered from DT with eeprom config containing a unique name:
>> static struct eeprom_config econfig = {
>> 	.name = "qfprom",
>> 	.id = 0,
>> };
>>
>> In the consumer case, the tsens driver could do some like in non DT way:
>>
>> 	struct eeprom_block blocks[4] ={
>> 		{
>> 		.offset = 0x404,
>> 		.count = 0x4,
>> 		},
>> 		{
>> 		.offset = 0x408,
>> 		.count = 0x4,
>> 		},
>> 		{
>> 		.offset = 0x40c,
>> 		.count = 0x4,
>> 		},
>> 		{
>> 		.offset = 0x410,
>> 		.count = 0x4,
>> 		},
>> 	};
>> 	calib_cell = eeprom_cell_get("qfprom0", blocks, 4);
>>
>>
>> Or in DT way
>> calib_cell  = of_eeprom_cell_get(np, "calib");
>>
>
> Ok. I guess I was hoping for a more device centric approach like
> we have for clks/regulators/etc. That way a driver doesn't need
> to know it's using DT or not to figure out which API to call.

That would be the best. Its easy to wrap up whats in eeprom core to
eeprom_get_cell(dev, "cell-name") for both DT and non-dt cases, if I
remove the nasty global name space thing.

Only thing which is limiting it is the existing bindings which are just 
phandle based. For eeprom to be more of device centric we need more
generic bindings/property names like

nvrom-cell = <&abc>, <&edf>
nvrom-cell-names = "cell1", "cell2";

Also we can have name associated to each eeprom cell which would help 
for non-dt cases. So they can just lookup by the cell name.


Sacha, Are you ok with such binding?  As this can provide a single 
interface for dt and non-dt. I remember you requested for changing from 
generic properties to specific property names.


> Also the global namespace is sort of worrying (qfprom0 part). How
> do we know it's qfprom0? What if it's qfprom1 sometimes?

I agree this is something which I don't like it in the first place too.
If we have something like names associated to each eeprom cell like clks
or regulators we can have some thing like eeprom_get_cell(dev, name);

>
> Also, how are we supposed to encode certain bits inside the
> stream of bytes (blocks)? In some situations (e.g. the qcom CPR
> stuff) we have quite a few fuse bits we need to read that are
> packed into different bytes and may cross byte boundaries (i.e.
> bits 6 to 10 of a 32-bit word). The current API looks to be byte
> focused when I have bit based/non-byte aligned data.
Yes, it is more of byte oriented. However we can add some new apis for
parsers like ones you are working on.

of_eeprom_get_provider_regmap(phandle) just to get handle to regmap from 
eeprom_core, which would provide most of the apis you would need.
Am guessing eeprom parsers would need need such interface to eeprom-core 
in future anyway.

>
> My current feeling is that I don't want to use any of the block
> stuff at all. I just want a simple byte-based API that allows me
> to read a number of contiguous bytes from the fuses. Then I'll
> need to shift that data down by a few bits and mask it with the
> width of the data I want to read to extract the data needed.
>
> The only thing after that where I have a problem is figuring out
> which eeprom is present in the consumer driver. I think I may
> need to open-code it and look at the phandle for the eeprom and
> do a compatible check to figure out which bits I want to read.
>
> The DT would be like this (note I left eeprom-cells/eeproms here
> because that allows us to generically find eeproms used by a
> device and find eeprom providers):

I though, having "eeprom-cells" would be make sense only if the bindings 
have possible arguments to a phandle. In this case it would be none all 
the time.

For provider lookups currently its generic/easy and fast as its done 
based on eeprom class. Am not sure what advantage would we get
Am I missing anything ?

If you are ok I will prepare a v5 with the proposed changes.


--srini
>
> 	qfprom: eeprom@58000 {
> 		compatible = "qcom,qfprom-msm8916";
> 		reg = <0x58000 0x7000>;
> 		#eeprom-cells = <0>;
> 	};
> 	
> 	cpr@b018000 {
> 		compatible = "qcom,cpr";
> 		reg = <0xb018000 0x1000>;
> 		interrupts = <0 15 1>, <0 16 1>, <0 17 1>;
> 		eeproms = <&qfprom>;
> 		...
> 	};
>

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

* Re: [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-03-30 21:57         ` [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers Srinivas Kandagatla
  2015-04-07 18:45           ` Stephen Boyd
@ 2015-05-06 17:28           ` Mark Brown
  1 sibling, 0 replies; 153+ messages in thread
From: Mark Brown @ 2015-05-06 17:28 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	s.hauer, Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd

[-- Attachment #1: Type: text/plain, Size: 459 bytes --]

On Mon, Mar 30, 2015 at 10:57:50PM +0100, Srinivas Kandagatla wrote:

> +
> +	for (i = 0; i < cell->nblocks; i++) {
> +		rc = regmap_raw_read(eeprom->regmap, cell->blocks[i].offset,
> +				      buf + offset, cell->blocks[i].count);

I *think* this is probably OK but please double check that the count
here is in bytes rather than words, it's a bit confusing since I'd read
a count as being in words.  Otherwise I think the regmap usage here all
looks good.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v4 04/10] eeprom: Add a simple EEPROM framework for eeprom consumers
  2015-05-05 11:46                 ` Srinivas Kandagatla
@ 2015-05-08  5:23                   ` Sascha Hauer
  0 siblings, 0 replies; 153+ messages in thread
From: Sascha Hauer @ 2015-05-08  5:23 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Stephen Boyd, linux-arm-kernel, Maxime Ripard, Rob Herring,
	Kumar Gala, Mark Brown, Greg Kroah-Hartman, linux-api,
	linux-kernel, devicetree, linux-arm-msm, arnd

On Tue, May 05, 2015 at 12:46:32PM +0100, Srinivas Kandagatla wrote:
> Hi Stephen,
> 
> Sorry I took so long to reply.
> 
> 
> On 09/04/15 15:45, Stephen Boyd wrote:
> >On 04/07, Srinivas Kandagatla wrote:
> >>On 07/04/15 19:45, Stephen Boyd wrote:
> >>>On 03/30, Srinivas Kandagatla wrote:
> >>>
> >>>Do you have an overview of how to use these APIs? Maybe some
> >>>Documentation/ is in order? I'm mostly interested in how the
> >>>blocks array is supposed to work and how this hooks up to drivers
> >>>that are using DT.
> >>
> >>Only doc ATM is function level kernel doc in c file.
> >>May be I can explain you for now and I will try to add some
> >>documentation with some usage examples in next version.
> >
> >Thanks.
> >
> >>
> >>eeprom block array is just another way intended to get hold of
> >>eeprom content for non-DT providers/consumers, but DT
> >>consumers/providers can also use it. As of today SOC/mach level code
> >>could use it as well.
> >>
> >>In eeprom_cell_get() case the lookup of provider is done based on
> >>provider name, this provider name is generally supplied by all the
> >>providers (both DT/non DT).
> >>
> >>for example in qfprom case,
> >>provider is registered from DT with eeprom config containing a unique name:
> >>static struct eeprom_config econfig = {
> >>	.name = "qfprom",
> >>	.id = 0,
> >>};
> >>
> >>In the consumer case, the tsens driver could do some like in non DT way:
> >>
> >>	struct eeprom_block blocks[4] ={
> >>		{
> >>		.offset = 0x404,
> >>		.count = 0x4,
> >>		},
> >>		{
> >>		.offset = 0x408,
> >>		.count = 0x4,
> >>		},
> >>		{
> >>		.offset = 0x40c,
> >>		.count = 0x4,
> >>		},
> >>		{
> >>		.offset = 0x410,
> >>		.count = 0x4,
> >>		},
> >>	};
> >>	calib_cell = eeprom_cell_get("qfprom0", blocks, 4);
> >>
> >>
> >>Or in DT way
> >>calib_cell  = of_eeprom_cell_get(np, "calib");
> >>
> >
> >Ok. I guess I was hoping for a more device centric approach like
> >we have for clks/regulators/etc. That way a driver doesn't need
> >to know it's using DT or not to figure out which API to call.
> 
> That would be the best. Its easy to wrap up whats in eeprom core to
> eeprom_get_cell(dev, "cell-name") for both DT and non-dt cases, if I
> remove the nasty global name space thing.
> 
> Only thing which is limiting it is the existing bindings which are
> just phandle based. For eeprom to be more of device centric we need
> more
> generic bindings/property names like
> 
> nvrom-cell = <&abc>, <&edf>
> nvrom-cell-names = "cell1", "cell2";
> 
> Also we can have name associated to each eeprom cell which would
> help for non-dt cases. So they can just lookup by the cell name.
> 
> 
> Sacha, Are you ok with such binding?  As this can provide a single
> interface for dt and non-dt. I remember you requested for changing
> from generic properties to specific property names.

Yes, I am fine with such a binding. The same type of binding is used for
clocks and other stuff already, so it has proven good and people are
famliar with it.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH v5 00/11] Add simple NVMEM Framework via regmap.
  2015-03-30 21:54       ` [PATCH v4 00/10] Add simple EEPROM Framework via regmap Srinivas Kandagatla
                           ` (9 preceding siblings ...)
  2015-03-30 21:58         ` [PATCH v4 10/10] eeprom: Add to MAINTAINERS for " Srinivas Kandagatla
@ 2015-05-21 16:42         ` Srinivas Kandagatla
  2015-05-21 16:42           ` [PATCH v5 01/11] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
                             ` (12 more replies)
  10 siblings, 13 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:42 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

Thankyou all for providing inputs and comments on previous versions of this patchset.
Here is the v5 of the patchset addressing all the issues raised as
part of previous versions review.

This patchset adds a new simple NVMEM framework to kernel.

Up until now, NVMEM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.
    
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
    
Introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs.
    
After learning few things about QCOM qfprom and other eeprom/efuses, which
has packed fields at bit level. Which makes it important to add support to
such memories. This version adds support to this type of non volatile
memories by adding support to bit level nvmem-cells.

Having regmap interface to this framework would give much better
abstraction for nvmems on different buses.

patch 1-2 Introduces two regmap helper functions.
patch 3-6 Introduces the NVMEM framework.
Patch 7 Adds helper functions for nvmems based on mmio.
Patch 8 migrates an existing driver to nvmem framework.
Patch 9-10 Adds Qualcomm specific qfprom driver.
Patch 11 adds entry in MAINTAINERS.

Its also possible to migrate other nvmem drivers to this framework.

Providers APIs:
	nvmem_register/unregister();

Consumers APIs:
Cell based apis for both DT/Non-DT:
	nvmem_cell_get()/nvmem_cell_put();
	nvmem_cell_read()/nvmem_cell_write();

Raw byte access apis for both DT/non-DT.
	nvmem_device_get()/nvmem_device_put()
	nvmem_device_read()/nvmem_device_write();
	nvmem_device_cell_read()/nvmem_device_cell_write();

Device Tree:

	/* Provider */
	qfprom: qfprom@00700000 {
		...

		/* Data cells */
		tsens_calibration: calib@404 {
			reg = <0x404 0x10>;
		};

		tsens_calibration_bckp: calib_bckp@504 {
			reg = <0x504 0x11>;
			bit-offset = 6;
			nbits = 128;
		};

		pvs_version: pvs-version@6 {
			reg = <0x6 0x2>
			bit-offset = 7;
			nbits = 2;
		};

		speed_bin: speed-bin@c{
			reg = <0xc 0x1>;
			bit-offset = 2;
			nbits	= 3;

		};
		...
	};

userspace interface: binary file in /sys/class/nvmem/*/nvmem

ex:
hexdump /sys/class/nvmem/qfprom0/nvmem
                                                                                                                                                                                                                  
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
0000000 0000 0000 0000 0000 0000 0000 0000 0000
...
*
0001000

Changes since v4(https://lkml.org/lkml/2015/3/30/725)
 * rename eeprom to nvmem suggested by Matt Porter
 * added bit level support to nvmem cells, if not framework is
 	not usable for qcom platforms.
 * removed ternary operator shortcut suggested by Mark B.
 * unified consumer/provider apis for both DT and non-DT.
 * added name support for cell.
 * added bit level bindings.
 * added read-only support suggested by Matt Porter and others.
 * added new nvmem_device based consumer apis.

Changes since v3(https://lkml.org/lkml/2015/3/24/1066)
 * simplified logic in bin_attr_eeprom_read/write spotted by Mark Brown.
 * moved from using regmap_bulk_read/write to regmap_raw_read/write
 spotted by Mark Brown
 * Fixed return error codes for the dummy wrappers spotted by Sascha Hauer
 * Fixed various error code checks in core spotted by Sascha Hauer.
 * Simplified consumer bindings suggested by Sascha Hauer.
 * Added eeprom-mmio helper functions.

Changes since v2(https://lkml.org/lkml/2015/3/13/168)
 * Fixed error handling in eeprom_register spotted by Mark Brown
 * Added new regmap_get_max_register() and regmap_get_reg_stride().
 * Fixed module build errors reported by kbuild robot.
 * recycle the ids when eeprom provider is released.

Changes since v1(https://lkml.org/lkml/2015/3/5/153)
 * Fix various Licencing issues spotted by Paul Bolle and Mark Brown
 * Allow eeprom core to build as module spotted by Paul Bolle.
 * Fix various kconfig issues spotted by Paul Bolle.
 * remove unessary atomic varible spotted by Mark Brown.
 * Few cleanups and common up some of the code in core.
 * Add qfprom bindings.

Changes since RFC(https://lkml.org/lkml/2015/2/19/307)
 * Fix documentation and error checks in read/write spotted by Andrew Lunn
 * Kconfig fix suggested by Stephen Boyd.
 * Add module owner suggested by Stephen Boyd and others.
 * Fix unsafe handling of eeprom in unregister spotted by Russell and Mark Brown.
 * seperate bindings patch as suggested by Rob.
 * Add MAINTAINERS as suggested by Rob.
 * Added support to allow reading eeprom for things like serial number which
 * canbe scatters across.
 * Added eeprom data using reg property suggested by Sascha and Stephen.
 * Added non-DT support.
 * Move kerneldoc to the src files spotted by Mark Brown.
 * Remove local list and do eeprom lookup by using class_find_device()


Thanks,
srini


Maxime Ripard (1):
  nvmem: sunxi: Move the SID driver to the nvmem framework

Srinivas Kandagatla (10):
  regmap: Introduce regmap_get_max_register.
  regmap: Introduce regmap_get_reg_stride.
  nvmem: Add a simple NVMEM framework for nvmem providers
  nvmem: Add a simple NVMEM framework for consumers
  nvmem: Add nvmem_device based consumer apis.
  nvmem: Add bindings for simple nvmem framework
  nvmem: Add simple nvmem-mmio consumer helper functions.
  nvmem: qfprom: Add Qualcomm QFPROM support.
  nvmem: qfprom: Add bindings for qfprom
  nvmem: Add to MAINTAINERS for nvmem framework

 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 -
 .../bindings/misc/allwinner,sunxi-sid.txt          |  17 -
 .../bindings/nvmem/allwinner,sunxi-sid.txt         |  21 +
 Documentation/devicetree/bindings/nvmem/nvmem.txt  |  84 ++
 Documentation/devicetree/bindings/nvmem/qfprom.txt |  35 +
 MAINTAINERS                                        |   9 +
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/base/regmap/regmap.c                       |  24 +
 drivers/misc/eeprom/Kconfig                        |  13 -
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 ----
 drivers/nvmem/Kconfig                              |  36 +
 drivers/nvmem/Makefile                             |  13 +
 drivers/nvmem/core.c                               | 864 +++++++++++++++++++++
 drivers/nvmem/nvmem-mmio.c                         |  69 ++
 drivers/nvmem/nvmem-mmio.h                         |  41 +
 drivers/nvmem/qfprom.c                             |  51 ++
 drivers/nvmem/sunxi-sid.c                          |  64 ++
 include/linux/nvmem-consumer.h                     | 106 +++
 include/linux/nvmem-provider.h                     |  47 ++
 include/linux/regmap.h                             |  14 +
 22 files changed, 1481 insertions(+), 209 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
 create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem.txt
 create mode 100644 Documentation/devicetree/bindings/nvmem/qfprom.txt
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
 create mode 100644 drivers/nvmem/Kconfig
 create mode 100644 drivers/nvmem/Makefile
 create mode 100644 drivers/nvmem/core.c
 create mode 100644 drivers/nvmem/nvmem-mmio.c
 create mode 100644 drivers/nvmem/nvmem-mmio.h
 create mode 100644 drivers/nvmem/qfprom.c
 create mode 100644 drivers/nvmem/sunxi-sid.c
 create mode 100644 include/linux/nvmem-consumer.h
 create mode 100644 include/linux/nvmem-provider.h

-- 
1.9.1


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

* [PATCH v5 01/11] regmap: Introduce regmap_get_max_register.
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
@ 2015-05-21 16:42           ` Srinivas Kandagatla
  2015-05-22 11:18             ` Mark Brown
  2015-05-21 16:42           ` [PATCH v5 02/11] regmap: Introduce regmap_get_reg_stride Srinivas Kandagatla
                             ` (11 subsequent siblings)
  12 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:42 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

This patch introduces regmap_get_max_register() function which would be
used by the infrastructures like nvmem framework built on top of
regmap.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/base/regmap/regmap.c | 12 ++++++++++++
 include/linux/regmap.h       |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6273ff0..d6c8404 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2613,6 +2613,18 @@ int regmap_get_val_bytes(struct regmap *map)
 }
 EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
 
+/**
+ * regmap_get_max_register(): Report the max register value
+ *
+ * Report the max register value, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_max_register(struct regmap *map)
+{
+	return map->max_register ? map->max_register : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regmap_get_max_register);
+
 int regmap_parse_val(struct regmap *map, const void *buf,
 			unsigned int *val)
 {
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 116655d..2d87ded 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -433,6 +433,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
 				   unsigned int mask, unsigned int val,
 				   bool *change);
 int regmap_get_val_bytes(struct regmap *map);
+int regmap_get_max_register(struct regmap *map);
 int regmap_async_complete(struct regmap *map);
 bool regmap_can_raw_write(struct regmap *map);
 
@@ -676,6 +677,12 @@ static inline int regmap_get_val_bytes(struct regmap *map)
 	return -EINVAL;
 }
 
+static inline int regmap_get_max_register(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline int regcache_sync(struct regmap *map)
 {
 	WARN_ONCE(1, "regmap API is disabled");
-- 
1.9.1


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

* [PATCH v5 02/11] regmap: Introduce regmap_get_reg_stride.
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
  2015-05-21 16:42           ` [PATCH v5 01/11] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
@ 2015-05-21 16:42           ` Srinivas Kandagatla
  2015-05-22 11:19             ` Mark Brown
  2015-05-21 16:43           ` [PATCH v5 03/11] nvmem: Add a simple NVMEM framework for nvmem providers Srinivas Kandagatla
                             ` (10 subsequent siblings)
  12 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:42 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

This patch introduces regmap_get_reg_stride() function which would
be used by the infrastructures like nvmem framework built on top of
regmap. Mostly this function would be used for sanity checks on inputs
within such infrastructure.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/base/regmap/regmap.c | 12 ++++++++++++
 include/linux/regmap.h       |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index d6c8404..e5eef6f 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2625,6 +2625,18 @@ int regmap_get_max_register(struct regmap *map)
 }
 EXPORT_SYMBOL_GPL(regmap_get_max_register);
 
+/**
+ * regmap_get_reg_stride(): Report the register address stride
+ *
+ * Report the register address stride, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_reg_stride(struct regmap *map)
+{
+	return map->reg_stride;
+}
+EXPORT_SYMBOL_GPL(regmap_get_reg_stride);
+
 int regmap_parse_val(struct regmap *map, const void *buf,
 			unsigned int *val)
 {
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 2d87ded..59c55ea 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -434,6 +434,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
 				   bool *change);
 int regmap_get_val_bytes(struct regmap *map);
 int regmap_get_max_register(struct regmap *map);
+int regmap_get_reg_stride(struct regmap *map);
 int regmap_async_complete(struct regmap *map);
 bool regmap_can_raw_write(struct regmap *map);
 
@@ -683,6 +684,12 @@ static inline int regmap_get_max_register(struct regmap *map)
 	return -EINVAL;
 }
 
+static inline int regmap_get_reg_stride(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline int regcache_sync(struct regmap *map)
 {
 	WARN_ONCE(1, "regmap API is disabled");
-- 
1.9.1


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

* [PATCH v5 03/11] nvmem: Add a simple NVMEM framework for nvmem providers
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
  2015-05-21 16:42           ` [PATCH v5 01/11] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
  2015-05-21 16:42           ` [PATCH v5 02/11] regmap: Introduce regmap_get_reg_stride Srinivas Kandagatla
@ 2015-05-21 16:43           ` Srinivas Kandagatla
  2015-06-16 22:43             ` Stephen Boyd
  2015-05-21 16:43           ` [PATCH v5 04/11] nvmem: Add a simple NVMEM framework for consumers Srinivas Kandagatla
                             ` (9 subsequent siblings)
  12 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:43 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

This patch adds just providers part of the framework just to enable easy
review.

Up until now, NVMEM drivers like eeprom were stored in drivers/misc,
where they all had to duplicate pretty much the same code to register
a sysfs file, allow in-kernel users to access the content of the devices
they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another,
there was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also
introduces DT representation for consumer devices to go get the data
they require (MAC Addresses, SoC/Revision ID, part numbers, and so on)
from the nvmems.

Having regmap interface to this framework would give much better
abstraction for nvmems on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/Kconfig                |   2 +
 drivers/Makefile               |   1 +
 drivers/nvmem/Kconfig          |  10 ++
 drivers/nvmem/Makefile         |   6 +
 drivers/nvmem/core.c           | 398 +++++++++++++++++++++++++++++++++++++++++
 include/linux/nvmem-provider.h |  53 ++++++
 6 files changed, 470 insertions(+)
 create mode 100644 drivers/nvmem/Kconfig
 create mode 100644 drivers/nvmem/Makefile
 create mode 100644 drivers/nvmem/core.c
 create mode 100644 include/linux/nvmem-provider.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index c0cc96b..69d7305 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -182,4 +182,6 @@ source "drivers/thunderbolt/Kconfig"
 
 source "drivers/android/Kconfig"
 
+source "drivers/nvmem/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 46d2554..f86b897 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= hwtracing/coresight/
 obj-$(CONFIG_ANDROID)		+= android/
+obj-$(CONFIG_NVMEM)		+= nvmem/
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
new file mode 100644
index 0000000..f157b6d
--- /dev/null
+++ b/drivers/nvmem/Kconfig
@@ -0,0 +1,10 @@
+menuconfig NVMEM
+	tristate "NVMEM Support"
+	select REGMAP
+	help
+	  Support for NVMEM devices.
+
+	  This framework is designed to provide a generic interface to NVMEM
+	  from both the Linux Kernel and the userspace.
+
+	  If unsure, say no.
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
new file mode 100644
index 0000000..6df2c69
--- /dev/null
+++ b/drivers/nvmem/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for nvmem drivers.
+#
+
+obj-$(CONFIG_NVMEM)		+= nvmem_core.o
+nvmem_core-y			:= core.o
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
new file mode 100644
index 0000000..6c2f0b1
--- /dev/null
+++ b/drivers/nvmem/core.c
@@ -0,0 +1,398 @@
+/*
+ * nvmem framework core.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/nvmem-provider.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+struct nvmem_device {
+	const char		*name;
+	struct regmap		*regmap;
+	struct module		*owner;
+	struct device		dev;
+	int			stride;
+	int			word_size;
+	int			ncells;
+	int			id;
+	int			users;
+	size_t			size;
+	bool			read_only;
+};
+
+struct nvmem_cell {
+	const char *name;
+	int			offset;
+	int			bytes;
+	int			bit_offset;
+	int			nbits;
+	struct nvmem_device	*nvmem;
+	struct list_head	node;
+};
+
+static DEFINE_MUTEX(nvmem_mutex);
+static DEFINE_IDA(nvmem_ida);
+
+static LIST_HEAD(nvmem_cells);
+static DEFINE_MUTEX(nvmem_cells_mutex);
+
+#define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
+
+static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
+				    struct bin_attribute *attr,
+				    char *buf, loff_t pos, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nvmem_device *nvmem = to_nvmem_device(dev);
+	int rc;
+
+	/* Stop the user from reading */
+	if (pos > nvmem->size)
+		return 0;
+
+	if (pos + count > nvmem->size)
+		count = nvmem->size - pos;
+
+	count = count/nvmem->word_size * nvmem->word_size;
+
+	rc = regmap_raw_read(nvmem->regmap, pos, buf, count);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count;
+}
+
+static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *attr,
+				     char *buf, loff_t pos, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nvmem_device *nvmem = to_nvmem_device(dev);
+	int rc;
+
+	/* Stop the user from writing */
+	if (pos > nvmem->size)
+		return 0;
+
+	if (pos + count > nvmem->size)
+		count = nvmem->size - pos;
+
+	count = count/nvmem->word_size * nvmem->word_size;
+
+	rc = regmap_raw_write(nvmem->regmap, pos, buf, count);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count;
+}
+
+/* default read/write permissions */
+static struct bin_attribute bin_attr_nvmem = {
+	.attr	= {
+		.name	= "nvmem",
+		.mode	= S_IWUSR | S_IRUGO,
+	},
+	.read	= bin_attr_nvmem_read,
+	.write	= bin_attr_nvmem_write,
+};
+
+static struct bin_attribute *nvmem_bin_attributes[] = {
+	&bin_attr_nvmem,
+	NULL,
+};
+
+static const struct attribute_group nvmem_bin_group = {
+	.bin_attrs	= nvmem_bin_attributes,
+};
+
+static const struct attribute_group *nvmem_dev_groups[] = {
+	&nvmem_bin_group,
+	NULL,
+};
+
+/* read only permission */
+static struct bin_attribute bin_attr_ro_nvmem = {
+	.attr	= {
+		.name	= "nvmem",
+		.mode	= S_IRUGO,
+	},
+	.read	= bin_attr_nvmem_read,
+};
+
+static struct bin_attribute *nvmem_bin_ro_attributes[] = {
+	&bin_attr_ro_nvmem,
+	NULL,
+};
+static const struct attribute_group nvmem_bin_ro_group = {
+	.bin_attrs	= nvmem_bin_ro_attributes,
+};
+
+static void nvmem_release(struct device *dev)
+{
+	struct nvmem_device *nvmem = to_nvmem_device(dev);
+
+	ida_simple_remove(&nvmem_ida, nvmem->id);
+	kfree(nvmem);
+}
+
+static struct class nvmem_class = {
+	.name		= "nvmem",
+	.dev_groups	= nvmem_dev_groups,
+	.dev_release	= nvmem_release,
+};
+
+static int of_nvmem_match(struct device *dev, const void *nvmem_np)
+{
+	return dev->of_node == nvmem_np;
+}
+
+static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
+{
+	struct device *d;
+
+	if (!nvmem_np)
+		return NULL;
+
+	d = class_find_device(&nvmem_class, NULL, nvmem_np, of_nvmem_match);
+
+	return d ? to_nvmem_device(d) : NULL;
+}
+
+static struct nvmem_cell *nvmem_find_cell(const char *cell_id)
+{
+	struct nvmem_cell *p;
+
+	list_for_each_entry(p, &nvmem_cells, node) {
+		if (p && !strcmp(p->name, cell_id))
+			return p;
+	}
+
+	return NULL;
+}
+
+static void nvmem_cell_drop(struct nvmem_cell *cell)
+{
+	mutex_lock(&nvmem_cells_mutex);
+	list_del(&cell->node);
+	mutex_unlock(&nvmem_cells_mutex);
+	kfree(cell);
+}
+
+static void nvmem_device_remove_all_cells(struct nvmem_device *nvmem)
+{
+	struct nvmem_cell *cell = NULL;
+	struct list_head *p, *n;
+
+	list_for_each_safe(p, n, &nvmem_cells) {
+		cell = list_entry(p, struct nvmem_cell, node);
+		if (cell->nvmem == nvmem)
+			nvmem_cell_drop(cell);
+	}
+}
+
+static void nvmem_cell_add(struct nvmem_cell *cell)
+{
+	mutex_lock(&nvmem_cells_mutex);
+	list_add_tail(&cell->node, &nvmem_cells);
+	mutex_unlock(&nvmem_cells_mutex);
+}
+
+static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
+				   struct nvmem_cell_info *info,
+				   struct nvmem_cell *cell)
+{
+	cell->nvmem = nvmem;
+	cell->offset = info->offset;
+	cell->bytes = info->bytes;
+	cell->name = info->name;
+
+	cell->bit_offset = info->bit_offset;
+	cell->nbits = info->nbits;
+
+	if (cell->nbits)
+		cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
+					   BITS_PER_BYTE);
+
+	if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
+		dev_err(&nvmem->dev,
+			"cell %s unaligned to nvmem stride %d\n",
+			cell->name, nvmem->stride);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nvmem_add_cells(struct nvmem_device *nvmem,
+			   struct nvmem_config *cfg)
+{
+	struct nvmem_cell **cells;
+	struct nvmem_cell_info *info = cfg->cells;
+	int i, rval;
+
+	cells = kzalloc(sizeof(*cells) * cfg->ncells, GFP_KERNEL);
+	if (!cells)
+		return -ENOMEM;
+
+	for (i = 0; i < cfg->ncells; i++) {
+		cells[i] = kzalloc(sizeof(struct nvmem_cell), GFP_KERNEL);
+		if (!cells[i]) {
+			rval = -ENOMEM;
+			goto err;
+		}
+
+		rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]);
+		if (IS_ERR_VALUE(rval)) {
+			kfree(cells[i]);
+			goto err;
+		}
+
+		nvmem_cell_add(cells[i]);
+	}
+
+	nvmem->ncells = cfg->ncells;
+	/* remove tmp array */
+	kfree(cells);
+
+	return 0;
+err:
+	while (--i)
+		nvmem_cell_drop(cells[i]);
+
+	return rval;
+}
+
+/**
+ * nvmem_register(): Register a nvmem device for given nvmem.
+ * Also creates an binary entry in /sys/class/nvmem/dev-name/nvmem
+ *
+ * @nvmem: nvmem device that needs to be created
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to nvmem_device.
+ */
+
+struct nvmem_device *nvmem_register(struct nvmem_config *config)
+{
+	struct nvmem_device *nvmem;
+	struct regmap *rm;
+	int rval;
+
+	if (!config->dev)
+		return ERR_PTR(-EINVAL);
+
+	rm = dev_get_regmap(config->dev, NULL);
+	if (!rm) {
+		dev_err(config->dev, "Regmap not found\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
+	if (!nvmem)
+		return ERR_PTR(-ENOMEM);
+
+	nvmem->id = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL);
+	if (nvmem->id < 0) {
+		kfree(nvmem);
+		return ERR_PTR(nvmem->id);
+	}
+
+	nvmem->regmap = rm;
+	nvmem->owner = config->owner;
+	nvmem->stride = regmap_get_reg_stride(rm);
+	nvmem->word_size = regmap_get_val_bytes(rm);
+	nvmem->size = regmap_get_max_register(rm) + nvmem->stride;
+	nvmem->dev.class = &nvmem_class;
+	nvmem->dev.parent = config->dev;
+	nvmem->dev.of_node = config->dev->of_node;
+	dev_set_name(&nvmem->dev, "%s%d",
+		     config->name ? : "nvmem", config->id);
+
+	nvmem->read_only = of_property_read_bool(nvmem->dev.of_node,
+						 "read-only");
+
+	device_initialize(&nvmem->dev);
+
+	dev_dbg(&nvmem->dev, "Registering nvmem device %s\n",
+		dev_name(&nvmem->dev));
+
+	rval = device_add(&nvmem->dev);
+	if (rval) {
+		ida_simple_remove(&nvmem_ida, nvmem->id);
+		kfree(nvmem);
+		return ERR_PTR(rval);
+	}
+
+	/* update sysfs attributes */
+	if (nvmem->read_only)
+		sysfs_update_group(&nvmem->dev.kobj, &nvmem_bin_ro_group);
+
+	if (config->cells)
+		nvmem_add_cells(nvmem, config);
+
+	return nvmem;
+}
+EXPORT_SYMBOL_GPL(nvmem_register);
+
+/**
+ * nvmem_unregister(): Unregister previously registered nvmem device
+ *
+ * @nvmem: Pointer to previously registered nvmem device.
+ *
+ * The return value will be an non zero on error or a zero on success.
+ */
+int nvmem_unregister(struct nvmem_device *nvmem)
+{
+	mutex_lock(&nvmem_mutex);
+	if (nvmem->users) {
+		mutex_unlock(&nvmem_mutex);
+		return -EBUSY;
+	}
+	mutex_unlock(&nvmem_mutex);
+
+	nvmem_device_remove_all_cells(nvmem);
+	device_del(&nvmem->dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nvmem_unregister);
+
+static int nvmem_init(void)
+{
+	return class_register(&nvmem_class);
+}
+
+static void nvmem_exit(void)
+{
+	class_unregister(&nvmem_class);
+}
+
+subsys_initcall(nvmem_init);
+module_exit(nvmem_exit);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("nvmem Driver Core");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
new file mode 100644
index 0000000..4908b37
--- /dev/null
+++ b/include/linux/nvmem-provider.h
@@ -0,0 +1,53 @@
+/*
+ * nvmem framework provider.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_NVMEM_PROVIDER_H
+#define _LINUX_NVMEM_PROVIDER_H
+
+struct nvmem_device;
+
+struct nvmem_cell_info {
+	const char		*name;
+	int			offset;
+	int			bytes;
+	int			bit_offset;
+	int			nbits;
+};
+
+struct nvmem_config {
+	struct device		*dev;
+	const char		*name;
+	int			id;
+	struct module		*owner;
+	struct nvmem_cell_info	*cells;
+	int			ncells;
+};
+
+#if IS_ENABLED(CONFIG_NVMEM)
+
+struct nvmem_device *nvmem_register(struct nvmem_config *cfg);
+int nvmem_unregister(struct nvmem_device *nvmem);
+
+#else
+
+static inline struct nvmem_device *nvmem_register(struct nvmem_config *cfg)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline int nvmem_unregister(struct nvmem_device *nvmem)
+{
+	return -ENOSYS;
+}
+
+#endif /* CONFIG_NVMEM */
+
+#endif  /* ifndef _LINUX_NVMEM_PROVIDER_H */
-- 
1.9.1


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

* [PATCH v5 04/11] nvmem: Add a simple NVMEM framework for consumers
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
                             ` (2 preceding siblings ...)
  2015-05-21 16:43           ` [PATCH v5 03/11] nvmem: Add a simple NVMEM framework for nvmem providers Srinivas Kandagatla
@ 2015-05-21 16:43           ` Srinivas Kandagatla
  2015-06-16 22:29             ` Stephen Boyd
  2015-05-21 16:43           ` [PATCH v5 05/11] nvmem: Add nvmem_device based consumer apis Srinivas Kandagatla
                             ` (8 subsequent siblings)
  12 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:43 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

This patch adds just consumers part of the framework just to enable easy
review.

Up until now, nvmem drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the nvmems.

Having regmap interface to this framework would give much better
abstraction for nvmems on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of the framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/nvmem/core.c           | 346 +++++++++++++++++++++++++++++++++++++++++
 include/linux/nvmem-consumer.h |  49 ++++++
 2 files changed, 395 insertions(+)
 create mode 100644 include/linux/nvmem-consumer.h

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 6c2f0b1..8a4b358 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -16,6 +16,7 @@
 
 #include <linux/device.h>
 #include <linux/nvmem-provider.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/idr.h>
@@ -379,6 +380,351 @@ int nvmem_unregister(struct nvmem_device *nvmem)
 }
 EXPORT_SYMBOL_GPL(nvmem_unregister);
 
+static struct nvmem_device *__nvmem_device_get(struct device_node *np,
+					       struct nvmem_cell **cellp,
+					       const char *cell_id)
+{
+	struct nvmem_device *nvmem = NULL;
+
+	mutex_lock(&nvmem_mutex);
+
+	if (np) {
+		nvmem = of_nvmem_find(np);
+		if (!nvmem) {
+			mutex_unlock(&nvmem_mutex);
+			return ERR_PTR(-EPROBE_DEFER);
+		}
+	} else {
+		struct nvmem_cell *cell = nvmem_find_cell(cell_id);
+
+		if (cell) {
+			nvmem = cell->nvmem;
+			*cellp = cell;
+		}
+
+		if (!nvmem) {
+			mutex_unlock(&nvmem_mutex);
+			return ERR_PTR(-ENOENT);
+		}
+	}
+
+	nvmem->users++;
+	mutex_unlock(&nvmem_mutex);
+
+	if (!try_module_get(nvmem->owner)) {
+		dev_err(&nvmem->dev,
+			"could not increase module refcount for cell %s\n",
+			nvmem->name);
+
+		mutex_lock(&nvmem_mutex);
+		nvmem->users--;
+		mutex_unlock(&nvmem_mutex);
+
+		return ERR_PTR(-EINVAL);
+	}
+
+	return nvmem;
+}
+
+static int __nvmem_device_put(struct nvmem_device *nvmem)
+{
+	module_put(nvmem->owner);
+	mutex_lock(&nvmem_mutex);
+	nvmem->users--;
+	mutex_unlock(&nvmem_mutex);
+
+	return 0;
+}
+
+static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id)
+{
+	struct nvmem_cell *cell = NULL;
+	struct nvmem_device *nvmem;
+
+	nvmem = __nvmem_device_get(NULL, &cell, cell_id);
+	if (IS_ERR(nvmem))
+		return (struct nvmem_cell *)nvmem;
+
+
+	return cell;
+
+}
+
+static struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
+					    const char *name)
+{
+	struct device_node *cell_np, *nvmem_np;
+	struct nvmem_cell *cell;
+	struct nvmem_device *nvmem;
+	const __be32 *addr;
+	int rval, len, index;
+
+	index = of_property_match_string(np, "nvmem-cell-names", name);
+
+	cell_np = of_parse_phandle(np, "nvmem-cell", index);
+	if (!cell_np)
+		return ERR_PTR(-EINVAL);
+
+	nvmem_np = of_get_next_parent(cell_np);
+	if (!nvmem_np)
+		return ERR_PTR(-EINVAL);
+
+	nvmem = __nvmem_device_get(nvmem_np, NULL, NULL);
+	if (IS_ERR(nvmem))
+		return (struct nvmem_cell *)nvmem;
+
+	addr = of_get_property(cell_np, "reg", &len);
+	if (!addr || (len < 2 * sizeof(int))) {
+		dev_err(&nvmem->dev, "of_i2c: invalid reg on %s\n",
+			cell_np->full_name);
+		rval  = -EINVAL;
+		goto err_mem;
+	}
+
+	cell = kzalloc(sizeof(*cell), GFP_KERNEL);
+	if (!cell) {
+		rval = -ENOMEM;
+		goto err_mem;
+	}
+
+	cell->nvmem = nvmem;
+	cell->offset = be32_to_cpup(addr++);
+	cell->bytes = be32_to_cpup(addr);
+	cell->name = cell_np->name;
+
+	of_property_read_u32(cell_np, "bit-offset", &cell->bit_offset);
+	of_property_read_u32(cell_np, "nbits", &cell->nbits);
+
+	if (cell->nbits)
+		cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
+					   BITS_PER_BYTE);
+
+	if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
+			dev_err(&nvmem->dev,
+				"cell %s unaligned to nvmem stride %d\n",
+				cell->name, nvmem->stride);
+		rval  = -EINVAL;
+		goto err_sanity;
+	}
+
+	nvmem_cell_add(cell);
+	
+	return cell;
+
+err_sanity:
+	kfree(cell);
+
+err_mem:
+	__nvmem_device_put(nvmem);
+
+	return ERR_PTR(rval);
+
+}
+
+/**
+ * nvmem_cell_get(): Get nvmem cell of device form a given index
+ *
+ * @dev node: Device tree node that uses the nvmem cell
+ * @index: nvmem index in nvmems property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct nvmem_cell.  The nvmem_cell will be freed by the
+ * nvmem_cell_put().
+ */
+struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id)
+{
+	struct nvmem_cell *cell;
+
+	if (dev->of_node) { /* try dt first */
+		cell = of_nvmem_cell_get(dev->of_node, cell_id);
+		if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER)
+			return cell;
+	}
+
+	return nvmem_cell_get_from_list(cell_id);
+
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_get);
+
+/**
+ * nvmem_cell_put(): Release previously allocated nvmem cell.
+ *
+ * @cell: Previously allocated nvmem cell by nvmem_cell_get()
+ * or nvmem_cell_get().
+ */
+void nvmem_cell_put(struct nvmem_cell *cell)
+{
+	struct nvmem_device *nvmem = cell->nvmem;
+
+	__nvmem_device_put(nvmem);
+	nvmem_cell_drop(cell);
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_put);
+
+static inline void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell,
+						    void *buf)
+{
+	u8 *p, *b;
+	int i, bit_offset = cell->bit_offset;
+
+	p = b = buf;
+	if (bit_offset) {
+		/* First shift */
+		*b++ >>= bit_offset;
+
+		/* setup rest of the bytes if any */
+		for (i = 1; i < cell->bytes; i++) {
+			/* Get bits from next byte and shift them towards msb */
+			*p |= *b << (BITS_PER_BYTE - bit_offset);
+
+			p = b;
+			*b++ >>= bit_offset;
+		}
+
+		/* result fits in less bytes */
+		if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE))
+			*p-- = 0;
+	}
+	/* clear msb bits if any leftover in the last byte */
+	*p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0);
+}
+
+static int __nvmem_cell_read(struct nvmem_device *nvmem,
+		      struct nvmem_cell *cell,
+		      void *buf, ssize_t *len)
+{
+	int rc;
+
+	rc = regmap_raw_read(nvmem->regmap, cell->offset, buf, cell->bytes);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	/* shift bits in-place */
+	if (cell->bit_offset || cell->bit_offset)
+		nvmem_shift_read_buffer_in_place(cell, buf);
+
+	*len = cell->bytes;
+
+	return *len;
+}
+/**
+ * nvmem_cell_read(): Read a given nvmem cell
+ *
+ * @cell: nvmem cell to be read.
+ * @len: pointer to length of cell which will be populated on successful read.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a char * bufffer.  The buffer should be freed by the consumer with a
+ * kfree().
+ */
+void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len)
+{
+	struct nvmem_device *nvmem = cell->nvmem;
+	u8 *buf;
+	int rc;
+
+	if (!nvmem || !nvmem->regmap)
+		return ERR_PTR(-EINVAL);
+
+	buf = kzalloc(cell->bytes, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	rc = __nvmem_cell_read(nvmem, cell, buf, len);
+	if (IS_ERR_VALUE(rc)) {
+		kfree(buf);
+		return ERR_PTR(rc);
+	}
+
+	return buf;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_read);
+
+static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
+						    u8 *_buf, int len)
+{
+	struct nvmem_device *nvmem = cell->nvmem;
+	int i, rc, nbits, bit_offset = cell->bit_offset;
+	u8 v, *p, *buf, *b, pbyte, pbits;
+
+	nbits = cell->nbits;
+	buf = kzalloc(cell->bytes, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	memcpy(buf, _buf, len);
+	p = b = buf;
+
+	if (bit_offset) {
+		pbyte = *b;
+		*b <<= bit_offset;
+
+		/* setup the first byte with lsb bits from nvmem */
+		rc = regmap_raw_read(nvmem->regmap, cell->offset, &v, 1);
+		*b++ |= GENMASK(bit_offset - 1, 0) & v;
+
+		/* setup rest of the byte if any */
+		for (i = 1; i < cell->bytes; i++) {
+			/* Get last byte bits and shift them towards lsb */
+			pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset);
+			pbyte = *b;
+			p = b;
+			*b <<= bit_offset;
+			*b++ |= pbits;
+		}
+	}
+
+	/* if it's not end on byte boundary */
+	if ((nbits + bit_offset) % BITS_PER_BYTE) {
+		/* setup the last byte with msb bits from nvmem */
+		rc = regmap_raw_read(nvmem->regmap,
+				    cell->offset + cell->bytes - 1, &v, 1);
+		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
+
+	}
+
+	return buf;
+}
+
+/**
+ * nvmem_cell_write(): Write to a given nvmem cell
+ *
+ * @cell: nvmem cell to be written.
+ * @buf: Buffer to be written.
+ * @len: length of buffer to be written to nvmem cell.
+ *
+ * The return value will be an length of bytes written or non zero on failure.
+ */
+int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len)
+{
+	struct nvmem_device *nvmem = cell->nvmem;
+	int rc;
+	void *wbuf = buf;
+
+	if (!nvmem || !nvmem->regmap || nvmem->read_only ||
+	    (cell->bit_offset == 0 && len != cell->bytes))
+		return -EINVAL;
+
+	if (cell->bit_offset || cell->nbits) {
+		wbuf = nvmem_cell_prepare_write_buffer(cell, buf, len);
+		if (IS_ERR(wbuf))
+			return PTR_ERR(wbuf);
+	}
+
+	rc = regmap_raw_write(nvmem->regmap, cell->offset, wbuf, cell->bytes);
+
+	/* free the tmp buffer */
+	if (cell->bit_offset)
+		kfree(wbuf);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_write);
+
 static int nvmem_init(void)
 {
 	return class_register(&nvmem_class);
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
new file mode 100644
index 0000000..c3fa8c7
--- /dev/null
+++ b/include/linux/nvmem-consumer.h
@@ -0,0 +1,49 @@
+/*
+ * nvmem framework consumer.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_NVMEM_CONSUMER_H
+#define _LINUX_NVMEM_CONSUMER_H
+
+/* consumer cookie */
+struct nvmem_cell;
+
+#if IS_ENABLED(CONFIG_NVMEM)
+
+/* Cell based interface */
+struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);
+void nvmem_cell_put(struct nvmem_cell *cell);
+void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len);
+int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len);
+
+#else
+
+struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline void nvmem_cell_put(struct nvmem_cell *cell)
+{
+}
+
+static inline char *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline int nvmem_cell_write(struct nvmem_cell *cell,
+				    const char *buf, ssize_t len)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_NVMEM */
+
+#endif  /* ifndef _LINUX_NVMEM_CONSUMER_H */
-- 
1.9.1


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

* [PATCH v5 05/11] nvmem: Add nvmem_device based consumer apis.
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
                             ` (3 preceding siblings ...)
  2015-05-21 16:43           ` [PATCH v5 04/11] nvmem: Add a simple NVMEM framework for consumers Srinivas Kandagatla
@ 2015-05-21 16:43           ` Srinivas Kandagatla
  2015-06-16 22:49             ` Stephen Boyd
  2015-05-21 16:44           ` [PATCH v5 06/11] nvmem: Add bindings for simple nvmem framework Srinivas Kandagatla
                             ` (7 subsequent siblings)
  12 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:43 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

This patch adds read/write apis which are based on nvmem_device. It is
common that the drivers like omap cape manager or qcom cpr driver to access
bytes directly at particular offset in the eeprom and not from nvmem
cell info in DT. These driver would need to get access to the nvmem
directly, which is what these new APIS provide.

These wrapper apis would help such users to avoid code duplication in
there drivers and also avoid them reading a big eeprom blob and parsing
it internally in there driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/nvmem/core.c           | 120 +++++++++++++++++++++++++++++++++++++++++
 include/linux/nvmem-consumer.h |  57 ++++++++++++++++++++
 include/linux/nvmem-provider.h |  10 +---
 3 files changed, 179 insertions(+), 8 deletions(-)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 8a4b358..68ee8d1 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -436,6 +436,51 @@ static int __nvmem_device_put(struct nvmem_device *nvmem)
 	return 0;
 }
 
+static int nvmem_match(struct device *dev, const void *data)
+{
+	return !strcmp(dev_name(dev), (const char *)data);
+}
+
+static struct nvmem_device *nvmem_find(const char *name)
+{
+	struct device *d;
+
+	d = class_find_device(&nvmem_class, NULL, (void *)name, nvmem_match);
+
+	return d ? to_nvmem_device(d) : NULL;
+}
+
+struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name)
+{
+	struct device_node *nvmem_np, *np = dev->of_node;
+	struct nvmem_device *nvmem;
+	int index;
+
+	if (np) { /* try dt first */
+		index = of_property_match_string(np, "nvmem-names", dev_name);
+
+		nvmem_np = of_parse_phandle(np, "nvmem", index);
+		if (!nvmem_np)
+			return ERR_PTR(-EINVAL);
+
+		nvmem = __nvmem_device_get(nvmem_np, NULL, NULL);
+
+		if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER)
+			return nvmem;
+
+	}
+
+	return nvmem_find(dev_name);
+
+}
+EXPORT_SYMBOL_GPL(nvmem_device_get);
+
+void nvmem_device_put(struct nvmem_device *nvmem)
+{
+	__nvmem_device_put(nvmem);
+}
+EXPORT_SYMBOL_GPL(nvmem_device_put);
+
 static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id)
 {
 	struct nvmem_cell *cell = NULL;
@@ -725,6 +770,81 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len)
 }
 EXPORT_SYMBOL_GPL(nvmem_cell_write);
 
+int nvmem_device_cell_read(struct nvmem_device *nvmem,
+			   struct nvmem_cell_info *info, void *buf)
+{
+	struct nvmem_cell cell;
+	int rc, len;
+
+	if (!nvmem || !nvmem->regmap)
+		return -EINVAL;
+
+	rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	rc = __nvmem_cell_read(nvmem, &cell, buf, &len);
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
+
+int nvmem_device_cell_write(struct nvmem_device *nvmem,
+			    struct nvmem_cell_info *info, void *buf)
+{
+	struct nvmem_cell cell;
+	int rc;
+
+	if (!nvmem || !nvmem->regmap)
+		return -EINVAL;
+
+	rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return nvmem_cell_write(&cell, buf, cell.bytes);
+}
+EXPORT_SYMBOL_GPL(nvmem_device_cell_write);
+
+int nvmem_device_read(struct nvmem_device *nvmem,
+		      unsigned int offset,
+		      size_t bytes, void *buf)
+{
+	int rc;
+
+	if (!nvmem || !nvmem->regmap)
+		return -EINVAL;
+
+	rc = regmap_raw_read(nvmem->regmap, offset, buf, bytes);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return bytes;
+}
+EXPORT_SYMBOL_GPL(nvmem_device_read);
+
+int nvmem_device_write(struct nvmem_device *nvmem,
+		       unsigned int offset,
+		       size_t bytes, void *buf)
+{
+	int rc;
+
+	if (!nvmem || !nvmem->regmap)
+		return -EINVAL;
+
+	rc = regmap_raw_write(nvmem->regmap, offset, buf, bytes);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+
+	return bytes;
+}
+EXPORT_SYMBOL_GPL(nvmem_device_write);
+
 static int nvmem_init(void)
 {
 	return class_register(&nvmem_class);
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
index c3fa8c7..66c67ba 100644
--- a/include/linux/nvmem-consumer.h
+++ b/include/linux/nvmem-consumer.h
@@ -14,6 +14,15 @@
 
 /* consumer cookie */
 struct nvmem_cell;
+struct nvmem_device;
+
+struct nvmem_cell_info {
+	const char		*name;
+	int			offset;
+	int			bytes;
+	int			bit_offset;
+	int			nbits;
+};
 
 #if IS_ENABLED(CONFIG_NVMEM)
 
@@ -23,6 +32,18 @@ void nvmem_cell_put(struct nvmem_cell *cell);
 void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len);
 int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len);
 
+/* direct nvmem device read/write interface */
+struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
+void nvmem_device_put(struct nvmem_device *nvmem);
+int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
+		      size_t bytes, void *buf);
+int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset,
+		       size_t bytes, void *buf);
+int nvmem_device_cell_read(struct nvmem_device *nvmem,
+			   struct nvmem_cell_info *info, void *buf);
+int nvmem_device_cell_write(struct nvmem_device *nvmem,
+			    struct nvmem_cell_info *info, void *buf);
+
 #else
 
 struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name)
@@ -44,6 +65,42 @@ static inline int nvmem_cell_write(struct nvmem_cell *cell,
 {
 	return -ENOSYS;
 }
+
+static inline struct nvmem_device *nvmem_device_get(struct device *dev,
+						    const char *name)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline void nvmem_device_put(struct nvmem_device *nvmem)
+{
+}
+
+static inline int nvmem_device_cell_read(struct nvmem_device *nvmem,
+					 struct nvmem_cell_info *info,
+					 void *buf)
+{
+	return -ENOSYS;
+}
+
+static inline int nvmem_device_cell_write(struct nvmem_device *nvmem,
+					  struct nvmem_cell_info *info,
+					  void *buf)
+{
+	return -ENOSYS;
+}
+
+static inline int nvmem_device_read(struct nvmem_device *nvmem,
+				    unsigned int offset, size_t bytes, void *buf)
+{
+	return -ENOSYS;
+}
+
+static inline int nvmem_device_write(struct nvmem_device *nvmem,
+				     unsigned int offset, size_t bytes, void *buf)
+{
+	return -ENOSYS;
+}
 #endif /* CONFIG_NVMEM */
 
 #endif  /* ifndef _LINUX_NVMEM_CONSUMER_H */
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index 4908b37..7a982cd 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -12,15 +12,9 @@
 #ifndef _LINUX_NVMEM_PROVIDER_H
 #define _LINUX_NVMEM_PROVIDER_H
 
-struct nvmem_device;
+#include <linux/nvmem-consumer.h>
 
-struct nvmem_cell_info {
-	const char		*name;
-	int			offset;
-	int			bytes;
-	int			bit_offset;
-	int			nbits;
-};
+struct nvmem_device;
 
 struct nvmem_config {
 	struct device		*dev;
-- 
1.9.1


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

* [PATCH v5 06/11] nvmem: Add bindings for simple nvmem framework
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
                             ` (4 preceding siblings ...)
  2015-05-21 16:43           ` [PATCH v5 05/11] nvmem: Add nvmem_device based consumer apis Srinivas Kandagatla
@ 2015-05-21 16:44           ` Srinivas Kandagatla
  2015-06-16 22:53             ` Stephen Boyd
  2015-06-19 10:36             ` maitysanchayan
  2015-05-21 16:44           ` [PATCH v5 07/11] nvmem: Add simple nvmem-mmio consumer helper functions Srinivas Kandagatla
                             ` (6 subsequent siblings)
  12 siblings, 2 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:44 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

This patch adds bindings for simple nvmem framework which allows nvmem
consumers to talk to nvmem providers to get access to nvmem cell data.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/devicetree/bindings/nvmem/nvmem.txt | 84 +++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem.txt

diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.txt b/Documentation/devicetree/bindings/nvmem/nvmem.txt
new file mode 100644
index 0000000..ecea654
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/nvmem.txt
@@ -0,0 +1,84 @@
+= NVMEM Data Device Tree Bindings =
+
+This binding is intended to represent the location of hardware
+configuration data stored in NVMEMs.
+
+On a significant proportion of boards, the manufacturer has stored
+some data on NVMEM, for the OS to be able to retrieve these information
+and act upon it. Obviously, the OS has to know about where to retrieve
+these data from, and where they are stored on the storage device.
+
+This document is here to document this.
+
+= Data providers =
+Contains bindings specific to provider drivers and data cells as children
+to this node.
+
+Optional properties:
+ read-only: Mark the provider as read only.
+
+= Data cells =
+These are the child nodes of the provider which contain data cell
+information like offset and size in nvmem provider.
+
+Required properties:
+reg:	specifies the offset in byte within that storage device, start bit
+	in the byte and the length in bits of the data we care about.
+	There could be more then one offset-length pairs in this property.
+
+Optional properties:
+
+bit-offset: specifies the offset in bit within the address range specified
+	by reg property. Can take values from 0-7.
+nbits: specifies number of bits this cell occupies starting from bit-offset.
+
+For example:
+
+	/* Provider */
+	qfprom: qfprom@00700000 {
+		...
+
+		/* Data cells */
+		tsens_calibration: calib@404 {
+			reg = <0x404 0x10>;
+		};
+
+		tsens_calibration_bckp: calib_bckp@504 {
+			reg = <0x504 0x11>;
+			bit-offset = 6;
+			nbits = 128;
+		};
+
+		pvs_version: pvs-version@6 {
+			reg = <0x6 0x2>
+			bit-offset = 7;
+			nbits = 2;
+		};
+
+		speed_bin: speed-bin@c{
+			reg = <0xc 0x1>;
+			bit-offset = 2;
+			nbits	= 3;
+
+		};
+		...
+	};
+
+= Data consumers =
+Are device nodes which consume nvmem data cells/providers.
+
+Required-properties:
+nvmem-cell: list of phandle to the nvmem data cells.
+nvmem-cell-names: names for the each nvmem-cell specified
+
+Optional-properties:
+nvmem	: list of phandles to nvmem providers.
+nvmem-names: names for the each nvmem provider.
+
+For example:
+
+	tsens {
+		...
+		nvmem-cell = <&tsens_calibration>;
+		nvmem-cell-names = "calibration";
+	};
-- 
1.9.1


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

* [PATCH v5 07/11] nvmem: Add simple nvmem-mmio consumer helper functions.
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
                             ` (5 preceding siblings ...)
  2015-05-21 16:44           ` [PATCH v5 06/11] nvmem: Add bindings for simple nvmem framework Srinivas Kandagatla
@ 2015-05-21 16:44           ` Srinivas Kandagatla
  2015-06-16 22:58             ` Stephen Boyd
  2015-05-21 16:44           ` [PATCH v5 08/11] nvmem: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
                             ` (5 subsequent siblings)
  12 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:44 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

This patch adds probe and remove helper functions for nvmems which are
mmio based, With these helper function new nvmem consumer drivers need
very little code add its driver.

This code is currently used for qfprom and sunxi-sid nvmem consumer
drivers.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/nvmem/Makefile     |  1 +
 drivers/nvmem/nvmem-mmio.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/nvmem/nvmem-mmio.h | 41 +++++++++++++++++++++++++++
 3 files changed, 111 insertions(+)
 create mode 100644 drivers/nvmem/nvmem-mmio.c
 create mode 100644 drivers/nvmem/nvmem-mmio.h

diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 6df2c69..f694cfc 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_NVMEM)		+= nvmem_core.o
 nvmem_core-y			:= core.o
+nvmem_core-y			+= nvmem-mmio.o
diff --git a/drivers/nvmem/nvmem-mmio.c b/drivers/nvmem/nvmem-mmio.c
new file mode 100644
index 0000000..0d8131f
--- /dev/null
+++ b/drivers/nvmem/nvmem-mmio.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include "nvmem-mmio.h"
+
+int nvmem_mmio_remove(struct platform_device *pdev)
+{
+	struct nvmem_device *nvmem = platform_get_drvdata(pdev);
+
+	return nvmem_unregister(nvmem);
+}
+EXPORT_SYMBOL_GPL(nvmem_mmio_remove);
+
+int nvmem_mmio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	const struct nvmem_mmio_data *data;
+	struct nvmem_device *nvmem;
+	struct regmap *regmap;
+	const struct of_device_id *match;
+	void __iomem *base;
+
+	if (!dev || !dev->driver)
+		return -ENODEV;
+
+	match = of_match_device(dev->driver->of_match_table, dev);
+	if (!match || !match->data)
+		return -EINVAL;
+
+	data = match->data;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	data->regmap_config->max_register = resource_size(res) - 1;
+
+	regmap = devm_regmap_init_mmio(dev, base, data->regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(regmap);
+	}
+	data->nvmem_config->dev = dev;
+	nvmem = nvmem_register(data->nvmem_config);
+	if (IS_ERR(nvmem))
+		return PTR_ERR(nvmem);
+
+	platform_set_drvdata(pdev, nvmem);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nvmem_mmio_probe);
diff --git a/drivers/nvmem/nvmem-mmio.h b/drivers/nvmem/nvmem-mmio.h
new file mode 100644
index 0000000..a2ad4e5
--- /dev/null
+++ b/drivers/nvmem/nvmem-mmio.h
@@ -0,0 +1,41 @@
+/*
+ * MMIO based nvmem providers.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_NVMEM_MMIO_H
+#define _LINUX_NVMEM_MMIO_H
+
+#include <linux/platform_device.h>
+#include <linux/nvmem-provider.h>
+#include <linux/regmap.h>
+
+struct nvmem_mmio_data {
+	struct regmap_config *regmap_config;
+	struct nvmem_config *nvmem_config;
+};
+
+#if IS_ENABLED(CONFIG_NVMEM)
+
+int nvmem_mmio_probe(struct platform_device *pdev);
+int nvmem_mmio_remove(struct platform_device *pdev);
+
+#else
+
+static inline int nvmem_mmio_probe(struct platform_device *pdev)
+{
+	return -ENOSYS;
+}
+
+static inline int nvmem_mmio_remove(struct platform_device *pdev)
+{
+	return -ENOSYS;
+}
+#endif
+
+#endif  /* ifndef _LINUX_NVMEM_MMIO_H */
-- 
1.9.1


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

* [PATCH v5 08/11] nvmem: qfprom: Add Qualcomm QFPROM support.
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
                             ` (6 preceding siblings ...)
  2015-05-21 16:44           ` [PATCH v5 07/11] nvmem: Add simple nvmem-mmio consumer helper functions Srinivas Kandagatla
@ 2015-05-21 16:44           ` Srinivas Kandagatla
  2015-06-16 23:00             ` Stephen Boyd
  2015-05-21 16:44           ` [PATCH v5 09/11] nvmem: qfprom: Add bindings for qfprom Srinivas Kandagatla
                             ` (4 subsequent siblings)
  12 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:44 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

This patch adds QFPROM support driver which is used by other drivers
like thermal sensor and cpufreq.

On MSM parts there are some efuses (called qfprom) these fuses store
things like calibration data, speed bins.. etc. Drivers like cpufreq,
thermal sensors would read out this data for configuring the driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/nvmem/Kconfig  | 15 +++++++++++++++
 drivers/nvmem/Makefile |  4 ++++
 drivers/nvmem/qfprom.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 70 insertions(+)
 create mode 100644 drivers/nvmem/qfprom.c

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index f157b6d..e665e23 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -8,3 +8,18 @@ menuconfig NVMEM
 	  from both the Linux Kernel and the userspace.
 
 	  If unsure, say no.
+
+if NVMEM
+
+config QCOM_QFPROM
+	tristate "QCOM QFPROM Support"
+	depends on ARCH_QCOM
+	select REGMAP_MMIO
+	help
+	  Say y here to enable QFPROM support. The QFPROM provides access
+	  functions for QFPROM data to rest of the drivers via nvmem interface.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called nvmem-qfprom.
+
+endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index f694cfc..caea611 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -5,3 +5,7 @@
 obj-$(CONFIG_NVMEM)		+= nvmem_core.o
 nvmem_core-y			:= core.o
 nvmem_core-y			+= nvmem-mmio.o
+
+# Devices
+obj-$(CONFIG_QCOM_QFPROM)	+= nvmem_qfprom.o
+nvmem_qfprom-y			:= qfprom.o
diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
new file mode 100644
index 0000000..5ea84bb
--- /dev/null
+++ b/drivers/nvmem/qfprom.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include "nvmem-mmio.h"
+
+static struct regmap_config qfprom_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+};
+
+static struct nvmem_config econfig = {
+	.name = "qfprom",
+	.owner = THIS_MODULE,
+};
+
+static struct nvmem_mmio_data qfprom_data = {
+	.nvmem_config = &econfig,
+	.regmap_config = &qfprom_regmap_config,
+};
+
+static const struct of_device_id qfprom_of_match[] = {
+	{ .compatible = "qcom,qfprom", .data = &qfprom_data},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, qfprom_of_match);
+
+static struct platform_driver qfprom_driver = {
+	.probe = nvmem_mmio_probe,
+	.remove = nvmem_mmio_remove,
+	.driver = {
+		.name = "qcom,qfprom",
+		.of_match_table = qfprom_of_match,
+	},
+};
+module_platform_driver(qfprom_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm QFPROM driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


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

* [PATCH v5 09/11] nvmem: qfprom: Add bindings for qfprom
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
                             ` (7 preceding siblings ...)
  2015-05-21 16:44           ` [PATCH v5 08/11] nvmem: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
@ 2015-05-21 16:44           ` Srinivas Kandagatla
  2015-06-16 23:01             ` Stephen Boyd
  2015-05-21 16:45           ` [PATCH v5 11/11] nvmem: Add to MAINTAINERS for nvmem framework Srinivas Kandagatla
                             ` (3 subsequent siblings)
  12 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:44 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

This patch adds bindings for qfprom found in QCOM SOCs. QFPROM driver
is based on simple nvmem framework.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/devicetree/bindings/nvmem/qfprom.txt | 35 ++++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/nvmem/qfprom.txt

diff --git a/Documentation/devicetree/bindings/nvmem/qfprom.txt b/Documentation/devicetree/bindings/nvmem/qfprom.txt
new file mode 100644
index 0000000..8a8d55f
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/qfprom.txt
@@ -0,0 +1,35 @@
+= Qualcomm QFPROM device tree bindings =
+
+This binding is intended to represent QFPROM which is found in most QCOM SOCs.
+
+Required properties:
+- compatible: should be "qcom,qfprom"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/nvmem/nvmem.txt
+
+Example:
+
+	qfprom: qfprom@00700000 {
+		compatible 	= "qcom,qfprom";
+		reg		= <0x00700000 0x8000>;
+		...
+		/* Data cells */
+		tsens_calibration: calib@404 {
+			reg = <0x4404 0x10>;
+		};
+	};
+
+
+= Data consumers =
+Are device nodes which consume nvmem data cells.
+
+For example:
+
+	tsens {
+		...
+		nvmem-cell = <&tsens_calibration>;
+		nvmem-cell-names = "calibration";
+	};
-- 
1.9.1


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

* [PATCH v5 11/11] nvmem: Add to MAINTAINERS for nvmem framework
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
                             ` (8 preceding siblings ...)
  2015-05-21 16:44           ` [PATCH v5 09/11] nvmem: qfprom: Add bindings for qfprom Srinivas Kandagatla
@ 2015-05-21 16:45           ` Srinivas Kandagatla
  2015-05-21 16:45           ` [PATCH v5 10/11] nvmem: sunxi: Move the SID driver to the " Srinivas Kandagatla
                             ` (2 subsequent siblings)
  12 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:45 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 790 bytes --]

This patch adds MAINTAINERS to nvmem framework.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b2ef613..26e1829 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6993,6 +6993,15 @@ S:	Supported
 F:	drivers/block/nvme*
 F:	include/linux/nvme.h
 
+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/
+F:	include/linux/nvmem-provider.h
+F:	include/linux/nvmem-consumer.h
+
 NXP-NCI NFC DRIVER
 M:	Clément Perrochaud <clement.perrochaud@effinnov.com>
 R:	Charles Gorand <charles.gorand@effinnov.com>
-- 
1.9.1


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

* [PATCH v5 10/11] nvmem: sunxi: Move the SID driver to the nvmem framework
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
                             ` (9 preceding siblings ...)
  2015-05-21 16:45           ` [PATCH v5 11/11] nvmem: Add to MAINTAINERS for nvmem framework Srinivas Kandagatla
@ 2015-05-21 16:45           ` Srinivas Kandagatla
  2015-06-16 23:04             ` Stephen Boyd
  2015-05-25 16:51           ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Pantelis Antoniou
  2015-05-29  1:20           ` Dan Williams
  12 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-21 16:45 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter

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

Now that we have the nvmem framework, we can consolidate the common driver
code. Move the driver to the framework, and hopefully, it will fix the sysfs
file creation race.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[srinivas.kandagatla: Moved to regmap based EEPROM framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 ---
 .../bindings/misc/allwinner,sunxi-sid.txt          |  17 ---
 .../bindings/nvmem/allwinner,sunxi-sid.txt         |  21 +++
 drivers/misc/eeprom/Kconfig                        |  13 --
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 ---------------------
 drivers/nvmem/Kconfig                              |  11 ++
 drivers/nvmem/Makefile                             |   2 +
 drivers/nvmem/sunxi-sid.c                          |  64 +++++++++
 9 files changed, 98 insertions(+), 209 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
 create mode 100644 drivers/nvmem/sunxi-sid.c

diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid
deleted file mode 100644
index ffb9536..0000000
--- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid
+++ /dev/null
@@ -1,22 +0,0 @@
-What:		/sys/devices/*/<our-device>/eeprom
-Date:		August 2013
-Contact:	Oliver Schinagl <oliver@schinagl.nl>
-Description:	read-only access to the SID (Security-ID) on current
-		A-series SoC's from Allwinner. Currently supports A10, A10s, A13
-		and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes,
-		whereas the newer A20 SoC exposes 512 bytes split into sections.
-		Besides the 16 bytes of SID, there's also an SJTAG area,
-		HDMI-HDCP key and some custom keys. Below a quick overview, for
-		details see the user manual:
-		0x000  128 bit root-key (sun[457]i)
-		0x010  128 bit boot-key (sun7i)
-		0x020   64 bit security-jtag-key (sun7i)
-		0x028   16 bit key configuration (sun7i)
-		0x02b   16 bit custom-vendor-key (sun7i)
-		0x02c  320 bit low general key (sun7i)
-		0x040   32 bit read-control access (sun7i)
-		0x064  224 bit low general key (sun7i)
-		0x080 2304 bit HDCP-key (sun7i)
-		0x1a0  768 bit high general key (sun7i)
-Users:		any user space application which wants to read the SID on
-		Allwinner's A-series of CPU's.
diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
deleted file mode 100644
index fabdf64..0000000
--- a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Allwinner sunxi-sid
-
-Required properties:
-- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
-- reg: Should contain registers location and length
-
-Example for sun4i:
-	sid@01c23800 {
-		compatible = "allwinner,sun4i-a10-sid";
-		reg = <0x01c23800 0x10>
-	};
-
-Example for sun7i:
-	sid@01c23800 {
-		compatible = "allwinner,sun7i-a20-sid";
-		reg = <0x01c23800 0x200>
-	};
diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
new file mode 100644
index 0000000..d543ed3
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
@@ -0,0 +1,21 @@
+Allwinner sunxi-sid
+
+Required properties:
+- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/nvmem/nvmem.txt
+
+Example for sun4i:
+	sid@01c23800 {
+		compatible = "allwinner,sun4i-a10-sid";
+		reg = <0x01c23800 0x10>
+	};
+
+Example for sun7i:
+	sid@01c23800 {
+		compatible = "allwinner,sun7i-a20-sid";
+		reg = <0x01c23800 0x200>
+	};
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 9536852f..04f2e1f 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG
 
 	  If unsure, say N.
 
-config EEPROM_SUNXI_SID
-	tristate "Allwinner sunxi security ID support"
-	depends on ARCH_SUNXI && SYSFS
-	help
-	  This is a driver for the 'security ID' available on various Allwinner
-	  devices.
-
-	  Due to the potential risks involved with changing e-fuses,
-	  this driver is read-only.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called sunxi_sid.
-
 endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 9507aec..fc1e81d 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY)	+= eeprom.o
 obj-$(CONFIG_EEPROM_MAX6875)	+= max6875.o
 obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
 obj-$(CONFIG_EEPROM_93XX46)	+= eeprom_93xx46.o
-obj-$(CONFIG_EEPROM_SUNXI_SID)	+= sunxi_sid.o
 obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
deleted file mode 100644
index 8385177..0000000
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
- * http://www.linux-sunxi.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * This driver exposes the Allwinner security ID, efuses exported in byte-
- * sized chunks.
- */
-
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#define DRV_NAME "sunxi-sid"
-
-struct sunxi_sid_data {
-	void __iomem *reg_base;
-	unsigned int keysize;
-};
-
-/* We read the entire key, due to a 32 bit read alignment requirement. Since we
- * want to return the requested byte, this results in somewhat slower code and
- * uses 4 times more reads as needed but keeps code simpler. Since the SID is
- * only very rarely probed, this is not really an issue.
- */
-static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data,
-			      const unsigned int offset)
-{
-	u32 sid_key;
-
-	if (offset >= sid_data->keysize)
-		return 0;
-
-	sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4));
-	sid_key >>= (offset % 4) * 8;
-
-	return sid_key; /* Only return the last byte */
-}
-
-static ssize_t sid_read(struct file *fd, struct kobject *kobj,
-			struct bin_attribute *attr, char *buf,
-			loff_t pos, size_t size)
-{
-	struct platform_device *pdev;
-	struct sunxi_sid_data *sid_data;
-	int i;
-
-	pdev = to_platform_device(kobj_to_dev(kobj));
-	sid_data = platform_get_drvdata(pdev);
-
-	if (pos < 0 || pos >= sid_data->keysize)
-		return 0;
-	if (size > sid_data->keysize - pos)
-		size = sid_data->keysize - pos;
-
-	for (i = 0; i < size; i++)
-		buf[i] = sunxi_sid_read_byte(sid_data, pos + i);
-
-	return i;
-}
-
-static struct bin_attribute sid_bin_attr = {
-	.attr = { .name = "eeprom", .mode = S_IRUGO, },
-	.read = sid_read,
-};
-
-static int sunxi_sid_remove(struct platform_device *pdev)
-{
-	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
-	dev_dbg(&pdev->dev, "driver unloaded\n");
-
-	return 0;
-}
-
-static const struct of_device_id sunxi_sid_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
-	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
-	{/* sentinel */},
-};
-MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-
-static int sunxi_sid_probe(struct platform_device *pdev)
-{
-	struct sunxi_sid_data *sid_data;
-	struct resource *res;
-	const struct of_device_id *of_dev_id;
-	u8 *entropy;
-	unsigned int i;
-
-	sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data),
-				GFP_KERNEL);
-	if (!sid_data)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(sid_data->reg_base))
-		return PTR_ERR(sid_data->reg_base);
-
-	of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev);
-	if (!of_dev_id)
-		return -ENODEV;
-	sid_data->keysize = (int)of_dev_id->data;
-
-	platform_set_drvdata(pdev, sid_data);
-
-	sid_bin_attr.size = sid_data->keysize;
-	if (device_create_bin_file(&pdev->dev, &sid_bin_attr))
-		return -ENODEV;
-
-	entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL);
-	for (i = 0; i < sid_data->keysize; i++)
-		entropy[i] = sunxi_sid_read_byte(sid_data, i);
-	add_device_randomness(entropy, sid_data->keysize);
-	kfree(entropy);
-
-	dev_dbg(&pdev->dev, "loaded\n");
-
-	return 0;
-}
-
-static struct platform_driver sunxi_sid_driver = {
-	.probe = sunxi_sid_probe,
-	.remove = sunxi_sid_remove,
-	.driver = {
-		.name = DRV_NAME,
-		.of_match_table = sunxi_sid_of_match,
-	},
-};
-module_platform_driver(sunxi_sid_driver);
-
-MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
-MODULE_DESCRIPTION("Allwinner sunxi security id driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index e665e23..17f1a57 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -22,4 +22,15 @@ config QCOM_QFPROM
 	  This driver can also be built as a module. If so, the module
 	  will be called nvmem-qfprom.
 
+config NVMEM_SUNXI_SID
+	tristate "Allwinner SoCs SID support"
+	depends on ARCH_SUNXI
+	select REGMAP_MMIO
+	help
+	  This is a driver for the 'security ID' available on various Allwinner
+	  devices.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called eeprom-sunxi-sid.
+
 endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index caea611..cc46791 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -9,3 +9,5 @@ nvmem_core-y			+= nvmem-mmio.o
 # Devices
 obj-$(CONFIG_QCOM_QFPROM)	+= nvmem_qfprom.o
 nvmem_qfprom-y			:= qfprom.o
+obj-$(CONFIG_NVMEM_SUNXI_SID)	+= nvmem-sunxi-sid.o
+nvmem-sunxi-sid-y		:= sunxi-sid.o
diff --git a/drivers/nvmem/sunxi-sid.c b/drivers/nvmem/sunxi-sid.c
new file mode 100644
index 0000000..5bfce35
--- /dev/null
+++ b/drivers/nvmem/sunxi-sid.c
@@ -0,0 +1,64 @@
+/*
+ * Allwinner sunXi SoCs Security ID support.
+ *
+ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include "nvmem-mmio.h"
+
+static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static struct nvmem_config econfig = {
+	.name = "sunix-sid",
+	.owner = THIS_MODULE,
+};
+
+static struct regmap_config sunxi_sid_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.writeable_reg = sunxi_sid_writeable_reg,
+};
+
+static struct nvmem_mmio_data sunxi_data = {
+	.nvmem_config = &econfig,
+	.regmap_config = &sunxi_sid_regmap_config,
+};
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-sid", .data = &sunxi_data},
+	{ .compatible = "allwinner,sun7i-a20-sid", .data = &sunxi_data},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = nvmem_mmio_probe,
+	.remove = nvmem_mmio_remove,
+	.driver = {
+		.name = "eeprom-sunxi-sid",
+		.of_match_table = sunxi_sid_of_match,
+	},
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1


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

* Re: [PATCH v5 01/11] regmap: Introduce regmap_get_max_register.
  2015-05-21 16:42           ` [PATCH v5 01/11] regmap: Introduce regmap_get_max_register Srinivas Kandagatla
@ 2015-05-22 11:18             ` Mark Brown
  0 siblings, 0 replies; 153+ messages in thread
From: Mark Brown @ 2015-05-22 11:18 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	s.hauer, Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, pantelis.antoniou, mporter

[-- Attachment #1: Type: text/plain, Size: 370 bytes --]

On Thu, May 21, 2015 at 05:42:43PM +0100, Srinivas Kandagatla wrote:
> This patch introduces regmap_get_max_register() function which would be
> used by the infrastructures like nvmem framework built on top of
> regmap.

Applied, thanks.  If the rest of the framework is ready to get merged
somewhere before it reaches Linus' tree let me know and we can handle it
then.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v5 02/11] regmap: Introduce regmap_get_reg_stride.
  2015-05-21 16:42           ` [PATCH v5 02/11] regmap: Introduce regmap_get_reg_stride Srinivas Kandagatla
@ 2015-05-22 11:19             ` Mark Brown
  0 siblings, 0 replies; 153+ messages in thread
From: Mark Brown @ 2015-05-22 11:19 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	s.hauer, Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, pantelis.antoniou, mporter

[-- Attachment #1: Type: text/plain, Size: 329 bytes --]

On Thu, May 21, 2015 at 05:42:54PM +0100, Srinivas Kandagatla wrote:
> This patch introduces regmap_get_reg_stride() function which would
> be used by the infrastructures like nvmem framework built on top of
> regmap. Mostly this function would be used for sanity checks on inputs
> within such infrastructure.

Applied, thanks.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v5 00/11] Add simple NVMEM Framework via regmap.
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
                             ` (10 preceding siblings ...)
  2015-05-21 16:45           ` [PATCH v5 10/11] nvmem: sunxi: Move the SID driver to the " Srinivas Kandagatla
@ 2015-05-25 16:51           ` Pantelis Antoniou
  2015-05-26  9:12             ` Srinivas Kandagatla
  2015-05-29  1:20           ` Dan Williams
  12 siblings, 1 reply; 153+ messages in thread
From: Pantelis Antoniou @ 2015-05-25 16:51 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, Sascha Hauer, Greg Kroah-Hartman, linux-api,
	Linux Kernel Mailing List, devicetree, linux-arm-msm,
	Arnd Bergmann, sboyd, Matt Porter

Hi Srinivas,

> On May 21, 2015, at 19:42 , Srinivas Kandagatla <srinivas.kandagatla@linaro.org> wrote:
> 
> Thankyou all for providing inputs and comments on previous versions of this patchset.
> Here is the v5 of the patchset addressing all the issues raised as
> part of previous versions review.
> 

> 

[snip]

I tried to use the updated patchset with my at24 & beaglebone capemanager patches.

I have a big problem with the removal of the raw of_* access APIs.

Take for instance the case where you have multiple slot accessing different EEPROMs.

> slots {
> 	slot@0 {
> 		eeprom = <&cape0_data>;
> 	};
> 
> 	slot@1 {
> 		eeprom = <&cape1_data>;
> 	};
> };

In that case there is no per-device node mapping; it’s a per-sub node.

For now I’m exporting the of_* accessors again, please consider exposing the of_* API again.

> -- 
> 1.9.1
> 

Regards

— Pantelis


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

* Re: [PATCH v5 00/11] Add simple NVMEM Framework via regmap.
  2015-05-25 16:51           ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Pantelis Antoniou
@ 2015-05-26  9:12             ` Srinivas Kandagatla
  2015-05-26 17:54               ` Pantelis Antoniou
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-26  9:12 UTC (permalink / raw)
  To: Pantelis Antoniou
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, Sascha Hauer, Greg Kroah-Hartman, linux-api,
	Linux Kernel Mailing List, devicetree, linux-arm-msm,
	Arnd Bergmann, sboyd, Matt Porter

Hi Pantelis,

On 25/05/15 17:51, Pantelis Antoniou wrote:
> Hi Srinivas,
>
>> On May 21, 2015, at 19:42 , Srinivas Kandagatla <srinivas.kandagatla@linaro.org> wrote:
>>
>> Thankyou all for providing inputs and comments on previous versions of this patchset.
>> Here is the v5 of the patchset addressing all the issues raised as
>> part of previous versions review.
>>
>
>>
>
> [snip]
>
> I tried to use the updated patchset with my at24 & beaglebone capemanager patches.
Thanks for trying it out and migrating at24 to it.

>
> I have a big problem with the removal of the raw of_* access APIs.
Ok,
>
> Take for instance the case where you have multiple slot accessing different EEPROMs.
>
>> slots {
>> 	slot@0 {
>> 		eeprom = <&cape0_data>;
>> 	};
>>
>> 	slot@1 {
>> 		eeprom = <&cape1_data>;
>> 	};
>> };

Can I ask you why should the slots be in sub-nodes?
Do you expect to have more properties associated with each slot in future?
Or is it just to get hold of eeprom data?

>
> In that case there is no per-device node mapping; it’s a per-sub node.
>
> For now I’m exporting the of_* accessors again, please consider exposing the of_* API again.
Sure, we can export of_nvmem_cell_get symbol for usecases like this.

Having said that, I got one comment on the way the nvmem is used in your 
case. You should try to use nvmem_device_get() and then use 
nvmem_device_read() apis, These apis are for consumers like this one. 
The advantage of this would be you do not need read and store all data 
in the driver and parse them internally. Basically your ee_field_get 
would just do nvmem_device_read(); Does it make sense?

We can work on how to get the of_*based once you decide to move to this api.



--srini
>
>> --
>> 1.9.1
>>
>
> Regards
>
> — Pantelis
>

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

* Re: [PATCH v5 00/11] Add simple NVMEM Framework via regmap.
  2015-05-26  9:12             ` Srinivas Kandagatla
@ 2015-05-26 17:54               ` Pantelis Antoniou
  0 siblings, 0 replies; 153+ messages in thread
From: Pantelis Antoniou @ 2015-05-26 17:54 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
	Mark Brown, Sascha Hauer, Greg Kroah-Hartman, linux-api,
	Linux Kernel Mailing List, devicetree, linux-arm-msm,
	Arnd Bergmann, sboyd, Matt Porter

Hi Srinivas,

> On May 26, 2015, at 12:12 , Srinivas Kandagatla <srinivas.kandagatla@linaro.org> wrote:
> 
> Hi Pantelis,
> 
> On 25/05/15 17:51, Pantelis Antoniou wrote:
>> Hi Srinivas,
>> 
>>> On May 21, 2015, at 19:42 , Srinivas Kandagatla <srinivas.kandagatla@linaro.org> wrote:
>>> 
>>> Thankyou all for providing inputs and comments on previous versions of this patchset.
>>> Here is the v5 of the patchset addressing all the issues raised as
>>> part of previous versions review.
>>> 
>> 
>>> 
>> 
>> [snip]
>> 
>> I tried to use the updated patchset with my at24 & beaglebone capemanager patches.
> Thanks for trying it out and migrating at24 to it.
> 

Don’t mention it…

>> 
>> I have a big problem with the removal of the raw of_* access APIs.
> Ok,
>> 
>> Take for instance the case where you have multiple slot accessing different EEPROMs.
>> 
>>> slots {
>>> 	slot@0 {
>>> 		eeprom = <&cape0_data>;
>>> 	};
>>> 
>>> 	slot@1 {
>>> 		eeprom = <&cape1_data>;
>>> 	};
>>> };
> 
> Can I ask you why should the slots be in sub-nodes?
> Do you expect to have more properties associated with each slot in future?
> Or is it just to get hold of eeprom data?
> 

For now I don’t have any more properties besides the eeprom phandle.
I’ve reworked capemanager to work with the API as it is, but it’s not very intuitive IMHO.

The problem is that I have both the baseboard and the slot eeproms in a single property list.

If more per-slot properties are required, I’ll have to add again the slots node and
then the nvmem eeprom handles would stick out like a sore thumb.

>> 
>> In that case there is no per-device node mapping; it’s a per-sub node.
>> 
>> For now I’m exporting the of_* accessors again, please consider exposing the of_* API again.
> Sure, we can export of_nvmem_cell_get symbol for usecases like this.
> 
> Having said that, I got one comment on the way the nvmem is used in your case. You should try to use nvmem_device_get() and then use nvmem_device_read() apis, These apis are for consumers like this one. The advantage of this would be you do not need read and store all data in the driver and parse them internally. Basically your ee_field_get would just do nvmem_device_read(); Does it make sense?
> 

Hmm, good idea; I’ll give it a shot.

> We can work on how to get the of_*based once you decide to move to this api.
> 
> 

OK, thanks a lot for taking the time to think about this Srinivas.

> 
> --srini
>> 

Regards

— Pantelis

>>> --
>>> 1.9.1
>>> 
>> 
>> Regards
>> 
>> — Pantelis
>> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v5 00/11] Add simple NVMEM Framework via regmap.
  2015-05-21 16:42         ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Srinivas Kandagatla
                             ` (11 preceding siblings ...)
  2015-05-25 16:51           ` [PATCH v5 00/11] Add simple NVMEM Framework via regmap Pantelis Antoniou
@ 2015-05-29  1:20           ` Dan Williams
  2015-05-29  7:09             ` Srinivas Kandagatla
  12 siblings, 1 reply; 153+ messages in thread
From: Dan Williams @ 2015-05-29  1:20 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Greg Kroah-Hartman,
	Sascha Hauer, sboyd, Linux Kernel Mailing List,
	pantelis.antoniou, Rob Herring, Mark Brown, Kumar Gala, mporter,
	Maxime Ripard, linux-api, linux-arm-msm

On Thu, May 21, 2015 at 9:42 AM, Srinivas Kandagatla
<srinivas.kandagatla@linaro.org> wrote:
> Thankyou all for providing inputs and comments on previous versions of this patchset.
> Here is the v5 of the patchset addressing all the issues raised as
> part of previous versions review.
>
> This patchset adds a new simple NVMEM framework to kernel.
>
> Up until now, NVMEM drivers were stored in drivers/misc, where they all had to
> duplicate pretty much the same code to register a sysfs file, allow in-kernel
> users to access the content of the devices they were driving, etc.
>
> This was also a problem as far as other in-kernel users were involved, since
> the solutions used were pretty much different from on driver to another, there
> was a rather big abstraction leak.
>
> Introduction of this framework aims at solving this. It also introduces DT
> representation for consumer devices to go get the data they require (MAC
> Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs.
>
> After learning few things about QCOM qfprom and other eeprom/efuses, which
> has packed fields at bit level. Which makes it important to add support to
> such memories. This version adds support to this type of non volatile
> memories by adding support to bit level nvmem-cells.
>
> Having regmap interface to this framework would give much better
> abstraction for nvmems on different buses.
>
> patch 1-2 Introduces two regmap helper functions.
> patch 3-6 Introduces the NVMEM framework.
> Patch 7 Adds helper functions for nvmems based on mmio.
> Patch 8 migrates an existing driver to nvmem framework.
> Patch 9-10 Adds Qualcomm specific qfprom driver.
> Patch 11 adds entry in MAINTAINERS.
>
> Its also possible to migrate other nvmem drivers to this framework.
>
> Providers APIs:
>         nvmem_register/unregister();
>
> Consumers APIs:
> Cell based apis for both DT/Non-DT:
>         nvmem_cell_get()/nvmem_cell_put();
>         nvmem_cell_read()/nvmem_cell_write();
>
> Raw byte access apis for both DT/non-DT.
>         nvmem_device_get()/nvmem_device_put()
>         nvmem_device_read()/nvmem_device_write();
>         nvmem_device_cell_read()/nvmem_device_cell_write();
>
> Device Tree:
>
>         /* Provider */
>         qfprom: qfprom@00700000 {
>                 ...
>
>                 /* Data cells */
>                 tsens_calibration: calib@404 {
>                         reg = <0x404 0x10>;
>                 };
>
>                 tsens_calibration_bckp: calib_bckp@504 {
>                         reg = <0x504 0x11>;
>                         bit-offset = 6;
>                         nbits = 128;
>                 };
>
>                 pvs_version: pvs-version@6 {
>                         reg = <0x6 0x2>
>                         bit-offset = 7;
>                         nbits = 2;
>                 };
>
>                 speed_bin: speed-bin@c{
>                         reg = <0xc 0x1>;
>                         bit-offset = 2;
>                         nbits   = 3;
>
>                 };
>                 ...
>         };
>
> userspace interface: binary file in /sys/class/nvmem/*/nvmem
>
> ex:
> hexdump /sys/class/nvmem/qfprom0/nvmem
>
> 0000000 0000 0000 0000 0000 0000 0000 0000 0000
> *
> 00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
> 0000000 0000 0000 0000 0000 0000 0000 0000 0000
> ...
> *
> 0001000
>
> Changes since v4(https://lkml.org/lkml/2015/3/30/725)
>  * rename eeprom to nvmem suggested by Matt Porter

Apologies for the bikeshed fly-by review, but given we already have
NVME and are adding an NVDIMM driver sub-system is s/eeprom/nvmem/ a
good idea?

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

* Re: [PATCH v5 00/11] Add simple NVMEM Framework via regmap.
  2015-05-29  1:20           ` Dan Williams
@ 2015-05-29  7:09             ` Srinivas Kandagatla
  2015-05-29 21:44               ` Dan Williams
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-05-29  7:09 UTC (permalink / raw)
  To: Dan Williams
  Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Greg Kroah-Hartman,
	Sascha Hauer, sboyd, Linux Kernel Mailing List,
	pantelis.antoniou, Rob Herring, Mark Brown, Kumar Gala, mporter,
	Maxime Ripard, linux-api, linux-arm-msm



On 29/05/15 02:20, Dan Williams wrote:
> On Thu, May 21, 2015 at 9:42 AM, Srinivas Kandagatla
> <srinivas.kandagatla@linaro.org> wrote:
>> Thankyou all for providing inputs and comments on previous versions of this patchset.
>> Here is the v5 of the patchset addressing all the issues raised as
>> part of previous versions review.
>>
>> This patchset adds a new simple NVMEM framework to kernel.
>>
>> Up until now, NVMEM drivers were stored in drivers/misc, where they all had to
>> duplicate pretty much the same code to register a sysfs file, allow in-kernel
>> users to access the content of the devices they were driving, etc.
>>
>> This was also a problem as far as other in-kernel users were involved, since
>> the solutions used were pretty much different from on driver to another, there
>> was a rather big abstraction leak.
>>
>> Introduction of this framework aims at solving this. It also introduces DT
>> representation for consumer devices to go get the data they require (MAC
>> Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs.
>>
>> After learning few things about QCOM qfprom and other eeprom/efuses, which
>> has packed fields at bit level. Which makes it important to add support to
>> such memories. This version adds support to this type of non volatile
>> memories by adding support to bit level nvmem-cells.
>>
>> Having regmap interface to this framework would give much better
>> abstraction for nvmems on different buses.
>>
>> patch 1-2 Introduces two regmap helper functions.
>> patch 3-6 Introduces the NVMEM framework.
>> Patch 7 Adds helper functions for nvmems based on mmio.
>> Patch 8 migrates an existing driver to nvmem framework.
>> Patch 9-10 Adds Qualcomm specific qfprom driver.
>> Patch 11 adds entry in MAINTAINERS.
>>
>> Its also possible to migrate other nvmem drivers to this framework.
>>
>> Providers APIs:
>>          nvmem_register/unregister();
>>
>> Consumers APIs:
>> Cell based apis for both DT/Non-DT:
>>          nvmem_cell_get()/nvmem_cell_put();
>>          nvmem_cell_read()/nvmem_cell_write();
>>
>> Raw byte access apis for both DT/non-DT.
>>          nvmem_device_get()/nvmem_device_put()
>>          nvmem_device_read()/nvmem_device_write();
>>          nvmem_device_cell_read()/nvmem_device_cell_write();
>>
>> Device Tree:
>>
>>          /* Provider */
>>          qfprom: qfprom@00700000 {
>>                  ...
>>
>>                  /* Data cells */
>>                  tsens_calibration: calib@404 {
>>                          reg = <0x404 0x10>;
>>                  };
>>
>>                  tsens_calibration_bckp: calib_bckp@504 {
>>                          reg = <0x504 0x11>;
>>                          bit-offset = 6;
>>                          nbits = 128;
>>                  };
>>
>>                  pvs_version: pvs-version@6 {
>>                          reg = <0x6 0x2>
>>                          bit-offset = 7;
>>                          nbits = 2;
>>                  };
>>
>>                  speed_bin: speed-bin@c{
>>                          reg = <0xc 0x1>;
>>                          bit-offset = 2;
>>                          nbits   = 3;
>>
>>                  };
>>                  ...
>>          };
>>
>> userspace interface: binary file in /sys/class/nvmem/*/nvmem
>>
>> ex:
>> hexdump /sys/class/nvmem/qfprom0/nvmem
>>
>> 0000000 0000 0000 0000 0000 0000 0000 0000 0000
>> *
>> 00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
>> 0000000 0000 0000 0000 0000 0000 0000 0000 0000
>> ...
>> *
>> 0001000
>>
>> Changes since v4(https://lkml.org/lkml/2015/3/30/725)
>>   * rename eeprom to nvmem suggested by Matt Porter
>
> Apologies for the bikeshed fly-by review, but given we already have
> NVME and are adding an NVDIMM driver sub-system is s/eeprom/nvmem/ a
> good idea?
>
IMO yes.

I did briefly looked at NVME before renaming the eeprom to nvmem,
NVME is aimed at defining the command/feature set for PCIe-based SSDs 
with the goals of increased and efficient performance and interoperability.

This patch-set introduces simple nvmem which is applicable for non 
volatile memories like efuses, eeprom, ROM, NVRAM .. etc, which are used 
in most boards/SBC's. Data like calibration table, mac address or opps, 
are generally stored this. This data is required by multiple drivers and 
currently there is no framework in the kernel to address/abstract this, 
resulting in code duplication.


--srini

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

* Re: [PATCH v5 00/11] Add simple NVMEM Framework via regmap.
  2015-05-29  7:09             ` Srinivas Kandagatla
@ 2015-05-29 21:44               ` Dan Williams
  0 siblings, 0 replies; 153+ messages in thread
From: Dan Williams @ 2015-05-29 21:44 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-msm, devicetree, Arnd Bergmann, Greg Kroah-Hartman,
	Sascha Hauer, sboyd, Linux Kernel Mailing List,
	Pantelis Antoniou, Rob Herring, Mark Brown, Kumar Gala,
	Matthew Porter, Maxime Ripard, linux-api, linux-arm-kernel

On Fri, May 29, 2015 at 12:09 AM, Srinivas Kandagatla
<srinivas.kandagatla@linaro.org> wrote:
>
>
> On 29/05/15 02:20, Dan Williams wrote:
>>
>> On Thu, May 21, 2015 at 9:42 AM, Srinivas Kandagatla
>> <srinivas.kandagatla@linaro.org> wrote:
>>>
>>> Thankyou all for providing inputs and comments on previous versions of
>>> this patchset.
>>> Here is the v5 of the patchset addressing all the issues raised as
>>> part of previous versions review.
>>>
>>> This patchset adds a new simple NVMEM framework to kernel.
>>>
>>> Up until now, NVMEM drivers were stored in drivers/misc, where they all
>>> had to
>>> duplicate pretty much the same code to register a sysfs file, allow
>>> in-kernel
>>> users to access the content of the devices they were driving, etc.
>>>
>>> This was also a problem as far as other in-kernel users were involved,
>>> since
>>> the solutions used were pretty much different from on driver to another,
>>> there
>>> was a rather big abstraction leak.
>>>
>>> Introduction of this framework aims at solving this. It also introduces
>>> DT
>>> representation for consumer devices to go get the data they require (MAC
>>> Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs.
>>>
>>> After learning few things about QCOM qfprom and other eeprom/efuses,
>>> which
>>> has packed fields at bit level. Which makes it important to add support
>>> to
>>> such memories. This version adds support to this type of non volatile
>>> memories by adding support to bit level nvmem-cells.
>>>
>>> Having regmap interface to this framework would give much better
>>> abstraction for nvmems on different buses.
>>>
>>> patch 1-2 Introduces two regmap helper functions.
>>> patch 3-6 Introduces the NVMEM framework.
>>> Patch 7 Adds helper functions for nvmems based on mmio.
>>> Patch 8 migrates an existing driver to nvmem framework.
>>> Patch 9-10 Adds Qualcomm specific qfprom driver.
>>> Patch 11 adds entry in MAINTAINERS.
>>>
>>> Its also possible to migrate other nvmem drivers to this framework.
>>>
>>> Providers APIs:
>>>          nvmem_register/unregister();
>>>
>>> Consumers APIs:
>>> Cell based apis for both DT/Non-DT:
>>>          nvmem_cell_get()/nvmem_cell_put();
>>>          nvmem_cell_read()/nvmem_cell_write();
>>>
>>> Raw byte access apis for both DT/non-DT.
>>>          nvmem_device_get()/nvmem_device_put()
>>>          nvmem_device_read()/nvmem_device_write();
>>>          nvmem_device_cell_read()/nvmem_device_cell_write();
>>>
>>> Device Tree:
>>>
>>>          /* Provider */
>>>          qfprom: qfprom@00700000 {
>>>                  ...
>>>
>>>                  /* Data cells */
>>>                  tsens_calibration: calib@404 {
>>>                          reg = <0x404 0x10>;
>>>                  };
>>>
>>>                  tsens_calibration_bckp: calib_bckp@504 {
>>>                          reg = <0x504 0x11>;
>>>                          bit-offset = 6;
>>>                          nbits = 128;
>>>                  };
>>>
>>>                  pvs_version: pvs-version@6 {
>>>                          reg = <0x6 0x2>
>>>                          bit-offset = 7;
>>>                          nbits = 2;
>>>                  };
>>>
>>>                  speed_bin: speed-bin@c{
>>>                          reg = <0xc 0x1>;
>>>                          bit-offset = 2;
>>>                          nbits   = 3;
>>>
>>>                  };
>>>                  ...
>>>          };
>>>
>>> userspace interface: binary file in /sys/class/nvmem/*/nvmem
>>>
>>> ex:
>>> hexdump /sys/class/nvmem/qfprom0/nvmem
>>>
>>> 0000000 0000 0000 0000 0000 0000 0000 0000 0000
>>> *
>>> 00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
>>> 0000000 0000 0000 0000 0000 0000 0000 0000 0000
>>> ...
>>> *
>>> 0001000
>>>
>>> Changes since v4(https://lkml.org/lkml/2015/3/30/725)
>>>   * rename eeprom to nvmem suggested by Matt Porter
>>
>>
>> Apologies for the bikeshed fly-by review, but given we already have
>> NVME and are adding an NVDIMM driver sub-system is s/eeprom/nvmem/ a
>> good idea?
>>
> IMO yes.
>
> I did briefly looked at NVME before renaming the eeprom to nvmem,
> NVME is aimed at defining the command/feature set for PCIe-based SSDs with
> the goals of increased and efficient performance and interoperability.
>
> This patch-set introduces simple nvmem which is applicable for non volatile
> memories like efuses, eeprom, ROM, NVRAM .. etc, which are used in most
> boards/SBC's. Data like calibration table, mac address or opps, are
> generally stored this. This data is required by multiple drivers and
> currently there is no framework in the kernel to address/abstract this,
> resulting in code duplication.

Understood, but don't be surprised when people confuse NVMEM support
(sub to single digit megabyte capacities for firmware) and NVDIMM
support (multiple gigabyte capacities for i/o).

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

* Re: [PATCH v5 04/11] nvmem: Add a simple NVMEM framework for consumers
  2015-05-21 16:43           ` [PATCH v5 04/11] nvmem: Add a simple NVMEM framework for consumers Srinivas Kandagatla
@ 2015-06-16 22:29             ` Stephen Boyd
  2015-06-17  8:00               ` Sascha Hauer
  2015-06-18 12:56               ` Srinivas Kandagatla
  0 siblings, 2 replies; 153+ messages in thread
From: Stephen Boyd @ 2015-06-16 22:29 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-arm-kernel
  Cc: devicetree, arnd, Greg Kroah-Hartman, s.hauer, linux-kernel,
	pantelis.antoniou, Rob Herring, Mark Brown, Kumar Gala, mporter,
	Maxime Ripard, linux-api, linux-arm-msm

On 05/21/2015 09:43 AM, Srinivas Kandagatla wrote:
> @@ -379,6 +380,351 @@ int nvmem_unregister(struct nvmem_device *nvmem)
[...]
> +
> +	return nvmem;
> +}
> +
> +static int __nvmem_device_put(struct nvmem_device *nvmem)

Why does this return int? It's not used anywhere.

> +{
> +	module_put(nvmem->owner);
> +	mutex_lock(&nvmem_mutex);
> +	nvmem->users--;
> +	mutex_unlock(&nvmem_mutex);
> +
> +	return 0;
> +}
> +
> +static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id)
> +{
> +	struct nvmem_cell *cell = NULL;
> +	struct nvmem_device *nvmem;
> +
> +	nvmem = __nvmem_device_get(NULL, &cell, cell_id);
> +	if (IS_ERR(nvmem))
> +		return (struct nvmem_cell *)nvmem;

ERR_CAST?

> +
> +
> +	return cell;
> +
> +}
> +
> +static struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
> +					    const char *name)
> +{
> +	struct device_node *cell_np, *nvmem_np;
> +	struct nvmem_cell *cell;
> +	struct nvmem_device *nvmem;
> +	const __be32 *addr;
> +	int rval, len, index;
> +
> +	index = of_property_match_string(np, "nvmem-cell-names", name);
> +
> +	cell_np = of_parse_phandle(np, "nvmem-cell", index);
> +	if (!cell_np)
> +		return ERR_PTR(-EINVAL);
> +
> +	nvmem_np = of_get_next_parent(cell_np);
> +	if (!nvmem_np)
> +		return ERR_PTR(-EINVAL);
> +
> +	nvmem = __nvmem_device_get(nvmem_np, NULL, NULL);
> +	if (IS_ERR(nvmem))
> +		return (struct nvmem_cell *)nvmem;

ERR_CAST?

> +
> +	addr = of_get_property(cell_np, "reg", &len);
> +	if (!addr || (len < 2 * sizeof(int))) {
> +		dev_err(&nvmem->dev, "of_i2c: invalid reg on %s\n",

huh? of_i2c?


> +
> +	/* if it's not end on byte boundary */
> +	if ((nbits + bit_offset) % BITS_PER_BYTE) {
> +		/* setup the last byte with msb bits from nvmem */
> +		rc = regmap_raw_read(nvmem->regmap,
> +				    cell->offset + cell->bytes - 1, &v, 1);
> +		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
> +
> +	}
> +
> +	return buf;
> +}
> +
> +/**
> + * nvmem_cell_write(): Write to a given nvmem cell

This isn't kernel doc notation. It should be like

    nvmem_cell_write - Write to a given nvmem cell

> + *
> + * @cell: nvmem cell to be written.
> + * @buf: Buffer to be written.
> + * @len: length of buffer to be written to nvmem cell.
> + *
> + * The return value will be an length of bytes written or non zero on failure.
> + */
> +int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len)
[..]
> +
>  static int nvmem_init(void)
>  {
>  	return class_register(&nvmem_class);
> diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
> new file mode 100644
> index 0000000..c3fa8c7
> --- /dev/null
> +++ b/include/linux/nvmem-consumer.h
> @@ -0,0 +1,49 @@
> +/*
> + * nvmem framework consumer.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_NVMEM_CONSUMER_H
> +#define _LINUX_NVMEM_CONSUMER_H
> +
> +/* consumer cookie */
> +struct nvmem_cell;
> +
> +#if IS_ENABLED(CONFIG_NVMEM)
> +
> +/* Cell based interface */
> +struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);

We should probably forward declare struct device in this file too.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v5 03/11] nvmem: Add a simple NVMEM framework for nvmem providers
  2015-05-21 16:43           ` [PATCH v5 03/11] nvmem: Add a simple NVMEM framework for nvmem providers Srinivas Kandagatla
@ 2015-06-16 22:43             ` Stephen Boyd
  2015-06-18 12:46               ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Stephen Boyd @ 2015-06-16 22:43 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter

On 05/21/2015 09:43 AM, Srinivas Kandagatla wrote:
>
> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> new file mode 100644
> index 0000000..6c2f0b1
> --- /dev/null
> +++ b/drivers/nvmem/core.c
> @@ -0,0 +1,398 @@
> +/*
> + * nvmem framework core.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/nvmem-provider.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/idr.h>
> +#include <linux/init.h>
> +#include <linux/regmap.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>

Is this include used?

> +
> +static int of_nvmem_match(struct device *dev, const void *nvmem_np)
> +{
> +	return dev->of_node == nvmem_np;
> +}
> +
> +static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)

const?

> +{
> +	struct device *d;
> +
> +	if (!nvmem_np)
> +		return NULL;
> +
> +	d = class_find_device(&nvmem_class, NULL, nvmem_np, of_nvmem_match);
> +
> +	return d ? to_nvmem_device(d) : NULL;
> +}
> +
> +static struct nvmem_cell *nvmem_find_cell(const char *cell_id)
> +{
> +	struct nvmem_cell *p;
> +
> +	list_for_each_entry(p, &nvmem_cells, node) {

Unnecessary braces.

> +		if (p && !strcmp(p->name, cell_id))
> +			return p;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void nvmem_cell_drop(struct nvmem_cell *cell)
> +{
> +	mutex_lock(&nvmem_cells_mutex);
> +	list_del(&cell->node);
> +	mutex_unlock(&nvmem_cells_mutex);
> +	kfree(cell);
> +}
> +
> +static void nvmem_device_remove_all_cells(struct nvmem_device *nvmem)
> +{
> +	struct nvmem_cell *cell = NULL;

Unnecessary initialization

> +	struct list_head *p, *n;
> +
> +	list_for_each_safe(p, n, &nvmem_cells) {
> +		cell = list_entry(p, struct nvmem_cell, node);
> +		if (cell->nvmem == nvmem)
> +			nvmem_cell_drop(cell);
> +	}
[..]
> +
> +static int nvmem_add_cells(struct nvmem_device *nvmem,
> +			   struct nvmem_config *cfg)
> +{
> +	struct nvmem_cell **cells;
> +	struct nvmem_cell_info *info = cfg->cells;
> +	int i, rval;
> +
> +	cells = kzalloc(sizeof(*cells) * cfg->ncells, GFP_KERNEL);

kcalloc

> +	if (!cells)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < cfg->ncells; i++) {
> +		cells[i] = kzalloc(sizeof(struct nvmem_cell), GFP_KERNEL);

sizeof(**cells) ?

> +		if (!cells[i]) {
> +			rval = -ENOMEM;
> +			goto err;
> +		}
> +
> +		rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]);
> +		if (IS_ERR_VALUE(rval)) {
> +			kfree(cells[i]);
> +			goto err;
> +		}
> +
> +		nvmem_cell_add(cells[i]);
> +	}
> +
> +	nvmem->ncells = cfg->ncells;
> +	/* remove tmp array */
> +	kfree(cells);
> +
> +	return 0;
> +err:
> +	while (--i)
> +		nvmem_cell_drop(cells[i]);
> +
> +	return rval;
> +}
> +
> +/**
> + * nvmem_register(): Register a nvmem device for given nvmem.
> + * Also creates an binary entry in /sys/class/nvmem/dev-name/nvmem
> + *
> + * @nvmem: nvmem device that needs to be created

You mean @config?

> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to nvmem_device.
> + */
> +
> +struct nvmem_device *nvmem_register(struct nvmem_config *config)
> +{
> +	struct nvmem_device *nvmem;
> +	struct regmap *rm;
> +	int rval;
> +
> +	if (!config->dev)
> +		return ERR_PTR(-EINVAL);
> +
> +	rm = dev_get_regmap(config->dev, NULL);
> +	if (!rm) {
> +		dev_err(config->dev, "Regmap not found\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
> +	if (!nvmem)
> +		return ERR_PTR(-ENOMEM);
> +
> +	nvmem->id = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL);
> +	if (nvmem->id < 0) {
> +		kfree(nvmem);
> +		return ERR_PTR(nvmem->id);
> +	}
> +
> +	nvmem->regmap = rm;
> +	nvmem->owner = config->owner;
> +	nvmem->stride = regmap_get_reg_stride(rm);
> +	nvmem->word_size = regmap_get_val_bytes(rm);
> +	nvmem->size = regmap_get_max_register(rm) + nvmem->stride;
> +	nvmem->dev.class = &nvmem_class;
> +	nvmem->dev.parent = config->dev;
> +	nvmem->dev.of_node = config->dev->of_node;
> +	dev_set_name(&nvmem->dev, "%s%d",
> +		     config->name ? : "nvmem", config->id);

It may be better to always name it nvmem%d so that we don't allow the
possibility of conflicts.

> +
> +	nvmem->read_only = of_property_read_bool(nvmem->dev.of_node,
> +						 "read-only");

What if we're not using DT? How would we specify read_only?

> +
> +	device_initialize(&nvmem->dev);
> +
> +	dev_dbg(&nvmem->dev, "Registering nvmem device %s\n",
> +		dev_name(&nvmem->dev));
> +
> +	rval = device_add(&nvmem->dev);
> +	if (rval) {
> +		ida_simple_remove(&nvmem_ida, nvmem->id);
> +		kfree(nvmem);
> +		return ERR_PTR(rval);
> +	}
> +
> +	/* update sysfs attributes */
> +	if (nvmem->read_only)
> +		sysfs_update_group(&nvmem->dev.kobj, &nvmem_bin_ro_group);

It would be nice if this could be done before the device was registered.
Perhaps have two device_types, one for read-only and one for read/write?

> +
> +	if (config->cells)
> +		nvmem_add_cells(nvmem, config);
> +
> +	return nvmem;
> +}
> +EXPORT_SYMBOL_GPL(nvmem_register);
> +
> +/**
> + * nvmem_unregister(): Unregister previously registered nvmem device
> + *
> + * @nvmem: Pointer to previously registered nvmem device.
> + *
> + * The return value will be an non zero on error or a zero on success.
> + */
> +int nvmem_unregister(struct nvmem_device *nvmem)
> +{
> +	mutex_lock(&nvmem_mutex);
> +	if (nvmem->users) {
> +		mutex_unlock(&nvmem_mutex);
> +		return -EBUSY;

Hmm... that doesn't seem nice. Typically when something is unregistered
we have to pull the rug out from underneath the users and start
returning errors to them. The provider needs to be free to unregister
because it's been forcibly removed. So really this function should
return void.

> +	}
> +	mutex_unlock(&nvmem_mutex);
> +
> +	nvmem_device_remove_all_cells(nvmem);
> +	device_del(&nvmem->dev);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(nvmem_unregister);
> +
> +static int nvmem_init(void)

__init? And __exit on nvmem_exit?

> +{
> +	return class_register(&nvmem_class);

I thought class was on the way out? Aren't we supposed to use bus types
for new stuff?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v5 05/11] nvmem: Add nvmem_device based consumer apis.
  2015-05-21 16:43           ` [PATCH v5 05/11] nvmem: Add nvmem_device based consumer apis Srinivas Kandagatla
@ 2015-06-16 22:49             ` Stephen Boyd
  2015-06-18 12:57               ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Stephen Boyd @ 2015-06-16 22:49 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter

On 05/21/2015 09:43 AM, Srinivas Kandagatla wrote:
> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> index 8a4b358..68ee8d1 100644
> --- a/drivers/nvmem/core.c
> +++ b/drivers/nvmem/core.c
> @@ -436,6 +436,51 @@ static int __nvmem_device_put(struct nvmem_device *nvmem)
>  	return 0;
>  }
>  
> +static int nvmem_match(struct device *dev, const void *data)
> +{
> +	return !strcmp(dev_name(dev), (const char *)data);

Unnecessary cast.

> +}
> +
> +static struct nvmem_device *nvmem_find(const char *name)
> +{
> +	struct device *d;
> +
> +	d = class_find_device(&nvmem_class, NULL, (void *)name, nvmem_match);

Unnecessary cast

> +
> +	return d ? to_nvmem_device(d) : NULL;
> +}

[...]
> +
> +void nvmem_device_put(struct nvmem_device *nvmem)
> +{
> +	__nvmem_device_put(nvmem);
> +}
> +EXPORT_SYMBOL_GPL(nvmem_device_put);
>
> +int nvmem_device_cell_read(struct nvmem_device *nvmem,
> +			   struct nvmem_cell_info *info, void *buf)
> +{
> +}
> +EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
> +
> +int nvmem_device_cell_write(struct nvmem_device *nvmem,
> +			    struct nvmem_cell_info *info, void *buf)
> +{
> +}
> +EXPORT_SYMBOL_GPL(nvmem_device_cell_write);
> +
> +int nvmem_device_read(struct nvmem_device *nvmem,
> +		      unsigned int offset,
> +		      size_t bytes, void *buf)
> +{
> +}
> +EXPORT_SYMBOL_GPL(nvmem_device_read);
> +
> +int nvmem_device_write(struct nvmem_device *nvmem,
> +		       unsigned int offset,
> +		       size_t bytes, void *buf)
> +{
> +}
> +EXPORT_SYMBOL_GPL(nvmem_device_write);

Can you please add kernel-doc on these exported APIs?

> +
>  static int nvmem_init(void)
>  {
>  	return class_register(&nvmem_class);
> diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
> index c3fa8c7..66c67ba 100644
> --- a/include/linux/nvmem-consumer.h
> +++ b/include/linux/nvmem-consumer.h
> @@ -23,6 +32,18 @@ void nvmem_cell_put(struct nvmem_cell *cell);
>  void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len);
>  int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len);
>  
> +/* direct nvmem device read/write interface */
> +struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
> +void nvmem_device_put(struct nvmem_device *nvmem);
> +int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
> +		      size_t bytes, void *buf);
> +int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset,
> +		       size_t bytes, void *buf);
> +int nvmem_device_cell_read(struct nvmem_device *nvmem,
> +			   struct nvmem_cell_info *info, void *buf);
> +int nvmem_device_cell_write(struct nvmem_device *nvmem,
> +			    struct nvmem_cell_info *info, void *buf);
> +

Can we also have devm_nvmem_*_get() APIs please?

> diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
> index 4908b37..7a982cd 100644
> --- a/include/linux/nvmem-provider.h
> +++ b/include/linux/nvmem-provider.h
> @@ -12,15 +12,9 @@
>  #ifndef _LINUX_NVMEM_PROVIDER_H
>  #define _LINUX_NVMEM_PROVIDER_H
>  
> -struct nvmem_device;
> +#include <linux/nvmem-consumer.h>
>  
> -struct nvmem_cell_info {
> -	const char		*name;
> -	int			offset;
> -	int			bytes;
> -	int			bit_offset;
> -	int			nbits;
> -};
> +struct nvmem_device;

Should this diff be part of an earlier patch?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v5 06/11] nvmem: Add bindings for simple nvmem framework
  2015-05-21 16:44           ` [PATCH v5 06/11] nvmem: Add bindings for simple nvmem framework Srinivas Kandagatla
@ 2015-06-16 22:53             ` Stephen Boyd
  2015-06-18 13:01               ` Srinivas Kandagatla
  2015-06-19 10:36             ` maitysanchayan
  1 sibling, 1 reply; 153+ messages in thread
From: Stephen Boyd @ 2015-06-16 22:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter

On 05/21/2015 09:44 AM, Srinivas Kandagatla wrote:
> diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.txt b/Documentation/devicetree/bindings/nvmem/nvmem.txt
> new file mode 100644
> index 0000000..ecea654
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/nvmem/nvmem.txt
> @@ -0,0 +1,84 @@
> += NVMEM Data Device Tree Bindings =
> +
> +This binding is intended to represent the location of hardware
> +configuration data stored in NVMEMs.

It would be worthwhile spelling out what NVMEM stands for.

> +
> +On a significant proportion of boards, the manufacturer has stored
> +some data on NVMEM, for the OS to be able to retrieve these information
> +and act upon it. Obviously, the OS has to know about where to retrieve
> +these data from, and where they are stored on the storage device.
> +
> +This document is here to document this.
> +
> += Data providers =
> +Contains bindings specific to provider drivers and data cells as children
> +to this node.

children of this node?

> +
> +Optional properties:
> + read-only: Mark the provider as read only.
> +
> += Data cells =
> +These are the child nodes of the provider which contain data cell
> +information like offset and size in nvmem provider.
> +
> +Required properties:
> +reg:	specifies the offset in byte within that storage device, start bit
> +	in the byte and the length in bits of the data we care about.
> +	There could be more then one offset-length pairs in this property.

s/then/than/

> +
> +Optional properties:
> +
> +bit-offset: specifies the offset in bit within the address range specified
> +	by reg property. Can take values from 0-7.
> +nbits: specifies number of bits this cell occupies starting from bit-offset.
> +

Hopefully the consumer knows the endianness of the data stored.

> +For example:
> +
> +	/* Provider */
> +	qfprom: qfprom@00700000 {
> +		...
> +
> +		/* Data cells */
> +		tsens_calibration: calib@404 {
> +			reg = <0x404 0x10>;
> +		};
> +
> +		tsens_calibration_bckp: calib_bckp@504 {
> +			reg = <0x504 0x11>;
> +			bit-offset = 6;
> +			nbits = 128;
> +		};
> +
> +		pvs_version: pvs-version@6 {
> +			reg = <0x6 0x2>
> +			bit-offset = 7;
> +			nbits = 2;
> +		};
> +
> +		speed_bin: speed-bin@c{
> +			reg = <0xc 0x1>;
> +			bit-offset = 2;
> +			nbits	= 3;
> +
> +		};
> +		...
> +	};
> +
> += Data consumers =
> +Are device nodes which consume nvmem data cells/providers.
> +
> +Required-properties:
> +nvmem-cell: list of phandle to the nvmem data cells.
> +nvmem-cell-names: names for the each nvmem-cell specified
> +
> +Optional-properties:
> +nvmem	: list of phandles to nvmem providers.
> +nvmem-names: names for the each nvmem provider.

Is nvmem-names required if nvmem is used?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v5 07/11] nvmem: Add simple nvmem-mmio consumer helper functions.
  2015-05-21 16:44           ` [PATCH v5 07/11] nvmem: Add simple nvmem-mmio consumer helper functions Srinivas Kandagatla
@ 2015-06-16 22:58             ` Stephen Boyd
  2015-06-18 13:08               ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Stephen Boyd @ 2015-06-16 22:58 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter

On 05/21/2015 09:44 AM, Srinivas Kandagatla wrote:
> diff --git a/drivers/nvmem/nvmem-mmio.c b/drivers/nvmem/nvmem-mmio.c
> new file mode 100644
> index 0000000..0d8131f
> --- /dev/null
> +++ b/drivers/nvmem/nvmem-mmio.c
> @@ -0,0 +1,69 @@
> +/*
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>

#include <linux/platform_device.h>
#include <linux/nvmem_provider.h>
#include <linux/regmap.h>

> +#include "nvmem-mmio.h"
> +
> +int nvmem_mmio_remove(struct platform_device *pdev)
> +{
> +	struct nvmem_device *nvmem = platform_get_drvdata(pdev);
> +
> +	return nvmem_unregister(nvmem);
> +}
> +EXPORT_SYMBOL_GPL(nvmem_mmio_remove);
> +
> +int nvmem_mmio_probe(struct platform_device *pdev)
> +{
> +
[...]
> +
> +	platform_set_drvdata(pdev, nvmem);

It may be better to return the nvmem device instead so that the one
drvdata member is usable by the calling driver.

> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(nvmem_mmio_probe);

Kernel-doc on these exported functions?

> diff --git a/drivers/nvmem/nvmem-mmio.h b/drivers/nvmem/nvmem-mmio.h
> new file mode 100644
> index 0000000..a2ad4e5
> --- /dev/null
> +++ b/drivers/nvmem/nvmem-mmio.h
> @@ -0,0 +1,41 @@
> +/*
> + * MMIO based nvmem providers.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_NVMEM_MMIO_H
> +#define _LINUX_NVMEM_MMIO_H
> +
> +#include <linux/platform_device.h>

Forward declare struct platform_device instead.

> +#include <linux/nvmem-provider.h>

Forward declare nvmem_config instead.

> +#include <linux/regmap.h>

Forward declare regmap_config instead.

> +
> +struct nvmem_mmio_data {
> +	struct regmap_config *regmap_config;
> +	struct nvmem_config *nvmem_config;
> +};
> +
> +#if IS_ENABLED(CONFIG_NVMEM)
> +
> +int nvmem_mmio_probe(struct platform_device *pdev);
> +int nvmem_mmio_remove(struct platform_device *pdev);

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v5 08/11] nvmem: qfprom: Add Qualcomm QFPROM support.
  2015-05-21 16:44           ` [PATCH v5 08/11] nvmem: qfprom: Add Qualcomm QFPROM support Srinivas Kandagatla
@ 2015-06-16 23:00             ` Stephen Boyd
  2015-06-18 13:22               ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Stephen Boyd @ 2015-06-16 23:00 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter

On 05/21/2015 09:44 AM, Srinivas Kandagatla wrote:
> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
> index f157b6d..e665e23 100644
> --- a/drivers/nvmem/Kconfig
> +++ b/drivers/nvmem/Kconfig
> @@ -8,3 +8,18 @@ menuconfig NVMEM
>  	  from both the Linux Kernel and the userspace.
>  
>  	  If unsure, say no.
> +
> +if NVMEM
> +
> +config QCOM_QFPROM
> +	tristate "QCOM QFPROM Support"
> +	depends on ARCH_QCOM

 || COMPILE_TEST?

> +	select REGMAP_MMIO
> +	help
> +	  Say y here to enable QFPROM support. The QFPROM provides access
> +	  functions for QFPROM data to rest of the drivers via nvmem interface.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called nvmem-qfprom.
> +
> +endif
> diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
> index f694cfc..caea611 100644
> --- a/drivers/nvmem/Makefile
> +++ b/drivers/nvmem/Makefile
> @@ -5,3 +5,7 @@
>  obj-$(CONFIG_NVMEM)		+= nvmem_core.o
>  nvmem_core-y			:= core.o
>  nvmem_core-y			+= nvmem-mmio.o
> +
> +# Devices
> +obj-$(CONFIG_QCOM_QFPROM)	+= nvmem_qfprom.o
> +nvmem_qfprom-y			:= qfprom.o

Why not just

obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o

?

> diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
> new file mode 100644
> index 0000000..5ea84bb
> --- /dev/null
> +++ b/drivers/nvmem/qfprom.c
> @@ -0,0 +1,51 @@
> +/*
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include "nvmem-mmio.h"
> +
> +static struct regmap_config qfprom_regmap_config = {

const?

> +	.reg_bits = 32,
> +	.val_bits = 8,
> +	.reg_stride = 1,
> +};
> +
> +static struct nvmem_config econfig = {

const?

> +	.name = "qfprom",
> +	.owner = THIS_MODULE,
> +};
> +
> +static struct nvmem_mmio_data qfprom_data = {

const?

> +	.nvmem_config = &econfig,
> +	.regmap_config = &qfprom_regmap_config,
> +};
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v5 09/11] nvmem: qfprom: Add bindings for qfprom
  2015-05-21 16:44           ` [PATCH v5 09/11] nvmem: qfprom: Add bindings for qfprom Srinivas Kandagatla
@ 2015-06-16 23:01             ` Stephen Boyd
  0 siblings, 0 replies; 153+ messages in thread
From: Stephen Boyd @ 2015-06-16 23:01 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter

On 05/21/2015 09:44 AM, Srinivas Kandagatla wrote:
> This patch adds bindings for qfprom found in QCOM SOCs. QFPROM driver
> is based on simple nvmem framework.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---

Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v5 10/11] nvmem: sunxi: Move the SID driver to the nvmem framework
  2015-05-21 16:45           ` [PATCH v5 10/11] nvmem: sunxi: Move the SID driver to the " Srinivas Kandagatla
@ 2015-06-16 23:04             ` Stephen Boyd
  2015-06-18 13:09               ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Stephen Boyd @ 2015-06-16 23:04 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter

On 05/21/2015 09:45 AM, Srinivas Kandagatla wrote:
> diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
> index caea611..cc46791 100644
> --- a/drivers/nvmem/Makefile
> +++ b/drivers/nvmem/Makefile
> @@ -9,3 +9,5 @@ nvmem_core-y			+= nvmem-mmio.o
>  # Devices
>  obj-$(CONFIG_QCOM_QFPROM)	+= nvmem_qfprom.o
>  nvmem_qfprom-y			:= qfprom.o
> +obj-$(CONFIG_NVMEM_SUNXI_SID)	+= nvmem-sunxi-sid.o
> +nvmem-sunxi-sid-y		:= sunxi-sid.o

Oh I see, so the module has nvmem- in the name. Isn't there some way to
add a rule to do that for all provider drivers?

> diff --git a/drivers/nvmem/sunxi-sid.c b/drivers/nvmem/sunxi-sid.c
> new file mode 100644
> index 0000000..5bfce35
> --- /dev/null
> +++ b/drivers/nvmem/sunxi-sid.c
> @@ -0,0 +1,64 @@
> +/*
> + * Allwinner sunXi SoCs Security ID support.
> + *
> + * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
> + * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include "nvmem-mmio.h"
> +
> +static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
> +{
> +	return false;
> +}
> +
> +static struct nvmem_config econfig = {

const?

> +	.name = "sunix-sid",
> +	.owner = THIS_MODULE,
> +};
> +
> +static struct regmap_config sunxi_sid_regmap_config = {

const?

> +	.reg_bits = 32,
> +	.val_bits = 32,
> +	.reg_stride = 4,
> +	.writeable_reg = sunxi_sid_writeable_reg,
> +};
> +
> +static struct nvmem_mmio_data sunxi_data = {

const?

> +	.nvmem_config = &econfig,
> +	.regmap_config = &sunxi_sid_regmap_config,
> +};
> +


-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v5 04/11] nvmem: Add a simple NVMEM framework for consumers
  2015-06-16 22:29             ` Stephen Boyd
@ 2015-06-17  8:00               ` Sascha Hauer
  2015-06-18 12:56               ` Srinivas Kandagatla
  1 sibling, 0 replies; 153+ messages in thread
From: Sascha Hauer @ 2015-06-17  8:00 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Srinivas Kandagatla, linux-arm-kernel, devicetree, arnd,
	Greg Kroah-Hartman, linux-kernel, pantelis.antoniou, Rob Herring,
	Mark Brown, Kumar Gala, mporter, Maxime Ripard, linux-api,
	linux-arm-msm

On Tue, Jun 16, 2015 at 03:29:25PM -0700, Stephen Boyd wrote:
> On 05/21/2015 09:43 AM, Srinivas Kandagatla wrote:
> > +	/* if it's not end on byte boundary */
> > +	if ((nbits + bit_offset) % BITS_PER_BYTE) {
> > +		/* setup the last byte with msb bits from nvmem */
> > +		rc = regmap_raw_read(nvmem->regmap,
> > +				    cell->offset + cell->bytes - 1, &v, 1);
> > +		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
> > +
> > +	}
> > +
> > +	return buf;
> > +}
> > +
> > +/**
> > + * nvmem_cell_write(): Write to a given nvmem cell
> 
> This isn't kernel doc notation. It should be like
> 
>     nvmem_cell_write - Write to a given nvmem cell

Almost. Should be:

      nvmem_cell_write() - Write to a given nvmem cell

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v5 03/11] nvmem: Add a simple NVMEM framework for nvmem providers
  2015-06-16 22:43             ` Stephen Boyd
@ 2015-06-18 12:46               ` Srinivas Kandagatla
  2015-06-24  0:24                 ` Stephen Boyd
  0 siblings, 1 reply; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-06-18 12:46 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter

Many thanks for review.

On 16/06/15 23:43, Stephen Boyd wrote:
> On 05/21/2015 09:43 AM, Srinivas Kandagatla wrote:
>>
>> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
>> new file mode 100644
>> index 0000000..6c2f0b1
>> --- /dev/null
>> +++ b/drivers/nvmem/core.c
>> @@ -0,0 +1,398 @@
>> +/*
>> + * nvmem framework core.
>> + *
>> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/device.h>
>> +#include <linux/nvmem-provider.h>
>> +#include <linux/export.h>
>> +#include <linux/fs.h>
>> +#include <linux/idr.h>
>> +#include <linux/init.h>
>> +#include <linux/regmap.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/slab.h>
>> +#include <linux/uaccess.h>
>
> Is this include used?
>
Yep, not required.
>> +
>> +static int of_nvmem_match(struct device *dev, const void *nvmem_np)
>> +{
>> +	return dev->of_node == nvmem_np;
>> +}
>> +
>> +static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
>
> const?
Sure,
>
>> +{
>> +	struct device *d;
>> +
>> +	if (!nvmem_np)
>> +		return NULL;
>> +
>> +	d = class_find_device(&nvmem_class, NULL, nvmem_np, of_nvmem_match);
>> +
>> +	return d ? to_nvmem_device(d) : NULL;
>> +}
>> +
>> +static struct nvmem_cell *nvmem_find_cell(const char *cell_id)
>> +{
>> +	struct nvmem_cell *p;
>> +
>> +	list_for_each_entry(p, &nvmem_cells, node) {
>
> Unnecessary braces.
Yep, Will remove it.
>
>> +		if (p && !strcmp(p->name, cell_id))
>> +			return p;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +static void nvmem_cell_drop(struct nvmem_cell *cell)
>> +{
>> +	mutex_lock(&nvmem_cells_mutex);
>> +	list_del(&cell->node);
>> +	mutex_unlock(&nvmem_cells_mutex);
>> +	kfree(cell);
>> +}
>> +
>> +static void nvmem_device_remove_all_cells(struct nvmem_device *nvmem)
>> +{
>> +	struct nvmem_cell *cell = NULL;
>
> Unnecessary initialization
Yes.
>
>> +	struct list_head *p, *n;
>> +
>> +	list_for_each_safe(p, n, &nvmem_cells) {
>> +		cell = list_entry(p, struct nvmem_cell, node);
>> +		if (cell->nvmem == nvmem)
>> +			nvmem_cell_drop(cell);
>> +	}
> [..]
>> +
>> +static int nvmem_add_cells(struct nvmem_device *nvmem,
>> +			   struct nvmem_config *cfg)
>> +{
>> +	struct nvmem_cell **cells;
>> +	struct nvmem_cell_info *info = cfg->cells;
>> +	int i, rval;
>> +
>> +	cells = kzalloc(sizeof(*cells) * cfg->ncells, GFP_KERNEL);
>
> kcalloc
This is temporary array, I did this on intention, to make it easy to 
kfree cells which are found invalid at runtime.
>
>> +	if (!cells)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < cfg->ncells; i++) {
>> +		cells[i] = kzalloc(sizeof(struct nvmem_cell), GFP_KERNEL);
>
> sizeof(**cells) ?
Yep.

>
>> +
>> +/**
>> + * nvmem_register(): Register a nvmem device for given nvmem.
>> + * Also creates an binary entry in /sys/class/nvmem/dev-name/nvmem
>> + *
>> + * @nvmem: nvmem device that needs to be created
>
> You mean @config?
>
Yes, I will fix it.

>> + *
>> + * The return value will be an ERR_PTR() on error or a valid pointer
>> +	nvmem->dev.of_node = config->dev->of_node;
>> +	dev_set_name(&nvmem->dev, "%s%d",
>> +		     config->name ? : "nvmem", config->id);
>
> It may be better to always name it nvmem%d so that we don't allow the
> possibility of conflicts.
We can do that, but I wanted to make the sysfs and dev entries more 
readable than just nvmem0, nvmem1...
>
>> +
>> +	nvmem->read_only = of_property_read_bool(nvmem->dev.of_node,
>> +						 "read-only");
>
> What if we're not using DT? How would we specify read_only?
>
Thanks for spotting, you are correct, I need to add read_only flag to 
nvmem_config too.


>> +
>> +	device_initialize(&nvmem->dev);
>> +
>> +	dev_dbg(&nvmem->dev, "Registering nvmem device %s\n",
>> +		dev_name(&nvmem->dev));
>> +
>> +	rval = device_add(&nvmem->dev);
>> +	if (rval) {
>> +		ida_simple_remove(&nvmem_ida, nvmem->id);
>> +		kfree(nvmem);
>> +		return ERR_PTR(rval);
>> +	}
>> +
>> +	/* update sysfs attributes */
>> +	if (nvmem->read_only)
>> +		sysfs_update_group(&nvmem->dev.kobj, &nvmem_bin_ro_group);
>
> It would be nice if this could be done before the device was registered.
> Perhaps have two device_types, one for read-only and one for read/write?

The attributes are actually coming from the class object, so we have no 
choice to update the attributes before the device is registered.

May it would be more safe to have default as read-only and modify it to 
read/write based on read-only flag?


>
>> +
>> + */
>> +int nvmem_unregister(struct nvmem_device *nvmem)
>> +{
>> +	mutex_lock(&nvmem_mutex);
>> +	if (nvmem->users) {
>> +		mutex_unlock(&nvmem_mutex);
>> +		return -EBUSY;
>
> Hmm... that doesn't seem nice. Typically when something is unregistered
> we have to pull the rug out from underneath the users and start
> returning errors to them. The provider needs to be free to unregister
> because it's been forcibly removed. So really this function should
> return void.
>
The consumer api is get/put style, so consumers who already have 
references to the provider, removing provider forcefully might lead to 
dangling pointer. Having said that I can give a try and see how it looks.

>> +	}
>> +	mutex_unlock(&nvmem_mutex);
>> +
>> +	nvmem_device_remove_all_cells(nvmem);
>> +	device_del(&nvmem->dev);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(nvmem_unregister);
>> +
>> +static int nvmem_init(void)
>
> __init? And __exit on nvmem_exit?
yep, will do that.
>
>> +{
>> +	return class_register(&nvmem_class);
>
> I thought class was on the way out? Aren't we supposed to use bus types
> for new stuff?
Do you remember any conversation on the list about this? I could not 
find it on web.

on the other hand, nvmem is not really a bus, making it a bus type 
sounds incorrect to me.


--srini

>

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

* Re: [PATCH v5 04/11] nvmem: Add a simple NVMEM framework for consumers
  2015-06-16 22:29             ` Stephen Boyd
  2015-06-17  8:00               ` Sascha Hauer
@ 2015-06-18 12:56               ` Srinivas Kandagatla
  1 sibling, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-06-18 12:56 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: devicetree, arnd, Greg Kroah-Hartman, s.hauer, linux-kernel,
	pantelis.antoniou, Rob Herring, Mark Brown, Kumar Gala, mporter,
	Maxime Ripard, linux-api, linux-arm-msm



On 16/06/15 23:29, Stephen Boyd wrote:
> On 05/21/2015 09:43 AM, Srinivas Kandagatla wrote:
>> @@ -379,6 +380,351 @@ int nvmem_unregister(struct nvmem_device *nvmem)
> [...]
>> +
>> +	return nvmem;
>> +}
>> +
>> +static int __nvmem_device_put(struct nvmem_device *nvmem)
>
> Why does this return int? It's not used anywhere.
>
I can remove it.
>> +{
>> +	module_put(nvmem->owner);
>> +	mutex_lock(&nvmem_mutex);
>> +	nvmem->users--;
>> +	mutex_unlock(&nvmem_mutex);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id)
>> +{
>> +	struct nvmem_cell *cell = NULL;
>> +	struct nvmem_device *nvmem;
>> +
>> +	nvmem = __nvmem_device_get(NULL, &cell, cell_id);
>> +	if (IS_ERR(nvmem))
>> +		return (struct nvmem_cell *)nvmem;
>
> ERR_CAST?
Will fix it.
>
>> +
>> +
>> +	return cell;
>> +
>> +}
>> +
>> +static struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
>> +					    const char *name)
>> +{
>> +	struct device_node *cell_np, *nvmem_np;
>> +	struct nvmem_cell *cell;
>> +	struct nvmem_device *nvmem;
>> +	const __be32 *addr;
>> +	int rval, len, index;
>> +
>> +	index = of_property_match_string(np, "nvmem-cell-names", name);
>> +
>> +	cell_np = of_parse_phandle(np, "nvmem-cell", index);
>> +	if (!cell_np)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	nvmem_np = of_get_next_parent(cell_np);
>> +	if (!nvmem_np)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	nvmem = __nvmem_device_get(nvmem_np, NULL, NULL);
>> +	if (IS_ERR(nvmem))
>> +		return (struct nvmem_cell *)nvmem;
>
> ERR_CAST?
Will fix it.

>
>> +
>> +	addr = of_get_property(cell_np, "reg", &len);
>> +	if (!addr || (len < 2 * sizeof(int))) {
>> +		dev_err(&nvmem->dev, "of_i2c: invalid reg on %s\n",
>
> huh? of_i2c?
>
  :-)
Will fix it.
>
>> +
>> +	/* if it's not end on byte boundary */
>> +	if ((nbits + bit_offset) % BITS_PER_BYTE) {
>> +		/* setup the last byte with msb bits from nvmem */
>> +		rc = regmap_raw_read(nvmem->regmap,
>> +				    cell->offset + cell->bytes - 1, &v, 1);
>> +		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
>> +
>> +	}
>> +
>> +	return buf;
>> +}
>> +
>> +/**
>> + * nvmem_cell_write(): Write to a given nvmem cell
>
> This isn't kernel doc notation. It should be like
>
>      nvmem_cell_write - Write to a given nvmem cell
>
Will fix as suggested by Sascha as

foobar() - short function description of foobar

Looks correct according to Documentation/kernel-doc-nano-HOWTO.txt

>> + *
>> + * @cell: nvmem cell to be written.
>> + * @buf: Buffer to be written.
>> + * @len: length of buffer to be written to nvmem cell.
>> + *
>> + * The return value will be an length of bytes written or non zero on failure.
>> + */
>> +int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len)
> [..]
>> +
>>   static int nvmem_init(void)
>>   {
>>   	return class_register(&nvmem_class);
>> diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
>> new file mode 100644
>> index 0000000..c3fa8c7
>> --- /dev/null
>> +++ b/include/linux/nvmem-consumer.h
>> @@ -0,0 +1,49 @@
>> +/*
>> + * nvmem framework consumer.
>> + *
>> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2.  This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#ifndef _LINUX_NVMEM_CONSUMER_H
>> +#define _LINUX_NVMEM_CONSUMER_H
>> +
>> +/* consumer cookie */
>> +struct nvmem_cell;
>> +
>> +#if IS_ENABLED(CONFIG_NVMEM)
>> +
>> +/* Cell based interface */
>> +struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);
>
> We should probably forward declare struct device in this file too.
Yep I will do it.
>

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

* Re: [PATCH v5 05/11] nvmem: Add nvmem_device based consumer apis.
  2015-06-16 22:49             ` Stephen Boyd
@ 2015-06-18 12:57               ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-06-18 12:57 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter



On 16/06/15 23:49, Stephen Boyd wrote:
> On 05/21/2015 09:43 AM, Srinivas Kandagatla wrote:
>> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
>> index 8a4b358..68ee8d1 100644
>> --- a/drivers/nvmem/core.c
>> +++ b/drivers/nvmem/core.c
>> @@ -436,6 +436,51 @@ static int __nvmem_device_put(struct nvmem_device *nvmem)
>>   	return 0;
>>   }
>>
>> +static int nvmem_match(struct device *dev, const void *data)
>> +{
>> +	return !strcmp(dev_name(dev), (const char *)data);
>
> Unnecessary cast.
Sure, will fix it.
>
>> +}
>> +
>> +static struct nvmem_device *nvmem_find(const char *name)
>> +{
>> +	struct device *d;
>> +
>> +	d = class_find_device(&nvmem_class, NULL, (void *)name, nvmem_match);
>
> Unnecessary cast
Will fix it.
>
>> +
>> +	return d ? to_nvmem_device(d) : NULL;
>> +}
>
> [...]
>> +
>> +void nvmem_device_put(struct nvmem_device *nvmem)
>> +{
>> +	__nvmem_device_put(nvmem);
>> +}
>> +EXPORT_SYMBOL_GPL(nvmem_device_put);
>>
>> +int nvmem_device_cell_read(struct nvmem_device *nvmem,
>> +			   struct nvmem_cell_info *info, void *buf)
>> +{
>> +}
>> +EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
>> +
>> +int nvmem_device_cell_write(struct nvmem_device *nvmem,
>> +			    struct nvmem_cell_info *info, void *buf)
>> +{
>> +}
>> +EXPORT_SYMBOL_GPL(nvmem_device_cell_write);
>> +
>> +int nvmem_device_read(struct nvmem_device *nvmem,
>> +		      unsigned int offset,
>> +		      size_t bytes, void *buf)
>> +{
>> +}
>> +EXPORT_SYMBOL_GPL(nvmem_device_read);
>> +
>> +int nvmem_device_write(struct nvmem_device *nvmem,
>> +		       unsigned int offset,
>> +		       size_t bytes, void *buf)
>> +{
>> +}
>> +EXPORT_SYMBOL_GPL(nvmem_device_write);
>
> Can you please add kernel-doc on these exported APIs?
>
Thanks for spotting, I will add them.

>> +
>>   static int nvmem_init(void)
>>   {
>>   	return class_register(&nvmem_class);
>> diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
>> index c3fa8c7..66c67ba 100644
>> --- a/include/linux/nvmem-consumer.h
>> +++ b/include/linux/nvmem-consumer.h
>> @@ -23,6 +32,18 @@ void nvmem_cell_put(struct nvmem_cell *cell);
>>   void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len);
>>   int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len);
>>
>> +/* direct nvmem device read/write interface */
>> +struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
>> +void nvmem_device_put(struct nvmem_device *nvmem);
>> +int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
>> +		      size_t bytes, void *buf);
>> +int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset,
>> +		       size_t bytes, void *buf);
>> +int nvmem_device_cell_read(struct nvmem_device *nvmem,
>> +			   struct nvmem_cell_info *info, void *buf);
>> +int nvmem_device_cell_write(struct nvmem_device *nvmem,
>> +			    struct nvmem_cell_info *info, void *buf);
>> +
>
> Can we also have devm_nvmem_*_get() APIs please?
Sure, I will spin it in next version.
>
>> diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
>> index 4908b37..7a982cd 100644
>> --- a/include/linux/nvmem-provider.h
>> +++ b/include/linux/nvmem-provider.h
>> @@ -12,15 +12,9 @@
>>   #ifndef _LINUX_NVMEM_PROVIDER_H
>>   #define _LINUX_NVMEM_PROVIDER_H
>>
>> -struct nvmem_device;
>> +#include <linux/nvmem-consumer.h>
>>
>> -struct nvmem_cell_info {
>> -	const char		*name;
>> -	int			offset;
>> -	int			bytes;
>> -	int			bit_offset;
>> -	int			nbits;
>> -};
>> +struct nvmem_device;
>
> Should this diff be part of an earlier patch?
Possibly, something wrong with this diff, I will fix it.
>

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

* Re: [PATCH v5 06/11] nvmem: Add bindings for simple nvmem framework
  2015-06-16 22:53             ` Stephen Boyd
@ 2015-06-18 13:01               ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-06-18 13:01 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter



On 16/06/15 23:53, Stephen Boyd wrote:
> On 05/21/2015 09:44 AM, Srinivas Kandagatla wrote:
>> diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.txt b/Documentation/devicetree/bindings/nvmem/nvmem.txt
>> new file mode 100644
>> index 0000000..ecea654
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/nvmem/nvmem.txt
>> @@ -0,0 +1,84 @@
>> += NVMEM Data Device Tree Bindings =
>> +
>> +This binding is intended to represent the location of hardware
>> +configuration data stored in NVMEMs.
>
> It would be worthwhile spelling out what NVMEM stands for.
>
>> +
>> +On a significant proportion of boards, the manufacturer has stored
>> +some data on NVMEM, for the OS to be able to retrieve these information
>> +and act upon it. Obviously, the OS has to know about where to retrieve
>> +these data from, and where they are stored on the storage device.
>> +
>> +This document is here to document this.
>> +
>> += Data providers =
>> +Contains bindings specific to provider drivers and data cells as children
>> +to this node.
>
> children of this node?
>
Yep, will fix the text
>> +
>> +Optional properties:
>> + read-only: Mark the provider as read only.
>> +
>> += Data cells =
>> +These are the child nodes of the provider which contain data cell
>> +information like offset and size in nvmem provider.
>> +
>> +Required properties:
>> +reg:	specifies the offset in byte within that storage device, start bit
>> +	in the byte and the length in bits of the data we care about.
>> +	There could be more then one offset-length pairs in this property.
>
> s/then/than/
Yep.
>
>> +
>> +Optional properties:
>> +
>> +bit-offset: specifies the offset in bit within the address range specified
>> +	by reg property. Can take values from 0-7.
>> +nbits: specifies number of bits this cell occupies starting from bit-offset.
>> +
>
> Hopefully the consumer knows the endianness of the data stored.

As we read byte-byte, does it matter, as long as consumer gets them in 
the same order as its stored.


>
>> +For example:
>> +
>> +	/* Provider */
>> +	qfprom: qfprom@00700000 {
>> +		...
>> +
>> +		/* Data cells */
>> +		tsens_calibration: calib@404 {
>> +			reg = <0x404 0x10>;
>> +		};
>> +
>> +		tsens_calibration_bckp: calib_bckp@504 {
>> +			reg = <0x504 0x11>;
>> +			bit-offset = 6;
>> +			nbits = 128;
>> +		};
>> +
>> +		pvs_version: pvs-version@6 {
>> +			reg = <0x6 0x2>
>> +			bit-offset = 7;
>> +			nbits = 2;
>> +		};
>> +
>> +		speed_bin: speed-bin@c{
>> +			reg = <0xc 0x1>;
>> +			bit-offset = 2;
>> +			nbits	= 3;
>> +
>> +		};
>> +		...
>> +	};
>> +
>> += Data consumers =
>> +Are device nodes which consume nvmem data cells/providers.
>> +
>> +Required-properties:
>> +nvmem-cell: list of phandle to the nvmem data cells.
>> +nvmem-cell-names: names for the each nvmem-cell specified
>> +
>> +Optional-properties:
>> +nvmem	: list of phandles to nvmem providers.
>> +nvmem-names: names for the each nvmem provider.
>
> Is nvmem-names required if nvmem is used?
Yes, will fix it.
>

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

* Re: [PATCH v5 07/11] nvmem: Add simple nvmem-mmio consumer helper functions.
  2015-06-16 22:58             ` Stephen Boyd
@ 2015-06-18 13:08               ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-06-18 13:08 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter



On 16/06/15 23:58, Stephen Boyd wrote:
> On 05/21/2015 09:44 AM, Srinivas Kandagatla wrote:
>> diff --git a/drivers/nvmem/nvmem-mmio.c b/drivers/nvmem/nvmem-mmio.c
>> new file mode 100644
>> index 0000000..0d8131f
>> --- /dev/null
>> +++ b/drivers/nvmem/nvmem-mmio.c
>> @@ -0,0 +1,69 @@
>> +/*
>> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/device.h>
>> +#include <linux/module.h>
>> +#include <linux/err.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>
> #include <linux/platform_device.h>
> #include <linux/nvmem_provider.h>
> #include <linux/regmap.h>
>
These are included in nvmem-mmio.h, however for clarity sake I could add 
them here too.
>> +#include "nvmem-mmio.h"
>> +
>> +int nvmem_mmio_remove(struct platform_device *pdev)
>> +{
>> +	struct nvmem_device *nvmem = platform_get_drvdata(pdev);
>> +
>> +	return nvmem_unregister(nvmem);
>> +}
>> +EXPORT_SYMBOL_GPL(nvmem_mmio_remove);
>> +
>> +int nvmem_mmio_probe(struct platform_device *pdev)
>> +{
>> +
> [...]
>> +
>> +	platform_set_drvdata(pdev, nvmem);
>
> It may be better to return the nvmem device instead so that the one
> drvdata member is usable by the calling driver.
Makes sense.. I will give it a try.

>
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(nvmem_mmio_probe);
>
> Kernel-doc on these exported functions?
Yep, thanks for spotting, I will fix it.
>
>> diff --git a/drivers/nvmem/nvmem-mmio.h b/drivers/nvmem/nvmem-mmio.h
>> new file mode 100644
>> index 0000000..a2ad4e5
>> --- /dev/null
>> +++ b/drivers/nvmem/nvmem-mmio.h
>> @@ -0,0 +1,41 @@
>> +/*
>> + * MMIO based nvmem providers.
>> + *
>> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2.  This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#ifndef _LINUX_NVMEM_MMIO_H
>> +#define _LINUX_NVMEM_MMIO_H
>> +
>> +#include <linux/platform_device.h>
>
> Forward declare struct platform_device instead.
>
>> +#include <linux/nvmem-provider.h>
>
> Forward declare nvmem_config instead.
>
>> +#include <linux/regmap.h>
>
> Forward declare regmap_config instead.
>
>> +
>> +struct nvmem_mmio_data {
>> +	struct regmap_config *regmap_config;
>> +	struct nvmem_config *nvmem_config;
>> +};
>> +
>> +#if IS_ENABLED(CONFIG_NVMEM)
>> +
>> +int nvmem_mmio_probe(struct platform_device *pdev);
>> +int nvmem_mmio_remove(struct platform_device *pdev);
>

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

* Re: [PATCH v5 10/11] nvmem: sunxi: Move the SID driver to the nvmem framework
  2015-06-16 23:04             ` Stephen Boyd
@ 2015-06-18 13:09               ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-06-18 13:09 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter



On 17/06/15 00:04, Stephen Boyd wrote:
> On 05/21/2015 09:45 AM, Srinivas Kandagatla wrote:
>> diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
>> index caea611..cc46791 100644
>> --- a/drivers/nvmem/Makefile
>> +++ b/drivers/nvmem/Makefile
>> @@ -9,3 +9,5 @@ nvmem_core-y			+= nvmem-mmio.o
>>   # Devices
>>   obj-$(CONFIG_QCOM_QFPROM)	+= nvmem_qfprom.o
>>   nvmem_qfprom-y			:= qfprom.o
>> +obj-$(CONFIG_NVMEM_SUNXI_SID)	+= nvmem-sunxi-sid.o
>> +nvmem-sunxi-sid-y		:= sunxi-sid.o
>
> Oh I see, so the module has nvmem- in the name. Isn't there some way to
> add a rule to do that for all provider drivers?
>
I will give it a try, and also fix the other comments on this patch.


>> diff --git a/drivers/nvmem/sunxi-sid.c b/drivers/nvmem/sunxi-sid.c
>> new file mode 100644
>> index 0000000..5bfce35
>> --- /dev/null
>> +++ b/drivers/nvmem/sunxi-sid.c
>> @@ -0,0 +1,64 @@
>> +/*
>> + * Allwinner sunXi SoCs Security ID support.
>> + *
>> + * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
>> + * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include "nvmem-mmio.h"
>> +
>> +static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
>> +{
>> +	return false;
>> +}
>> +
>> +static struct nvmem_config econfig = {
>
> const?
>
>> +	.name = "sunix-sid",
>> +	.owner = THIS_MODULE,
>> +};
>> +
>> +static struct regmap_config sunxi_sid_regmap_config = {
>
> const?
>
>> +	.reg_bits = 32,
>> +	.val_bits = 32,
>> +	.reg_stride = 4,
>> +	.writeable_reg = sunxi_sid_writeable_reg,
>> +};
>> +
>> +static struct nvmem_mmio_data sunxi_data = {
>
> const?
>
>> +	.nvmem_config = &econfig,
>> +	.regmap_config = &sunxi_sid_regmap_config,
>> +};
>> +
>
>

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

* Re: [PATCH v5 08/11] nvmem: qfprom: Add Qualcomm QFPROM support.
  2015-06-16 23:00             ` Stephen Boyd
@ 2015-06-18 13:22               ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-06-18 13:22 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter



On 17/06/15 00:00, Stephen Boyd wrote:
> On 05/21/2015 09:44 AM, Srinivas Kandagatla wrote:
>> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
>> index f157b6d..e665e23 100644
>> --- a/drivers/nvmem/Kconfig
>> +++ b/drivers/nvmem/Kconfig
>> @@ -8,3 +8,18 @@ menuconfig NVMEM
>>   	  from both the Linux Kernel and the userspace.
>>
>>   	  If unsure, say no.
>> +
>> +if NVMEM
>> +
>> +config QCOM_QFPROM
>> +	tristate "QCOM QFPROM Support"
>> +	depends on ARCH_QCOM
>
>   || COMPILE_TEST?
>
Yes, makes sense. I will add it.
>> +	select REGMAP_MMIO
>> +	help
>> +	  Say y here to enable QFPROM support. The QFPROM provides access
>> +	  functions for QFPROM data to rest of the drivers via nvmem interface.
>> +
>> +	  This driver can also be built as a module. If so, the module
>> +	  will be called nvmem-qfprom.
>> +
>> +endif
>> diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
>> index f694cfc..caea611 100644
>> --- a/drivers/nvmem/Makefile
>> +++ b/drivers/nvmem/Makefile
>> @@ -5,3 +5,7 @@
>>   obj-$(CONFIG_NVMEM)		+= nvmem_core.o
>>   nvmem_core-y			:= core.o
>>   nvmem_core-y			+= nvmem-mmio.o
>> +
>> +# Devices
>> +obj-$(CONFIG_QCOM_QFPROM)	+= nvmem_qfprom.o
>> +nvmem_qfprom-y			:= qfprom.o
>
> Why not just
>
> obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o
>
> ?
I will recheck on this.
>
>> diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
>> new file mode 100644
>> index 0000000..5ea84bb
>> --- /dev/null
>> +++ b/drivers/nvmem/qfprom.c
>> @@ -0,0 +1,51 @@
>> +/*
>> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include "nvmem-mmio.h"
>> +
>> +static struct regmap_config qfprom_regmap_config = {
>
> const?

Will fix all the comments.
>
>> +	.reg_bits = 32,
>> +	.val_bits = 8,
>> +	.reg_stride = 1,
>> +};
>> +
>> +static struct nvmem_config econfig = {
>
> const?
>
>> +	.name = "qfprom",
>> +	.owner = THIS_MODULE,
>> +};
>> +
>> +static struct nvmem_mmio_data qfprom_data = {
>
> const?
>
>> +	.nvmem_config = &econfig,
>> +	.regmap_config = &qfprom_regmap_config,
>> +};
>>
>

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

* Re: [PATCH v5 06/11] nvmem: Add bindings for simple nvmem framework
  2015-05-21 16:44           ` [PATCH v5 06/11] nvmem: Add bindings for simple nvmem framework Srinivas Kandagatla
  2015-06-16 22:53             ` Stephen Boyd
@ 2015-06-19 10:36             ` maitysanchayan
  2015-06-19 10:59               ` Srinivas Kandagatla
  1 sibling, 1 reply; 153+ messages in thread
From: maitysanchayan @ 2015-06-19 10:36 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, devicetree, arnd, Greg Kroah-Hartman, s.hauer,
	sboyd, linux-kernel, pantelis.antoniou, Rob Herring, Mark Brown,
	Kumar Gala, mporter, Maxime Ripard, linux-api, linux-arm-msm,
	Stefan Agner

Hello Srinivas,

On 15-05-21 17:44:12, Srinivas Kandagatla wrote:
> This patch adds bindings for simple nvmem framework which allows nvmem
> consumers to talk to nvmem providers to get access to nvmem cell data.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> [Maxime Ripard: intial version of eeprom framework]
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  Documentation/devicetree/bindings/nvmem/nvmem.txt | 84 +++++++++++++++++++++++
>  1 file changed, 84 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem.txt
> 
> diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.txt b/Documentation/devicetree/bindings/nvmem/nvmem.txt
> new file mode 100644
> index 0000000..ecea654
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/nvmem/nvmem.txt
> @@ -0,0 +1,84 @@
> += NVMEM Data Device Tree Bindings =
> +
> +This binding is intended to represent the location of hardware
> +configuration data stored in NVMEMs.
> +
> +On a significant proportion of boards, the manufacturer has stored
> +some data on NVMEM, for the OS to be able to retrieve these information
> +and act upon it. Obviously, the OS has to know about where to retrieve
> +these data from, and where they are stored on the storage device.
> +
> +This document is here to document this.
> +
> += Data providers =
> +Contains bindings specific to provider drivers and data cells as children
> +to this node.
> +
> +Optional properties:
> + read-only: Mark the provider as read only.
> +
> += Data cells =
> +These are the child nodes of the provider which contain data cell
> +information like offset and size in nvmem provider.
> +
> +Required properties:
> +reg:	specifies the offset in byte within that storage device, start bit
> +	in the byte and the length in bits of the data we care about.
> +	There could be more then one offset-length pairs in this property.
> +
> +Optional properties:
> +
> +bit-offset: specifies the offset in bit within the address range specified
> +	by reg property. Can take values from 0-7.
> +nbits: specifies number of bits this cell occupies starting from bit-offset.
> +
> +For example:
> +
> +	/* Provider */
> +	qfprom: qfprom@00700000 {
> +		...
> +
> +		/* Data cells */
> +		tsens_calibration: calib@404 {
> +			reg = <0x404 0x10>;
> +		};
> +
> +		tsens_calibration_bckp: calib_bckp@504 {
> +			reg = <0x504 0x11>;
> +			bit-offset = 6;
> +			nbits = 128;
> +		};
> +
> +		pvs_version: pvs-version@6 {
> +			reg = <0x6 0x2>
> +			bit-offset = 7;
> +			nbits = 2;
> +		};
> +
> +		speed_bin: speed-bin@c{
> +			reg = <0xc 0x1>;
> +			bit-offset = 2;
> +			nbits	= 3;
> +
> +		};
> +		...
> +	};

We have a need of exposing information like SoC ID, revision and such
which is what this nvmem framework proposes to be suitable for. Till
now I was trying a different approach for the same [1].

The On Chip One Time Programmable block on the Vybrid can be handled
nicely with this nvmem framework however I had a few queries with
regards to the framework after trying it on a Vybrid VF61 SoC. 

1. From what I understand, getting the information in hex is the only
way possible as of now? Would it be possible to expose the information
as strings from different paths under /sys/class/nvmem/*/nvmem/?

For example, if I have a sub node as below

ocotp: ocotp@400a5000 {
	compatible = "fsl,vf610-ocotp";
	reg = <0x400a5000 0x1000>;

	ocotp_cfg0: cfg0@410 {
		reg = <0x410 0x1>;
	};

	ocotp_cfg1: cfg1@420 {
		reg = <0x420 0x1>;
	};
};

The values from the above register locations represented by the two
sub nodes above can perhaps be exposed as strings? Even if they are
not exposed as strings, making them available in separate paths, is
that something which can be done? So depending on the sub node as
above, /sys/class/nvmem/ocotp0/nvmem/cfg0/ would give values from
the registers specified.

Basically the output of /sys/class/nvmem/*/nvmem being restricted
to only the subnodes specified is what I was hoping to get along
with separate paths.

2. What if the required information is scattered across different memory
regions? In my case, the SoC ID is available from one OCOTP peripheral
block, the revision is in a separate ROM area at the start of the memory
map and some CPU information I am interested in is in another memory
region. I am not sure what would be the right way to approach it with
the nvmem framework.

[1] https://lkml.org/lkml/2015/6/5/189

Thanks & Regards,
Sanchayan Maity.

<snip>

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

* Re: [PATCH v5 06/11] nvmem: Add bindings for simple nvmem framework
  2015-06-19 10:36             ` maitysanchayan
@ 2015-06-19 10:59               ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-06-19 10:59 UTC (permalink / raw)
  To: maitysanchayan
  Cc: linux-arm-kernel, devicetree, arnd, Greg Kroah-Hartman, s.hauer,
	sboyd, linux-kernel, pantelis.antoniou, Rob Herring, Mark Brown,
	Kumar Gala, mporter, Maxime Ripard, linux-api, linux-arm-msm,
	Stefan Agner



On 19/06/15 11:36, maitysanchayan@gmail.com wrote:
> Hello Srinivas,
>
> On 15-05-21 17:44:12, Srinivas Kandagatla wrote:
>> This patch adds bindings for simple nvmem framework which allows nvmem
>> consumers to talk to nvmem providers to get access to nvmem cell data.
>>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> [Maxime Ripard: intial version of eeprom framework]
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> ---
>>   Documentation/devicetree/bindings/nvmem/nvmem.txt | 84 +++++++++++++++++++++++
>>   1 file changed, 84 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem.txt
>>
>> diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.txt b/Documentation/devicetree/bindings/nvmem/nvmem.txt
>> new file mode 100644
>> index 0000000..ecea654
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/nvmem/nvmem.txt
>> @@ -0,0 +1,84 @@
>> += NVMEM Data Device Tree Bindings =
>> +
>> +This binding is intended to represent the location of hardware
>> +configuration data stored in NVMEMs.
>> +
>> +On a significant proportion of boards, the manufacturer has stored
>> +some data on NVMEM, for the OS to be able to retrieve these information
>> +and act upon it. Obviously, the OS has to know about where to retrieve
>> +these data from, and where they are stored on the storage device.
>> +
>> +This document is here to document this.
>> +
>> += Data providers =
>> +Contains bindings specific to provider drivers and data cells as children
>> +to this node.
>> +
>> +Optional properties:
>> + read-only: Mark the provider as read only.
>> +
>> += Data cells =
>> +These are the child nodes of the provider which contain data cell
>> +information like offset and size in nvmem provider.
>> +
>> +Required properties:
>> +reg:	specifies the offset in byte within that storage device, start bit
>> +	in the byte and the length in bits of the data we care about.
>> +	There could be more then one offset-length pairs in this property.
>> +
>> +Optional properties:
>> +
>> +bit-offset: specifies the offset in bit within the address range specified
>> +	by reg property. Can take values from 0-7.
>> +nbits: specifies number of bits this cell occupies starting from bit-offset.
>> +
>> +For example:
>> +
>> +	/* Provider */
>> +	qfprom: qfprom@00700000 {
>> +		...
>> +
>> +		/* Data cells */
>> +		tsens_calibration: calib@404 {
>> +			reg = <0x404 0x10>;
>> +		};
>> +
>> +		tsens_calibration_bckp: calib_bckp@504 {
>> +			reg = <0x504 0x11>;
>> +			bit-offset = 6;
>> +			nbits = 128;
>> +		};
>> +
>> +		pvs_version: pvs-version@6 {
>> +			reg = <0x6 0x2>
>> +			bit-offset = 7;
>> +			nbits = 2;
>> +		};
>> +
>> +		speed_bin: speed-bin@c{
>> +			reg = <0xc 0x1>;
>> +			bit-offset = 2;
>> +			nbits	= 3;
>> +
>> +		};
>> +		...
>> +	};
>
> We have a need of exposing information like SoC ID, revision and such
> which is what this nvmem framework proposes to be suitable for. Till
> now I was trying a different approach for the same [1].
>
> The On Chip One Time Programmable block on the Vybrid can be handled
> nicely with this nvmem framework however I had a few queries with
> regards to the framework after trying it on a Vybrid VF61 SoC.
>
> 1. From what I understand, getting the information in hex is the only
> way possible as of now? Would it be possible to expose the information
nvmem file in the /sys/ is just a binary file. hexdump is one of the 
ways to dump the data, the user can read the binary file and interpret 
the data in the way he wants it.

> as strings from different paths under /sys/class/nvmem/*/nvmem/?
>
> For example, if I have a sub node as below
>
> ocotp: ocotp@400a5000 {
> 	compatible = "fsl,vf610-ocotp";
> 	reg = <0x400a5000 0x1000>;
>
> 	ocotp_cfg0: cfg0@410 {
> 		reg = <0x410 0x1>;
> 	};
>
> 	ocotp_cfg1: cfg1@420 {
> 		reg = <0x420 0x1>;
> 	};
> };
>

> The values from the above register locations represented by the two
> sub nodes above can perhaps be exposed as strings? Even if they are
> not exposed as strings, making them available in separate paths, is
> that something which can be done? So depending on the sub node as
> above, /sys/class/nvmem/ocotp0/nvmem/cfg0/ would give values from
> the registers specified.

I was thinking of add similar support to show cells in 
/sys/class/nvmem/*/cells/cfg0 in future once the framework is merged. 
For now I want to keep it simple. This would be binary content again. 
you can dump it using strings any program which wants to interpret it 
differently.
>
> Basically the output of /sys/class/nvmem/*/nvmem being restricted
> to only the subnodes specified is what I was hoping to get along
> with separate paths.
>
> 2. What if the required information is scattered across different memory
> regions? In my case, the SoC ID is available from one OCOTP peripheral
> block, the revision is in a separate ROM area at the start of the memory
> map and some CPU information I am interested in is in another memory
> region. I am not sure what would be the right way to approach it with
> the nvmem framework.

I think you would have two providers in that case one is ocotp and other 
is ROM.
DT would look something like this:

/* Provider */
ocotp {
	...
	soc-id {
		reg = ...;
	};
};

rom {
	...
	soc-reg {
		reg = ...;
	};
};

/* consumer */
consumer {
	nvmem-cell  = <&soc_id>, <&soc_rev>;
	nvmem-cell-names = "soc-id", "soc-revision";
};

--srini
>
> [1] https://lkml.org/lkml/2015/6/5/189
>
> Thanks & Regards,
> Sanchayan Maity.
>
> <snip>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH v5 03/11] nvmem: Add a simple NVMEM framework for nvmem providers
  2015-06-18 12:46               ` Srinivas Kandagatla
@ 2015-06-24  0:24                 ` Stephen Boyd
  2015-06-24 10:05                   ` Srinivas Kandagatla
  0 siblings, 1 reply; 153+ messages in thread
From: Stephen Boyd @ 2015-06-24  0:24 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter

On 06/18/2015 05:46 AM, Srinivas Kandagatla wrote:
> Many thanks for review.
>
> On 16/06/15 23:43, Stephen Boyd wrote:
>> On 05/21/2015 09:43 AM, Srinivas Kandagatla wrote:
>>>
>>>> +
>>>> +static int nvmem_add_cells(struct nvmem_device *nvmem,
>>>> +               struct nvmem_config *cfg)
>>>> +{
>>>> +    struct nvmem_cell **cells;
>>>> +    struct nvmem_cell_info *info = cfg->cells;
>>>> +    int i, rval;
>>>> +
>>>> +    cells = kzalloc(sizeof(*cells) * cfg->ncells, GFP_KERNEL);
>>>
>>> kcalloc
> This is temporary array, I did this on intention, to make it easy to
> kfree cells which are found invalid at runtime.

Ok, but how does that change using kcalloc over kzalloc? I must have
missed something.

>
>
>>> + *
>>> + * The return value will be an ERR_PTR() on error or a valid pointer
>>> +    nvmem->dev.of_node = config->dev->of_node;
>>> +    dev_set_name(&nvmem->dev, "%s%d",
>>> +             config->name ? : "nvmem", config->id);
>>
>> It may be better to always name it nvmem%d so that we don't allow the
>> possibility of conflicts.
> We can do that, but I wanted to make the sysfs and dev entries more
> readable than just nvmem0, nvmem1...

Well sysfs is not really for humans. It's for machines. The nvmem
devices could have a name property so that a more human readable string
is present.

>
>>> +
>>> +    device_initialize(&nvmem->dev);
>>> +
>>> +    dev_dbg(&nvmem->dev, "Registering nvmem device %s\n",
>>> +        dev_name(&nvmem->dev));
>>> +
>>> +    rval = device_add(&nvmem->dev);
>>> +    if (rval) {
>>> +        ida_simple_remove(&nvmem_ida, nvmem->id);
>>> +        kfree(nvmem);
>>> +        return ERR_PTR(rval);
>>> +    }
>>> +
>>> +    /* update sysfs attributes */
>>> +    if (nvmem->read_only)
>>> +        sysfs_update_group(&nvmem->dev.kobj, &nvmem_bin_ro_group);
>>
>> It would be nice if this could be done before the device was registered.
>> Perhaps have two device_types, one for read-only and one for read/write?
>
> The attributes are actually coming from the class object, so we have
> no choice to update the attributes before the device is registered.
>
> May it would be more safe to have default as read-only and modify it
> to read/write based on read-only flag?
>
>

Can you assign the attributes to the device_type in the nvmem::struct
device? I don't see why these attributes need to be part of the class.

>>
>>> +{
>>> +    return class_register(&nvmem_class);
>>
>> I thought class was on the way out? Aren't we supposed to use bus types
>> for new stuff?
> Do you remember any conversation on the list about this? I could not
> find it on web.
>
> on the other hand, nvmem is not really a bus, making it a bus type
> sounds incorrect to me.
>

I found this post on the cpu class that Sudeep tried to introduce[1].
And there's this post from Kay that alludes to a unification of busses
and classes[2]. And some other post where Kay says class is dead [3].

[1] https://lkml.org/lkml/2014/8/21/191
[2] https://lwn.net/Articles/471821/
[3] https://lkml.org/lkml/2010/11/11/17

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v5 03/11] nvmem: Add a simple NVMEM framework for nvmem providers
  2015-06-24  0:24                 ` Stephen Boyd
@ 2015-06-24 10:05                   ` Srinivas Kandagatla
  0 siblings, 0 replies; 153+ messages in thread
From: Srinivas Kandagatla @ 2015-06-24 10:05 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, pantelis.antoniou, mporter



On 24/06/15 01:24, Stephen Boyd wrote:
> Can you assign the attributes to the device_type in the nvmem::struct
> device? I don't see why these attributes need to be part of the class.
>
I will fix this.
>>> >>
>>>> >>>+{
>>>> >>>+    return class_register(&nvmem_class);
>>> >>
>>> >>I thought class was on the way out? Aren't we supposed to use bus types
>>> >>for new stuff?
>> >Do you remember any conversation on the list about this? I could not
>> >find it on web.
>> >
>> >on the other hand, nvmem is not really a bus, making it a bus type
>> >sounds incorrect to me.
>> >
> I found this post on the cpu class that Sudeep tried to introduce[1].
> And there's this post from Kay that alludes to a unification of busses
> and classes[2]. And some other post where Kay says class is dead [3].
Thanks for the links,
Yep, looks like Class is dead, I will change the code to use bus type 
instead.

>
> [1]https://lkml.org/lkml/2014/8/21/191
> [2]https://lwn.net/Articles/471821/
> [3]https://lkml.org/lkml/2010/11/11/17
--srini

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

end of thread, other threads:[~2015-06-24 10:06 UTC | newest]

Thread overview: 153+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-19 17:07 [RFC PATCH 0/3] Add simple EEPROM Framework via regmap Srinivas Kandagatla
2015-02-19 17:08 ` [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework Srinivas Kandagatla
2015-02-19 18:12   ` Andrew Lunn
2015-02-20  8:27     ` Srinivas Kandagatla
2015-02-20  2:36   ` Stephen Boyd
2015-02-20  8:14     ` Srinivas Kandagatla
2015-02-20 10:24       ` Srinivas Kandagatla
2015-02-20 17:21   ` Rob Herring
2015-02-20 19:25     ` Srinivas Kandagatla
2015-02-20 22:01       ` Rob Herring
2015-02-21 11:31         ` Srinivas Kandagatla
2015-02-22 14:34           ` Maxime Ripard
2015-02-22 14:32         ` Maxime Ripard
2015-02-23  0:57           ` Rob Herring
2015-02-23 23:11             ` Stephen Boyd
2015-02-24  7:08               ` Srinivas Kandagatla
2015-02-24  9:21               ` Maxime Ripard
2015-02-25  1:30                 ` Stephen Boyd
2015-02-26  9:16                   ` Srinivas Kandagatla
2015-02-26 13:21                     ` Maxime Ripard
2015-02-26 14:56                       ` Srinivas Kandagatla
2015-02-26 13:18                   ` Maxime Ripard
2015-02-23  9:15         ` Sascha Hauer
2015-02-20 17:46   ` Russell King - ARM Linux
2015-02-20 19:00     ` Srinivas Kandagatla