Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1295818 > unrolled thread

[PatchV2 0/6] Convert exiting EEPROM drivers to NVMEM

Started byAndrew Lunn <andrew@lunn.ch>
First post2015-12-21 09:30 +0100
Last post2015-12-21 09:30 +0100
Articles 5 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PatchV2 0/6] Convert exiting EEPROM drivers to NVMEM Andrew Lunn <andrew@lunn.ch> - 2015-12-21 09:30 +0100
    [PatchV2 1/6] nvmem: Add flag to export NVMEM to root only Andrew Lunn <andrew@lunn.ch> - 2015-12-21 09:30 +0100
    [PatchV2 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework Andrew Lunn <andrew@lunn.ch> - 2015-12-21 09:30 +0100
    [PatchV2 5/6] eeprom: at25: extend driver to plug into the NVMEM framework Andrew Lunn <andrew@lunn.ch> - 2015-12-21 09:30 +0100
    [PatchV2 2/6] nvmem: Add backwards compatibility support for older EEPROM drivers. Andrew Lunn <andrew@lunn.ch> - 2015-12-21 09:30 +0100

#1295818 — [PatchV2 0/6] Convert exiting EEPROM drivers to NVMEM

FromAndrew Lunn <andrew@lunn.ch>
Date2015-12-21 09:30 +0100
Subject[PatchV2 0/6] Convert exiting EEPROM drivers to NVMEM
Message-ID<qI40W-43S-3@gated-at.bofh.it>
This patch set converts the old EEPROM drivers in driver/misc/eeprom to
use the NVMEM framework. These drivers export there content in /sys as
read only to root, since the EEPROM may contain sensitive information.
So the first patch adds a flag so the NVMEM framework will create its
file in /sys as root read only.

To keep backwards compatibility with these older drivers, the contents
of the EEPROM must be exports in sysfs in a file called eeprom in the
devices node in sys, where as the NVMEM places them under class/nvmem.
So add this optional backwards compatible to the framework, again
using a flag.

Then convert the at24, at25 and 93xx46 by adding regmap support,
removing each drivers own /sys code and registering with the NVMEM
framework.

AT24 and 93xx46 has been boot tested, at25 compile tested only.

v2:

nvmem_register() now supports a backwards compatible flag, and the
Kconfig option has been removed.

Andrew Lunn (6):
  nvmem: Add flag to export NVMEM to root only
  nvmem: Add backwards compatibility support for older EEPROM drivers.
  eeprom: at24: extend driver to plug into the NVMEM framework
  eeprom: at25: Remove in kernel API for accessing the EEPROM
  eeprom: at25: extend driver to plug into the NVMEM framework
  eeprom: 93xx46: extend driver to plug into the NVMEM framework

 drivers/misc/eeprom/Kconfig         |   6 ++
 drivers/misc/eeprom/at24.c          | 121 +++++++++++++++++++----------
 drivers/misc/eeprom/at25.c          | 148 +++++++++++++++++-------------------
 drivers/misc/eeprom/eeprom_93xx46.c | 122 ++++++++++++++++++++++-------
 drivers/nvmem/core.c                | 134 +++++++++++++++++++++++++++++---
 include/linux/nvmem-provider.h      |   5 +-
 include/linux/spi/eeprom.h          |   2 -
 7 files changed, 378 insertions(+), 160 deletions(-)

-- 
2.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1295819 — [PatchV2 1/6] nvmem: Add flag to export NVMEM to root only

FromAndrew Lunn <andrew@lunn.ch>
Date2015-12-21 09:30 +0100
Subject[PatchV2 1/6] nvmem: Add flag to export NVMEM to root only
Message-ID<qI40W-43S-9@gated-at.bofh.it>
In reply to#1295818
Legacy AT24, AT25 EEPROMs are exported in sys so that only root can
read the contents. The EEPROMs may contain sensitive information. Add
a flag so the provide can indicate that NVMEM should also restrict
access to root only.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/nvmem/core.c           | 57 ++++++++++++++++++++++++++++++++++++++++--
 include/linux/nvmem-provider.h |  1 +
 2 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 6fd4e5a5ef4a..4ccf03da6467 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -155,6 +155,53 @@ static const struct attribute_group *nvmem_ro_dev_groups[] = {
 	NULL,
 };
 
+/* default read/write permissions, root only */
+static struct bin_attribute bin_attr_rw_root_nvmem = {
+	.attr	= {
+		.name	= "nvmem",
+		.mode	= S_IWUSR | S_IRUSR,
+	},
+	.read	= bin_attr_nvmem_read,
+	.write	= bin_attr_nvmem_write,
+};
+
+static struct bin_attribute *nvmem_bin_rw_root_attributes[] = {
+	&bin_attr_rw_root_nvmem,
+	NULL,
+};
+
+static const struct attribute_group nvmem_bin_rw_root_group = {
+	.bin_attrs	= nvmem_bin_rw_root_attributes,
+};
+
+static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
+	&nvmem_bin_rw_root_group,
+	NULL,
+};
+
+/* read only permission, root only */
+static struct bin_attribute bin_attr_ro_root_nvmem = {
+	.attr	= {
+		.name	= "nvmem",
+		.mode	= S_IRUSR,
+	},
+	.read	= bin_attr_nvmem_read,
+};
+
+static struct bin_attribute *nvmem_bin_ro_root_attributes[] = {
+	&bin_attr_ro_root_nvmem,
+	NULL,
+};
+
+static const struct attribute_group nvmem_bin_ro_root_group = {
+	.bin_attrs	= nvmem_bin_ro_root_attributes,
+};
+
+static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
+	&nvmem_bin_ro_root_group,
+	NULL,
+};
+
 static void nvmem_release(struct device *dev)
 {
 	struct nvmem_device *nvmem = to_nvmem_device(dev);
@@ -347,8 +394,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
 	nvmem->read_only = of_property_read_bool(np, "read-only") |
 			   config->read_only;
 
-	nvmem->dev.groups = nvmem->read_only ? nvmem_ro_dev_groups :
-					       nvmem_rw_dev_groups;
+	if (config->root_only)
+		nvmem->dev.groups = nvmem->read_only ?
+			nvmem_ro_root_dev_groups :
+			nvmem_rw_root_dev_groups;
+	else
+		nvmem->dev.groups = nvmem->read_only ?
+			nvmem_ro_dev_groups :
+			nvmem_rw_dev_groups;
 
 	device_initialize(&nvmem->dev);
 
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index 0b68caff1b3c..d24fefa0c11d 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -23,6 +23,7 @@ struct nvmem_config {
 	const struct nvmem_cell_info	*cells;
 	int			ncells;
 	bool			read_only;
+	bool			root_only;
 };
 
 #if IS_ENABLED(CONFIG_NVMEM)
-- 
2.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1295822 — [PatchV2 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework

FromAndrew Lunn <andrew@lunn.ch>
Date2015-12-21 09:30 +0100
Subject[PatchV2 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework
Message-ID<qI40W-43S-17@gated-at.bofh.it>
In reply to#1295818
Add a regmap for accessing the EEPROM, and then use that with the
NVMEM framework. Enable backward compatibility in the MVMEM config
structure, so that the 'eeprom' file in sys is provided by the
framework.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/misc/eeprom/Kconfig         |   2 +
 drivers/misc/eeprom/eeprom_93xx46.c | 122 ++++++++++++++++++++++++++++--------
 2 files changed, 98 insertions(+), 26 deletions(-)

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 8c43a222ae55..cfc493c2e30a 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -78,6 +78,8 @@ config EEPROM_93CX6
 config EEPROM_93XX46
 	tristate "Microwire EEPROM 93XX46 support"
 	depends on SPI && SYSFS
+	select REGMAP
+	select NVMEM
 	help
 	  Driver for the microwire EEPROM chipsets 93xx46x. The driver
 	  supports both read and write commands and also the command to
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index ff63f05edc76..feb74d3f95b5 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -15,7 +15,8 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
-#include <linux/sysfs.h>
+#include <linux/nvmem-provider.h>
+#include <linux/regmap.h>
 #include <linux/eeprom_93xx46.h>
 
 #define OP_START	0x4
@@ -28,25 +29,29 @@
 struct eeprom_93xx46_dev {
 	struct spi_device *spi;
 	struct eeprom_93xx46_platform_data *pdata;
-	struct bin_attribute bin;
 	struct mutex lock;
+	struct regmap_config regmap_config;
+	struct nvmem_config nvmem_config;
+	struct nvmem_device *nvmem;
 	int addrlen;
+	int size;
 };
 
 static ssize_t
-eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj,
-		       struct bin_attribute *bin_attr,
-		       char *buf, loff_t off, size_t count)
+eeprom_93xx46_read(struct eeprom_93xx46_dev *edev, char *buf,
+		   unsigned off, size_t count)
 {
-	struct eeprom_93xx46_dev *edev;
-	struct device *dev;
 	struct spi_message m;
 	struct spi_transfer t[2];
 	int bits, ret;
 	u16 cmd_addr;
 
-	dev = container_of(kobj, struct device, kobj);
-	edev = dev_get_drvdata(dev);
+	if (unlikely(off >= edev->size))
+		return 0;
+	if ((off + count) > edev->size)
+		count = edev->size - off;
+	if (unlikely(!count))
+		return count;
 
 	cmd_addr = OP_READ << edev->addrlen;
 
@@ -94,6 +99,7 @@ eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj,
 	return ret ? : count;
 }
 
+
 static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
 {
 	struct spi_message m;
@@ -182,16 +188,17 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
 }
 
 static ssize_t
-eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj,
-			struct bin_attribute *bin_attr,
-			char *buf, loff_t off, size_t count)
+eeprom_93xx46_write(struct eeprom_93xx46_dev *edev, const char *buf,
+		    loff_t off, size_t count)
 {
-	struct eeprom_93xx46_dev *edev;
-	struct device *dev;
 	int i, ret, step = 1;
 
-	dev = container_of(kobj, struct device, kobj);
-	edev = dev_get_drvdata(dev);
+	if (unlikely(off >= edev->size))
+		return -EFBIG;
+	if ((off + count) > edev->size)
+		count = edev->size - off;
+	if (unlikely(!count))
+		return count;
 
 	/* only write even number of bytes on 16-bit devices */
 	if (edev->addrlen == 6) {
@@ -228,6 +235,49 @@ eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj,
 	return ret ? : count;
 }
 
+/*
+ * Provide a regmap interface, which is registered with the NVMEM
+ * framework
+*/
+static int eeprom_93xx46_regmap_read(void *context, const void *reg,
+				     size_t reg_size, void *val,
+				     size_t val_size)
+{
+	struct eeprom_93xx46_dev *eeprom_93xx46 = context;
+	off_t offset = *(u32 *)reg;
+	int err;
+
+	err = eeprom_93xx46_read(eeprom_93xx46, val, offset, val_size);
+	if (err)
+		return err;
+	return 0;
+}
+
+static int eeprom_93xx46_regmap_write(void *context, const void *data,
+				      size_t count)
+{
+	struct eeprom_93xx46_dev *eeprom_93xx46 = context;
+	const char *buf;
+	u32 offset;
+	size_t len;
+	int err;
+
+	memcpy(&offset, data, sizeof(offset));
+	buf = (const char *)data + sizeof(offset);
+	len = count - sizeof(offset);
+
+	err = eeprom_93xx46_write(eeprom_93xx46, buf, offset, len);
+	if (err)
+		return err;
+	return 0;
+}
+
+static const struct regmap_bus eeprom_93xx46_regmap_bus = {
+	.read = eeprom_93xx46_regmap_read,
+	.write = eeprom_93xx46_regmap_write,
+	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
 static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
 {
 	struct eeprom_93xx46_platform_data *pd = edev->pdata;
@@ -298,6 +348,7 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
 {
 	struct eeprom_93xx46_platform_data *pd;
 	struct eeprom_93xx46_dev *edev;
+	struct regmap *regmap;
 	int err;
 
 	pd = spi->dev.platform_data;
@@ -325,19 +376,37 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
 	edev->spi = spi_dev_get(spi);
 	edev->pdata = pd;
 
-	sysfs_bin_attr_init(&edev->bin);
-	edev->bin.attr.name = "eeprom";
-	edev->bin.attr.mode = S_IRUSR;
-	edev->bin.read = eeprom_93xx46_bin_read;
-	edev->bin.size = 128;
+	edev->size = 128;
+
 	if (!(pd->flags & EE_READONLY)) {
-		edev->bin.write = eeprom_93xx46_bin_write;
-		edev->bin.attr.mode |= S_IWUSR;
 	}
 
-	err = sysfs_create_bin_file(&spi->dev.kobj, &edev->bin);
-	if (err)
+	edev->regmap_config.reg_bits = 32;
+	edev->regmap_config.val_bits = 8;
+	edev->regmap_config.reg_stride = 1;
+	edev->regmap_config.max_register = edev->size - 1;
+
+	regmap = devm_regmap_init(&spi->dev, &eeprom_93xx46_regmap_bus, edev,
+				  &edev->regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&spi->dev, "regmap init failed\n");
+		err = PTR_ERR(regmap);
 		goto fail;
+	}
+
+	edev->nvmem_config.name = dev_name(&spi->dev);
+	edev->nvmem_config.dev = &spi->dev;
+	edev->nvmem_config.read_only = pd->flags & EE_READONLY;
+	edev->nvmem_config.root_only = true;
+	edev->nvmem_config.owner = THIS_MODULE;
+	edev->nvmem_config.compat = true;
+	edev->nvmem_config.base_dev = &spi->dev;
+
+	edev->nvmem = nvmem_register(&edev->nvmem_config);
+	if (IS_ERR(edev->nvmem)) {
+		err = PTR_ERR(edev->nvmem);
+		goto fail;
+	}
 
 	dev_info(&spi->dev, "%d-bit eeprom %s\n",
 		(pd->flags & EE_ADDR8) ? 8 : 16,
@@ -359,10 +428,11 @@ static int eeprom_93xx46_remove(struct spi_device *spi)
 {
 	struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi);
 
+	nvmem_unregister(edev->nvmem);
+
 	if (!(edev->pdata->flags & EE_READONLY))
 		device_remove_file(&spi->dev, &dev_attr_erase);
 
-	sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin);
 	kfree(edev);
 	return 0;
 }
-- 
2.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1295823 — [PatchV2 5/6] eeprom: at25: extend driver to plug into the NVMEM framework

FromAndrew Lunn <andrew@lunn.ch>
Date2015-12-21 09:30 +0100
Subject[PatchV2 5/6] eeprom: at25: extend driver to plug into the NVMEM framework
Message-ID<qI40W-43S-1@gated-at.bofh.it>
In reply to#1295818
Add a regmap for accessing the EEPROM, and then use that with the
NVMEM framework. Enable backwards compatibility in the NVMEM config,
so that the 'eeprom' file in sys is provided by the framework.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/misc/eeprom/Kconfig |   2 +
 drivers/misc/eeprom/at25.c  | 124 ++++++++++++++++++++++++--------------------
 2 files changed, 71 insertions(+), 55 deletions(-)

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 24935473393b..8c43a222ae55 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -32,6 +32,8 @@ config EEPROM_AT24
 config EEPROM_AT25
 	tristate "SPI EEPROMs from most vendors"
 	depends on SPI && SYSFS
+	select REGMAP
+	select NVMEM
 	help
 	  Enable this driver to get read/write support to most SPI EEPROMs,
 	  after you configure the board init code to know about each eeprom
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 4732f6997289..fa36a6e37084 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -16,6 +16,8 @@
 #include <linux/device.h>
 #include <linux/sched.h>
 
+#include <linux/nvmem-provider.h>
+#include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/eeprom.h>
 #include <linux/property.h>
@@ -31,8 +33,10 @@ struct at25_data {
 	struct spi_device	*spi;
 	struct mutex		lock;
 	struct spi_eeprom	chip;
-	struct bin_attribute	bin;
 	unsigned		addrlen;
+	struct regmap_config	regmap_config;
+	struct nvmem_config	nvmem_config;
+	struct nvmem_device	*nvmem;
 };
 
 #define	AT25_WREN	0x06		/* latch the write enable */
@@ -76,10 +80,10 @@ at25_ee_read(
 	struct spi_message	m;
 	u8			instr;
 
-	if (unlikely(offset >= at25->bin.size))
+	if (unlikely(offset >= at25->chip.byte_len))
 		return 0;
-	if ((offset + count) > at25->bin.size)
-		count = at25->bin.size - offset;
+	if ((offset + count) > at25->chip.byte_len)
+		count = at25->chip.byte_len - offset;
 	if (unlikely(!count))
 		return count;
 
@@ -130,21 +134,19 @@ at25_ee_read(
 	return status ? status : count;
 }
 
-static ssize_t
-at25_bin_read(struct file *filp, struct kobject *kobj,
-	      struct bin_attribute *bin_attr,
-	      char *buf, loff_t off, size_t count)
+static int at25_regmap_read(void *context, const void *reg, size_t reg_size,
+			    void *val, size_t val_size)
 {
-	struct device		*dev;
-	struct at25_data	*at25;
-
-	dev = container_of(kobj, struct device, kobj);
-	at25 = dev_get_drvdata(dev);
+	struct at25_data *at25 = context;
+	off_t offset = *(u32 *)reg;
+	int err;
 
-	return at25_ee_read(at25, buf, off, count);
+	err = at25_ee_read(at25, val, offset, val_size);
+	if (err)
+		return err;
+	return 0;
 }
 
-
 static ssize_t
 at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
 	      size_t count)
@@ -154,10 +156,10 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
 	unsigned		buf_size;
 	u8			*bounce;
 
-	if (unlikely(off >= at25->bin.size))
+	if (unlikely(off >= at25->chip.byte_len))
 		return -EFBIG;
-	if ((off + count) > at25->bin.size)
-		count = at25->bin.size - off;
+	if ((off + count) > at25->chip.byte_len)
+		count = at25->chip.byte_len - off;
 	if (unlikely(!count))
 		return count;
 
@@ -264,20 +266,30 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
 	return written ? written : status;
 }
 
-static ssize_t
-at25_bin_write(struct file *filp, struct kobject *kobj,
-	       struct bin_attribute *bin_attr,
-	       char *buf, loff_t off, size_t count)
+static int at25_regmap_write(void *context, const void *data, size_t count)
 {
-	struct device		*dev;
-	struct at25_data	*at25;
+	struct at25_data *at25 = context;
+	const char *buf;
+	u32 offset;
+	size_t len;
+	int err;
 
-	dev = container_of(kobj, struct device, kobj);
-	at25 = dev_get_drvdata(dev);
+	memcpy(&offset, data, sizeof(offset));
+	buf = (const char *)data + sizeof(offset);
+	len = count - sizeof(offset);
 
-	return at25_ee_write(at25, buf, off, count);
+	err = at25_ee_write(at25, buf, offset, len);
+	if (err)
+		return err;
+	return 0;
 }
 
+static const struct regmap_bus at25_regmap_bus = {
+	.read = at25_regmap_read,
+	.write = at25_regmap_write,
+	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
 /*-------------------------------------------------------------------------*/
 
 static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
@@ -337,6 +349,7 @@ static int at25_probe(struct spi_device *spi)
 {
 	struct at25_data	*at25 = NULL;
 	struct spi_eeprom	chip;
+	struct regmap		*regmap;
 	int			err;
 	int			sr;
 	int			addrlen;
@@ -381,35 +394,35 @@ static int at25_probe(struct spi_device *spi)
 	spi_set_drvdata(spi, at25);
 	at25->addrlen = addrlen;
 
-	/* Export the EEPROM bytes through sysfs, since that's convenient.
-	 * And maybe to other kernel code; it might hold a board's Ethernet
-	 * address, or board-specific calibration data generated on the
-	 * manufacturing floor.
-	 *
-	 * Default to root-only access to the data; EEPROMs often hold data
-	 * that's sensitive for read and/or write, like ethernet addresses,
-	 * security codes, board-specific manufacturing calibrations, etc.
-	 */
-	sysfs_bin_attr_init(&at25->bin);
-	at25->bin.attr.name = "eeprom";
-	at25->bin.attr.mode = S_IRUSR;
-	at25->bin.read = at25_bin_read;
-
-	at25->bin.size = at25->chip.byte_len;
-	if (!(chip.flags & EE_READONLY)) {
-		at25->bin.write = at25_bin_write;
-		at25->bin.attr.mode |= S_IWUSR;
-	}
+	at25->regmap_config.reg_bits = 32;
+	at25->regmap_config.val_bits = 8;
+	at25->regmap_config.reg_stride = 1;
+	at25->regmap_config.max_register = chip.byte_len - 1;
 
-	err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
-	if (err)
-		return err;
+	regmap = devm_regmap_init(&spi->dev, &at25_regmap_bus, at25,
+				  &at25->regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&spi->dev, "regmap init failed\n");
+		return PTR_ERR(regmap);
+	}
 
-	dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
-		(at25->bin.size < 1024)
-			? at25->bin.size
-			: (at25->bin.size / 1024),
-		(at25->bin.size < 1024) ? "Byte" : "KByte",
+	at25->nvmem_config.name = dev_name(&spi->dev);
+	at25->nvmem_config.dev = &spi->dev;
+	at25->nvmem_config.read_only = chip.flags & EE_READONLY;
+	at25->nvmem_config.root_only = true;
+	at25->nvmem_config.owner = THIS_MODULE;
+	at25->nvmem_config.compat = true;
+	at25->nvmem_config.base_dev = &spi->dev;
+
+	at25->nvmem = nvmem_register(&at25->nvmem_config);
+	if (IS_ERR(at25->nvmem))
+		return PTR_ERR(at25->nvmem);
+
+	dev_info(&spi->dev, "%d %s %s eeprom%s, pagesize %u\n",
+		(chip.byte_len < 1024)
+			? chip.byte_len
+			: (chip.byte_len / 1024),
+		(chip.byte_len < 1024) ? "Byte" : "KByte",
 		at25->chip.name,
 		(chip.flags & EE_READONLY) ? " (readonly)" : "",
 		at25->chip.page_size);
@@ -421,7 +434,8 @@ static int at25_remove(struct spi_device *spi)
 	struct at25_data	*at25;
 
 	at25 = spi_get_drvdata(spi);
-	sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin);
+	nvmem_unregister(at25->nvmem);
+
 	return 0;
 }
 
-- 
2.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1295824 — [PatchV2 2/6] nvmem: Add backwards compatibility support for older EEPROM drivers.

FromAndrew Lunn <andrew@lunn.ch>
Date2015-12-21 09:30 +0100
Subject[PatchV2 2/6] nvmem: Add backwards compatibility support for older EEPROM drivers.
Message-ID<qI40X-43S-25@gated-at.bofh.it>
In reply to#1295818
Older drivers made an 'eeprom' file available in the /sys device
directory. Have the NVMEM core provide this to retain backwards
compatibility.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/nvmem/core.c           | 77 +++++++++++++++++++++++++++++++++++++-----
 include/linux/nvmem-provider.h |  4 ++-
 2 files changed, 72 insertions(+), 9 deletions(-)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 4ccf03da6467..15b09ff2dac3 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -38,8 +38,13 @@ struct nvmem_device {
 	int			users;
 	size_t			size;
 	bool			read_only;
+	int			flags;
+	struct bin_attribute	eeprom;
+	struct device		*base_dev;
 };
 
+#define FLAG_COMPAT		BIT(0)
+
 struct nvmem_cell {
 	const char		*name;
 	int			offset;
@@ -62,10 +67,16 @@ 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);
+	struct device *dev;
+	struct nvmem_device *nvmem;
 	int rc;
 
+	if (attr->private)
+		dev = attr->private;
+	else
+		dev = container_of(kobj, struct device, kobj);
+	nvmem = to_nvmem_device(dev);
+
 	/* Stop the user from reading */
 	if (pos >= nvmem->size)
 		return 0;
@@ -87,10 +98,16 @@ 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);
+	struct device *dev;
+	struct nvmem_device *nvmem;
 	int rc;
 
