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
9 * Tel: +19(0)7223/9493-0
10 * Fax: +49(0)7223/9493-92
11 * http://www.addi-data.com
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.
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
25 #define NVRAM_USER_DATA_START 0x100
27 #define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */
28 #define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */
29 #define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */
31 #define EE93C76_CLK_BIT (1 << 0)
32 #define EE93C76_CS_BIT (1 << 1)
33 #define EE93C76_DOUT_BIT (1 << 2)
34 #define EE93C76_DIN_BIT (1 << 3)
35 #define EE93C76_READ_CMD (0x0180 << 4)
36 #define EE93C76_CMD_LEN 13
38 #define EEPROM_DIGITALINPUT 0
39 #define EEPROM_DIGITALOUTPUT 1
40 #define EEPROM_ANALOGINPUT 2
41 #define EEPROM_ANALOGOUTPUT 3
42 #define EEPROM_TIMER 4
43 #define EEPROM_WATCHDOG 5
44 #define EEPROM_TIMER_WATCHDOG_COUNTER 10
46 static void addi_eeprom_clk_93c76(unsigned long iobase
, unsigned int val
)
48 outl(val
& ~EE93C76_CLK_BIT
, iobase
);
51 outl(val
| EE93C76_CLK_BIT
, iobase
);
55 static unsigned int addi_eeprom_cmd_93c76(unsigned long iobase
,
59 unsigned int val
= EE93C76_CS_BIT
;
62 /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */
66 /* Send EEPROM command - one bit at a time */
67 for (i
= (len
- 1); i
>= 0; i
--) {
69 val
|= EE93C76_DOUT_BIT
;
71 val
&= ~EE93C76_DOUT_BIT
;
73 /* Write the command */
77 addi_eeprom_clk_93c76(iobase
, val
);
82 static unsigned short addi_eeprom_readw_93c76(unsigned long iobase
,
85 unsigned short val
= 0;
90 /* Send EEPROM read command and offset to EEPROM */
91 cmd
= EE93C76_READ_CMD
| (addr
/ 2);
92 cmd
= addi_eeprom_cmd_93c76(iobase
, cmd
, EE93C76_CMD_LEN
);
94 /* Get the 16-bit value */
95 for (i
= 0; i
< 16; i
++) {
96 addi_eeprom_clk_93c76(iobase
, cmd
);
102 if (tmp
& EE93C76_DIN_BIT
)
106 /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */
113 static void addi_eeprom_nvram_wait(unsigned long iobase
)
118 val
= inb(iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
119 } while (val
& 0x80);
122 static unsigned short addi_eeprom_readw_nvram(unsigned long iobase
,
125 unsigned short val
= 0;
129 for (i
= 0; i
< 2; i
++) {
130 /* Load the low 8 bit address */
131 outb(NVCMD_LOAD_LOW
, iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
132 addi_eeprom_nvram_wait(iobase
);
133 outb((addr
+ i
) & 0xff, iobase
+ AMCC_OP_REG_MCSR_NVDATA
);
134 addi_eeprom_nvram_wait(iobase
);
136 /* Load the high 8 bit address */
137 outb(NVCMD_LOAD_HIGH
, iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
138 addi_eeprom_nvram_wait(iobase
);
139 outb(((addr
+ i
) >> 8) & 0xff,
140 iobase
+ AMCC_OP_REG_MCSR_NVDATA
);
141 addi_eeprom_nvram_wait(iobase
);
143 /* Read the eeprom data byte */
144 outb(NVCMD_BEGIN_READ
, iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
145 addi_eeprom_nvram_wait(iobase
);
146 tmp
= inb(iobase
+ AMCC_OP_REG_MCSR_NVDATA
);
147 addi_eeprom_nvram_wait(iobase
);
158 static unsigned short addi_eeprom_readw(unsigned long iobase
,
162 unsigned short val
= 0;
164 /* Add the offset to the start of the user data */
165 addr
+= NVRAM_USER_DATA_START
;
167 if (!strcmp(type
, "S5920") || !strcmp(type
, "S5933"))
168 val
= addi_eeprom_readw_nvram(iobase
, addr
);
170 if (!strcmp(type
, "93C76"))
171 val
= addi_eeprom_readw_93c76(iobase
, addr
);
176 static void addi_eeprom_read_di_info(struct comedi_device
*dev
,
177 unsigned long iobase
,
180 const struct addi_board
*this_board
= comedi_board(dev
);
181 struct addi_private
*devpriv
= dev
->private;
182 char *type
= this_board
->pc_EepromChip
;
185 /* Number of channels */
186 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 6);
187 devpriv
->s_EeParameters
.i_NbrDiChannel
= tmp
;
189 /* Interruptible or not */
190 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 8);
191 tmp
= (tmp
>> 7) & 0x01;
193 /* How many interruptible logic */
194 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 10);
197 static void addi_eeprom_read_do_info(struct comedi_device
*dev
,
198 unsigned long iobase
,
201 const struct addi_board
*this_board
= comedi_board(dev
);
202 struct addi_private
*devpriv
= dev
->private;
203 char *type
= this_board
->pc_EepromChip
;
206 /* Number of channels */
207 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 6);
208 devpriv
->s_EeParameters
.i_NbrDoChannel
= tmp
;
210 devpriv
->s_EeParameters
.i_DoMaxdata
= 0xffffffff >> (32 - tmp
);
213 static void addi_eeprom_read_timer_info(struct comedi_device
*dev
,
214 unsigned long iobase
,
217 struct addi_private
*devpriv
= dev
->private;
219 const struct addi_board
*this_board
= comedi_board(dev
);
220 char *type
= this_board
->pc_EepromChip
;
221 unsigned short offset
= 0;
222 unsigned short ntimers
;
226 /* Number of Timers */
227 ntimers
= addi_eeprom_readw(iobase
, type
, addr
+ 6);
229 /* Read header size */
230 for (i
= 0; i
< ntimers
; i
++) {
234 unsigned short min_timing
;
235 unsigned short timebase
;
237 size
= addi_eeprom_readw(iobase
, type
, addr
+ 8 + offset
+ 0);
239 /* Resolution / Mode */
240 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 8 + offset
+ 2);
241 res
= (tmp
>> 10) & 0x3f;
242 mode
= (tmp
>> 4) & 0x3f;
244 /* MinTiming / Timebase */
245 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 8 + offset
+ 4);
246 min_timing
= (tmp
>> 6) & 0x3ff;
247 Timebase
= tmp
& 0x3f;
252 /* Timer subdevice present */
253 devpriv
->s_EeParameters
.i_Timer
= 1;
256 static void addi_eeprom_read_ao_info(struct comedi_device
*dev
,
257 unsigned long iobase
,
260 const struct addi_board
*this_board
= comedi_board(dev
);
261 struct addi_private
*devpriv
= dev
->private;
262 char *type
= this_board
->pc_EepromChip
;
265 /* No of channels for 1st hard component */
266 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 10);
267 devpriv
->s_EeParameters
.i_NbrAoChannel
= (tmp
>> 4) & 0x3ff;
269 /* Resolution for 1st hard component */
270 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 16);
271 tmp
= (tmp
>> 8) & 0xff;
272 devpriv
->s_EeParameters
.i_AoMaxdata
= 0xfff >> (16 - tmp
);
275 static void addi_eeprom_read_ai_info(struct comedi_device
*dev
,
276 unsigned long iobase
,
279 const struct addi_board
*this_board
= comedi_board(dev
);
280 struct addi_private
*devpriv
= dev
->private;
281 char *type
= this_board
->pc_EepromChip
;
282 unsigned short offset
;
285 /* No of channels for 1st hard component */
286 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 10);
287 devpriv
->s_EeParameters
.i_NbrAiChannel
= (tmp
>> 4) & 0x3ff;
288 if (!strcmp(this_board
->pc_DriverName
, "apci3200"))
289 devpriv
->s_EeParameters
.i_NbrAiChannel
*= 4;
291 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 16);
292 devpriv
->s_EeParameters
.ui_MinAcquisitiontimeNs
= tmp
* 1000;
294 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 30);
295 devpriv
->s_EeParameters
.ui_MinDelaytimeNs
= tmp
* 1000;
297 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 20);
298 devpriv
->s_EeParameters
.i_Dma
= (tmp
>> 13) & 0x01;
300 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ 72) & 0xff;
302 /* offset of first analog input single header */
303 offset
= 74 + (2 * tmp
) + (10 * (1 + (tmp
/ 16)));
309 tmp
= addi_eeprom_readw(iobase
, type
, addr
+ offset
+ 2) & 0x1f;
310 devpriv
->s_EeParameters
.i_AiMaxdata
= 0xffff >> (16 - tmp
);
313 static void addi_eeprom_read_info(struct comedi_device
*dev
,
314 unsigned long iobase
)
316 const struct addi_board
*this_board
= comedi_board(dev
);
317 char *type
= this_board
->pc_EepromChip
;
319 unsigned char nfuncs
;
322 size
= addi_eeprom_readw(iobase
, type
, 8);
323 nfuncs
= addi_eeprom_readw(iobase
, type
, 10) & 0xff;
325 /* Read functionality details */
326 for (i
= 0; i
< nfuncs
; i
++) {
327 unsigned short offset
= i
* 4;
331 func
= addi_eeprom_readw(iobase
, type
, 12 + offset
) & 0x3f;
332 addr
= addi_eeprom_readw(iobase
, type
, 14 + offset
);
335 case EEPROM_DIGITALINPUT
:
336 addi_eeprom_read_di_info(dev
, iobase
, addr
);
339 case EEPROM_DIGITALOUTPUT
:
340 addi_eeprom_read_do_info(dev
, iobase
, addr
);
343 case EEPROM_ANALOGINPUT
:
344 addi_eeprom_read_ai_info(dev
, iobase
, addr
);
347 case EEPROM_ANALOGOUTPUT
:
348 addi_eeprom_read_ao_info(dev
, iobase
, addr
);
352 case EEPROM_WATCHDOG
:
353 case EEPROM_TIMER_WATCHDOG_COUNTER
:
354 addi_eeprom_read_timer_info(dev
, iobase
, addr
);