[go: nahoru, domu]

1/*
2 * addi_eeprom.c - ADDI EEPROM Module
3 * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
4 * Project manager: Eric Stolz
5 *
6 *	ADDI-DATA GmbH
7 *	Dieselstrasse 3
8 *	D-77833 Ottersweier
9 *	Tel: +19(0)7223/9493-0
10 *	Fax: +49(0)7223/9493-92
11 *	http://www.addi-data.com
12 *	info@addi-data.com
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 */
24
25#include <linux/delay.h>
26
27#define NVRAM_USER_DATA_START	0x100
28
29#define NVCMD_BEGIN_READ	(0x7 << 5)	/* nvRam begin read command */
30#define NVCMD_LOAD_LOW		(0x4 << 5)	/* nvRam load low command */
31#define NVCMD_LOAD_HIGH		(0x5 << 5)	/* nvRam load high command */
32
33#define EE93C76_CLK_BIT		(1 << 0)
34#define EE93C76_CS_BIT		(1 << 1)
35#define EE93C76_DOUT_BIT	(1 << 2)
36#define EE93C76_DIN_BIT		(1 << 3)
37#define EE93C76_READ_CMD	(0x0180 << 4)
38#define EE93C76_CMD_LEN		13
39
40#define EEPROM_DIGITALINPUT		0
41#define EEPROM_DIGITALOUTPUT		1
42#define EEPROM_ANALOGINPUT		2
43#define EEPROM_ANALOGOUTPUT		3
44#define EEPROM_TIMER			4
45#define EEPROM_WATCHDOG			5
46#define EEPROM_TIMER_WATCHDOG_COUNTER	10
47
48static void addi_eeprom_clk_93c76(unsigned long iobase, unsigned int val)
49{
50	outl(val & ~EE93C76_CLK_BIT, iobase);
51	udelay(100);
52
53	outl(val | EE93C76_CLK_BIT, iobase);
54	udelay(100);
55}
56
57static unsigned int addi_eeprom_cmd_93c76(unsigned long iobase,
58					  unsigned int cmd,
59					  unsigned char len)
60{
61	unsigned int val = EE93C76_CS_BIT;
62	int i;
63
64	/* Toggle EEPROM's Chip select to get it out of Shift Register Mode */
65	outl(val, iobase);
66	udelay(100);
67
68	/* Send EEPROM command - one bit at a time */
69	for (i = (len - 1); i >= 0; i--) {
70		if (cmd & (1 << i))
71			val |= EE93C76_DOUT_BIT;
72		else
73			val &= ~EE93C76_DOUT_BIT;
74
75		/* Write the command */
76		outl(val, iobase);
77		udelay(100);
78
79		addi_eeprom_clk_93c76(iobase, val);
80	}
81	return val;
82}
83
84static unsigned short addi_eeprom_readw_93c76(unsigned long iobase,
85					      unsigned short addr)
86{
87	unsigned short val = 0;
88	unsigned int cmd;
89	unsigned int tmp;
90	int i;
91
92	/* Send EEPROM read command and offset to EEPROM */
93	cmd = EE93C76_READ_CMD | (addr / 2);
94	cmd = addi_eeprom_cmd_93c76(iobase, cmd, EE93C76_CMD_LEN);
95
96	/* Get the 16-bit value */
97	for (i = 0; i < 16; i++) {
98		addi_eeprom_clk_93c76(iobase, cmd);
99
100		tmp = inl(iobase);
101		udelay(100);
102
103		val <<= 1;
104		if (tmp & EE93C76_DIN_BIT)
105			val |= 0x1;
106	}
107
108	/* Toggle EEPROM's Chip select to get it out of Shift Register Mode */
109	outl(0, iobase);
110	udelay(100);
111
112	return val;
113}
114
115static void addi_eeprom_nvram_wait(unsigned long iobase)
116{
117	unsigned char val;
118
119	do {
120		val = inb(iobase + AMCC_OP_REG_MCSR_NVCMD);
121	} while (val & 0x80);
122}
123
124static unsigned short addi_eeprom_readw_nvram(unsigned long iobase,
125					      unsigned short addr)
126{
127	unsigned short val = 0;
128	unsigned char tmp;
129	unsigned char i;
130
131	for (i = 0; i < 2; i++) {
132		/* Load the low 8 bit address */
133		outb(NVCMD_LOAD_LOW, iobase + AMCC_OP_REG_MCSR_NVCMD);
134		addi_eeprom_nvram_wait(iobase);
135		outb((addr + i) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
136		addi_eeprom_nvram_wait(iobase);
137
138		/* Load the high 8 bit address */
139		outb(NVCMD_LOAD_HIGH, iobase + AMCC_OP_REG_MCSR_NVCMD);
140		addi_eeprom_nvram_wait(iobase);
141		outb(((addr + i) >> 8) & 0xff,
142			iobase + AMCC_OP_REG_MCSR_NVDATA);
143		addi_eeprom_nvram_wait(iobase);
144
145		/* Read the eeprom data byte */
146		outb(NVCMD_BEGIN_READ, iobase + AMCC_OP_REG_MCSR_NVCMD);
147		addi_eeprom_nvram_wait(iobase);
148		tmp = inb(iobase + AMCC_OP_REG_MCSR_NVDATA);
149		addi_eeprom_nvram_wait(iobase);
150
151		if (i == 0)
152			val |= tmp;
153		else
154			val |= (tmp << 8);
155	}
156
157	return val;
158}
159
160static unsigned short addi_eeprom_readw(unsigned long iobase,
161					char *type,
162					unsigned short addr)
163{
164	unsigned short val = 0;
165
166	/* Add the offset to the start of the user data */
167	addr += NVRAM_USER_DATA_START;
168
169	if (!strcmp(type, "S5920") || !strcmp(type, "S5933"))
170		val = addi_eeprom_readw_nvram(iobase, addr);
171
172	if (!strcmp(type, "93C76"))
173		val = addi_eeprom_readw_93c76(iobase, addr);
174
175	return val;
176}
177
178static void addi_eeprom_read_di_info(struct comedi_device *dev,
179				     unsigned long iobase,
180				     unsigned short addr)
181{
182	const struct addi_board *this_board = dev->board_ptr;
183	struct addi_private *devpriv = dev->private;
184	char *type = this_board->pc_EepromChip;
185	unsigned short tmp;
186
187	/* Number of channels */
188	tmp = addi_eeprom_readw(iobase, type, addr + 6);
189	devpriv->s_EeParameters.i_NbrDiChannel = tmp;
190
191	/* Interruptible or not */
192	tmp = addi_eeprom_readw(iobase, type, addr + 8);
193	tmp = (tmp >> 7) & 0x01;
194
195	/* How many interruptible logic */
196	tmp = addi_eeprom_readw(iobase, type, addr + 10);
197}
198
199static void addi_eeprom_read_do_info(struct comedi_device *dev,
200				     unsigned long iobase,
201				     unsigned short addr)
202{
203	const struct addi_board *this_board = dev->board_ptr;
204	struct addi_private *devpriv = dev->private;
205	char *type = this_board->pc_EepromChip;
206	unsigned short tmp;
207
208	/* Number of channels */
209	tmp = addi_eeprom_readw(iobase, type, addr + 6);
210	devpriv->s_EeParameters.i_NbrDoChannel = tmp;
211
212	devpriv->s_EeParameters.i_DoMaxdata = 0xffffffff >> (32 - tmp);
213}
214
215static void addi_eeprom_read_timer_info(struct comedi_device *dev,
216					unsigned long iobase,
217					unsigned short addr)
218{
219	struct addi_private *devpriv = dev->private;
220#if 0
221	const struct addi_board *this_board = dev->board_ptr;
222	char *type = this_board->pc_EepromChip;
223	unsigned short offset = 0;
224	unsigned short ntimers;
225	unsigned short tmp;
226	int i;
227
228	/* Number of Timers */
229	ntimers = addi_eeprom_readw(iobase, type, addr + 6);
230
231	/* Read header size */
232	for (i = 0; i < ntimers; i++) {
233		unsigned short size;
234		unsigned short res;
235		unsigned short mode;
236		unsigned short min_timing;
237		unsigned short timebase;
238
239		size = addi_eeprom_readw(iobase, type, addr + 8 + offset + 0);
240
241		/* Resolution / Mode */
242		tmp = addi_eeprom_readw(iobase, type, addr + 8 + offset + 2);
243		res = (tmp >> 10) & 0x3f;
244		mode = (tmp >> 4) & 0x3f;
245
246		/* MinTiming / Timebase */
247		tmp = addi_eeprom_readw(iobase, type, addr + 8 + offset + 4);
248		min_timing = (tmp  >> 6) & 0x3ff;
249		Timebase = tmp & 0x3f;
250
251		offset += size;
252	}
253#endif
254	/* Timer subdevice present */
255	devpriv->s_EeParameters.i_Timer = 1;
256}
257
258static void addi_eeprom_read_ao_info(struct comedi_device *dev,
259				     unsigned long iobase,
260				     unsigned short addr)
261{
262	const struct addi_board *this_board = dev->board_ptr;
263	struct addi_private *devpriv = dev->private;
264	char *type = this_board->pc_EepromChip;
265	unsigned short tmp;
266
267	/* No of channels for 1st hard component */
268	tmp = addi_eeprom_readw(iobase, type, addr + 10);
269	devpriv->s_EeParameters.i_NbrAoChannel = (tmp >> 4) & 0x3ff;
270
271	/* Resolution for 1st hard component */
272	tmp = addi_eeprom_readw(iobase, type, addr + 16);
273	tmp = (tmp >> 8) & 0xff;
274	devpriv->s_EeParameters.i_AoMaxdata = 0xfff >> (16 - tmp);
275}
276
277static void addi_eeprom_read_ai_info(struct comedi_device *dev,
278				     unsigned long iobase,
279				     unsigned short addr)
280{
281	const struct addi_board *this_board = dev->board_ptr;
282	struct addi_private *devpriv = dev->private;
283	char *type = this_board->pc_EepromChip;
284	unsigned short offset;
285	unsigned short tmp;
286
287	/* No of channels for 1st hard component */
288	tmp = addi_eeprom_readw(iobase, type, addr + 10);
289	devpriv->s_EeParameters.i_NbrAiChannel = (tmp >> 4) & 0x3ff;
290	if (!strcmp(this_board->pc_DriverName, "apci3200"))
291		devpriv->s_EeParameters.i_NbrAiChannel *= 4;
292
293	tmp = addi_eeprom_readw(iobase, type, addr + 16);
294	devpriv->s_EeParameters.ui_MinAcquisitiontimeNs = tmp * 1000;
295
296	tmp = addi_eeprom_readw(iobase, type, addr + 30);
297	devpriv->s_EeParameters.ui_MinDelaytimeNs = tmp * 1000;
298
299	tmp = addi_eeprom_readw(iobase, type, addr + 20);
300	/* dma = (tmp >> 13) & 0x01; */
301
302	tmp = addi_eeprom_readw(iobase, type, addr + 72) & 0xff;
303	if (tmp) {		/* > 0 */
304		/* offset of first analog input single header */
305		offset = 74 + (2 * tmp) + (10 * (1 + (tmp / 16)));
306	} else {		/* = 0 */
307		offset = 74;
308	}
309
310	/* Resolution */
311	tmp = addi_eeprom_readw(iobase, type, addr + offset + 2) & 0x1f;
312	devpriv->s_EeParameters.i_AiMaxdata = 0xffff >> (16 - tmp);
313}
314
315static void addi_eeprom_read_info(struct comedi_device *dev,
316				  unsigned long iobase)
317{
318	const struct addi_board *this_board = dev->board_ptr;
319	char *type = this_board->pc_EepromChip;
320	unsigned short size;
321	unsigned char nfuncs;
322	int i;
323
324	size = addi_eeprom_readw(iobase, type, 8);
325	nfuncs = addi_eeprom_readw(iobase, type, 10) & 0xff;
326
327	/* Read functionality details */
328	for (i = 0; i < nfuncs; i++) {
329		unsigned short offset = i * 4;
330		unsigned short addr;
331		unsigned char func;
332
333		func = addi_eeprom_readw(iobase, type, 12 + offset) & 0x3f;
334		addr = addi_eeprom_readw(iobase, type, 14 + offset);
335
336		switch (func) {
337		case EEPROM_DIGITALINPUT:
338			addi_eeprom_read_di_info(dev, iobase, addr);
339			break;
340
341		case EEPROM_DIGITALOUTPUT:
342			addi_eeprom_read_do_info(dev, iobase, addr);
343			break;
344
345		case EEPROM_ANALOGINPUT:
346			addi_eeprom_read_ai_info(dev, iobase, addr);
347			break;
348
349		case EEPROM_ANALOGOUTPUT:
350			addi_eeprom_read_ao_info(dev, iobase, addr);
351			break;
352
353		case EEPROM_TIMER:
354		case EEPROM_WATCHDOG:
355		case EEPROM_TIMER_WATCHDOG_COUNTER:
356			addi_eeprom_read_timer_info(dev, iobase, addr);
357			break;
358		}
359	}
360}
361