Commit 5a99f570 authored by Andrew Lunn's avatar Andrew Lunn Committed by Greg Kroah-Hartman

eeprom: at25: extend driver to plug into the NVMEM framework

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: default avatarAndrew Lunn <andrew@lunn.ch>
Acked-by: default avatarSrinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3ccea0e1
......@@ -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
......
......@@ -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 = kobj_to_dev(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 = kobj_to_dev(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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment