19467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn/*
2654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
3654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * <http://rt2x00.serialmonkey.com>
4654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham *
5654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * This program is free software; you can redistribute it and/or modify
6654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * it under the terms of the GNU General Public License as published by
7654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * the Free Software Foundation; either version 2 of the License, or
8654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * (at your option) any later version.
9654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham *
10654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * This program is distributed in the hope that it will be useful,
11654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * but WITHOUT ANY WARRANTY; without even the implied warranty of
12654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * GNU General Public License for more details.
14654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham *
15654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * Module: eeprom_93cx6
16654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * Abstract: EEPROM reader routines for 93cx6 chipsets.
17654087faf8ad0695d6b384465e3380a1d8de1cb2Arce, Abraham * Supported chipsets: 93c46 & 93c66.
189467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn */
199467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
209467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn#include <linux/kernel.h>
219467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn#include <linux/module.h>
229467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn#include <linux/delay.h>
239467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn#include <linux/eeprom_93cx6.h>
249467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
259467d64b0e88763914c01f71ddf591b166c4f526Ivo van DoornMODULE_AUTHOR("http://rt2x00.serialmonkey.com");
269467d64b0e88763914c01f71ddf591b166c4f526Ivo van DoornMODULE_VERSION("1.0");
279467d64b0e88763914c01f71ddf591b166c4f526Ivo van DoornMODULE_DESCRIPTION("EEPROM 93cx6 chip driver");
289467d64b0e88763914c01f71ddf591b166c4f526Ivo van DoornMODULE_LICENSE("GPL");
299467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
309467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doornstatic inline void eeprom_93cx6_pulse_high(struct eeprom_93cx6 *eeprom)
319467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn{
329467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_clock = 1;
339467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->register_write(eeprom);
344b914dc0493edff19ff698a18198a173a14ba9d2Ivo van Doorn
354b914dc0493edff19ff698a18198a173a14ba9d2Ivo van Doorn	/*
364b914dc0493edff19ff698a18198a173a14ba9d2Ivo van Doorn	 * Add a short delay for the pulse to work.
377e9400f178d291b2208c4ed9aac0f425c1364000John W. Linville	 * According to the specifications the "maximum minimum"
387e9400f178d291b2208c4ed9aac0f425c1364000John W. Linville	 * time should be 450ns.
394b914dc0493edff19ff698a18198a173a14ba9d2Ivo van Doorn	 */
407e9400f178d291b2208c4ed9aac0f425c1364000John W. Linville	ndelay(450);
419467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn}
429467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
439467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doornstatic inline void eeprom_93cx6_pulse_low(struct eeprom_93cx6 *eeprom)
449467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn{
459467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_clock = 0;
469467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->register_write(eeprom);
474b914dc0493edff19ff698a18198a173a14ba9d2Ivo van Doorn
484b914dc0493edff19ff698a18198a173a14ba9d2Ivo van Doorn	/*
494b914dc0493edff19ff698a18198a173a14ba9d2Ivo van Doorn	 * Add a short delay for the pulse to work.
508abd531e3f77188de2fc41e677d075cc66e61631Francois Romieu	 * According to the specifications the "maximum minimum"
518abd531e3f77188de2fc41e677d075cc66e61631Francois Romieu	 * time should be 450ns.
524b914dc0493edff19ff698a18198a173a14ba9d2Ivo van Doorn	 */
538abd531e3f77188de2fc41e677d075cc66e61631Francois Romieu	ndelay(450);
549467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn}
559467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
569467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doornstatic void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom)
579467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn{
589467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
599467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * Clear all flags, and enable chip select.
609467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
619467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->register_read(eeprom);
629467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_in = 0;
639467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_out = 0;
649467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_clock = 0;
659467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_chip_select = 1;
66b30f8bdcfa7dd05f4268348f3388ff903132f28eBen Dooks	eeprom->drive_data = 1;
679467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->register_write(eeprom);
689467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
699467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
709467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * kick a pulse.
719467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
729467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom_93cx6_pulse_high(eeprom);
739467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom_93cx6_pulse_low(eeprom);
749467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn}
759467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
769467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doornstatic void eeprom_93cx6_cleanup(struct eeprom_93cx6 *eeprom)
779467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn{
789467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
799467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * Clear chip_select and data_in flags.
809467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
819467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->register_read(eeprom);
829467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_in = 0;
839467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_chip_select = 0;
849467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->register_write(eeprom);
859467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
869467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
879467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * kick a pulse.
889467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
899467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom_93cx6_pulse_high(eeprom);
909467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom_93cx6_pulse_low(eeprom);
919467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn}
929467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
939467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doornstatic void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom,
949467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	const u16 data, const u16 count)
959467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn{
969467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	unsigned int i;
979467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
989467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->register_read(eeprom);
999467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1009467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
1019467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * Clear data flags.
1029467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
1039467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_in = 0;
1049467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_out = 0;
105b30f8bdcfa7dd05f4268348f3388ff903132f28eBen Dooks	eeprom->drive_data = 1;
1069467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1079467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
1089467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * Start writing all bits.
1099467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
1109467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	for (i = count; i > 0; i--) {
1119467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		/*
1129467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		 * Check if this bit needs to be set.
1139467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		 */
1149467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		eeprom->reg_data_in = !!(data & (1 << (i - 1)));
1159467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1169467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		/*
1179467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		 * Write the bit to the eeprom register.
1189467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		 */
1199467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		eeprom->register_write(eeprom);
1209467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1219467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		/*
1229467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		 * Kick a pulse.
1239467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		 */
1249467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		eeprom_93cx6_pulse_high(eeprom);
1259467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		eeprom_93cx6_pulse_low(eeprom);
1269467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	}
1279467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1289467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_in = 0;
1299467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->register_write(eeprom);
1309467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn}
1319467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1329467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doornstatic void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom,
1339467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	u16 *data, const u16 count)
1349467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn{
1359467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	unsigned int i;
1369467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	u16 buf = 0;
1379467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1389467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->register_read(eeprom);
1399467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1409467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
1419467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * Clear data flags.
1429467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
1439467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_in = 0;
1449467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom->reg_data_out = 0;
145b30f8bdcfa7dd05f4268348f3388ff903132f28eBen Dooks	eeprom->drive_data = 0;
1469467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1479467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
1489467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * Start reading all bits.
1499467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
1509467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	for (i = count; i > 0; i--) {
1519467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		eeprom_93cx6_pulse_high(eeprom);
1529467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1539467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		eeprom->register_read(eeprom);
1549467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1559467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		/*
1569467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		 * Clear data_in flag.
1579467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		 */
1589467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		eeprom->reg_data_in = 0;
1599467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1609467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		/*
1619467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		 * Read if the bit has been set.
1629467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		 */
1639467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		if (eeprom->reg_data_out)
1649467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn			buf |= (1 << (i - 1));
1659467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1669467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		eeprom_93cx6_pulse_low(eeprom);
1679467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	}
1689467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1699467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	*data = buf;
1709467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn}
1719467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1729467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn/**
1739467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * eeprom_93cx6_read - Read multiple words from eeprom
1749467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * @eeprom: Pointer to eeprom structure
1759467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * @word: Word index from where we should start reading
1769467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * @data: target pointer where the information will have to be stored
1779467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn *
1789467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * This function will read the eeprom data as host-endian word
1799467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * into the given data pointer.
1809467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn */
1819467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doornvoid eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word,
1829467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	u16 *data)
1839467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn{
1849467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	u16 command;
1859467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1869467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
1879467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * Initialize the eeprom register
1889467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
1899467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom_93cx6_startup(eeprom);
1909467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1919467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
1929467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * Select the read opcode and the word to be read.
1939467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
1949467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	command = (PCI_EEPROM_READ_OPCODE << eeprom->width) | word;
1959467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom_93cx6_write_bits(eeprom, command,
1969467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
1979467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
1989467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
1999467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * Read the requested 16 bits.
2009467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
2019467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom_93cx6_read_bits(eeprom, data, 16);
2029467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
2039467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	/*
2049467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 * Cleanup eeprom register.
2059467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	 */
2069467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	eeprom_93cx6_cleanup(eeprom);
2079467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn}
2089467d64b0e88763914c01f71ddf591b166c4f526Ivo van DoornEXPORT_SYMBOL_GPL(eeprom_93cx6_read);
2099467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
2109467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn/**
2119467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * eeprom_93cx6_multiread - Read multiple words from eeprom
2129467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * @eeprom: Pointer to eeprom structure
2139467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * @word: Word index from where we should start reading
2149467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * @data: target pointer where the information will have to be stored
2159467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * @words: Number of words that should be read.
2169467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn *
2179467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * This function will read all requested words from the eeprom,
2189467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * this is done by calling eeprom_93cx6_read() multiple times.
2199467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * But with the additional change that while the eeprom_93cx6_read
2209467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * will return host ordered bytes, this method will return little
2219467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn * endian words.
2229467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn */
2239467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doornvoid eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word,
2249467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	__le16 *data, const u16 words)
2259467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn{
2269467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	unsigned int i;
2279467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	u16 tmp;
2289467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
2299467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	for (i = 0; i < words; i++) {
2309467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		tmp = 0;
2319467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		eeprom_93cx6_read(eeprom, word + i, &tmp);
2329467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn		data[i] = cpu_to_le16(tmp);
2339467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn	}
2349467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn}
2359467d64b0e88763914c01f71ddf591b166c4f526Ivo van DoornEXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
2369467d64b0e88763914c01f71ddf591b166c4f526Ivo van Doorn
237072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks/**
238072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * eeprom_93cx6_wren - set the write enable state
239072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * @eeprom: Pointer to eeprom structure
240072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * @enable: true to enable writes, otherwise disable writes
241072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks *
242072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * Set the EEPROM write enable state to either allow or deny
243072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * writes depending on the @enable value.
244072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks */
245072bc80156729f853e8bcafe1b17c48c74462887Ben Dooksvoid eeprom_93cx6_wren(struct eeprom_93cx6 *eeprom, bool enable)
246072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks{
247072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	u16 command;
248072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
249072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	/* start the command */
250072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	eeprom_93cx6_startup(eeprom);
251072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
252072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	/* create command to enable/disable */
253072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
254072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	command = enable ? PCI_EEPROM_EWEN_OPCODE : PCI_EEPROM_EWDS_OPCODE;
255072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	command <<= (eeprom->width - 2);
256072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
257072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	eeprom_93cx6_write_bits(eeprom, command,
258072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks				PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
259072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
260072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	eeprom_93cx6_cleanup(eeprom);
261072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks}
262072bc80156729f853e8bcafe1b17c48c74462887Ben DooksEXPORT_SYMBOL_GPL(eeprom_93cx6_wren);
263072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
264072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks/**
265072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * eeprom_93cx6_write - write data to the EEPROM
266072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * @eeprom: Pointer to eeprom structure
267072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * @addr: Address to write data to.
268072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * @data: The data to write to address @addr.
269072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks *
270072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * Write the @data to the specified @addr in the EEPROM and
271072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * waiting for the device to finish writing.
272072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks *
273072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * Note, since we do not expect large number of write operations
274072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * we delay in between parts of the operation to avoid using excessive
275072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks * amounts of CPU time busy waiting.
276072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks */
277072bc80156729f853e8bcafe1b17c48c74462887Ben Dooksvoid eeprom_93cx6_write(struct eeprom_93cx6 *eeprom, u8 addr, u16 data)
278072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks{
279072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	int timeout = 100;
280072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	u16 command;
281072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
282072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	/* start the command */
283072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	eeprom_93cx6_startup(eeprom);
284072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
285072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	command = PCI_EEPROM_WRITE_OPCODE << eeprom->width;
286072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	command |= addr;
287072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
288072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	/* send write command */
289072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	eeprom_93cx6_write_bits(eeprom, command,
290072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks				PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
291072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
292072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	/* send data */
293072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	eeprom_93cx6_write_bits(eeprom, data, 16);
294072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
295072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	/* get ready to check for busy */
296072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	eeprom->drive_data = 0;
297072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	eeprom->reg_chip_select = 1;
298072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	eeprom->register_write(eeprom);
299072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
300072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	/* wait at-least 250ns to get DO to be the busy signal */
301072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	usleep_range(1000, 2000);
302072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
303072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	/* wait for DO to go high to signify finish */
304072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
305072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	while (true) {
306072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks		eeprom->register_read(eeprom);
307072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
308072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks		if (eeprom->reg_data_out)
309072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks			break;
310072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
311072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks		usleep_range(1000, 2000);
312072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
313072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks		if (--timeout <= 0) {
314072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks			printk(KERN_ERR "%s: timeout\n", __func__);
315072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks			break;
316072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks		}
317072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	}
318072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks
319072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks	eeprom_93cx6_cleanup(eeprom);
320072bc80156729f853e8bcafe1b17c48c74462887Ben Dooks}
321072bc80156729f853e8bcafe1b17c48c74462887Ben DooksEXPORT_SYMBOL_GPL(eeprom_93cx6_write);
322