Commit 06b4501e88ad10f02849a3f9d7408ed6ae15a53f

Authored by Anatolij Gustschin
Committed by Linus Torvalds
1 parent 6e60c02e9d

misc/eeprom: add driver for microwire 93xx46 EEPROMs

Add EEPROM driver for 93xx46 chips.  It can also be used with spi_gpio
driver to access 93xx46 EEPROMs connected over GPIO lines.  This driver
supports read/write/erase access to the EEPROM chips over sysfs files.

[rdunlap@xenotime.net: fix printk format]
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Jonathan Cameron <jic23@cam.ac.uk>
Cc: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 4 changed files with 442 additions and 0 deletions Side-by-side Diff

drivers/misc/eeprom/Kconfig
... ... @@ -70,5 +70,18 @@
70 70  
71 71 If unsure, say N.
72 72  
  73 +config EEPROM_93XX46
  74 + tristate "Microwire EEPROM 93XX46 support"
  75 + depends on SPI && SYSFS
  76 + help
  77 + Driver for the microwire EEPROM chipsets 93xx46x. The driver
  78 + supports both read and write commands and also the command to
  79 + erase the whole EEPROM.
  80 +
  81 + This driver can also be built as a module. If so, the module
  82 + will be called eeprom_93xx46.
  83 +
  84 + If unsure, say N.
  85 +
73 86 endmenu
drivers/misc/eeprom/Makefile
... ... @@ -3,4 +3,5 @@
3 3 obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o
4 4 obj-$(CONFIG_EEPROM_MAX6875) += max6875.o
5 5 obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
  6 +obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o
