aic7xxx_93cx6.c revision 39220
139220Sgibbs/*
239220Sgibbs * Interface for the 93C66/56/46/26/06 serial eeprom parts.
339220Sgibbs *
439220Sgibbs * Copyright (c) 1995, 1996 Daniel M. Eischen
539220Sgibbs * All rights reserved.
639220Sgibbs *
739220Sgibbs * Redistribution and use in source and binary forms, with or without
839220Sgibbs * modification, are permitted provided that the following conditions
939220Sgibbs * are met:
1039220Sgibbs * 1. Redistributions of source code must retain the above copyright
1139220Sgibbs *    notice immediately at the beginning of the file, without modification,
1239220Sgibbs *    this list of conditions, and the following disclaimer.
1339220Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1439220Sgibbs *    notice, this list of conditions and the following disclaimer in the
1539220Sgibbs *    documentation and/or other materials provided with the distribution.
1639220Sgibbs * 3. Absolutely no warranty of function or purpose is made by the author
1739220Sgibbs *    Daniel M. Eischen.
1839220Sgibbs * 4. Modifications may be freely made to this file if the above conditions
1939220Sgibbs *    are met.
2039220Sgibbs *
2139220Sgibbs *      $Id: 93cx6.c,v 1.10 1997/02/22 09:38:36 peter Exp $
2239220Sgibbs */
2339220Sgibbs
2439220Sgibbs/*
2539220Sgibbs *   The instruction set of the 93C66/56/46/26/06 chips are as follows:
2639220Sgibbs *
2739220Sgibbs *               Start  OP	    *
2839220Sgibbs *     Function   Bit  Code  Address**  Data     Description
2939220Sgibbs *     -------------------------------------------------------------------
3039220Sgibbs *     READ        1    10   A5 - A0             Reads data stored in memory,
3139220Sgibbs *                                               starting at specified address
3239220Sgibbs *     EWEN        1    00   11XXXX              Write enable must preceed
3339220Sgibbs *                                               all programming modes
3439220Sgibbs *     ERASE       1    11   A5 - A0             Erase register A5A4A3A2A1A0
3539220Sgibbs *     WRITE       1    01   A5 - A0   D15 - D0  Writes register
3639220Sgibbs *     ERAL        1    00   10XXXX              Erase all registers
3739220Sgibbs *     WRAL        1    00   01XXXX    D15 - D0  Writes to all registers
3839220Sgibbs *     EWDS        1    00   00XXXX              Disables all programming
3939220Sgibbs *                                               instructions
4039220Sgibbs *     *Note: A value of X for address is a don't care condition.
4139220Sgibbs *    **Note: There are 8 address bits for the 93C56/66 chips unlike
4239220Sgibbs *	      the 93C46/26/06 chips which have 6 address bits.
4339220Sgibbs *
4439220Sgibbs *   The 93C46 has a four wire interface: clock, chip select, data in, and
4539220Sgibbs *   data out.  In order to perform one of the above functions, you need
4639220Sgibbs *   to enable the chip select for a clock period (typically a minimum of
4739220Sgibbs *   1 usec, with the clock high and low a minimum of 750 and 250 nsec
4839220Sgibbs *   respectively).  While the chip select remains high, you can clock in
4939220Sgibbs *   the instructions (above) starting with the start bit, followed by the
5039220Sgibbs *   OP code, Address, and Data (if needed).  For the READ instruction, the
5139220Sgibbs *   requested 16-bit register contents is read from the data out line but
5239220Sgibbs *   is preceded by an initial zero (leading 0, followed by 16-bits, MSB
5339220Sgibbs *   first).  The clock cycling from low to high initiates the next data
5439220Sgibbs *   bit to be sent from the chip.
5539220Sgibbs *
5639220Sgibbs */
5739220Sgibbs
5839220Sgibbs#include <sys/param.h>
5939220Sgibbs#include <sys/systm.h>
6039220Sgibbs#include <machine/bus_memio.h>
6139220Sgibbs#include <machine/bus_pio.h>
6239220Sgibbs#include <machine/bus.h>
6339220Sgibbs#include <dev/aic7xxx/93cx6.h>
6439220Sgibbs
6539220Sgibbs/*
6639220Sgibbs * Right now, we only have to read the SEEPROM.  But we make it easier to
6739220Sgibbs * add other 93Cx6 functions.
6839220Sgibbs */
6939220Sgibbsstatic struct seeprom_cmd {
7039220Sgibbs  	unsigned char len;
7139220Sgibbs 	unsigned char bits[3];
7239220Sgibbs} seeprom_read = {3, {1, 1, 0}};
7339220Sgibbs
7439220Sgibbs/*
7539220Sgibbs * Wait for the SEERDY to go high; about 800 ns.
7639220Sgibbs */
7739220Sgibbs#define CLOCK_PULSE(sd, rdy)				\
7839220Sgibbs	while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) {	\
7939220Sgibbs		;  /* Do nothing */			\
8039220Sgibbs	}						\
8139220Sgibbs	(void)SEEPROM_INB(sd);	/* Clear clock */
8239220Sgibbs
8339220Sgibbs/*
8439220Sgibbs * Read the serial EEPROM and returns 1 if successful and 0 if
8539220Sgibbs * not successful.
8639220Sgibbs */
8739220Sgibbsint
8839220Sgibbsread_seeprom(sd, buf, start_addr, count)
8939220Sgibbs	struct seeprom_descriptor *sd;
9039220Sgibbs	u_int16_t *buf;
9139220Sgibbs	bus_size_t start_addr;
9239220Sgibbs	bus_size_t count;
9339220Sgibbs{
9439220Sgibbs	int i = 0;
9539220Sgibbs	u_int k = 0;
9639220Sgibbs	u_int16_t v;
9739220Sgibbs	u_int8_t temp;
9839220Sgibbs
9939220Sgibbs	/*
10039220Sgibbs	 * Read the requested registers of the seeprom.  The loop
10139220Sgibbs	 * will range from 0 to count-1.
10239220Sgibbs	 */
10339220Sgibbs	for (k = start_addr; k < count + start_addr; k++) {
10439220Sgibbs		/* Send chip select for one clock cycle. */
10539220Sgibbs		temp = sd->sd_MS ^ sd->sd_CS;
10639220Sgibbs		SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
10739220Sgibbs		CLOCK_PULSE(sd, sd->sd_RDY);
10839220Sgibbs
10939220Sgibbs		/*
11039220Sgibbs		 * Now we're ready to send the read command followed by the
11139220Sgibbs		 * address of the 16-bit register we want to read.
11239220Sgibbs		 */
11339220Sgibbs		for (i = 0; i < seeprom_read.len; i++) {
11439220Sgibbs			if (seeprom_read.bits[i] != 0)
11539220Sgibbs				temp ^= sd->sd_DO;
11639220Sgibbs			SEEPROM_OUTB(sd, temp);
11739220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
11839220Sgibbs			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
11939220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
12039220Sgibbs			if (seeprom_read.bits[i] != 0)
12139220Sgibbs				temp ^= sd->sd_DO;
12239220Sgibbs		}
12339220Sgibbs		/* Send the 6 or 8 bit address (MSB first, LSB last). */
12439220Sgibbs		for (i = (sd->sd_chip - 1); i >= 0; i--) {
12539220Sgibbs			if ((k & (1 << i)) != 0)
12639220Sgibbs				temp ^= sd->sd_DO;
12739220Sgibbs			SEEPROM_OUTB(sd, temp);
12839220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
12939220Sgibbs			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
13039220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
13139220Sgibbs			if ((k & (1 << i)) != 0)
13239220Sgibbs				temp ^= sd->sd_DO;
13339220Sgibbs		}
13439220Sgibbs
13539220Sgibbs		/*
13639220Sgibbs		 * Now read the 16 bit register.  An initial 0 precedes the
13739220Sgibbs		 * register contents which begins with bit 15 (MSB) and ends
13839220Sgibbs		 * with bit 0 (LSB).  The initial 0 will be shifted off the
13939220Sgibbs		 * top of our word as we let the loop run from 0 to 16.
14039220Sgibbs		 */
14139220Sgibbs		v = 0;
14239220Sgibbs		for (i = 16; i >= 0; i--) {
14339220Sgibbs			SEEPROM_OUTB(sd, temp);
14439220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
14539220Sgibbs			v <<= 1;
14639220Sgibbs			if (SEEPROM_DATA_INB(sd) & sd->sd_DI)
14739220Sgibbs				v |= 1;
14839220Sgibbs			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
14939220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
15039220Sgibbs		}
15139220Sgibbs
15239220Sgibbs		buf[k - start_addr] = v;
15339220Sgibbs
15439220Sgibbs		/* Reset the chip select for the next command cycle. */
15539220Sgibbs		temp = sd->sd_MS;
15639220Sgibbs		SEEPROM_OUTB(sd, temp);
15739220Sgibbs		CLOCK_PULSE(sd, sd->sd_RDY);
15839220Sgibbs		SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
15939220Sgibbs		CLOCK_PULSE(sd, sd->sd_RDY);
16039220Sgibbs		SEEPROM_OUTB(sd, temp);
16139220Sgibbs		CLOCK_PULSE(sd, sd->sd_RDY);
16239220Sgibbs	}
16339220Sgibbs#ifdef 93CX6_DUMP_EEPROM
16439220Sgibbs	printf("\nSerial EEPROM:");
16539220Sgibbs	for (k = 0; k < count; k = k + 1) {
16639220Sgibbs		if (((k % 8) == 0) && (k != 0)) {
16739220Sgibbs			printf ("\n              ");
16839220Sgibbs		}
16939220Sgibbs		printf (" 0x%x", buf[k]);
17039220Sgibbs	}
17139220Sgibbs	printf ("\n");
17239220Sgibbs#endif
17339220Sgibbs	return (1);
17439220Sgibbs}
175