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
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * You should also find the complete GPL in the COPYING file accompanying
32 #define NVRAM_USER_DATA_START 0x100
34 #define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */
35 #define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */
36 #define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */
38 #define EE93C76_CLK_BIT (1 << 0)
39 #define EE93C76_CS_BIT (1 << 1)
40 #define EE93C76_DOUT_BIT (1 << 2)
41 #define EE93C76_DIN_BIT (1 << 3)
42 #define EE93C76_READ_CMD (0x0180 << 4)
43 #define EE93C76_CMD_LEN 13
45 #define EEPROM_DIGITALINPUT 0
46 #define EEPROM_DIGITALOUTPUT 1
47 #define EEPROM_ANALOGINPUT 2
48 #define EEPROM_ANALOGOUTPUT 3
49 #define EEPROM_TIMER 4
50 #define EEPROM_WATCHDOG 5
51 #define EEPROM_TIMER_WATCHDOG_COUNTER 10
53 static void addi_eeprom_clk_93c76(unsigned long iobase, unsigned int val)
55 outl(val & ~EE93C76_CLK_BIT, iobase);
58 outl(val | EE93C76_CLK_BIT, iobase);
62 static unsigned int addi_eeprom_cmd_93c76(unsigned long iobase,
66 unsigned int val = EE93C76_CS_BIT;
69 /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */
73 /* Send EEPROM command - one bit at a time */
74 for (i = (len - 1); i >= 0; i--) {
76 val |= EE93C76_DOUT_BIT;
78 val &= ~EE93C76_DOUT_BIT;
80 /* Write the command */
84 addi_eeprom_clk_93c76(iobase, val);
89 static unsigned short addi_eeprom_readw_93c76(unsigned long iobase,
92 unsigned short val = 0;
97 /* Send EEPROM read command and offset to EEPROM */
98 cmd = EE93C76_READ_CMD | (addr / 2);
99 cmd = addi_eeprom_cmd_93c76(iobase, cmd, EE93C76_CMD_LEN);
101 /* Get the 16-bit value */
102 for (i = 0; i < 16; i++) {
103 addi_eeprom_clk_93c76(iobase, cmd);
109 if (tmp & EE93C76_DIN_BIT)
113 /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */
120 static void addi_eeprom_nvram_wait(unsigned long iobase)
125 val = inb(iobase + AMCC_OP_REG_MCSR_NVCMD);
126 } while (val & 0x80);
129 static unsigned short addi_eeprom_readw_nvram(unsigned long iobase,
132 unsigned short val = 0;
136 for (i = 0; i < 2; i++) {
137 /* Load the low 8 bit address */
138 outb(NVCMD_LOAD_LOW, iobase + AMCC_OP_REG_MCSR_NVCMD);
139 addi_eeprom_nvram_wait(iobase);
140 outb((addr + i) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
141 addi_eeprom_nvram_wait(iobase);
143 /* Load the high 8 bit address */
144 outb(NVCMD_LOAD_HIGH, iobase + AMCC_OP_REG_MCSR_NVCMD);
145 addi_eeprom_nvram_wait(iobase);
146 outb(((addr + i) >> 8) & 0xff,
147 iobase + AMCC_OP_REG_MCSR_NVDATA);
148 addi_eeprom_nvram_wait(iobase);
150 /* Read the eeprom data byte */
151 outb(NVCMD_BEGIN_READ, iobase + AMCC_OP_REG_MCSR_NVCMD);
152 addi_eeprom_nvram_wait(iobase);
153 tmp = inb(iobase + AMCC_OP_REG_MCSR_NVDATA);
154 addi_eeprom_nvram_wait(iobase);
165 static unsigned short addi_eeprom_readw(unsigned long iobase,
169 unsigned short val = 0;
171 /* Add the offset to the start of the user data */
172 addr += NVRAM_USER_DATA_START;
174 if (!strcmp(type, "S5920") || !strcmp(type, "S5933"))
175 val = addi_eeprom_readw_nvram(iobase, addr);
177 if (!strcmp(type, "93C76"))
178 val = addi_eeprom_readw_93c76(iobase, addr);
183 static void addi_eeprom_read_di_info(struct comedi_device *dev,
184 unsigned long iobase,
187 const struct addi_board *this_board = comedi_board(dev);
188 struct addi_private *devpriv = dev->private;
189 char *type = this_board->pc_EepromChip;
192 /* Number of channels */
193 tmp = addi_eeprom_readw(iobase, type, addr + 6);
194 devpriv->s_EeParameters.i_NbrDiChannel = tmp;
196 /* Interruptible or not */
197 tmp = addi_eeprom_readw(iobase, type, addr + 8);
198 tmp = (tmp >> 7) & 0x01;
200 /* How many interruptible logic */
201 tmp = addi_eeprom_readw(iobase, type, addr + 10);
204 static void addi_eeprom_read_do_info(struct comedi_device *dev,
205 unsigned long iobase,
208 const struct addi_board *this_board = comedi_board(dev);
209 struct addi_private *devpriv = dev->private;
210 char *type = this_board->pc_EepromChip;
213 /* Number of channels */
214 tmp = addi_eeprom_readw(iobase, type, addr + 6);
215 devpriv->s_EeParameters.i_NbrDoChannel = tmp;
217 devpriv->s_EeParameters.i_DoMaxdata = 0xffffffff >> (32 - tmp);
220 static void addi_eeprom_read_timer_info(struct comedi_device *dev,
221 unsigned long iobase,
224 struct addi_private *devpriv = dev->private;
226 const struct addi_board *this_board = comedi_board(dev);
227 char *type = this_board->pc_EepromChip;
228 unsigned short offset = 0;
229 unsigned short ntimers;
233 /* Number of Timers */
234 ntimers = addi_eeprom_readw(iobase, type, addr + 6);
236 /* Read header size */
237 for (i = 0; i < ntimers; i++) {
241 unsigned short min_timing;
242 unsigned short timebase;
244 size = addi_eeprom_readw(iobase, type, addr + 8 + offset + 0);
246 /* Resolution / Mode */
247 tmp = addi_eeprom_readw(iobase, type, addr + 8 + offset + 2);
248 res = (tmp >> 10) & 0x3f;
249 mode = (tmp >> 4) & 0x3f;
251 /* MinTiming / Timebase */
252 tmp = addi_eeprom_readw(iobase, type, addr + 8 + offset + 4);
253 min_timing = (tmp >> 6) & 0x3ff;
254 Timebase = tmp & 0x3f;
259 /* Timer subdevice present */
260 devpriv->s_EeParameters.i_Timer = 1;
263 static void addi_eeprom_read_ao_info(struct comedi_device *dev,
264 unsigned long iobase,
267 const struct addi_board *this_board = comedi_board(dev);
268 struct addi_private *devpriv = dev->private;
269 char *type = this_board->pc_EepromChip;
272 /* No of channels for 1st hard component */
273 tmp = addi_eeprom_readw(iobase, type, addr + 10);
274 devpriv->s_EeParameters.i_NbrAoChannel = (tmp >> 4) & 0x3ff;
276 /* Resolution for 1st hard component */
277 tmp = addi_eeprom_readw(iobase, type, addr + 16);
278 tmp = (tmp >> 8) & 0xff;
279 devpriv->s_EeParameters.i_AoMaxdata = 0xfff >> (16 - tmp);
282 static void addi_eeprom_read_ai_info(struct comedi_device *dev,
283 unsigned long iobase,
286 const struct addi_board *this_board = comedi_board(dev);
287 struct addi_private *devpriv = dev->private;
288 char *type = this_board->pc_EepromChip;
289 unsigned short offset;
292 /* No of channels for 1st hard component */
293 tmp = addi_eeprom_readw(iobase, type, addr + 10);
294 devpriv->s_EeParameters.i_NbrAiChannel = (tmp >> 4) & 0x3ff;
295 if (!strcmp(this_board->pc_DriverName, "apci3200"))
296 devpriv->s_EeParameters.i_NbrAiChannel *= 4;
298 tmp = addi_eeprom_readw(iobase, type, addr + 16);
299 devpriv->s_EeParameters.ui_MinAcquisitiontimeNs = tmp * 1000;
301 tmp = addi_eeprom_readw(iobase, type, addr + 30);
302 devpriv->s_EeParameters.ui_MinDelaytimeNs = tmp * 1000;
304 tmp = addi_eeprom_readw(iobase, type, addr + 20);
305 devpriv->s_EeParameters.i_Dma = (tmp >> 13) & 0x01;
307 tmp = addi_eeprom_readw(iobase, type, addr + 72) & 0xff;
309 /* offset of first analog input single header */
310 offset = 74 + (2 * tmp) + (10 * (1 + (tmp / 16)));
316 tmp = addi_eeprom_readw(iobase, type, addr + offset + 2) & 0x1f;
317 devpriv->s_EeParameters.i_AiMaxdata = 0xffff >> (16 - tmp);
320 static void addi_eeprom_read_info(struct comedi_device *dev,
321 unsigned long iobase)
323 const struct addi_board *this_board = comedi_board(dev);
324 char *type = this_board->pc_EepromChip;
326 unsigned char nfuncs;
329 size = addi_eeprom_readw(iobase, type, 8);
330 nfuncs = addi_eeprom_readw(iobase, type, 10) & 0xff;
332 /* Read functionality details */
333 for (i = 0; i < nfuncs; i++) {
334 unsigned short offset = i * 4;
338 func = addi_eeprom_readw(iobase, type, 12 + offset) & 0x3f;
339 addr = addi_eeprom_readw(iobase, type, 14 + offset);
342 case EEPROM_DIGITALINPUT:
343 addi_eeprom_read_di_info(dev, iobase, addr);
346 case EEPROM_DIGITALOUTPUT:
347 addi_eeprom_read_do_info(dev, iobase, addr);
350 case EEPROM_ANALOGINPUT:
351 addi_eeprom_read_ai_info(dev, iobase, addr);
354 case EEPROM_ANALOGOUTPUT:
355 addi_eeprom_read_ao_info(dev, iobase, addr);
359 case EEPROM_WATCHDOG:
360 case EEPROM_TIMER_WATCHDOG_COUNTER:
361 addi_eeprom_read_timer_info(dev, iobase, addr);