drivers/misc/eeprom/eeprom_93xx46.c
  1 +/*
  2 + * Driver for 93xx46 EEPROMs
  3 + *
  4 + * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License version 2 as
  8 + * published by the Free Software Foundation.
  9 + */
  10 +
  11 +#include <linux/delay.h>
  12 +#include <linux/device.h>
  13 +#include <linux/kernel.h>
  14 +#include <linux/init.h>
  15 +#include <linux/module.h>
  16 +#include <linux/mutex.h>
  17 +#include <linux/slab.h>
  18 +#include <linux/spi/spi.h>
  19 +#include <linux/sysfs.h>
  20 +#include <linux/eeprom_93xx46.h>
  21 +
  22 +#define OP_START 0x4
  23 +#define OP_WRITE (OP_START | 0x1)
  24 +#define OP_READ (OP_START | 0x2)
  25 +#define ADDR_EWDS 0x00
  26 +#define ADDR_ERAL 0x20
  27 +#define ADDR_EWEN 0x30
  28 +
  29 +struct eeprom_93xx46_dev {
  30 + struct spi_device *spi;
  31 + struct eeprom_93xx46_platform_data *pdata;
  32 + struct bin_attribute bin;
  33 + struct mutex lock;
  34 + int addrlen;
  35 +};
  36 +
  37 +static ssize_t
  38 +eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj,
  39 + struct bin_attribute *bin_attr,
  40 + char *buf, loff_t off, size_t count)
  41 +{
  42 + struct eeprom_93xx46_dev *edev;
  43 + struct device *dev;
  44 + struct spi_message m;
  45 + struct spi_transfer t[2];
  46 + int bits, ret;
  47 + u16 cmd_addr;
  48 +
  49 + dev = container_of(kobj, struct device, kobj);
  50 + edev = dev_get_drvdata(dev);
  51 +
  52 + if (unlikely(off >= edev->bin.size))
  53 + return 0;
  54 + if ((off + count) > edev->bin.size)
  55 + count = edev->bin.size - off;
  56 + if (unlikely(!count))
  57 + return count;
  58 +
  59 + cmd_addr = OP_READ << edev->addrlen;
  60 +
  61 + if (edev->addrlen == 7) {
  62 + cmd_addr |= off & 0x7f;
  63 + bits = 10;
  64 + } else {
  65 + cmd_addr |= off & 0x3f;
  66 + bits = 9;
  67 + }
  68 +
  69 + dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n",
  70 + cmd_addr, edev->spi->max_speed_hz);
  71 +
  72 + spi_message_init(&m);
  73 + memset(t, 0, sizeof(t));
  74 +
  75 + t[0].tx_buf = (char *)&cmd_addr;
  76 + t[0].len = 2;
  77 + t[0].bits_per_word = bits;
  78 + spi_message_add_tail(&t[0], &m);
  79 +
  80 + t[1].rx_buf = buf;
  81 + t[1].len = count;
  82 + t[1].bits_per_word = 8;
  83 + spi_message_add_tail(&t[1], &m);
  84 +
  85 + mutex_lock(&edev->lock);
  86 +
  87 + if (edev->pdata->prepare)
  88 + edev->pdata->prepare(edev);
  89 +
  90 + ret = spi_sync(edev->spi, &m);
  91 + /* have to wait at least Tcsl ns */
  92 + ndelay(250);
  93 + if (ret) {
  94 + dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n",
  95 + count, (int)off, ret);
  96 + }
  97 +
  98 + if (edev->pdata->finish)
  99 + edev->pdata->finish(edev);
  100 +
  101 + mutex_unlock(&edev->lock);
  102 + return ret ? : count;
  103 +}
  104 +
  105 +static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
  106 +{
  107 + struct spi_message m;
  108 + struct spi_transfer t;
  109 + int bits, ret;
  110 + u16 cmd_addr;
  111 +
  112 + cmd_addr = OP_START << edev->addrlen;
  113 + if (edev->addrlen == 7) {
  114 + cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1;
  115 + bits = 10;
  116 + } else {
  117 + cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS);
  118 + bits = 9;
  119 + }
  120 +
  121 + dev_dbg(&edev->spi->dev, "ew cmd 0x%04x\n", cmd_addr);
  122 +
  123 + spi_message_init(&m);
  124 + memset(&t, 0, sizeof(t));
  125 +
  126 + t.tx_buf = &cmd_addr;
  127 + t.len = 2;
  128 + t.bits_per_word = bits;
  129 + spi_message_add_tail(&t, &m);
  130 +
  131 + mutex_lock(&edev->lock);
  132 +
  133 + if (edev->pdata->prepare)
  134 + edev->pdata->prepare(edev);
  135 +
  136 + ret = spi_sync(edev->spi, &m);
  137 + /* have to wait at least Tcsl ns */
  138 + ndelay(250);
  139 + if (ret)
  140 + dev_err(&edev->spi->dev, "erase/write %sable error %d\n",
  141 + is_on ? "en" : "dis", ret);
  142 +
  143 + if (edev->pdata->finish)
  144 + edev->pdata->finish(edev);
  145 +
  146 + mutex_unlock(&edev->lock);
  147 + return ret;
  148 +}
  149 +
  150 +static ssize_t
  151 +eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
  152 + const char *buf, unsigned off)
  153 +{
  154 + struct spi_message m;
  155 + struct spi_transfer t[2];
  156 + int bits, data_len, ret;
  157 + u16 cmd_addr;
  158 +
  159 + cmd_addr = OP_WRITE << edev->addrlen;
  160 +
  161 + if (edev->addrlen == 7) {
  162 + cmd_addr |= off & 0x7f;
  163 + bits = 10;
  164 + data_len = 1;
  165 + } else {
  166 + cmd_addr |= off & 0x3f;
  167 + bits = 9;
  168 + data_len = 2;
  169 + }
  170 +
  171 + dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr);
  172 +
  173 + spi_message_init(&m);
  174 + memset(t, 0, sizeof(t));
  175 +
  176 + t[0].tx_buf = (char *)&cmd_addr;
  177 + t[0].len = 2;
  178 + t[0].bits_per_word = bits;
  179 + spi_message_add_tail(&t[0], &m);
  180 +
  181 + t[1].tx_buf = buf;
  182 + t[1].len = data_len;
  183 + t[1].bits_per_word = 8;
  184 + spi_message_add_tail(&t[1], &m);
  185 +
  186 + ret = spi_sync(edev->spi, &m);
  187 + /* have to wait program cycle time Twc ms */
  188 + mdelay(6);
  189 + return ret;
  190 +}
  191 +
  192 +static ssize_t
  193 +eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj,
  194 + struct bin_attribute *bin_attr,
  195 + char *buf, loff_t off, size_t count)
  196 +{
  197 + struct eeprom_93xx46_dev *edev;
  198 + struct device *dev;
  199 + int i, ret, step = 1;
  200 +
  201 + dev = container_of(kobj, struct device, kobj);
  202 + edev = dev_get_drvdata(dev);
  203 +
  204 + if (unlikely(off >= edev->bin.size))
  205 + return 0;
  206 + if ((off + count) > edev->bin.size)
  207 + count = edev->bin.size - off;
  208 + if (unlikely(!count))
  209 + return count;
  210 +
  211 + /* only write even number of bytes on 16-bit devices */
  212 + if (edev->addrlen == 6) {
  213 + step = 2;
  214 + count &= ~1;
  215 + }
  216 +
  217 + /* erase/write enable */
  218 + ret = eeprom_93xx46_ew(edev, 1);
  219 + if (ret)
  220 + return ret;
  221 +
  222 + mutex_lock(&edev->lock);
  223 +
  224 + if (edev->pdata->prepare)
  225 + edev->pdata->prepare(edev);
  226 +
  227 + for (i = 0; i < count; i += step) {
  228 + ret = eeprom_93xx46_write_word(edev, &buf[i], off + i);
  229 + if (ret) {
  230 + dev_err(&edev->spi->dev, "write failed at %d: %d\n",
  231 + (int)off + i, ret);
  232 + break;
  233 + }
  234 + }
  235 +
  236 + if (edev->pdata->finish)
  237 + edev->pdata->finish(edev);
  238 +
  239 + mutex_unlock(&edev->lock);
  240 +
  241 + /* erase/write disable */
  242 + eeprom_93xx46_ew(edev, 0);
  243 + return ret ? : count;
  244 +}
  245 +
  246 +static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
  247 +{
  248 + struct eeprom_93xx46_platform_data *pd = edev->pdata;
  249 + struct spi_message m;
  250 + struct spi_transfer t;
  251 + int bits, ret;
  252 + u16 cmd_addr;
  253 +
  254 + cmd_addr = OP_START << edev->addrlen;
  255 + if (edev->addrlen == 7) {
  256 + cmd_addr |= ADDR_ERAL << 1;
  257 + bits = 10;
  258 + } else {
  259 + cmd_addr |= ADDR_ERAL;
  260 + bits = 9;
  261 + }
  262 +
  263 + spi_message_init(&m);
  264 + memset(&t, 0, sizeof(t));
  265 +
  266 + t.tx_buf = &cmd_addr;
  267 + t.len = 2;
  268 + t.bits_per_word = bits;
  269 + spi_message_add_tail(&t, &m);
  270 +
  271 + mutex_lock(&edev->lock);
  272 +
  273 + if (edev->pdata->prepare)
  274 + edev->pdata->prepare(edev);
  275 +
  276 + ret = spi_sync(edev->spi, &m);
  277 + if (ret)
  278 + dev_err(&edev->spi->dev, "erase error %d\n", ret);
  279 + /* have to wait erase cycle time Tec ms */
  280 + mdelay(6);
  281 +
  282 + if (pd->finish)
  283 + pd->finish(edev);
  284 +
  285 + mutex_unlock(&edev->lock);
  286 + return ret;
  287 +}
  288 +
  289 +static ssize_t eeprom_93xx46_store_erase(struct device *dev,
  290 + struct device_attribute *attr,
  291 + const char *buf, size_t count)
  292 +{
  293 + struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev);
  294 + int erase = 0, ret;
  295 +
  296 + sscanf(buf, "%d", &erase);
  297 + if (erase) {
  298 + ret = eeprom_93xx46_ew(edev, 1);
  299 + if (ret)
  300 + return ret;
  301 + ret = eeprom_93xx46_eral(edev);
  302 + if (ret)
  303 + return ret;
  304 + ret = eeprom_93xx46_ew(edev, 0);
  305 + if (ret)
  306 + return ret;
  307 + }
  308 + return count;
  309 +}
  310 +static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase);
  311 +
  312 +static int __devinit eeprom_93xx46_probe(struct spi_device *spi)
  313 +{
  314 + struct eeprom_93xx46_platform_data *pd;
  315 + struct eeprom_93xx46_dev *edev;
  316 + int err;
  317 +
  318 + pd = spi->dev.platform_data;
  319 + if (!pd) {
  320 + dev_err(&spi->dev, "missing platform data\n");
  321 + return -ENODEV;
  322 + }
  323 +
  324 + edev = kzalloc(sizeof(*edev), GFP_KERNEL);
  325 + if (!edev)
  326 + return -ENOMEM;
  327 +
  328 + if (pd->flags & EE_ADDR8)
  329 + edev->addrlen = 7;
  330 + else if (pd->flags & EE_ADDR16)
  331 + edev->addrlen = 6;
  332 + else {
  333 + dev_err(&spi->dev, "unspecified address type\n");
  334 + err = -EINVAL;
  335 + goto fail;
  336 + }
  337 +
  338 + mutex_init(&edev->lock);
  339 +
  340 + edev->spi = spi_dev_get(spi);
  341 + edev->pdata = pd;
  342 +
  343 + sysfs_bin_attr_init(&edev->bin);
  344 + edev->bin.attr.name = "eeprom";
  345 + edev->bin.attr.mode = S_IRUSR;
  346 + edev->bin.read = eeprom_93xx46_bin_read;
  347 + edev->bin.size = 128;
  348 + if (!(pd->flags & EE_READONLY)) {
  349 + edev->bin.write = eeprom_93xx46_bin_write;
  350 + edev->bin.attr.mode |= S_IWUSR;
  351 + }
  352 +
  353 + err = sysfs_create_bin_file(&spi->dev.kobj, &edev->bin);
  354 + if (err)
  355 + goto fail;
  356 +
  357 + dev_info(&spi->dev, "%d-bit eeprom %s\n",
  358 + (pd->flags & EE_ADDR8) ? 8 : 16,
  359 + (pd->flags & EE_READONLY) ? "(readonly)" : "");
  360 +
  361 + if (!(pd->flags & EE_READONLY)) {
  362 + if (device_create_file(&spi->dev, &dev_attr_erase))
  363 + dev_err(&spi->dev, "can't create erase interface\n");
  364 + }
  365 +
  366 + dev_set_drvdata(&spi->dev, edev);
  367 + return 0;
  368 +fail:
  369 + kfree(edev);
  370 + return err;
  371 +}
  372 +
  373 +static int __devexit eeprom_93xx46_remove(struct spi_device *spi)
  374 +{
  375 + struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev);
  376 +
  377 + if (!(edev->pdata->flags & EE_READONLY))
  378 + device_remove_file(&spi->dev, &dev_attr_erase);
  379 +
  380 + sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin);
  381 + dev_set_drvdata(&spi->dev, NULL);
  382 + kfree(edev);
  383 + return 0;
  384 +}
  385 +
  386 +static struct spi_driver eeprom_93xx46_driver = {
  387 + .driver = {
  388 + .name = "93xx46",
  389 + .owner = THIS_MODULE,
  390 + },
  391 + .probe = eeprom_93xx46_probe,
  392 + .remove = __devexit_p(eeprom_93xx46_remove),
  393 +};
  394 +
  395 +static int __init eeprom_93xx46_init(void)
  396 +{
  397 + return spi_register_driver(&eeprom_93xx46_driver);
  398 +}
  399 +module_init(eeprom_93xx46_init);
  400 +
  401 +static void __exit eeprom_93xx46_exit(void)
  402 +{
  403 + spi_unregister_driver(&eeprom_93xx46_driver);
  404 +}
  405 +module_exit(eeprom_93xx46_exit);
  406 +
  407 +MODULE_LICENSE("GPL");
  408 +MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs");
  409 +MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
  410 +MODULE_ALIAS("spi:93xx46");
include/linux/eeprom_93xx46.h
  1 +/*
  2 + * Module: eeprom_93xx46
  3 + * platform description for 93xx46 EEPROMs.
  4 + */
  5 +
  6 +struct eeprom_93xx46_platform_data {
  7 + unsigned char flags;
  8 +#define EE_ADDR8 0x01 /* 8 bit addr. cfg */
  9 +#define EE_ADDR16 0x02 /* 16 bit addr. cfg */
  10 +#define EE_READONLY 0x08 /* forbid writing */
  11 +
  12 + /*
  13 + * optional hooks to control additional logic
  14 + * before and after spi transfer.
  15 + */
  16 + void (*prepare)(void *);
  17 + void (*finish)(void *);
  18 +};