1/* 2 * linux/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c 3 * Copyright (C) 2000-2001 Toshiba Corporation 4 * 5 * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the 6 * terms of the GNU General Public License version 2. This program is 7 * licensed "as is" without any warranty of any kind, whether express 8 * or implied. 9 * 10 * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) 11 */ 12#include <linux/init.h> 13#include <linux/delay.h> 14#include <linux/proc_fs.h> 15#include <linux/spinlock.h> 16#include <asm/tx4938/spi.h> 17#include <asm/tx4938/tx4938.h> 18 19/* ATMEL 250x0 instructions */ 20#define ATMEL_WREN 0x06 21#define ATMEL_WRDI 0x04 22#define ATMEL_RDSR 0x05 23#define ATMEL_WRSR 0x01 24#define ATMEL_READ 0x03 25#define ATMEL_WRITE 0x02 26 27#define ATMEL_SR_BSY 0x01 28#define ATMEL_SR_WEN 0x02 29#define ATMEL_SR_BP0 0x04 30#define ATMEL_SR_BP1 0x08 31 32DEFINE_SPINLOCK(spi_eeprom_lock); 33 34static struct spi_dev_desc seeprom_dev_desc = { 35 .baud = 1500000, /* 1.5Mbps */ 36 .tcss = 1, 37 .tcsh = 1, 38 .tcsr = 1, 39 .byteorder = 1, /* MSB-First */ 40 .polarity = 0, /* High-Active */ 41 .phase = 0, /* Sample-Then-Shift */ 42 43}; 44static inline int 45spi_eeprom_io(int chipid, 46 unsigned char **inbufs, unsigned int *incounts, 47 unsigned char **outbufs, unsigned int *outcounts) 48{ 49 return txx9_spi_io(chipid, &seeprom_dev_desc, 50 inbufs, incounts, outbufs, outcounts, 0); 51} 52 53int spi_eeprom_write_enable(int chipid, int enable) 54{ 55 unsigned char inbuf[1]; 56 unsigned char *inbufs[1]; 57 unsigned int incounts[2]; 58 unsigned long flags; 59 int stat; 60 inbuf[0] = enable ? ATMEL_WREN : ATMEL_WRDI; 61 inbufs[0] = inbuf; 62 incounts[0] = sizeof(inbuf); 63 incounts[1] = 0; 64 spin_lock_irqsave(&spi_eeprom_lock, flags); 65 stat = spi_eeprom_io(chipid, inbufs, incounts, NULL, NULL); 66 spin_unlock_irqrestore(&spi_eeprom_lock, flags); 67 return stat; 68} 69 70static int spi_eeprom_read_status_nolock(int chipid) 71{ 72 unsigned char inbuf[2], outbuf[2]; 73 unsigned char *inbufs[1], *outbufs[1]; 74 unsigned int incounts[2], outcounts[2]; 75 int stat; 76 inbuf[0] = ATMEL_RDSR; 77 inbuf[1] = 0; 78 inbufs[0] = inbuf; 79 incounts[0] = sizeof(inbuf); 80 incounts[1] = 0; 81 outbufs[0] = outbuf; 82 outcounts[0] = sizeof(outbuf); 83 outcounts[1] = 0; 84 stat = spi_eeprom_io(chipid, inbufs, incounts, outbufs, outcounts); 85 if (stat < 0) 86 return stat; 87 return outbuf[1]; 88} 89 90int spi_eeprom_read_status(int chipid) 91{ 92 unsigned long flags; 93 int stat; 94 spin_lock_irqsave(&spi_eeprom_lock, flags); 95 stat = spi_eeprom_read_status_nolock(chipid); 96 spin_unlock_irqrestore(&spi_eeprom_lock, flags); 97 return stat; 98} 99 100int spi_eeprom_read(int chipid, int address, unsigned char *buf, int len) 101{ 102 unsigned char inbuf[2]; 103 unsigned char *inbufs[2], *outbufs[2]; 104 unsigned int incounts[2], outcounts[3]; 105 unsigned long flags; 106 int stat; 107 inbuf[0] = ATMEL_READ; 108 inbuf[1] = address; 109 inbufs[0] = inbuf; 110 inbufs[1] = NULL; 111 incounts[0] = sizeof(inbuf); 112 incounts[1] = 0; 113 outbufs[0] = NULL; 114 outbufs[1] = buf; 115 outcounts[0] = 2; 116 outcounts[1] = len; 117 outcounts[2] = 0; 118 spin_lock_irqsave(&spi_eeprom_lock, flags); 119 stat = spi_eeprom_io(chipid, inbufs, incounts, outbufs, outcounts); 120 spin_unlock_irqrestore(&spi_eeprom_lock, flags); 121 return stat; 122} 123 124int spi_eeprom_write(int chipid, int address, unsigned char *buf, int len) 125{ 126 unsigned char inbuf[2]; 127 unsigned char *inbufs[2]; 128 unsigned int incounts[3]; 129 unsigned long flags; 130 int i, stat; 131 132 if (address / 8 != (address + len - 1) / 8) 133 return -EINVAL; 134 stat = spi_eeprom_write_enable(chipid, 1); 135 if (stat < 0) 136 return stat; 137 stat = spi_eeprom_read_status(chipid); 138 if (stat < 0) 139 return stat; 140 if (!(stat & ATMEL_SR_WEN)) 141 return -EPERM; 142 143 inbuf[0] = ATMEL_WRITE; 144 inbuf[1] = address; 145 inbufs[0] = inbuf; 146 inbufs[1] = buf; 147 incounts[0] = sizeof(inbuf); 148 incounts[1] = len; 149 incounts[2] = 0; 150 spin_lock_irqsave(&spi_eeprom_lock, flags); 151 stat = spi_eeprom_io(chipid, inbufs, incounts, NULL, NULL); 152 if (stat < 0) 153 goto unlock_return; 154 155 /* write start. max 10ms */ 156 for (i = 10; i > 0; i--) { 157 int stat = spi_eeprom_read_status_nolock(chipid); 158 if (stat < 0) 159 goto unlock_return; 160 if (!(stat & ATMEL_SR_BSY)) 161 break; 162 mdelay(1); 163 } 164 spin_unlock_irqrestore(&spi_eeprom_lock, flags); 165 if (i == 0) 166 return -EIO; 167 return len; 168 unlock_return: 169 spin_unlock_irqrestore(&spi_eeprom_lock, flags); 170 return stat; 171} 172 173#ifdef CONFIG_PROC_FS 174#define MAX_SIZE 0x80 /* for ATMEL 25010 */ 175static int spi_eeprom_read_proc(char *page, char **start, off_t off, 176 int count, int *eof, void *data) 177{ 178 unsigned int size = MAX_SIZE; 179 if (spi_eeprom_read((int)data, 0, (unsigned char *)page, size) < 0) 180 size = 0; 181 return size; 182} 183 184static int spi_eeprom_write_proc(struct file *file, const char *buffer, 185 unsigned long count, void *data) 186{ 187 unsigned int size = MAX_SIZE; 188 int i; 189 if (file->f_pos >= size) 190 return -EIO; 191 if (file->f_pos + count > size) 192 count = size - file->f_pos; 193 for (i = 0; i < count; i += 8) { 194 int len = count - i < 8 ? count - i : 8; 195 if (spi_eeprom_write((int)data, file->f_pos, 196 (unsigned char *)buffer, len) < 0) { 197 count = -EIO; 198 break; 199 } 200 buffer += len; 201 file->f_pos += len; 202 } 203 return count; 204} 205 206__init void spi_eeprom_proc_create(struct proc_dir_entry *dir, int chipid) 207{ 208 struct proc_dir_entry *entry; 209 char name[128]; 210 sprintf(name, "seeprom-%d", chipid); 211 entry = create_proc_entry(name, 0600, dir); 212 if (entry) { 213 entry->read_proc = spi_eeprom_read_proc; 214 entry->write_proc = spi_eeprom_write_proc; 215 entry->data = (void *)chipid; 216 } 217} 218#endif /* CONFIG_PROC_FS */ 219