• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/linux/linux-2.6/arch/mips/tx4938/toshiba_rbtx4938/
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