The SPI on DM355 EVM and DM6467 EVM is conencted only to EEPROM.
This patch adds support for the EEPROM client driver

Signed-off-by: Sandeep Paulraj <[email protected]>
Signed-off-by: Steve Chen <[email protected]>
---
 drivers/mtd/devices/Makefile         |    1 +
 drivers/mtd/devices/at25xxA_eeprom.c |  267 ++++++++++++++++++++++++++++++++++
 include/linux/spi/at25xxA_eeprom.h   |   51 +++++++
 3 files changed, 319 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/devices/at25xxA_eeprom.c
 create mode 100644 include/linux/spi/at25xxA_eeprom.h

diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index e51521d..ccee6b1 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_MTD_BLOCK2MTD)   += block2mtd.o
 obj-$(CONFIG_MTD_DATAFLASH)    += mtd_dataflash.o
 obj-$(CONFIG_MTD_M25P80)       += m25p80.o
 obj-$(CONFIG_MTD_PS3VRAM)      += ps3vram.o
+obj-$(CONFIG_DAVINCI_SPI_EEPROM)+= at25xxA_eeprom.o
diff --git a/drivers/mtd/devices/at25xxA_eeprom.c 
b/drivers/mtd/devices/at25xxA_eeprom.c
new file mode 100644
index 0000000..24ecc65
--- /dev/null
+++ b/drivers/mtd/devices/at25xxA_eeprom.c
@@ -0,0 +1,267 @@
+/*
+ * Davinci SPI-EEPROM client driver
+ *
+ * Author: Steve Chen <[email protected]>
+ *
+ * 2007-2009 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/mutex.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/uaccess.h>
+
+#include <linux/spi/at25xxA_eeprom.h>
+#include <linux/spi/davinci_spi_master.h>
+
+/*
+ *  Utilities functions
+ */
+static int spi_generic_eeprom_read(struct mtd_info *mtd, loff_t from,
+                                  size_t count, size_t *retlen, u_char *buf)
+{
+       u8 *tx_ptr, *rx_ptr;
+       int rx_cnt;
+       unsigned int addr;
+       unsigned long flags;
+       struct spi_transfer x[2];
+       struct spi_message msg;
+       struct davinci_eeprom_info *priv_dat = mtd->priv;
+
+       addr = (u16) from;
+       *retlen = 0;
+       if (addr > priv_dat->eeprom_size)
+               return -EINVAL;
+
+       if (count > priv_dat->eeprom_size)
+               return -EINVAL;
+
+       if ((addr + count) > priv_dat->eeprom_size)
+               return -EINVAL;
+
+       memset(x, 0, sizeof x);
+       mutex_lock(&priv_dat->lock);
+       x[0].tx_buf = tx_ptr = priv_dat->tx_buffer;
+
+       tx_ptr[0] = DAVINCI_EEPROM_READ;
+
+       x[0].len = 3;
+
+       /* Handle data return from EEPROM */
+       x[1].rx_buf = rx_ptr = priv_dat->rx_buffer;
+
+       while (count > 0) {
+               if (likely(count > SPI_BUFFER_SIZE))
+                       rx_cnt = SPI_BUFFER_SIZE;
+               else
+                       rx_cnt = count;
+
+               spi_message_init(&msg);
+               /* setup read command */
+               tx_ptr[1] = (addr >> 8) & 0xFF;
+               tx_ptr[2] = (addr & 0xFF);
+
+               local_irq_save(flags);
+               spi_message_add_tail(&x[0], &msg);
+
+               /* read the eeprom */
+               x[1].len = rx_cnt;
+               spi_message_add_tail(&x[1], &msg);
+               local_irq_restore(flags);
+
+               spi_sync(priv_dat->spi, &msg);
+
+               /* spi_read(priv_dat->spi, rx_ptr, rx_cnt); */
+               memcpy(buf, rx_ptr, rx_cnt);
+
+               buf += rx_cnt;
+               count -= rx_cnt;
+               addr += rx_cnt;
+               *retlen += rx_cnt;
+       }
+       mutex_unlock(&priv_dat->lock);
+
+       return 0;
+}
+
+static int spi_generic_eeprom_write(struct mtd_info *mtd, loff_t to,
+                                   size_t count, size_t *retlen,
+                                   const u_char *buf)
+{
+       char *ptr;
+       int status;
+       int tx_cnt;
+       unsigned int addr;
+       struct spi_transfer xfer[2];
+       struct spi_message msg;
+       struct davinci_eeprom_info *priv_dat = mtd->priv;
+       unsigned long flags;
+
+       addr = (u16) (to);
+       *retlen = 0;
+       memset(xfer, 0, sizeof xfer);
+       if (addr > priv_dat->eeprom_size)
+               return -EINVAL;
+
+       if (count > priv_dat->eeprom_size)
+               return -EINVAL;
+
+       if ((addr + count) > priv_dat->eeprom_size)
+               return -EINVAL;
+
+       mutex_lock(&priv_dat->lock);
+       while (count > 0) {
+               xfer[0].tx_buf = ptr = priv_dat->tx_buffer;
+
+               /* set write enable */
+               ptr[0] = DAVINCI_EEPROM_WREN;
+               spi_write(priv_dat->spi, ptr, 1);
+
+               spi_message_init(&msg);
+
+               /* set the write command */
+               ptr[0] = DAVINCI_EEPROM_WRITE;
+               ptr[1] = (addr >> 8) & 0xFF;
+               ptr[2] = (addr & 0xFF);
+               xfer[0].len = DAVINCI_SPI_TX_CMD_SIZE;
+               local_irq_save(flags);
+               spi_message_add_tail(&xfer[0], &msg);
+
+               /* figure out the max transfer within a page */
+               tx_cnt = priv_dat->page_size - (addr & priv_dat->page_mask);
+
+               if (count < tx_cnt)
+                       tx_cnt = count;
+
+               ptr = &priv_dat->tx_buffer[DAVINCI_SPI_TX_CMD_SIZE];
+               xfer[1].tx_buf = ptr;
+               xfer[1].len = tx_cnt;
+               memcpy(ptr, buf, tx_cnt);
+               spi_message_add_tail(&xfer[1], &msg);
+               local_irq_restore(flags);
+               status = spi_sync(priv_dat->spi, &msg);
+
+               count -= tx_cnt;
+               buf += tx_cnt;
+               addr += tx_cnt;
+               *retlen += tx_cnt;
+               /* Some SPI-EEPROM (CSI for example) starts an internal
+                  transfer (from buffer to EEPROM) when WREN is disalbed.
+                  All requrests are ignored until the transfer is completed.
+                  This delay ensure no data is lost */
+               if (priv_dat->commit_delay)
+                       mdelay(priv_dat->commit_delay);
+       }
+       mutex_unlock(&priv_dat->lock);
+
+       return 0;
+}
+
+static int spi_eeprom_generic_erase(struct mtd_info *mtd,
+                                   struct erase_info *instr)
+{
+       instr->state = MTD_ERASE_DONE;
+       mtd_erase_callback(instr);
+       return 0;
+}
+
+static struct mtd_info davinci_at25;
+
+static int __devinit eeprom_probe(struct spi_device *spi)
+{
+       int ret;
+       static struct mtd_info *mtd;
+       struct davinci_eeprom_info *info;
+
+       mtd = &davinci_at25;
+       memset(mtd, 0, sizeof(struct mtd_info));
+
+       info = spi->dev.platform_data;
+       info->spi = spi;
+       info->spi_data = spi_master_get_devdata(spi->master);
+       mutex_init(&info->lock);
+
+       mtd->priv = info;
+       mtd->size = info->eeprom_size;
+       mtd->flags = MTD_CAP_RAM;
+       mtd->read = spi_generic_eeprom_read;
+       mtd->write = spi_generic_eeprom_write;
+       mtd->erase = spi_eeprom_generic_erase;
+       mtd->type = MTD_RAM;
+       mtd->name = "spi_eeprom";
+       mtd->erasesize = 0x10;
+       mtd->writesize = 1;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       if (info->nr_parts)
+               ret = add_mtd_partitions(mtd, info->parts, info->nr_parts);
+       else
+               ret = add_mtd_device(mtd);
+#else
+       ret = add_mtd_device(mtd);
+#endif
+
+       if (ret < 0)
+               pr_info("at25xxA_spi_eeprom device register failed\n");
+
+       return ret;
+}
+
+static int __devexit eeprom_remove(struct spi_device *spi)
+{
+       int ret;
+       struct mtd_info *mtd;
+       struct davinci_eeprom_info *info;
+
+       mtd = &davinci_at25;
+       info = spi->dev.platform_data;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       if (info->nr_parts)
+               ret = del_mtd_partitions(mtd);
+       else
+               ret = del_mtd_device(mtd);
+#else
+       ret = del_mtd_device(mtd);
+#endif
+
+       return ret;
+}
+
+static struct spi_driver spi_eeprom_driver = {
+       .driver = {
+                  .name = DAVINCI_SPI_EEPROM_NAME,
+                  .bus = &spi_bus_type,
+                  .owner = THIS_MODULE,
+                  },
+       .probe = eeprom_probe,
+       .remove = eeprom_remove,
+};
+
+static int __init spi_eeprom_init(void)
+{
+       return spi_register_driver(&spi_eeprom_driver);
+}
+
+module_init(spi_eeprom_init);
+
+static void __exit spi_eeprom_exit(void)
+{
+       spi_unregister_driver(&spi_eeprom_driver);
+}
+
+module_exit(spi_eeprom_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Steve Chen");
+MODULE_DESCRIPTION("SPI EEPROM driver");
diff --git a/include/linux/spi/at25xxA_eeprom.h 
b/include/linux/spi/at25xxA_eeprom.h
new file mode 100644
index 0000000..01e31b3
--- /dev/null
+++ b/include/linux/spi/at25xxA_eeprom.h
@@ -0,0 +1,51 @@
+/*
+ * DaVinci SPI-EEPROM client driver header file
+ *
+ * Author: Steve Chen <[email protected]>
+ *
+ * 2007-2009 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef DAVINCI_SPI_EEPROM_H
+#define DAVINCI_SPI_EEPROM_H
+
+#include <linux/cache.h>
+/*
+ *  EEPROM op-codes
+ */
+#define DAVINCI_EEPROM_READ    0x03    /* read */
+#define DAVINCI_EEPROM_WRITE   0x02    /* write */
+#define DAVINCI_EEPROM_WREN    0x06    /* write enable */
+#define DAVINCI_EEPROM_WRDIS   0x04    /* write disable */
+#define DAVINCI_EEPROM_RDSTAT  0x05    /* read status register */
+#define DAVINCI_EEPROM_WRSTAT  0x01    /* write status register */
+
+#define SPI_BUFFER_SIZE SMP_CACHE_BYTES
+#define DAVINCI_SPI_TX_CMD_SIZE 3
+
+#define DAVINCI_SPI_EEPROM_NAME "davinci_spi_eeprom"
+
+struct mtd_partition;
+
+struct davinci_eeprom_info {
+       unsigned int eeprom_size;
+       unsigned int page_size;
+       unsigned int page_mask;
+       unsigned long chip_sel;
+       unsigned int commit_delay;
+       struct spi_device *spi;
+       struct davinci_spi *spi_data;
+
+       struct mtd_partition *parts;
+       unsigned int nr_parts;
+
+       struct mutex lock;
+       char tx_buffer[SPI_BUFFER_SIZE + DAVINCI_SPI_TX_CMD_SIZE];
+       char rx_buffer[SPI_BUFFER_SIZE];
+};
+
+#endif                         /*DAVINCI_SPI_EEPROM_H */
+
-- 
1.6.0.4

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to