summaryrefslogtreecommitdiffstats
path: root/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c')
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c261
1 files changed, 71 insertions, 190 deletions
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c b/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c
index 89596e6..4d6b4ad 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c
@@ -10,209 +10,90 @@
* Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
*/
#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
#include <asm/tx4938/spi.h>
-#include <asm/tx4938/tx4938.h>
-/* ATMEL 250x0 instructions */
-#define ATMEL_WREN 0x06
-#define ATMEL_WRDI 0x04
-#define ATMEL_RDSR 0x05
-#define ATMEL_WRSR 0x01
-#define ATMEL_READ 0x03
-#define ATMEL_WRITE 0x02
+#define AT250X0_PAGE_SIZE 8
-#define ATMEL_SR_BSY 0x01
-#define ATMEL_SR_WEN 0x02
-#define ATMEL_SR_BP0 0x04
-#define ATMEL_SR_BP1 0x08
-
-DEFINE_SPINLOCK(spi_eeprom_lock);
-
-static struct spi_dev_desc seeprom_dev_desc = {
- .baud = 1500000, /* 1.5Mbps */
- .tcss = 1,
- .tcsh = 1,
- .tcsr = 1,
- .byteorder = 1, /* MSB-First */
- .polarity = 0, /* High-Active */
- .phase = 0, /* Sample-Then-Shift */
-
-};
-static inline int
-spi_eeprom_io(int chipid,
- unsigned char **inbufs, unsigned int *incounts,
- unsigned char **outbufs, unsigned int *outcounts)
-{
- return txx9_spi_io(chipid, &seeprom_dev_desc,
- inbufs, incounts, outbufs, outcounts, 0);
-}
-
-int spi_eeprom_write_enable(int chipid, int enable)
+/* register board information for at25 driver */
+int __init spi_eeprom_register(int chipid)
{
- unsigned char inbuf[1];
- unsigned char *inbufs[1];
- unsigned int incounts[2];
- unsigned long flags;
- int stat;
- inbuf[0] = enable ? ATMEL_WREN : ATMEL_WRDI;
- inbufs[0] = inbuf;
- incounts[0] = sizeof(inbuf);
- incounts[1] = 0;
- spin_lock_irqsave(&spi_eeprom_lock, flags);
- stat = spi_eeprom_io(chipid, inbufs, incounts, NULL, NULL);
- spin_unlock_irqrestore(&spi_eeprom_lock, flags);
- return stat;
-}
-
-static int spi_eeprom_read_status_nolock(int chipid)
-{
- unsigned char inbuf[2], outbuf[2];
- unsigned char *inbufs[1], *outbufs[1];
- unsigned int incounts[2], outcounts[2];
- int stat;
- inbuf[0] = ATMEL_RDSR;
- inbuf[1] = 0;
- inbufs[0] = inbuf;
- incounts[0] = sizeof(inbuf);
- incounts[1] = 0;
- outbufs[0] = outbuf;
- outcounts[0] = sizeof(outbuf);
- outcounts[1] = 0;
- stat = spi_eeprom_io(chipid, inbufs, incounts, outbufs, outcounts);
- if (stat < 0)
- return stat;
- return outbuf[1];
+ static struct spi_eeprom eeprom = {
+ .name = "at250x0",
+ .byte_len = 128,
+ .page_size = AT250X0_PAGE_SIZE,
+ .flags = EE_ADDR1,
+ };
+ struct spi_board_info info = {
+ .modalias = "at25",
+ .max_speed_hz = 1500000, /* 1.5Mbps */
+ .bus_num = 0,
+ .chip_select = chipid,
+ .platform_data = &eeprom,
+ /* Mode 0: High-Active, Sample-Then-Shift */
+ };
+
+ return spi_register_board_info(&info, 1);
}
-int spi_eeprom_read_status(int chipid)
-{
- unsigned long flags;
- int stat;
- spin_lock_irqsave(&spi_eeprom_lock, flags);
- stat = spi_eeprom_read_status_nolock(chipid);
- spin_unlock_irqrestore(&spi_eeprom_lock, flags);
- return stat;
-}
+/* simple temporary spi driver to provide early access to seeprom. */
-int spi_eeprom_read(int chipid, int address, unsigned char *buf, int len)
-{
- unsigned char inbuf[2];
- unsigned char *inbufs[2], *outbufs[2];
- unsigned int incounts[2], outcounts[3];
- unsigned long flags;
- int stat;
- inbuf[0] = ATMEL_READ;
- inbuf[1] = address;
- inbufs[0] = inbuf;
- inbufs[1] = NULL;
- incounts[0] = sizeof(inbuf);
- incounts[1] = 0;
- outbufs[0] = NULL;
- outbufs[1] = buf;
- outcounts[0] = 2;
- outcounts[1] = len;
- outcounts[2] = 0;
- spin_lock_irqsave(&spi_eeprom_lock, flags);
- stat = spi_eeprom_io(chipid, inbufs, incounts, outbufs, outcounts);
- spin_unlock_irqrestore(&spi_eeprom_lock, flags);
- return stat;
-}
+static struct read_param {
+ int chipid;
+ int address;
+ unsigned char *buf;
+ int len;
+} *read_param;
-int spi_eeprom_write(int chipid, int address, unsigned char *buf, int len)
+static int __init early_seeprom_probe(struct spi_device *spi)
{
- unsigned char inbuf[2];
- unsigned char *inbufs[2];
- unsigned int incounts[3];
- unsigned long flags;
- int i, stat;
-
- if (address / 8 != (address + len - 1) / 8)
- return -EINVAL;
- stat = spi_eeprom_write_enable(chipid, 1);
- if (stat < 0)
- return stat;
- stat = spi_eeprom_read_status(chipid);
- if (stat < 0)
- return stat;
- if (!(stat & ATMEL_SR_WEN))
- return -EPERM;
-
- inbuf[0] = ATMEL_WRITE;
- inbuf[1] = address;
- inbufs[0] = inbuf;
- inbufs[1] = buf;
- incounts[0] = sizeof(inbuf);
- incounts[1] = len;
- incounts[2] = 0;
- spin_lock_irqsave(&spi_eeprom_lock, flags);
- stat = spi_eeprom_io(chipid, inbufs, incounts, NULL, NULL);
- if (stat < 0)
- goto unlock_return;
-
- /* write start. max 10ms */
- for (i = 10; i > 0; i--) {
- int stat = spi_eeprom_read_status_nolock(chipid);
- if (stat < 0)
- goto unlock_return;
- if (!(stat & ATMEL_SR_BSY))
- break;
- mdelay(1);
+ int stat = 0;
+ u8 cmd[2];
+ int len = read_param->len;
+ char *buf = read_param->buf;
+ int address = read_param->address;
+
+ dev_info(&spi->dev, "spiclk %u KHz.\n",
+ (spi->max_speed_hz + 500) / 1000);
+ if (read_param->chipid != spi->chip_select)
+ return -ENODEV;
+ while (len > 0) {
+ /* spi_write_then_read can only work with small chunk */
+ int c = len < AT250X0_PAGE_SIZE ? len : AT250X0_PAGE_SIZE;
+ cmd[0] = 0x03; /* AT25_READ */
+ cmd[1] = address;
+ stat = spi_write_then_read(spi, cmd, sizeof(cmd), buf, c);
+ buf += c;
+ len -= c;
+ address += c;
}
- spin_unlock_irqrestore(&spi_eeprom_lock, flags);
- if (i == 0)
- return -EIO;
- return len;
- unlock_return:
- spin_unlock_irqrestore(&spi_eeprom_lock, flags);
return stat;
}
-#ifdef CONFIG_PROC_FS
-#define MAX_SIZE 0x80 /* for ATMEL 25010 */
-static int spi_eeprom_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- unsigned int size = MAX_SIZE;
- if (spi_eeprom_read((int)data, 0, (unsigned char *)page, size) < 0)
- size = 0;
- return size;
-}
-
-static int spi_eeprom_write_proc(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- unsigned int size = MAX_SIZE;
- int i;
- if (file->f_pos >= size)
- return -EIO;
- if (file->f_pos + count > size)
- count = size - file->f_pos;
- for (i = 0; i < count; i += 8) {
- int len = count - i < 8 ? count - i : 8;
- if (spi_eeprom_write((int)data, file->f_pos,
- (unsigned char *)buffer, len) < 0) {
- count = -EIO;
- break;
- }
- buffer += len;
- file->f_pos += len;
- }
- return count;
-}
+static struct spi_driver early_seeprom_driver __initdata = {
+ .driver = {
+ .name = "at25",
+ .owner = THIS_MODULE,
+ },
+ .probe = early_seeprom_probe,
+};
-__init void spi_eeprom_proc_create(struct proc_dir_entry *dir, int chipid)
+int __init spi_eeprom_read(int chipid, int address,
+ unsigned char *buf, int len)
{
- struct proc_dir_entry *entry;
- char name[128];
- sprintf(name, "seeprom-%d", chipid);
- entry = create_proc_entry(name, 0600, dir);
- if (entry) {
- entry->read_proc = spi_eeprom_read_proc;
- entry->write_proc = spi_eeprom_write_proc;
- entry->data = (void *)chipid;
- }
+ int ret;
+ struct read_param param = {
+ .chipid = chipid,
+ .address = address,
+ .buf = buf,
+ .len = len
+ };
+
+ read_param = &param;
+ ret = spi_register_driver(&early_seeprom_driver);
+ if (!ret)
+ spi_unregister_driver(&early_seeprom_driver);
+ return ret;
}
-#endif /* CONFIG_PROC_FS */
OpenPOWER on IntegriCloud