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