1 /* 2 * Copyright (C) 2004 - 2006 rt2x00 SourceForge Project 3 * <http://rt2x00.serialmonkey.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * Module: eeprom_93cx6 16 * Abstract: EEPROM reader routines for 93cx6 chipsets. 17 * Supported chipsets: 93c46 & 93c66. 18 */ 19 20 #include <linux/kernel.h> 21 #include <linux/module.h> 22 #include <linux/delay.h> 23 #include <linux/eeprom_93cx6.h> 24 25 MODULE_AUTHOR("http://rt2x00.serialmonkey.com"); 26 MODULE_VERSION("1.0"); 27 MODULE_DESCRIPTION("EEPROM 93cx6 chip driver"); 28 MODULE_LICENSE("GPL"); 29 30 static inline void eeprom_93cx6_pulse_high(struct eeprom_93cx6 *eeprom) 31 { 32 eeprom->reg_data_clock = 1; 33 eeprom->register_write(eeprom); 34 35 /* 36 * Add a short delay for the pulse to work. 37 * According to the specifications the "maximum minimum" 38 * time should be 450ns. 39 */ 40 ndelay(450); 41 } 42 43 static inline void eeprom_93cx6_pulse_low(struct eeprom_93cx6 *eeprom) 44 { 45 eeprom->reg_data_clock = 0; 46 eeprom->register_write(eeprom); 47 48 /* 49 * Add a short delay for the pulse to work. 50 * According to the specifications the "maximum minimum" 51 * time should be 450ns. 52 */ 53 ndelay(450); 54 } 55 56 static void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom) 57 { 58 /* 59 * Clear all flags, and enable chip select. 60 */ 61 eeprom->register_read(eeprom); 62 eeprom->reg_data_in = 0; 63 eeprom->reg_data_out = 0; 64 eeprom->reg_data_clock = 0; 65 eeprom->reg_chip_select = 1; 66 eeprom->drive_data = 1; 67 eeprom->register_write(eeprom); 68 69 /* 70 * kick a pulse. 71 */ 72 eeprom_93cx6_pulse_high(eeprom); 73 eeprom_93cx6_pulse_low(eeprom); 74 } 75 76 static void eeprom_93cx6_cleanup(struct eeprom_93cx6 *eeprom) 77 { 78 /* 79 * Clear chip_select and data_in flags. 80 */ 81 eeprom->register_read(eeprom); 82 eeprom->reg_data_in = 0; 83 eeprom->reg_chip_select = 0; 84 eeprom->register_write(eeprom); 85 86 /* 87 * kick a pulse. 88 */ 89 eeprom_93cx6_pulse_high(eeprom); 90 eeprom_93cx6_pulse_low(eeprom); 91 } 92 93 static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom, 94 const u16 data, const u16 count) 95 { 96 unsigned int i; 97 98 eeprom->register_read(eeprom); 99 100 /* 101 * Clear data flags. 102 */ 103 eeprom->reg_data_in = 0; 104 eeprom->reg_data_out = 0; 105 eeprom->drive_data = 1; 106 107 /* 108 * Start writing all bits. 109 */ 110 for (i = count; i > 0; i--) { 111 /* 112 * Check if this bit needs to be set. 113 */ 114 eeprom->reg_data_in = !!(data & (1 << (i - 1))); 115 116 /* 117 * Write the bit to the eeprom register. 118 */ 119 eeprom->register_write(eeprom); 120 121 /* 122 * Kick a pulse. 123 */ 124 eeprom_93cx6_pulse_high(eeprom); 125 eeprom_93cx6_pulse_low(eeprom); 126 } 127 128 eeprom->reg_data_in = 0; 129 eeprom->register_write(eeprom); 130 } 131 132 static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom, 133 u16 *data, const u16 count) 134 { 135 unsigned int i; 136 u16 buf = 0; 137 138 eeprom->register_read(eeprom); 139 140 /* 141 * Clear data flags. 142 */ 143 eeprom->reg_data_in = 0; 144 eeprom->reg_data_out = 0; 145 eeprom->drive_data = 0; 146 147 /* 148 * Start reading all bits. 149 */ 150 for (i = count; i > 0; i--) { 151 eeprom_93cx6_pulse_high(eeprom); 152 153 eeprom->register_read(eeprom); 154 155 /* 156 * Clear data_in flag. 157 */ 158 eeprom->reg_data_in = 0; 159 160 /* 161 * Read if the bit has been set. 162 */ 163 if (eeprom->reg_data_out) 164 buf |= (1 << (i - 1)); 165 166 eeprom_93cx6_pulse_low(eeprom); 167 } 168 169 *data = buf; 170 } 171 172 /** 173 * eeprom_93cx6_read - Read multiple words from eeprom 174 * @eeprom: Pointer to eeprom structure 175 * @word: Word index from where we should start reading 176 * @data: target pointer where the information will have to be stored 177 * 178 * This function will read the eeprom data as host-endian word 179 * into the given data pointer. 180 */ 181 void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word, 182 u16 *data) 183 { 184 u16 command; 185 186 /* 187 * Initialize the eeprom register 188 */ 189 eeprom_93cx6_startup(eeprom); 190 191 /* 192 * Select the read opcode and the word to be read. 193 */ 194 command = (PCI_EEPROM_READ_OPCODE << eeprom->width) | word; 195 eeprom_93cx6_write_bits(eeprom, command, 196 PCI_EEPROM_WIDTH_OPCODE + eeprom->width); 197 198 /* 199 * Read the requested 16 bits. 200 */ 201 eeprom_93cx6_read_bits(eeprom, data, 16); 202 203 /* 204 * Cleanup eeprom register. 205 */ 206 eeprom_93cx6_cleanup(eeprom); 207 } 208 EXPORT_SYMBOL_GPL(eeprom_93cx6_read); 209 210 /** 211 * eeprom_93cx6_multiread - Read multiple words from eeprom 212 * @eeprom: Pointer to eeprom structure 213 * @word: Word index from where we should start reading 214 * @data: target pointer where the information will have to be stored 215 * @words: Number of words that should be read. 216 * 217 * This function will read all requested words from the eeprom, 218 * this is done by calling eeprom_93cx6_read() multiple times. 219 * But with the additional change that while the eeprom_93cx6_read 220 * will return host ordered bytes, this method will return little 221 * endian words. 222 */ 223 void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word, 224 __le16 *data, const u16 words) 225 { 226 unsigned int i; 227 u16 tmp; 228 229 for (i = 0; i < words; i++) { 230 tmp = 0; 231 eeprom_93cx6_read(eeprom, word + i, &tmp); 232 data[i] = cpu_to_le16(tmp); 233 } 234 } 235 EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread); 236 237 /** 238 * eeprom_93cx6_wren - set the write enable state 239 * @eeprom: Pointer to eeprom structure 240 * @enable: true to enable writes, otherwise disable writes 241 * 242 * Set the EEPROM write enable state to either allow or deny 243 * writes depending on the @enable value. 244 */ 245 void eeprom_93cx6_wren(struct eeprom_93cx6 *eeprom, bool enable) 246 { 247 u16 command; 248 249 /* start the command */ 250 eeprom_93cx6_startup(eeprom); 251 252 /* create command to enable/disable */ 253 254 command = enable ? PCI_EEPROM_EWEN_OPCODE : PCI_EEPROM_EWDS_OPCODE; 255 command <<= (eeprom->width - 2); 256 257 eeprom_93cx6_write_bits(eeprom, command, 258 PCI_EEPROM_WIDTH_OPCODE + eeprom->width); 259 260 eeprom_93cx6_cleanup(eeprom); 261 } 262 EXPORT_SYMBOL_GPL(eeprom_93cx6_wren); 263 264 /** 265 * eeprom_93cx6_write - write data to the EEPROM 266 * @eeprom: Pointer to eeprom structure 267 * @addr: Address to write data to. 268 * @data: The data to write to address @addr. 269 * 270 * Write the @data to the specified @addr in the EEPROM and 271 * waiting for the device to finish writing. 272 * 273 * Note, since we do not expect large number of write operations 274 * we delay in between parts of the operation to avoid using excessive 275 * amounts of CPU time busy waiting. 276 */ 277 void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom, u8 addr, u16 data) 278 { 279 int timeout = 100; 280 u16 command; 281 282 /* start the command */ 283 eeprom_93cx6_startup(eeprom); 284 285 command = PCI_EEPROM_WRITE_OPCODE << eeprom->width; 286 command |= addr; 287 288 /* send write command */ 289 eeprom_93cx6_write_bits(eeprom, command, 290 PCI_EEPROM_WIDTH_OPCODE + eeprom->width); 291 292 /* send data */ 293 eeprom_93cx6_write_bits(eeprom, data, 16); 294 295 /* get ready to check for busy */ 296 eeprom->drive_data = 0; 297 eeprom->reg_chip_select = 1; 298 eeprom->register_write(eeprom); 299 300 /* wait at-least 250ns to get DO to be the busy signal */ 301 usleep_range(1000, 2000); 302 303 /* wait for DO to go high to signify finish */ 304 305 while (true) { 306 eeprom->register_read(eeprom); 307 308 if (eeprom->reg_data_out) 309 break; 310 311 usleep_range(1000, 2000); 312 313 if (--timeout <= 0) { 314 printk(KERN_ERR "%s: timeout\n", __func__); 315 break; 316 } 317 } 318 319 eeprom_93cx6_cleanup(eeprom); 320 } 321 EXPORT_SYMBOL_GPL(eeprom_93cx6_write); 322