+	if (attr->private)
+		dev = attr->private;
+	else
+		dev = container_of(kobj, struct device, kobj);
+	nvmem = to_nvmem_device(dev);
+
 	/* Stop the user from writing */
 	if (pos >= nvmem->size)
 		return 0;
@@ -341,6 +358,40 @@ err:
 	return rval;
 }
 
+/*
+ * nvmem_setup_compat() - Create an additional binary entry in
+ * drivers sys directory, to be backwards compatible with the older
+ * drivers/misc/eeprom drivers.
+ */
+static int nvmem_setup_compat(struct nvmem_device *nvmem,
+			      const struct nvmem_config *config)
+{
+	int rval;
+
+	if (!config->base_dev)
+		return -EINVAL;
+
+	if (nvmem->read_only)
+		nvmem->eeprom = bin_attr_ro_root_nvmem;
+	else
+		nvmem->eeprom = bin_attr_rw_root_nvmem;
+	nvmem->eeprom.attr.name = "eeprom";
+	nvmem->eeprom.size = nvmem->size;
+	nvmem->eeprom.private = &nvmem->dev;
+	nvmem->base_dev = config->base_dev;
+
+	rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
+	if (rval) {
+		dev_err(&nvmem->dev,
+			"Failed to create eeprom binary file %d\n", rval);
+		return rval;
+	}
+
+	nvmem->flags |= FLAG_COMPAT;
+
+	return 0;
+}
+
 /**
  * nvmem_register() - Register a nvmem device for given nvmem_config.
  * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
@@ -408,16 +459,23 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
 	dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
 
 	rval = device_add(&nvmem->dev);
-	if (rval) {
-		ida_simple_remove(&nvmem_ida, nvmem->id);
-		kfree(nvmem);
-		return ERR_PTR(rval);
+	if (rval)
+		goto out;
+
+	if (config->compat) {
+		rval = nvmem_setup_compat(nvmem, config);
+		if (rval)
+			goto out;
 	}
 
 	if (config->cells)
 		nvmem_add_cells(nvmem, config);
 
 	return nvmem;
+out:
+	ida_simple_remove(&nvmem_ida, nvmem->id);
+	kfree(nvmem);
+	return ERR_PTR(rval);
 }
 EXPORT_SYMBOL_GPL(nvmem_register);
 
@@ -437,6 +495,9 @@ int nvmem_unregister(struct nvmem_device *nvmem)
 	}
 	mutex_unlock(&nvmem_mutex);
 
+	if (nvmem->flags & FLAG_COMPAT)
+		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
+
 	nvmem_device_remove_all_cells(nvmem);
 	device_del(&nvmem->dev);
 
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index d24fefa0c11d..a4fcc90b0f20 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -24,6 +24,9 @@ struct nvmem_config {
 	int			ncells;
 	bool			read_only;
 	bool			root_only;
+	/* To be only used by old driver/misc/eeprom drivers */
+	bool			compat;
+	struct device		*base_dev;
 };
 
 #if IS_ENABLED(CONFIG_NVMEM)
@@ -44,5 +47,4 @@ static inline int nvmem_unregister(struct nvmem_device *nvmem)
 }
 
 #endif /* CONFIG_NVMEM */
-
 #endif  /* ifndef _LINUX_NVMEM_PROVIDER_H */
-- 
2.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web