Line data Source code
1 : /* $OpenBSD: smc93cx6.c,v 1.18 2012/03/24 20:19:05 miod Exp $ */
2 : /* $NetBSD: smc93cx6.c,v 1.10 2003/05/02 19:12:19 dyoung Exp $ */
3 :
4 : /*
5 : * Interface for the 93C66/56/46/26/06 serial eeprom parts.
6 : *
7 : * Copyright (c) 1995, 1996 Daniel M. Eischen
8 : * All rights reserved.
9 : *
10 : * Redistribution and use in source and binary forms, with or without
11 : * modification, are permitted provided that the following conditions
12 : * are met:
13 : * 1. Redistributions of source code must retain the above copyright
14 : * notice immediately at the beginning of the file, without modification,
15 : * this list of conditions, and the following disclaimer.
16 : * 2. Redistributions in binary form must reproduce the above copyright
17 : * notice, this list of conditions and the following disclaimer in the
18 : * documentation and/or other materials provided with the distribution.
19 : * 3. Absolutely no warranty of function or purpose is made by the author
20 : * Daniel M. Eischen.
21 : * 4. Modifications may be freely made to this file if the above conditions
22 : * are met.
23 : *
24 : * $FreeBSD: src/sys/dev/aic7xxx/93cx6.c,v 1.5 2000/01/07 23:08:17 gibbs Exp $
25 : */
26 :
27 : /*
28 : * The instruction set of the 93C66/56/46/26/06 chips are as follows:
29 : *
30 : * Start OP *
31 : * Function Bit Code Address** Data Description
32 : * -------------------------------------------------------------------
33 : * READ 1 10 A5 - A0 Reads data stored in memory,
34 : * starting at specified address
35 : * EWEN 1 00 11XXXX Write enable must precede
36 : * all programming modes
37 : * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0
38 : * WRITE 1 01 A5 - A0 D15 - D0 Writes register
39 : * ERAL 1 00 10XXXX Erase all registers
40 : * WRAL 1 00 01XXXX D15 - D0 Writes to all registers
41 : * EWDS 1 00 00XXXX Disables all programming
42 : * instructions
43 : * *Note: A value of X for address is a don't care condition.
44 : * **Note: There are 8 address bits for the 93C56/66 chips unlike
45 : * the 93C46/26/06 chips which have 6 address bits.
46 : *
47 : * The 93C46 has a four wire interface: clock, chip select, data in, and
48 : * data out. In order to perform one of the above functions, you need
49 : * to enable the chip select for a clock period (typically a minimum of
50 : * 1 usec, with the clock high and low a minimum of 750 and 250 nsec
51 : * respectively). While the chip select remains high, you can clock in
52 : * the instructions (above) starting with the start bit, followed by the
53 : * OP code, Address, and Data (if needed). For the READ instruction, the
54 : * requested 16-bit register contents is read from the data out line but
55 : * is preceded by an initial zero (leading 0, followed by 16-bits, MSB
56 : * first). The clock cycling from low to high initiates the next data
57 : * bit to be sent from the chip.
58 : *
59 : */
60 :
61 : #include <sys/param.h>
62 : #include <sys/systm.h>
63 : #include <machine/bus.h>
64 : #include <dev/ic/smc93cx6var.h>
65 :
66 : /*
67 : * Right now, we only have to read the SEEPROM. But we make it easier to
68 : * add other 93Cx6 functions.
69 : */
70 : static struct seeprom_cmd {
71 : unsigned char len;
72 : unsigned char bits[3];
73 : } seeprom_read = {3, {1, 1, 0}};
74 :
75 : #define CLOCK_PULSE(sd, rdy) do { \
76 : /* \
77 : * Wait for the SEERDY to go high; about 800 ns. \
78 : */ \
79 : int cpi = 1000; \
80 : if (rdy == 0) { \
81 : DELAY(4); /* more than long enough */ \
82 : break; \
83 : } \
84 : while ((SEEPROM_STATUS_INB(sd) & rdy) == 0 && cpi-- > 0) { \
85 : ; /* Do nothing */ \
86 : } \
87 : (void)SEEPROM_INB(sd); /* Clear clock */ \
88 : } while (0)
89 :
90 : /*
91 : * Read the serial EEPROM and returns 1 if successful and 0 if
92 : * not successful.
93 : */
94 : int
95 0 : read_seeprom(sd, buf, start_addr, count)
96 : struct seeprom_descriptor *sd;
97 : u_int16_t *buf;
98 : bus_size_t start_addr;
99 : bus_size_t count;
100 : {
101 : int i = 0;
102 : u_int k = 0;
103 : u_int16_t v;
104 : u_int32_t temp;
105 :
106 : /*
107 : * Read the requested registers of the seeprom. The loop
108 : * will range from 0 to count-1.
109 : */
110 0 : for (k = start_addr; k < count + start_addr; k++) {
111 : /* Send chip select for one clock cycle. */
112 0 : temp = sd->sd_MS ^ sd->sd_CS;
113 0 : SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
114 0 : CLOCK_PULSE(sd, sd->sd_RDY);
115 :
116 : /*
117 : * Now we're ready to send the read command followed by the
118 : * address of the 16-bit register we want to read.
119 : */
120 0 : for (i = 0; i < seeprom_read.len; i++) {
121 0 : if (seeprom_read.bits[i] != 0)
122 0 : temp ^= sd->sd_DO;
123 0 : SEEPROM_OUTB(sd, temp);
124 0 : CLOCK_PULSE(sd, sd->sd_RDY);
125 0 : SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
126 0 : CLOCK_PULSE(sd, sd->sd_RDY);
127 0 : if (seeprom_read.bits[i] != 0)
128 0 : temp ^= sd->sd_DO;
129 : }
130 : /* Send the 6 or 8 bit address (MSB first, LSB last). */
131 0 : for (i = (sd->sd_chip - 1); i >= 0; i--) {
132 0 : if ((k & (1 << i)) != 0)
133 0 : temp ^= sd->sd_DO;
134 0 : SEEPROM_OUTB(sd, temp);
135 0 : CLOCK_PULSE(sd, sd->sd_RDY);
136 0 : SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
137 0 : CLOCK_PULSE(sd, sd->sd_RDY);
138 0 : if ((k & (1 << i)) != 0)
139 0 : temp ^= sd->sd_DO;
140 : }
141 :
142 : /*
143 : * Now read the 16 bit register. An initial 0 precedes the
144 : * register contents which begins with bit 15 (MSB) and ends
145 : * with bit 0 (LSB). The initial 0 will be shifted off the
146 : * top of our word as we let the loop run from 0 to 16.
147 : */
148 : v = 0;
149 0 : for (i = 16; i >= 0; i--) {
150 0 : SEEPROM_OUTB(sd, temp);
151 0 : CLOCK_PULSE(sd, sd->sd_RDY);
152 0 : v <<= 1;
153 0 : if (SEEPROM_DATA_INB(sd) & sd->sd_DI)
154 0 : v |= 1;
155 0 : SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
156 0 : CLOCK_PULSE(sd, sd->sd_RDY);
157 : }
158 :
159 0 : buf[k - start_addr] = v;
160 :
161 : /* Reset the chip select for the next command cycle. */
162 0 : temp = sd->sd_MS;
163 0 : SEEPROM_OUTB(sd, temp);
164 0 : CLOCK_PULSE(sd, sd->sd_RDY);
165 0 : SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
166 0 : CLOCK_PULSE(sd, sd->sd_RDY);
167 0 : SEEPROM_OUTB(sd, temp);
168 0 : CLOCK_PULSE(sd, sd->sd_RDY);
169 : }
170 : #ifdef AHC_DUMP_EEPROM
171 : printf("\nSerial EEPROM:\n\t");
172 : for (k = 0; k < count; k = k + 1) {
173 : if (((k % 8) == 0) && (k != 0)) {
174 : printf ("\n\t");
175 : }
176 : printf (" 0x%04x", buf[k]);
177 : }
178 : printf ("\n");
179 : #endif
180 0 : return (1);
181 : }
|