aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/eeprom/at25.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/eeprom/at25.c')
-rw-r--r--drivers/misc/eeprom/at25.c129
1 files changed, 94 insertions, 35 deletions
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 0842c2994ee..634f72929e1 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -10,7 +10,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -19,7 +18,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
-
+#include <linux/of.h>
/*
* NOTE: this is an *EEPROM* driver. The vagaries of product naming
@@ -302,33 +301,93 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
/*-------------------------------------------------------------------------*/
+static int at25_np_to_chip(struct device *dev,
+ struct device_node *np,
+ struct spi_eeprom *chip)
+{
+ u32 val;
+
+ memset(chip, 0, sizeof(*chip));
+ strncpy(chip->name, np->name, sizeof(chip->name));
+
+ if (of_property_read_u32(np, "size", &val) == 0 ||
+ of_property_read_u32(np, "at25,byte-len", &val) == 0) {
+ chip->byte_len = val;
+ } else {
+ dev_err(dev, "Error: missing \"size\" property\n");
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(np, "pagesize", &val) == 0 ||
+ of_property_read_u32(np, "at25,page-size", &val) == 0) {
+ chip->page_size = (u16)val;
+ } else {
+ dev_err(dev, "Error: missing \"pagesize\" property\n");
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) {
+ chip->flags = (u16)val;
+ } else {
+ if (of_property_read_u32(np, "address-width", &val)) {
+ dev_err(dev,
+ "Error: missing \"address-width\" property\n");
+ return -ENODEV;
+ }
+ switch (val) {
+ case 8:
+ chip->flags |= EE_ADDR1;
+ break;
+ case 16:
+ chip->flags |= EE_ADDR2;
+ break;
+ case 24:
+ chip->flags |= EE_ADDR3;
+ break;
+ default:
+ dev_err(dev,
+ "Error: bad \"address-width\" property: %u\n",
+ val);
+ return -ENODEV;
+ }
+ if (of_find_property(np, "read-only", NULL))
+ chip->flags |= EE_READONLY;
+ }
+ return 0;
+}
+
static int at25_probe(struct spi_device *spi)
{
struct at25_data *at25 = NULL;
- const struct spi_eeprom *chip;
+ struct spi_eeprom chip;
+ struct device_node *np = spi->dev.of_node;
int err;
int sr;
int addrlen;
/* Chip description */
- chip = spi->dev.platform_data;
- if (!chip) {
- dev_dbg(&spi->dev, "no chip description\n");
- err = -ENODEV;
- goto fail;
- }
+ if (!spi->dev.platform_data) {
+ if (np) {
+ err = at25_np_to_chip(&spi->dev, np, &chip);
+ if (err)
+ return err;
+ } else {
+ dev_err(&spi->dev, "Error: no chip description\n");
+ return -ENODEV;
+ }
+ } else
+ chip = *(struct spi_eeprom *)spi->dev.platform_data;
/* For now we only support 8/16/24 bit addressing */
- if (chip->flags & EE_ADDR1)
+ if (chip.flags & EE_ADDR1)
addrlen = 1;
- else if (chip->flags & EE_ADDR2)
+ else if (chip.flags & EE_ADDR2)
addrlen = 2;
- else if (chip->flags & EE_ADDR3)
+ else if (chip.flags & EE_ADDR3)
addrlen = 3;
else {
dev_dbg(&spi->dev, "unsupported address type\n");
- err = -EINVAL;
- goto fail;
+ return -EINVAL;
}
/* Ping the chip ... the status register is pretty portable,
@@ -338,19 +397,17 @@ static int at25_probe(struct spi_device *spi)
sr = spi_w8r8(spi, AT25_RDSR);
if (sr < 0 || sr & AT25_SR_nRDY) {
dev_dbg(&spi->dev, "rdsr --> %d (%02x)\n", sr, sr);
- err = -ENXIO;
- goto fail;
+ return -ENXIO;
}
- if (!(at25 = kzalloc(sizeof *at25, GFP_KERNEL))) {
- err = -ENOMEM;
- goto fail;
- }
+ at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);
+ if (!at25)
+ return -ENOMEM;
mutex_init(&at25->lock);
- at25->chip = *chip;
+ at25->chip = chip;
at25->spi = spi_dev_get(spi);
- dev_set_drvdata(&spi->dev, at25);
+ spi_set_drvdata(spi, at25);
at25->addrlen = addrlen;
/* Export the EEPROM bytes through sysfs, since that's convenient.
@@ -369,7 +426,7 @@ static int at25_probe(struct spi_device *spi)
at25->mem.read = at25_mem_read;
at25->bin.size = at25->chip.byte_len;
- if (!(chip->flags & EE_READONLY)) {
+ if (!(chip.flags & EE_READONLY)) {
at25->bin.write = at25_bin_write;
at25->bin.attr.mode |= S_IWUSR;
at25->mem.write = at25_mem_write;
@@ -377,10 +434,10 @@ static int at25_probe(struct spi_device *spi)
err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
if (err)
- goto fail;
+ return err;
- if (chip->setup)
- chip->setup(&at25->mem, chip->context);
+ if (chip.setup)
+ chip.setup(&at25->mem, chip.context);
dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
(at25->bin.size < 1024)
@@ -388,34 +445,36 @@ static int at25_probe(struct spi_device *spi)
: (at25->bin.size / 1024),
(at25->bin.size < 1024) ? "Byte" : "KByte",
at25->chip.name,
- (chip->flags & EE_READONLY) ? " (readonly)" : "",
+ (chip.flags & EE_READONLY) ? " (readonly)" : "",
at25->chip.page_size);
return 0;
-fail:
- dev_dbg(&spi->dev, "probe err %d\n", err);
- kfree(at25);
- return err;
}
-static int __devexit at25_remove(struct spi_device *spi)
+static int at25_remove(struct spi_device *spi)
{
struct at25_data *at25;
- at25 = dev_get_drvdata(&spi->dev);
+ at25 = spi_get_drvdata(spi);
sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin);
- kfree(at25);
return 0;
}
/*-------------------------------------------------------------------------*/
+static const struct of_device_id at25_of_match[] = {
+ { .compatible = "atmel,at25", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, at25_of_match);
+
static struct spi_driver at25_driver = {
.driver = {
.name = "at25",
.owner = THIS_MODULE,
+ .of_match_table = at25_of_match,
},
.probe = at25_probe,
- .remove = __devexit_p(at25_remove),
+ .remove = at25_remove,
};
module_spi_driver(at25_driver);