linux/drivers/misc/eeprom/eeprom_93xx46.c
<<
>>
Prefs
   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
  29struct 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
  37static ssize_t
  38eeprom_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
 105static 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
 150static ssize_t
 151eeprom_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
 192static ssize_t
 193eeprom_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
 246static 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
 289static 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}
 310static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase);
 311
 312static 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;
 368fail:
 369        kfree(edev);
 370        return err;
 371}
 372
 373static 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
 386static 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
 395static int __init eeprom_93xx46_init(void)
 396{
 397        return spi_register_driver(&eeprom_93xx46_driver);
 398}
 399module_init(eeprom_93xx46_init);
 400
 401static void __exit eeprom_93xx46_exit(void)
 402{
 403        spi_unregister_driver(&eeprom_93xx46_driver);
 404}
 405module_exit(eeprom_93xx46_exit);
 406
 407MODULE_LICENSE("GPL");
 408MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs");
 409MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
 410MODULE_ALIAS("spi:93xx46");
 411
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.