0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/delay.h>
0014 #include <linux/eeprom_93cx6.h>
0015
0016 MODULE_AUTHOR("http://rt2x00.serialmonkey.com");
0017 MODULE_VERSION("1.0");
0018 MODULE_DESCRIPTION("EEPROM 93cx6 chip driver");
0019 MODULE_LICENSE("GPL");
0020
0021 static inline void eeprom_93cx6_pulse_high(struct eeprom_93cx6 *eeprom)
0022 {
0023 eeprom->reg_data_clock = 1;
0024 eeprom->register_write(eeprom);
0025
0026
0027
0028
0029
0030
0031 ndelay(450);
0032 }
0033
0034 static inline void eeprom_93cx6_pulse_low(struct eeprom_93cx6 *eeprom)
0035 {
0036 eeprom->reg_data_clock = 0;
0037 eeprom->register_write(eeprom);
0038
0039
0040
0041
0042
0043
0044 ndelay(450);
0045 }
0046
0047 static void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom)
0048 {
0049
0050
0051
0052 eeprom->register_read(eeprom);
0053 eeprom->reg_data_in = 0;
0054 eeprom->reg_data_out = 0;
0055 eeprom->reg_data_clock = 0;
0056 eeprom->reg_chip_select = 1;
0057 eeprom->drive_data = 1;
0058 eeprom->register_write(eeprom);
0059
0060
0061
0062
0063 eeprom_93cx6_pulse_high(eeprom);
0064 eeprom_93cx6_pulse_low(eeprom);
0065 }
0066
0067 static void eeprom_93cx6_cleanup(struct eeprom_93cx6 *eeprom)
0068 {
0069
0070
0071
0072 eeprom->register_read(eeprom);
0073 eeprom->reg_data_in = 0;
0074 eeprom->reg_chip_select = 0;
0075 eeprom->register_write(eeprom);
0076
0077
0078
0079
0080 eeprom_93cx6_pulse_high(eeprom);
0081 eeprom_93cx6_pulse_low(eeprom);
0082 }
0083
0084 static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom,
0085 const u16 data, const u16 count)
0086 {
0087 unsigned int i;
0088
0089 eeprom->register_read(eeprom);
0090
0091
0092
0093
0094 eeprom->reg_data_in = 0;
0095 eeprom->reg_data_out = 0;
0096 eeprom->drive_data = 1;
0097
0098
0099
0100
0101 for (i = count; i > 0; i--) {
0102
0103
0104
0105 eeprom->reg_data_in = !!(data & (1 << (i - 1)));
0106
0107
0108
0109
0110 eeprom->register_write(eeprom);
0111
0112
0113
0114
0115 eeprom_93cx6_pulse_high(eeprom);
0116 eeprom_93cx6_pulse_low(eeprom);
0117 }
0118
0119 eeprom->reg_data_in = 0;
0120 eeprom->register_write(eeprom);
0121 }
0122
0123 static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom,
0124 u16 *data, const u16 count)
0125 {
0126 unsigned int i;
0127 u16 buf = 0;
0128
0129 eeprom->register_read(eeprom);
0130
0131
0132
0133
0134 eeprom->reg_data_in = 0;
0135 eeprom->reg_data_out = 0;
0136 eeprom->drive_data = 0;
0137
0138
0139
0140
0141 for (i = count; i > 0; i--) {
0142 eeprom_93cx6_pulse_high(eeprom);
0143
0144 eeprom->register_read(eeprom);
0145
0146
0147
0148
0149 eeprom->reg_data_in = 0;
0150
0151
0152
0153
0154 if (eeprom->reg_data_out)
0155 buf |= (1 << (i - 1));
0156
0157 eeprom_93cx6_pulse_low(eeprom);
0158 }
0159
0160 *data = buf;
0161 }
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172 void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word,
0173 u16 *data)
0174 {
0175 u16 command;
0176
0177
0178
0179
0180 eeprom_93cx6_startup(eeprom);
0181
0182
0183
0184
0185 command = (PCI_EEPROM_READ_OPCODE << eeprom->width) | word;
0186 eeprom_93cx6_write_bits(eeprom, command,
0187 PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
0188
0189
0190
0191
0192 eeprom_93cx6_read_bits(eeprom, data, 16);
0193
0194
0195
0196
0197 eeprom_93cx6_cleanup(eeprom);
0198 }
0199 EXPORT_SYMBOL_GPL(eeprom_93cx6_read);
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214 void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word,
0215 __le16 *data, const u16 words)
0216 {
0217 unsigned int i;
0218 u16 tmp;
0219
0220 for (i = 0; i < words; i++) {
0221 tmp = 0;
0222 eeprom_93cx6_read(eeprom, word + i, &tmp);
0223 data[i] = cpu_to_le16(tmp);
0224 }
0225 }
0226 EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237 void eeprom_93cx6_readb(struct eeprom_93cx6 *eeprom, const u8 byte,
0238 u8 *data)
0239 {
0240 u16 command;
0241 u16 tmp;
0242
0243
0244
0245
0246 eeprom_93cx6_startup(eeprom);
0247
0248
0249
0250
0251 command = (PCI_EEPROM_READ_OPCODE << (eeprom->width + 1)) | byte;
0252 eeprom_93cx6_write_bits(eeprom, command,
0253 PCI_EEPROM_WIDTH_OPCODE + eeprom->width + 1);
0254
0255
0256
0257
0258 eeprom_93cx6_read_bits(eeprom, &tmp, 8);
0259 *data = tmp & 0xff;
0260
0261
0262
0263
0264 eeprom_93cx6_cleanup(eeprom);
0265 }
0266 EXPORT_SYMBOL_GPL(eeprom_93cx6_readb);
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278 void eeprom_93cx6_multireadb(struct eeprom_93cx6 *eeprom, const u8 byte,
0279 u8 *data, const u16 bytes)
0280 {
0281 unsigned int i;
0282
0283 for (i = 0; i < bytes; i++)
0284 eeprom_93cx6_readb(eeprom, byte + i, &data[i]);
0285 }
0286 EXPORT_SYMBOL_GPL(eeprom_93cx6_multireadb);
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296 void eeprom_93cx6_wren(struct eeprom_93cx6 *eeprom, bool enable)
0297 {
0298 u16 command;
0299
0300
0301 eeprom_93cx6_startup(eeprom);
0302
0303
0304
0305 command = enable ? PCI_EEPROM_EWEN_OPCODE : PCI_EEPROM_EWDS_OPCODE;
0306 command <<= (eeprom->width - 2);
0307
0308 eeprom_93cx6_write_bits(eeprom, command,
0309 PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
0310
0311 eeprom_93cx6_cleanup(eeprom);
0312 }
0313 EXPORT_SYMBOL_GPL(eeprom_93cx6_wren);
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328 void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom, u8 addr, u16 data)
0329 {
0330 int timeout = 100;
0331 u16 command;
0332
0333
0334 eeprom_93cx6_startup(eeprom);
0335
0336 command = PCI_EEPROM_WRITE_OPCODE << eeprom->width;
0337 command |= addr;
0338
0339
0340 eeprom_93cx6_write_bits(eeprom, command,
0341 PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
0342
0343
0344 eeprom_93cx6_write_bits(eeprom, data, 16);
0345
0346
0347 eeprom->drive_data = 0;
0348 eeprom->reg_chip_select = 1;
0349 eeprom->register_write(eeprom);
0350
0351
0352 usleep_range(1000, 2000);
0353
0354
0355
0356 while (true) {
0357 eeprom->register_read(eeprom);
0358
0359 if (eeprom->reg_data_out)
0360 break;
0361
0362 usleep_range(1000, 2000);
0363
0364 if (--timeout <= 0) {
0365 printk(KERN_ERR "%s: timeout\n", __func__);
0366 break;
0367 }
0368 }
0369
0370 eeprom_93cx6_cleanup(eeprom);
0371 }
0372 EXPORT_SYMBOL_GPL(eeprom_93cx6_write);