Annotation of funnyos/dev/sdmmc/sdmmc_spi.c, Revision 1.3
1.1 nbrk 1: /*
1.3 ! nbrk 2: * $Id: sdmmc_spi.c,v 1.2 2007/12/21 17:45:26 nbrk Exp $
1.1 nbrk 3: */
4: #include <sys/types.h>
5: #include <sys/device.h>
6: #include <sys/bus_spi.h>
7:
8: #include <dev/sdmmc/sdmmcvar.h>
9: #include <libkern/printf.h>
10:
11: /*
12: * SD/MMC conversation over SPI bus.
13: */
14: struct spisdmmc_dd {
15: struct spi_bus_handle *ss_sbhp;
16:
17: // struct sdmmc_bus_handle;
18: };
19:
20: int spisdmmc_attach(struct device *, uint32_t, uint8_t);
1.2 nbrk 21: void spisdmmc_send_command(struct spisdmmc_dd *ddp, uint8_t cmd, uint32_t arg, uint32_t crc);
22: uint8_t spisdmmc_get_response(struct spisdmmc_dd *ddp);
23: int spisdmmc_set_block_size(struct spisdmmc_dd *ddp, uint16_t blksize);
24: void spisdmmc_read_block(struct spisdmmc_dd *ddp, uint16_t nbytes, char *buffp);
25: uint8_t spisdmmc_get_token(struct spisdmmc_dd *ddp);
26: void spisdmmc_read_cid(struct spisdmmc_dd *ddp, struct sdmmc_cid *cidp);
27:
28:
1.1 nbrk 29:
30: struct driver spisdmmc_dr = {
31: sizeof(struct spisdmmc_dd),
32: spisdmmc_attach,
33: NULL,
34: NULL
35: };
36:
37:
38: int
39: spisdmmc_attach(struct device *self, uint32_t loc, uint8_t flags)
40: {
41: struct spisdmmc_dd *ddp = self->dv_devdata;
42: ddp->ss_sbhp = self->dv_parent->dv_aux;
43:
44: printf("SPI SD/MMC\n");
45:
1.2 nbrk 46: spisdmmc_init(ddp);
47:
1.1 nbrk 48: return(0);
49: }
50:
51:
52: int
53: spisdmmc_init(struct spisdmmc_dd *ddp)
54: {
55: uint8_t i, resp;
1.2 nbrk 56: struct sdmmc_cid cid;
1.1 nbrk 57:
58: /*
59: * Apply 80 clock pulses.
60: * XXX assert CS. (NPCS0)
61: */
1.2 nbrk 62: spi_cs_high(ddp->ss_sbhp);
1.1 nbrk 63: for (i = 0; i < 9; i++)
64: spi_transmit(ddp->ss_sbhp, 0xff);
65:
66: /*
67: * Send CMD0_GO_IDLE_STATE.
68: */
1.2 nbrk 69: spi_cs_low(ddp->ss_sbhp);
1.1 nbrk 70: spisdmmc_send_command(ddp, CMD0_GO_IDLE_STATE, 0, CMD0_HARDCODED_CRC);
1.2 nbrk 71:
72: resp = spisdmmc_get_response(ddp);
73:
1.3 ! nbrk 74: if (resp & R1_IN_IDLE_STATE != 1) {
1.1 nbrk 75: printf("spisdmmc_init: CMD0_GO_IDLE_STATE failed with %d\n", resp);
76:
77: return(-1);
78: }
1.2 nbrk 79: printf("spisdmmc_init: Card replied to CMD0_GO_IDLE_STATE with 0x%x\n", resp);
80:
81: /*
82: * Okay. Try to initialize the card.
83: * Periodically send CMD1 and poll for response with 0x01 cleared (card exit Idle state).
84: * CRC is off so we can set it 0xff.
85: * XXX send 0xff before.
86: */
87: do {
1.3 ! nbrk 88: spi_cs_high(ddp->ss_sbhp);
! 89: spi_transmit(ddp->ss_sbhp, 0xff);
! 90:
! 91: spi_cs_low(ddp->ss_sbhp);
! 92:
1.2 nbrk 93: spisdmmc_send_command(ddp, CMD1_SEND_OP_COND, 0, 0xff);
94: resp = spisdmmc_get_response(ddp);
95: } while(resp != 0x00);
96:
97: printf("spisdmmc_init: Card initialization completed\n");
98:
99: /*
100: * Set block size to 512 bytes.
101: */
102: if(spisdmmc_set_block_size(ddp, SDMMC_BLOCK_SIZE) == -1) {
103: printf("spisdmmc_init: failed to set block size\n");
104: return(-1);
105: }
106: printf("spisdmmc_init: block size set to %d\n", SDMMC_BLOCK_SIZE);
1.1 nbrk 107:
1.2 nbrk 108: spisdmmc_read_cid(ddp, &cid);
109: printf("cid.pnm: %s%s%s%s%s\n", cid.cid_pnm[0], cid.cid_pnm[1], cid.cid_pnm[2], cid.cid_pnm[3], cid.cid_pnm[4]);
1.3 ! nbrk 110:
1.2 nbrk 111: return(0);
1.1 nbrk 112: }
113:
114:
115: void
116: spisdmmc_send_command(struct spisdmmc_dd *ddp, uint8_t cmd, uint32_t arg, uint32_t crc)
117: {
118: struct sdmmc_cmdframe sdcf;
119: uint8_t i;
120:
121: /* construct frame */
122: sdcf = sdmmc_command(cmd, arg, crc);
123:
1.3 ! nbrk 124: // printf("spisdmmc_send_command: sending cmd %d arg 0x%x crc 0x%x\n", sdcf.sc_cmd & ~0xc0, sdcf.sc_arg, sdcf.sc_crc);
1.2 nbrk 125: /* transmit cmd */
1.1 nbrk 126: spi_transmit(ddp->ss_sbhp, sdcf.sc_cmd);
127:
128: /* transmit 32 bit argument XXX MSB first */
129: for(i = 0; i < 4; i++)
130: spi_transmit(ddp->ss_sbhp, ((sdcf.sc_arg & (0xff000000 >> i)) >> (8 * (4 - i + 1))) );
131:
132: /* transmit CRC field */
1.2 nbrk 133: spi_transmit(ddp->ss_sbhp, sdcf.sc_crc);
134:
135: /* XXX Apply NCR clock pulses */
1.3 ! nbrk 136: spi_transmit(ddp->ss_sbhp, 0xff);
1.2 nbrk 137: }
138:
139:
140: uint8_t
141: spisdmmc_get_response(struct spisdmmc_dd *ddp)
142: {
143: uint8_t i, resp;
144: /*
145: * Get response from card.
146: * After command response comes in 8 to 64 pulses (all this bits will be 1).
147: */
148:
149: for(i = 0; i < 64; i++) {
150: resp = spi_transmit(ddp->ss_sbhp, 0xff);
151:
1.3 ! nbrk 152: // if (resp == 0 || resp == 1)
! 153: if (resp != 0xff)
1.2 nbrk 154: return(resp);
155: }
156: }
157:
158: uint8_t
159: spisdmmc_get_token(struct spisdmmc_dd *ddp)
160: {
161: uint16_t i, token;
162: /*
163: * Get token.
164: */
165:
166: for(i = 0; i < 1000; i++) {
167: token = spi_transmit(ddp->ss_sbhp, 0xff);
168:
169: if (token == TOK_READ_BLOCK || token == TOK_WRITE_BLOCK_MULTIPLE)
170: return(token);
171: }
172: }
173:
1.1 nbrk 174:
1.2 nbrk 175: int
176: spisdmmc_set_block_size(struct spisdmmc_dd *ddp, uint16_t blksize)
177: {
178: uint8_t resp;
179: /*
180: * Set block size (CMD16).
181: */
182: spisdmmc_send_command(ddp,CMD16_SET_BLOCKLEN, blksize, 0xff);
183: resp = spisdmmc_get_response(ddp);
184: if (resp != 0x00) {
185: printf("spisdmmc_set_block_size: set block size to %d failed (0x%x)\n", blksize, resp);
186: return(-1);
187: }
188: return(0);
1.1 nbrk 189: }
190:
1.2 nbrk 191: void
192: spisdmmc_read_cid(struct spisdmmc_dd *ddp, struct sdmmc_cid *cidp)
193: {
194: uint8_t resp;
195: struct sdmmc_cid cid;
196: /*
197: * Read Card ID register.
198: */
199: spisdmmc_send_command(ddp, CMD10_SEND_CID, 0, 0xff);
200: resp = spisdmmc_get_response(ddp);
201: printf("spisdmmc_read_cid: got r1 response 0x%x\n", resp);
202:
203: /*
204: * Wait R1 response.
205: */
206: if (resp != 0x00) {
207: printf("spisdmmc_read_cid: bad response 0x%x\n", resp);
208: return;
209: }
210:
211: spisdmmc_read_block(ddp, 16, (char *)&cid);
212: }
213:
214:
215: void
216: spisdmmc_read_block(struct spisdmmc_dd *ddp, uint16_t nbytes, char *buffp)
217: {
218: uint8_t token;
219: uint16_t crc;
220: /*
221: * Read block.
222: */
223: token = spisdmmc_get_token(ddp);
224: printf("spisdmmc_read_block: got token 0x%x\n", token);
225: if (token != TOK_READ_BLOCK) {
226: printf("spisdmmc_read_block: error, foreign token\n");
227: return;
228: }
229: /*
230: * Okay, next is the data.
231: */
232: while(nbytes != 0) {
233: *buffp = spi_transmit(ddp->ss_sbhp, 0xff);
234: printf("byte read 0x%x\n", *buffp);
235:
236: buffp++;
237: nbytes--;
238: }
239:
240: /*
241: * Read CRC.
242: */
243: crc = spi_transmit(ddp->ss_sbhp, 0xff);
244: crc <<= 8;
245: crc = spi_transmit(ddp->ss_sbhp, 0xff);
246: };
1.1 nbrk 247:
CVSweb