Annotation of funnyos/dev/sdmmc/sdmmc_spi.c, Revision 1.2
1.1 nbrk 1: /*
1.2 ! nbrk 2: * $Id: sdmmc_spi.c,v 1.1 2007/12/20 15:23:15 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: * Apply 16 clocks.
67: * XXX deassert CS.
68: */
1.2 ! nbrk 69: // for (i = 0; i < 2; i ++)
! 70: // spi_transmit(ddp->ss_sbhp, 0xff);
1.1 nbrk 71:
72: /*
73: * Send CMD0_GO_IDLE_STATE.
74: */
1.2 ! nbrk 75: spi_cs_low(ddp->ss_sbhp);
1.1 nbrk 76: spisdmmc_send_command(ddp, CMD0_GO_IDLE_STATE, 0, CMD0_HARDCODED_CRC);
1.2 ! nbrk 77:
! 78: resp = spisdmmc_get_response(ddp);
! 79:
! 80: if (resp != 0) {
1.1 nbrk 81: printf("spisdmmc_init: CMD0_GO_IDLE_STATE failed with %d\n", resp);
82:
83: return(-1);
84: }
1.2 ! nbrk 85: printf("spisdmmc_init: Card replied to CMD0_GO_IDLE_STATE with 0x%x\n", resp);
! 86:
! 87: /*
! 88: * Okay. Try to initialize the card.
! 89: * Periodically send CMD1 and poll for response with 0x01 cleared (card exit Idle state).
! 90: * CRC is off so we can set it 0xff.
! 91: * XXX send 0xff before.
! 92: */
! 93: // spi_transmit(ddp->ss_sbhp, 0xff);
! 94: do {
! 95: spisdmmc_send_command(ddp, CMD1_SEND_OP_COND, 0, 0xff);
! 96: resp = spisdmmc_get_response(ddp);
! 97: } while(resp != 0x00);
! 98:
! 99: printf("spisdmmc_init: Card initialization completed\n");
! 100:
! 101: /*
! 102: * Set block size to 512 bytes.
! 103: */
! 104: if(spisdmmc_set_block_size(ddp, SDMMC_BLOCK_SIZE) == -1) {
! 105: printf("spisdmmc_init: failed to set block size\n");
! 106: return(-1);
! 107: }
! 108: printf("spisdmmc_init: block size set to %d\n", SDMMC_BLOCK_SIZE);
1.1 nbrk 109:
1.2 ! nbrk 110: spisdmmc_read_cid(ddp, &cid);
! 111: 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]);
! 112:
! 113: return(0);
1.1 nbrk 114: }
115:
116:
117: void
118: spisdmmc_send_command(struct spisdmmc_dd *ddp, uint8_t cmd, uint32_t arg, uint32_t crc)
119: {
120: struct sdmmc_cmdframe sdcf;
121: uint8_t i;
122:
123: /* construct frame */
124: sdcf = sdmmc_command(cmd, arg, crc);
125:
1.2 ! nbrk 126: printf("spisdmmc_send_command: sending cmd %d arg 0x%x crc 0x%x\n", sdcf.sc_cmd & ~0xc0, sdcf.sc_arg, sdcf.sc_crc);
! 127: /* transmit cmd */
1.1 nbrk 128: spi_transmit(ddp->ss_sbhp, sdcf.sc_cmd);
129:
130: /* transmit 32 bit argument XXX MSB first */
131: for(i = 0; i < 4; i++)
132: spi_transmit(ddp->ss_sbhp, ((sdcf.sc_arg & (0xff000000 >> i)) >> (8 * (4 - i + 1))) );
133:
134: /* transmit CRC field */
1.2 ! nbrk 135: spi_transmit(ddp->ss_sbhp, sdcf.sc_crc);
! 136:
! 137: /* XXX Apply NCR clock pulses */
! 138: // spi_transmit(ddp->ss_sbhp, 0xff);
! 139: }
! 140:
! 141:
! 142: uint8_t
! 143: spisdmmc_get_response(struct spisdmmc_dd *ddp)
! 144: {
! 145: uint8_t i, resp;
! 146: /*
! 147: * Get response from card.
! 148: * After command response comes in 8 to 64 pulses (all this bits will be 1).
! 149: */
! 150:
! 151: for(i = 0; i < 64; i++) {
! 152: resp = spi_transmit(ddp->ss_sbhp, 0xff);
! 153:
! 154: if (resp == 0x00 || resp == 0x01)
! 155: return(resp);
! 156: }
! 157: }
! 158:
! 159: uint8_t
! 160: spisdmmc_get_token(struct spisdmmc_dd *ddp)
! 161: {
! 162: uint16_t i, token;
! 163: /*
! 164: * Get token.
! 165: */
! 166:
! 167: for(i = 0; i < 1000; i++) {
! 168: token = spi_transmit(ddp->ss_sbhp, 0xff);
! 169:
! 170: if (token == TOK_READ_BLOCK || token == TOK_WRITE_BLOCK_MULTIPLE)
! 171: return(token);
! 172: }
! 173: }
! 174:
1.1 nbrk 175:
1.2 ! nbrk 176: int
! 177: spisdmmc_set_block_size(struct spisdmmc_dd *ddp, uint16_t blksize)
! 178: {
! 179: uint8_t resp;
! 180: /*
! 181: * Set block size (CMD16).
! 182: */
! 183: spisdmmc_send_command(ddp,CMD16_SET_BLOCKLEN, blksize, 0xff);
! 184: resp = spisdmmc_get_response(ddp);
! 185: if (resp != 0x00) {
! 186: printf("spisdmmc_set_block_size: set block size to %d failed (0x%x)\n", blksize, resp);
! 187: return(-1);
! 188: }
! 189: return(0);
1.1 nbrk 190: }
191:
1.2 ! nbrk 192: void
! 193: spisdmmc_read_cid(struct spisdmmc_dd *ddp, struct sdmmc_cid *cidp)
! 194: {
! 195: uint8_t resp;
! 196: struct sdmmc_cid cid;
! 197: /*
! 198: * Read Card ID register.
! 199: */
! 200: spisdmmc_send_command(ddp, CMD10_SEND_CID, 0, 0xff);
! 201: resp = spisdmmc_get_response(ddp);
! 202: printf("spisdmmc_read_cid: got r1 response 0x%x\n", resp);
! 203:
! 204: /*
! 205: * Wait R1 response.
! 206: */
! 207: if (resp != 0x00) {
! 208: printf("spisdmmc_read_cid: bad response 0x%x\n", resp);
! 209: return;
! 210: }
! 211:
! 212: spisdmmc_read_block(ddp, 16, (char *)&cid);
! 213: }
! 214:
! 215:
! 216: void
! 217: spisdmmc_read_block(struct spisdmmc_dd *ddp, uint16_t nbytes, char *buffp)
! 218: {
! 219: uint8_t token;
! 220: uint16_t crc;
! 221: /*
! 222: * Read block.
! 223: */
! 224: token = spisdmmc_get_token(ddp);
! 225: printf("spisdmmc_read_block: got token 0x%x\n", token);
! 226: if (token != TOK_READ_BLOCK) {
! 227: printf("spisdmmc_read_block: error, foreign token\n");
! 228: return;
! 229: }
! 230: /*
! 231: * Okay, next is the data.
! 232: */
! 233: while(nbytes != 0) {
! 234: *buffp = spi_transmit(ddp->ss_sbhp, 0xff);
! 235: printf("byte read 0x%x\n", *buffp);
! 236:
! 237: buffp++;
! 238: nbytes--;
! 239: }
! 240:
! 241: /*
! 242: * Read CRC.
! 243: */
! 244: crc = spi_transmit(ddp->ss_sbhp, 0xff);
! 245: crc <<= 8;
! 246: crc = spi_transmit(ddp->ss_sbhp, 0xff);
! 247: };
1.1 nbrk 248:
CVSweb