packaging: release out (3.8.3)
[profile/ivi/kernel-adaptation-intel-automotive.git] / drivers / staging / comedi / drivers / addi-data / addi_eeprom.c
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  * 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
27  *
28  * You should also find the complete GPL in the COPYING file accompanying
29  * this source code.
30  */
31
32 #define NVRAM_USER_DATA_START   0x100
33
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 */
37
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
44
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
52
53 static void addi_eeprom_clk_93c76(unsigned long iobase, unsigned int val)
54 {
55         outl(val & ~EE93C76_CLK_BIT, iobase);
56         udelay(100);
57
58         outl(val | EE93C76_CLK_BIT, iobase);
59         udelay(100);
60 }
61
62 static unsigned int addi_eeprom_cmd_93c76(unsigned long iobase,
63                                           unsigned int cmd,
64                                           unsigned char len)
65 {
66         unsigned int val = EE93C76_CS_BIT;
67         int i;
68
69         /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */
70         outl(val, iobase);
71         udelay(100);
72
73         /* Send EEPROM command - one bit at a time */
74         for (i = (len - 1); i >= 0; i--) {
75                 if (cmd & (1 << i))
76                         val |= EE93C76_DOUT_BIT;
77                 else
78                         val &= ~EE93C76_DOUT_BIT;
79
80                 /* Write the command */
81                 outl(val, iobase);
82                 udelay(100);
83
84                 addi_eeprom_clk_93c76(iobase, val);
85         }
86         return val;
87 }
88
89 static unsigned short addi_eeprom_readw_93c76(unsigned long iobase,
90                                               unsigned short addr)
91 {
92         unsigned short val = 0;
93         unsigned int cmd;
94         unsigned int tmp;
95         int i;
96
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);
100
101         /* Get the 16-bit value */
102         for (i = 0; i < 16; i++) {
103                 addi_eeprom_clk_93c76(iobase, cmd);
104
105                 tmp = inl(iobase);
106                 udelay(100);
107
108                 val <<= 1;
109                 if (tmp & EE93C76_DIN_BIT)
110                         val |= 0x1;
111         }
112
113         /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */
114         outl(0, iobase);
115         udelay(100);
116
117         return val;
118 }
119
120 static void addi_eeprom_nvram_wait(unsigned long iobase)
121 {
122         unsigned char val;
123
124         do {
125                 val = inb(iobase + AMCC_OP_REG_MCSR_NVCMD);
126         } while (val & 0x80);
127 }
128
129 static unsigned short addi_eeprom_readw_nvram(unsigned long iobase,
130                                               unsigned short addr)
131 {
132         unsigned short val = 0;
133         unsigned char tmp;
134         unsigned char i;
135
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);
142
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);
149
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);
155
156                 if (i == 0)
157                         val |= tmp;
158                 else
159                         val |= (tmp << 8);
160         }
161
162         return val;
163 }
164
165 static unsigned short addi_eeprom_readw(unsigned long iobase,
166                                         char *type,
167                                         unsigned short addr)
168 {
169         unsigned short val = 0;
170
171         /* Add the offset to the start of the user data */
172         addr += NVRAM_USER_DATA_START;
173
174         if (!strcmp(type, "S5920") || !strcmp(type, "S5933"))
175                 val = addi_eeprom_readw_nvram(iobase, addr);
176
177         if (!strcmp(type, "93C76"))
178                 val = addi_eeprom_readw_93c76(iobase, addr);
179
180         return val;
181 }
182
183 static void addi_eeprom_read_di_info(struct comedi_device *dev,
184                                      unsigned long iobase,
185                                      unsigned short addr)
186 {
187         const struct addi_board *this_board = comedi_board(dev);
188         struct addi_private *devpriv = dev->private;
189         char *type = this_board->pc_EepromChip;
190         unsigned short tmp;
191
192         /* Number of channels */
193         tmp = addi_eeprom_readw(iobase, type, addr + 6);
194         devpriv->s_EeParameters.i_NbrDiChannel = tmp;
195
196         /* Interruptible or not */
197         tmp = addi_eeprom_readw(iobase, type, addr + 8);
198         tmp = (tmp >> 7) & 0x01;
199
200         /* How many interruptible logic */
201         tmp = addi_eeprom_readw(iobase, type, addr + 10);
202 }
203
204 static void addi_eeprom_read_do_info(struct comedi_device *dev,
205                                      unsigned long iobase,
206                                      unsigned short addr)
207 {
208         const struct addi_board *this_board = comedi_board(dev);
209         struct addi_private *devpriv = dev->private;
210         char *type = this_board->pc_EepromChip;
211         unsigned short tmp;
212
213         /* Number of channels */
214         tmp = addi_eeprom_readw(iobase, type, addr + 6);
215         devpriv->s_EeParameters.i_NbrDoChannel = tmp;
216
217         devpriv->s_EeParameters.i_DoMaxdata = 0xffffffff >> (32 - tmp);
218 }
219
220 static void addi_eeprom_read_timer_info(struct comedi_device *dev,
221                                         unsigned long iobase,
222                                         unsigned short addr)
223 {
224         struct addi_private *devpriv = dev->private;
225 #if 0
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;
230         unsigned short tmp;
231         int i;
232
233         /* Number of Timers */
234         ntimers = addi_eeprom_readw(iobase, type, addr + 6);
235
236         /* Read header size */
237         for (i = 0; i < ntimers; i++) {
238                 unsigned short size;
239                 unsigned short res;
240                 unsigned short mode;
241                 unsigned short min_timing;
242                 unsigned short timebase;
243
244                 size = addi_eeprom_readw(iobase, type, addr + 8 + offset + 0);
245
246                 /* Resolution / Mode */
247                 tmp = addi_eeprom_readw(iobase, type, addr + 8 + offset + 2);
248                 res = (tmp >> 10) & 0x3f;
249                 mode = (tmp >> 4) & 0x3f;
250
251                 /* MinTiming / Timebase */
252                 tmp = addi_eeprom_readw(iobase, type, addr + 8 + offset + 4);
253                 min_timing = (tmp  >> 6) & 0x3ff;
254                 Timebase = tmp & 0x3f;
255
256                 offset += size;
257         }
258 #endif
259         /* Timer subdevice present */
260         devpriv->s_EeParameters.i_Timer = 1;
261 }
262
263 static void addi_eeprom_read_ao_info(struct comedi_device *dev,
264                                      unsigned long iobase,
265                                      unsigned short addr)
266 {
267         const struct addi_board *this_board = comedi_board(dev);
268         struct addi_private *devpriv = dev->private;
269         char *type = this_board->pc_EepromChip;
270         unsigned short tmp;
271
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;
275
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);
280 }
281
282 static void addi_eeprom_read_ai_info(struct comedi_device *dev,
283                                      unsigned long iobase,
284                                      unsigned short addr)
285 {
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;
290         unsigned short tmp;
291
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;
297
298         tmp = addi_eeprom_readw(iobase, type, addr + 16);
299         devpriv->s_EeParameters.ui_MinAcquisitiontimeNs = tmp * 1000;
300
301         tmp = addi_eeprom_readw(iobase, type, addr + 30);
302         devpriv->s_EeParameters.ui_MinDelaytimeNs = tmp * 1000;
303
304         tmp = addi_eeprom_readw(iobase, type, addr + 20);
305         devpriv->s_EeParameters.i_Dma = (tmp >> 13) & 0x01;
306
307         tmp = addi_eeprom_readw(iobase, type, addr + 72) & 0xff;
308         if (tmp) {              /* > 0 */
309                 /* offset of first analog input single header */
310                 offset = 74 + (2 * tmp) + (10 * (1 + (tmp / 16)));
311         } else {                /* = 0 */
312                 offset = 74;
313         }
314
315         /* Resolution */
316         tmp = addi_eeprom_readw(iobase, type, addr + offset + 2) & 0x1f;
317         devpriv->s_EeParameters.i_AiMaxdata = 0xffff >> (16 - tmp);
318 }
319
320 static void addi_eeprom_read_info(struct comedi_device *dev,
321                                   unsigned long iobase)
322 {
323         const struct addi_board *this_board = comedi_board(dev);
324         char *type = this_board->pc_EepromChip;
325         unsigned short size;
326         unsigned char nfuncs;
327         int i;
328
329         size = addi_eeprom_readw(iobase, type, 8);
330         nfuncs = addi_eeprom_readw(iobase, type, 10) & 0xff;
331
332         /* Read functionality details */
333         for (i = 0; i < nfuncs; i++) {
334                 unsigned short offset = i * 4;
335                 unsigned short addr;
336                 unsigned char func;
337
338                 func = addi_eeprom_readw(iobase, type, 12 + offset) & 0x3f;
339                 addr = addi_eeprom_readw(iobase, type, 14 + offset);
340
341                 switch (func) {
342                 case EEPROM_DIGITALINPUT:
343                         addi_eeprom_read_di_info(dev, iobase, addr);
344                         break;
345
346                 case EEPROM_DIGITALOUTPUT:
347                         addi_eeprom_read_do_info(dev, iobase, addr);
348                         break;
349
350                 case EEPROM_ANALOGINPUT:
351                         addi_eeprom_read_ai_info(dev, iobase, addr);
352                         break;
353
354                 case EEPROM_ANALOGOUTPUT:
355                         addi_eeprom_read_ao_info(dev, iobase, addr);
356                         break;
357
358                 case EEPROM_TIMER:
359                 case EEPROM_WATCHDOG:
360                 case EEPROM_TIMER_WATCHDOG_COUNTER:
361                         addi_eeprom_read_timer_info(dev, iobase, addr);
362                         break;
363                 }
364         }
365 }