1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15:
16: 17: 18: 19:
20:
21: #include "clkdrv.h"
22: #include <tk/util.h>
23:
24: #ifdef DEBUG
25: #define DP(x) printf x
26: #else
27: #define DP(x)
28: #endif
29:
30: #define SPIMAX 3
31: LOCAL FastLock SPILock[SPIMAX];
32: LOCAL ID SPITskID[SPIMAX];
33: LOCAL const UW SPIBase[SPIMAX] = {0xc0120000, 0xc0130000, 0x40130000};
34: LOCAL const UW SPIVec[SPIMAX] = {IV_IRQ(24), IV_IRQ(25), IV_IRQ(42)};
35: LOCAL const UW SPIPol[SPIMAX] = {0x009a, 0x0000, 0x0003};
36: LOCAL const UW SPIMode[SPIMAX] = {0x2700, 0x0700, 0x2700};
37:
38: #define SPn_MODE(n) (SPIBase[n] + 0x0000)
39: #define SPn_POL(n) (SPIBase[n] + 0x0004)
40: #define SPn_CONTROL(n) (SPIBase[n] + 0x0008)
41: #define SPn_TX_DATA(n) (SPIBase[n] + 0x0010)
42: #define SPn_RX_DATA(n) (SPIBase[n] + 0x0014)
43: #define SPn_STATUS(n) (SPIBase[n] + 0x0018)
44: #define SPn_RAW_STATUS(n) (SPIBase[n] + 0x001c)
45: #define SPn_ENSET(n) (SPIBase[n] + 0x0020)
46: #define SPn_ENCLR(n) (SPIBase[n] + 0x0024)
47: #define SPn_FFCLR(n) (SPIBase[n] + 0x0028)
48: #define SPn_CONTROL2(n) (SPIBase[n] + 0x0034)
49: #define SPn_TIECS(n) (SPIBase[n] + 0x0038)
50:
51: #define TIMEOUT 10
52:
53:
54: LOCAL void spi_inthdr(INTVEC vec)
55: {
56: W i;
57:
58: for (i = 0; i < SPIMAX; i++) {
59: if (vec == SPIVec[i]) {
60: out_w(SPn_FFCLR(i), ~0);
61: tk_wup_tsk(SPITskID[i]);
62: break;
63: }
64: }
65:
66: return;
67: }
68:
69:
70: LOCAL ER wait_int(void)
71: {
72: return tk_slp_tsk(TIMEOUT);
73: }
74:
75:
76: LOCAL void spi_init(W ch)
77: {
78: out_w(SPn_MODE(ch), SPIMode[ch]);
79: out_w(SPn_TIECS(ch), 0x000f);
80: out_w(SPn_POL(ch), SPIPol[ch]);
81: out_w(SPn_ENCLR(ch), ~0);
82:
83: out_w(SPn_CONTROL(ch), 0x0100);
84: WaitUsec(10);
85: out_w(SPn_CONTROL(ch), 0x0000);
86: out_w(SPn_CONTROL2(ch), 0x0000);
87:
88: out_w(SPn_FFCLR(ch), ~0);
89: out_w(SPn_ENSET(ch), 0x0004);
90:
91: return;
92: }
93:
94:
95: LOCAL void spi_cs(W ch, W cs, BOOL enable)
96: {
97: WaitNsec(200);
98: out_w(SPn_POL(ch), SPIPol[ch] ^ (enable ? (1 << (cs * 3)) : 0));
99: WaitNsec(200);
100:
101: return;
102: }
103:
104:
105: EXPORT ER SPIXfer(W ch_cs, UB *xmit, UB *recv, W len)
106: {
107: ER er;
108: W i, ch, cs;
109:
110:
111: ch = (ch_cs >> 8) & 0xff;
112: cs = (ch_cs >> 0) & 0xff;
113: if (ch > 2 || cs > 3) {
114: er = E_PAR;
115: goto fin0;
116: }
117:
118: Lock(&SPILock[ch]);
119: SPITskID[ch] = tk_get_tid();
120: tk_can_wup(TSK_SELF);
121:
122: spi_cs(ch, cs, TRUE);
123:
124:
125: for (i = 0; i < len; i++) {
126: if (xmit != NULL) {
127: out_w(SPn_TX_DATA(ch), *xmit++);
128: } else {
129: out_w(SPn_TX_DATA(ch), ~0);
130: }
131:
132: out_w(SPn_CONTROL(ch), 0x000d);
133: er = wait_int();
134: if (er < E_OK) {
135: DP(("spi_txrx: wait_int %d\n", er));
136: spi_init(ch);
137: goto fin1;
138: }
139:
140: if (recv != NULL) {
141: *recv++ = in_w(SPn_RX_DATA(ch));
142: } else {
143: in_w(SPn_RX_DATA(ch));
144: }
145: }
146:
147: er = E_OK;
148:
149: fin1:
150: spi_cs(ch, cs, FALSE);
151: Unlock(&SPILock[ch]);
152: fin0:
153: return er;
154: }
155:
156:
157: EXPORT ER SPIup(W ch, BOOL start)
158: {
159: #define SPITag "SPI_"
160:
161: ER er;
162: T_DINT dint;
163:
164:
165: if (ch < 0 || ch > 2) {
166: er = E_PAR;
167: goto fin0;
168: }
169:
170:
171: if (!start) {
172: er = E_OK;
173: goto fin2;
174: }
175:
176:
177: er = CreateLock(&SPILock[ch], SPITag);
178: if (er < E_OK) {
179: DP(("SPIup: CreateLock %d\n", er));
180: goto fin0;
181: }
182:
183:
184: dint.intatr = TA_HLNG;
185: dint.inthdr = spi_inthdr;
186: er = tk_def_int(SPIVec[ch], &dint);
187: if (er < E_OK) {
188: DP(("SPIup: tk_def_int %d\n", er));
189: goto fin1;
190: }
191:
192:
193: spi_init(ch);
194: SetIntMode(SPIVec[ch], IM_ENA);
195: EnableInt(SPIVec[ch]);
196:
197: er = E_OK;
198: goto fin0;
199:
200: fin2:
201: DisableInt(SPIVec[ch]);
202: SetIntMode(SPIVec[ch], IM_DIS);
203: tk_def_int(SPIVec[ch], NULL);
204: fin1:
205: DeleteLock(&SPILock[ch]);
206: fin0:
207: return er;
208: }