diff options
-rw-r--r-- | firmware/target/arm/imx233/sd-imx233.c | 324 | ||||
-rw-r--r-- | firmware/target/arm/imx233/ssp-imx233.c | 40 | ||||
-rw-r--r-- | firmware/target/arm/imx233/ssp-imx233.h | 13 |
3 files changed, 249 insertions, 128 deletions
diff --git a/firmware/target/arm/imx233/sd-imx233.c b/firmware/target/arm/imx233/sd-imx233.c index 1e9d001bbd..d3c29ee5be 100644 --- a/firmware/target/arm/imx233/sd-imx233.c +++ b/firmware/target/arm/imx233/sd-imx233.c | |||
@@ -24,62 +24,107 @@ | |||
24 | #include "sdmmc.h" | 24 | #include "sdmmc.h" |
25 | #include "ssp-imx233.h" | 25 | #include "ssp-imx233.h" |
26 | #include "pinctrl-imx233.h" | 26 | #include "pinctrl-imx233.h" |
27 | #include "partitions-imx233.h" | ||
27 | #include "button-target.h" | 28 | #include "button-target.h" |
28 | #include "fat.h" | 29 | #include "fat.h" |
29 | #include "disk.h" | 30 | #include "disk.h" |
30 | #include "usb.h" | 31 | #include "usb.h" |
31 | #include "debug.h" | 32 | #include "debug.h" |
32 | 33 | ||
33 | /** | 34 | struct sd_config_t |
34 | * This code assumes a single SD card slot | 35 | { |
35 | */ | 36 | const char *name; /* name(for debug) */ |
36 | 37 | int flags; /* flags */ | |
38 | int power_pin; /* power pin */ | ||
39 | int power_delay; /* extra power up delay */ | ||
40 | int ssp; /* associated ssp block */ | ||
41 | }; | ||
42 | |||
43 | /* flags */ | ||
44 | #define POWER_PIN (1 << 0) | ||
45 | #define POWER_INVERTED (1 << 1) | ||
46 | #define REMOVABLE (1 << 2) | ||
47 | #define DETECT_INVERTED (1 << 3) | ||
48 | #define POWER_DELAY (1 << 4) | ||
49 | #define WINDOW (1 << 5) | ||
50 | |||
51 | #define PIN(bank,pin) ((bank) << 5 | (pin)) | ||
52 | #define PIN2BANK(v) ((v) >> 5) | ||
53 | #define PIN2PIN(v) ((v) & 0x1f) | ||
54 | |||
55 | struct sd_config_t sd_config[] = | ||
56 | { | ||
37 | #ifdef SANSA_FUZEPLUS | 57 | #ifdef SANSA_FUZEPLUS |
38 | #define SD_SSP 1 | 58 | /* The Fuze+ uses pin #B0P8 for power */ |
59 | { | ||
60 | .name = "microSD", | ||
61 | .flags = POWER_PIN | POWER_INVERTED | REMOVABLE, | ||
62 | .power_pin = PIN(0, 8), | ||
63 | .ssp = 1 | ||
64 | }, | ||
39 | #else | 65 | #else |
40 | #error You need to configure the ssp to use | 66 | #error You need to write the sd config! |
41 | #endif | 67 | #endif |
68 | }; | ||
42 | 69 | ||
43 | static tCardInfo card_info; | 70 | #define SD_NUM_DRIVES (sizeof(sd_config) / sizeof(sd_config[0])) |
44 | static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)]; | 71 | |
72 | #define SD_CONF(drive) sd_config[drive] | ||
73 | #define SD_FLAGS(drive) SD_CONF(drive).flags | ||
74 | #define SD_SSP(drive) SD_CONF(drive).ssp | ||
75 | #define IF_FIRST_DRIVE(drive) if((drive) == 0) | ||
76 | #define IF_SECOND_DRIVE(drive) if((drive) == 1) | ||
77 | |||
78 | static tCardInfo card_info[SD_NUM_DRIVES]; | ||
79 | static long sd_stack[(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)]; | ||
45 | static struct mutex sd_mutex; | 80 | static struct mutex sd_mutex; |
46 | static const char sd_thread_name[] = "sd"; | 81 | static const char sd_thread_name[] = "sd"; |
47 | static struct event_queue sd_queue; | 82 | static struct event_queue sd_queue; |
48 | static int sd_first_drive; | 83 | static int sd_first_drive; |
49 | static int last_disk_activity; | 84 | static int last_disk_activity; |
85 | static unsigned sd_window_start[SD_NUM_DRIVES]; | ||
86 | static unsigned sd_window_end[SD_NUM_DRIVES]; | ||
50 | 87 | ||
51 | static void sd_detect_callback(int ssp) | 88 | static void sd_detect_callback(int ssp) |
52 | { | 89 | { |
53 | (void)ssp; | ||
54 | /* This is called only if the state was stable for 300ms - check state | 90 | /* This is called only if the state was stable for 300ms - check state |
55 | * and post appropriate event. */ | 91 | * and post appropriate event. */ |
56 | if(imx233_ssp_sdmmc_detect(SD_SSP)) | 92 | if(imx233_ssp_sdmmc_detect(ssp)) |
57 | queue_broadcast(SYS_HOTSWAP_INSERTED, 0); | 93 | queue_broadcast(SYS_HOTSWAP_INSERTED, 0); |
58 | else | 94 | else |
59 | queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); | 95 | queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); |
60 | imx233_ssp_sdmmc_setup_detect(SD_SSP, true, sd_detect_callback, false); | 96 | imx233_ssp_sdmmc_setup_detect(ssp, true, sd_detect_callback, false, |
97 | imx233_ssp_sdmmc_is_detect_inverted(ssp)); | ||
61 | } | 98 | } |
62 | 99 | ||
63 | void sd_power(bool on) | 100 | void sd_power(int drive, bool on) |
64 | { | 101 | { |
65 | #ifdef SANSA_FUZEPLUS | 102 | /* power chip if needed */ |
66 | /* The Fuze+ uses pin B0P8 for whatever reason, power ? */ | 103 | if(SD_FLAGS(drive) & POWER_PIN) |
67 | imx233_pinctrl_acquire_pin(0, 8, "sd power"); | 104 | { |
68 | imx233_set_pin_function(0, 8, PINCTRL_FUNCTION_GPIO); | 105 | int bank = PIN2BANK(SD_CONF(drive).power_pin); |
69 | imx233_enable_gpio_output(0, 8, true); | 106 | int pin = PIN2PIN(SD_CONF(drive).power_pin); |
70 | imx233_set_gpio_output(0, 8, !on); | 107 | imx233_pinctrl_acquire_pin(bank, pin, "sd power"); |
71 | /* disable pull ups when not needed to save power */ | 108 | imx233_set_pin_function(bank, pin, PINCTRL_FUNCTION_GPIO); |
72 | imx233_ssp_setup_ssp1_sd_mmc_pins(on, 4, PINCTRL_DRIVE_4mA, false); | 109 | imx233_enable_gpio_output(bank, pin, true); |
73 | #endif | 110 | if(SD_FLAGS(drive) & POWER_INVERTED) |
111 | imx233_set_gpio_output(bank, pin, !on); | ||
112 | else | ||
113 | imx233_set_gpio_output(bank, pin, on); | ||
114 | } | ||
115 | if(SD_FLAGS(drive) & POWER_DELAY) | ||
116 | sleep(SD_CONF(drive).power_delay); | ||
117 | /* setup pins, never use alternatives pin on SSP1 because these are force | ||
118 | * bus width >= 4 and SD cannot use more than 4 data lines. */ | ||
119 | if(SD_SSP(drive) == 1) | ||
120 | imx233_ssp_setup_ssp1_sd_mmc_pins(on, 4, PINCTRL_DRIVE_4mA, false); | ||
121 | else | ||
122 | imx233_ssp_setup_ssp2_sd_mmc_pins(on, 4, PINCTRL_DRIVE_4mA); | ||
74 | } | 123 | } |
75 | 124 | ||
76 | void sd_enable(bool on) | 125 | void sd_enable(bool on) |
77 | { | 126 | { |
78 | static int sd_enable = 2; /* 2 means not on and not off, for init purpose */ | 127 | (void) on; |
79 | if(sd_enable == on) | ||
80 | return; | ||
81 | |||
82 | sd_enable = on; | ||
83 | } | 128 | } |
84 | 129 | ||
85 | #define MCI_NO_RESP 0 | 130 | #define MCI_NO_RESP 0 |
@@ -89,15 +134,15 @@ void sd_enable(bool on) | |||
89 | #define MCI_NOCRC (1<<3) | 134 | #define MCI_NOCRC (1<<3) |
90 | #define MCI_BUSY (1<<4) | 135 | #define MCI_BUSY (1<<4) |
91 | 136 | ||
92 | static bool send_cmd(uint8_t cmd, uint32_t arg, uint32_t flags, uint32_t *resp) | 137 | static bool send_cmd(int drive, uint8_t cmd, uint32_t arg, uint32_t flags, uint32_t *resp) |
93 | { | 138 | { |
94 | if((flags & MCI_ACMD) && !send_cmd(SD_APP_CMD, card_info.rca, MCI_RESP, resp)) | 139 | if((flags & MCI_ACMD) && !send_cmd(drive, SD_APP_CMD, card_info[drive].rca, MCI_RESP, resp)) |
95 | return false; | 140 | return false; |
96 | 141 | ||
97 | enum imx233_ssp_resp_t resp_type = (flags & MCI_LONG_RESP) ? SSP_LONG_RESP : | 142 | enum imx233_ssp_resp_t resp_type = (flags & MCI_LONG_RESP) ? SSP_LONG_RESP : |
98 | (flags & MCI_RESP) ? SSP_SHORT_RESP : SSP_NO_RESP; | 143 | (flags & MCI_RESP) ? SSP_SHORT_RESP : SSP_NO_RESP; |
99 | enum imx233_ssp_error_t ret = imx233_ssp_sd_mmc_transfer(SD_SSP, cmd, arg, | 144 | enum imx233_ssp_error_t ret = imx233_ssp_sd_mmc_transfer(SD_SSP(drive), cmd, |
100 | resp_type, NULL, 0, !!(flags & MCI_BUSY), false, resp); | 145 | arg, resp_type, NULL, 0, !!(flags & MCI_BUSY), false, resp); |
101 | if(resp_type == SSP_LONG_RESP) | 146 | if(resp_type == SSP_LONG_RESP) |
102 | { | 147 | { |
103 | /* Our SD codes assume most significant word first, so reverse resp */ | 148 | /* Our SD codes assume most significant word first, so reverse resp */ |
@@ -111,7 +156,7 @@ static bool send_cmd(uint8_t cmd, uint32_t arg, uint32_t flags, uint32_t *resp) | |||
111 | return ret == SSP_SUCCESS; | 156 | return ret == SSP_SUCCESS; |
112 | } | 157 | } |
113 | 158 | ||
114 | static int sd_wait_for_tran_state(void) | 159 | static int sd_wait_for_tran_state(int drive) |
115 | { | 160 | { |
116 | unsigned long response; | 161 | unsigned long response; |
117 | unsigned int timeout = current_tick + 5*HZ; | 162 | unsigned int timeout = current_tick + 5*HZ; |
@@ -119,7 +164,7 @@ static int sd_wait_for_tran_state(void) | |||
119 | 164 | ||
120 | while (1) | 165 | while (1) |
121 | { | 166 | { |
122 | while(!send_cmd(SD_SEND_STATUS, card_info.rca, MCI_RESP, &response) && cmd_retry > 0) | 167 | while(!send_cmd(drive, SD_SEND_STATUS, card_info[drive].rca, MCI_RESP, &response) && cmd_retry > 0) |
123 | cmd_retry--; | 168 | cmd_retry--; |
124 | 169 | ||
125 | if(cmd_retry <= 0) | 170 | if(cmd_retry <= 0) |
@@ -135,33 +180,35 @@ static int sd_wait_for_tran_state(void) | |||
135 | } | 180 | } |
136 | } | 181 | } |
137 | 182 | ||
138 | static int sd_init_card(void) | 183 | static int sd_init_card(int drive) |
139 | { | 184 | { |
140 | sd_enable(false); | 185 | /* sanity check against bad configuration of SD_NUM_DRIVES/NUM_DRIVES */ |
141 | sd_power(false); | 186 | if((unsigned)drive >= SD_NUM_DRIVES) |
142 | sd_power(true); | 187 | panicf("drive >= SD_NUM_DRIVES in sd_init_card!"); |
143 | sd_enable(true); | 188 | int ssp = SD_SSP(drive); |
144 | imx233_ssp_start(SD_SSP); | 189 | sd_power(drive, false); |
145 | imx233_ssp_softreset(SD_SSP); | 190 | sd_power(drive, true); |
146 | imx233_ssp_set_mode(SD_SSP, HW_SSP_CTRL1__SSP_MODE__SD_MMC); | 191 | imx233_ssp_start(ssp); |
192 | imx233_ssp_softreset(ssp); | ||
193 | imx233_ssp_set_mode(ssp, HW_SSP_CTRL1__SSP_MODE__SD_MMC); | ||
147 | /* SSPCLK @ 96MHz | 194 | /* SSPCLK @ 96MHz |
148 | * gives bitrate of 96000 / 240 / 1 = 400kHz */ | 195 | * gives bitrate of 96000 / 240 / 1 = 400kHz */ |
149 | imx233_ssp_set_timings(SD_SSP, 240, 0, 0xffff); | 196 | imx233_ssp_set_timings(ssp, 240, 0, 0xffff); |
150 | 197 | ||
151 | imx233_ssp_sd_mmc_power_up_sequence(SD_SSP); | 198 | imx233_ssp_sd_mmc_power_up_sequence(ssp); |
152 | imx233_ssp_set_bus_width(SD_SSP, 1); | 199 | imx233_ssp_set_bus_width(ssp, 1); |
153 | imx233_ssp_set_block_size(SD_SSP, 9); | 200 | imx233_ssp_set_block_size(ssp, 9); |
154 | 201 | ||
155 | card_info.rca = 0; | 202 | card_info[drive].rca = 0; |
156 | bool sd_v2 = false; | 203 | bool sd_v2 = false; |
157 | uint32_t resp; | 204 | uint32_t resp; |
158 | long init_timeout; | 205 | long init_timeout; |
159 | /* go to idle state */ | 206 | /* go to idle state */ |
160 | if(!send_cmd(SD_GO_IDLE_STATE, 0, MCI_NO_RESP, NULL)) | 207 | if(!send_cmd(drive, SD_GO_IDLE_STATE, 0, MCI_NO_RESP, NULL)) |
161 | return -1; | 208 | return -1; |
162 | /* CMD8 Check for v2 sd card. Must be sent before using ACMD41 | 209 | /* CMD8 Check for v2 sd card. Must be sent before using ACMD41 |
163 | Non v2 cards will not respond to this command */ | 210 | Non v2 cards will not respond to this command */ |
164 | if(send_cmd(SD_SEND_IF_COND, 0x1AA, MCI_RESP, &resp)) | 211 | if(send_cmd(drive, SD_SEND_IF_COND, 0x1AA, MCI_RESP, &resp)) |
165 | if((resp & 0xFFF) == 0x1AA) | 212 | if((resp & 0xFFF) == 0x1AA) |
166 | sd_v2 = true; | 213 | sd_v2 = true; |
167 | /* timeout for initialization is 1sec, from SD Specification 2.00 */ | 214 | /* timeout for initialization is 1sec, from SD Specification 2.00 */ |
@@ -173,67 +220,84 @@ static int sd_init_card(void) | |||
173 | return -2; | 220 | return -2; |
174 | 221 | ||
175 | /* ACMD41 For v2 cards set HCS bit[30] & send host voltage range to all */ | 222 | /* ACMD41 For v2 cards set HCS bit[30] & send host voltage range to all */ |
176 | if(!send_cmd(SD_APP_OP_COND, (0x00FF8000 | (sd_v2 ? 1<<30 : 0)), | 223 | if(!send_cmd(drive, SD_APP_OP_COND, (0x00FF8000 | (sd_v2 ? 1<<30 : 0)), |
177 | MCI_ACMD|MCI_NOCRC|MCI_RESP, &card_info.ocr)) | 224 | MCI_ACMD|MCI_NOCRC|MCI_RESP, &card_info[drive].ocr)) |
178 | return -100; | 225 | return -100; |
179 | } while(!(card_info.ocr & (1<<31))); | 226 | } while(!(card_info[drive].ocr & (1<<31))); |
180 | 227 | ||
181 | /* CMD2 send CID */ | 228 | /* CMD2 send CID */ |
182 | if(!send_cmd(SD_ALL_SEND_CID, 0, MCI_RESP|MCI_LONG_RESP, card_info.cid)) | 229 | if(!send_cmd(drive, SD_ALL_SEND_CID, 0, MCI_RESP|MCI_LONG_RESP, card_info[drive].cid)) |
183 | return -3; | 230 | return -3; |
184 | 231 | ||
185 | /* CMD3 send RCA */ | 232 | /* CMD3 send RCA */ |
186 | if(!send_cmd(SD_SEND_RELATIVE_ADDR, 0, MCI_RESP, &card_info.rca)) | 233 | if(!send_cmd(drive, SD_SEND_RELATIVE_ADDR, 0, MCI_RESP, &card_info[drive].rca)) |
187 | return -4; | 234 | return -4; |
188 | 235 | ||
189 | /* Try to switch V2 cards to HS timings, non HS seem to ignore this */ | 236 | /* Try to switch V2 cards to HS timings, non HS seem to ignore this */ |
190 | if(sd_v2) | 237 | if(sd_v2) |
191 | { | 238 | { |
192 | /* CMD7 w/rca: Select card to put it in TRAN state */ | 239 | /* CMD7 w/rca: Select card to put it in TRAN state */ |
193 | if(!send_cmd(SD_SELECT_CARD, card_info.rca, MCI_RESP, NULL)) | 240 | if(!send_cmd(drive, SD_SELECT_CARD, card_info[drive].rca, MCI_RESP, NULL)) |
194 | return -5; | 241 | return -5; |
195 | 242 | ||
196 | if(sd_wait_for_tran_state()) | 243 | if(sd_wait_for_tran_state(drive)) |
197 | return -6; | 244 | return -6; |
198 | 245 | ||
199 | /* CMD6 */ | 246 | /* CMD6 */ |
200 | if(!send_cmd(SD_SWITCH_FUNC, 0x80fffff1, MCI_NO_RESP, NULL)) | 247 | if(!send_cmd(drive, SD_SWITCH_FUNC, 0x80fffff1, MCI_NO_RESP, NULL)) |
201 | return -7; | 248 | return -7; |
202 | sleep(HZ/10); | 249 | sleep(HZ/10); |
203 | 250 | ||
204 | /* go back to STBY state so we can read csd */ | 251 | /* go back to STBY state so we can read csd */ |
205 | /* CMD7 w/rca=0: Deselect card to put it in STBY state */ | 252 | /* CMD7 w/rca=0: Deselect card to put it in STBY state */ |
206 | if(!send_cmd(SD_DESELECT_CARD, 0, MCI_NO_RESP, NULL)) | 253 | if(!send_cmd(drive, SD_DESELECT_CARD, 0, MCI_NO_RESP, NULL)) |
207 | return -8; | 254 | return -8; |
208 | } | 255 | } |
209 | 256 | ||
210 | /* CMD9 send CSD */ | 257 | /* CMD9 send CSD */ |
211 | if(!send_cmd(SD_SEND_CSD, card_info.rca, MCI_RESP|MCI_LONG_RESP, card_info.csd)) | 258 | if(!send_cmd(drive, SD_SEND_CSD, card_info[drive].rca, MCI_RESP|MCI_LONG_RESP, card_info[drive].csd)) |
212 | return -9; | 259 | return -9; |
213 | 260 | ||
214 | sd_parse_csd(&card_info); | 261 | sd_parse_csd(&card_info[drive]); |
215 | 262 | ||
216 | /* SSPCLK @ 96MHz | 263 | /* SSPCLK @ 96MHz |
217 | * gives bitrate of 96 / 4 / 1 = 24MHz */ | 264 | * gives bitrate of 96 / 4 / 1 = 24MHz */ |
218 | imx233_ssp_set_timings(SD_SSP, 4, 0, 0xffff); | 265 | imx233_ssp_set_timings(ssp, 4, 0, 0xffff); |
219 | 266 | ||
220 | /* CMD7 w/rca: Select card to put it in TRAN state */ | 267 | /* CMD7 w/rca: Select card to put it in TRAN state */ |
221 | if(!send_cmd(SD_SELECT_CARD, card_info.rca, MCI_RESP, &resp)) | 268 | if(!send_cmd(drive, SD_SELECT_CARD, card_info[drive].rca, MCI_RESP, &resp)) |
222 | return -12; | 269 | return -12; |
223 | if(sd_wait_for_tran_state() < 0) | 270 | if(sd_wait_for_tran_state(drive) < 0) |
224 | return -13; | 271 | return -13; |
225 | 272 | ||
226 | /* ACMD6: set bus width to 4-bit */ | 273 | /* ACMD6: set bus width to 4-bit */ |
227 | if(!send_cmd(SD_SET_BUS_WIDTH, 2, MCI_RESP|MCI_ACMD, &resp)) | 274 | if(!send_cmd(drive, SD_SET_BUS_WIDTH, 2, MCI_RESP|MCI_ACMD, &resp)) |
228 | return -15; | 275 | return -15; |
229 | /* ACMD42: disconnect the pull-up resistor on CD/DAT3 */ | 276 | /* ACMD42: disconnect the pull-up resistor on CD/DAT3 */ |
230 | if(!send_cmd(SD_SET_CLR_CARD_DETECT, 0, MCI_RESP|MCI_ACMD, &resp)) | 277 | if(!send_cmd(drive, SD_SET_CLR_CARD_DETECT, 0, MCI_RESP|MCI_ACMD, &resp)) |
231 | return -17; | 278 | return -17; |
232 | 279 | ||
233 | /* Switch to 4-bit */ | 280 | /* Switch to 4-bit */ |
234 | imx233_ssp_set_bus_width(SD_SSP, 4); | 281 | imx233_ssp_set_bus_width(ssp, 4); |
235 | 282 | ||
236 | card_info.initialized = 1; | 283 | card_info[drive].initialized = 1; |
284 | |||
285 | /* compute window */ | ||
286 | sd_window_start[drive] = 0; | ||
287 | sd_window_end[drive] = card_info[drive].numblocks; | ||
288 | if((SD_FLAGS(drive) & WINDOW) && imx233_partitions_is_window_enabled()) | ||
289 | { | ||
290 | /* WARNING: sd_first_drive is not set at this point */ | ||
291 | uint8_t mbr[512]; | ||
292 | int ret = sd_read_sectors(IF_MD2(drive,) 0, 1, mbr); | ||
293 | if(ret) | ||
294 | panicf("Cannot read MBR: %d", ret); | ||
295 | ret = imx233_partitions_compute_window(mbr, &sd_window_start[drive], | ||
296 | &sd_window_end[drive]); | ||
297 | if(ret) | ||
298 | panicf("cannot compute partitions window: %d", ret); | ||
299 | card_info[drive].numblocks = sd_window_end[drive] - sd_window_start[drive]; | ||
300 | } | ||
237 | 301 | ||
238 | return 0; | 302 | return 0; |
239 | } | 303 | } |
@@ -253,45 +317,51 @@ static void sd_thread(void) | |||
253 | case SYS_HOTSWAP_EXTRACTED: | 317 | case SYS_HOTSWAP_EXTRACTED: |
254 | { | 318 | { |
255 | int microsd_init = 1; | 319 | int microsd_init = 1; |
256 | fat_lock(); /* lock-out FAT activity first - | 320 | /* lock-out FAT activity first - |
257 | prevent deadlocking via disk_mount that | 321 | * prevent deadlocking via disk_mount that |
258 | would cause a reverse-order attempt with | 322 | * would cause a reverse-order attempt with |
259 | another thread */ | 323 | * another thread */ |
260 | mutex_lock(&sd_mutex); /* lock-out card activity - direct calls | 324 | fat_lock(); |
261 | into driver that bypass the fat cache */ | 325 | /* lock-out card activity - direct calls |
262 | 326 | * into driver that bypass the fat cache */ | |
263 | /* We now have exclusive control of fat cache and sd */ | 327 | mutex_lock(&sd_mutex); |
264 | 328 | ||
265 | disk_unmount(sd_first_drive); /* release "by force", ensure file | 329 | /* We now have exclusive control of fat cache and sd. |
266 | descriptors aren't leaked and any busy | 330 | * Release "by force", ensure file |
267 | ones are invalid if mounting */ | 331 | * descriptors aren't leaked and any busy |
268 | /* Force card init for new card, re-init for re-inserted one or | 332 | * ones are invalid if mounting. */ |
269 | * clear if the last attempt to init failed with an error. */ | 333 | for(unsigned drive = 0; drive < SD_NUM_DRIVES; drive++) |
270 | card_info.initialized = 0; | ||
271 | |||
272 | if(ev.id == SYS_HOTSWAP_INSERTED) | ||
273 | { | 334 | { |
274 | microsd_init = sd_init_card(); | 335 | /* Skip non-removable drivers */ |
275 | if(microsd_init < 0) /* initialisation failed */ | 336 | if(!sd_removable(drive)) |
276 | panicf("microSD init failed : %d", microsd_init); | 337 | continue; |
277 | 338 | disk_unmount(sd_first_drive + drive); | |
278 | microsd_init = disk_mount(sd_first_drive); /* 0 if fail */ | 339 | /* Force card init for new card, re-init for re-inserted one or |
340 | * clear if the last attempt to init failed with an error. */ | ||
341 | card_info[drive].initialized = 0; | ||
342 | |||
343 | if(ev.id == SYS_HOTSWAP_INSERTED) | ||
344 | { | ||
345 | microsd_init = sd_init_card(drive); | ||
346 | if(microsd_init < 0) /* initialisation failed */ | ||
347 | panicf("%s init failed : %d", SD_CONF(drive).name, microsd_init); | ||
348 | |||
349 | microsd_init = disk_mount(sd_first_drive + drive); /* 0 if fail */ | ||
350 | } | ||
351 | /* | ||
352 | * Mount succeeded, or this was an EXTRACTED event, | ||
353 | * in both cases notify the system about the changed filesystems | ||
354 | */ | ||
355 | if(microsd_init) | ||
356 | queue_broadcast(SYS_FS_CHANGED, 0); | ||
279 | } | 357 | } |
280 | /* | ||
281 | * Mount succeeded, or this was an EXTRACTED event, | ||
282 | * in both cases notify the system about the changed filesystems | ||
283 | */ | ||
284 | if(microsd_init) | ||
285 | queue_broadcast(SYS_FS_CHANGED, 0); | ||
286 | |||
287 | sd_enable(false); | ||
288 | /* Access is now safe */ | 358 | /* Access is now safe */ |
289 | mutex_unlock(&sd_mutex); | 359 | mutex_unlock(&sd_mutex); |
290 | fat_unlock(); | 360 | fat_unlock(); |
291 | break; | 361 | break; |
292 | } | 362 | } |
293 | case SYS_TIMEOUT: | 363 | case SYS_TIMEOUT: |
294 | if(!TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) | 364 | if(!TIME_BEFORE(current_tick, last_disk_activity +3 * HZ)) |
295 | sd_enable(false); | 365 | sd_enable(false); |
296 | break; | 366 | break; |
297 | case SYS_USB_CONNECTED: | 367 | case SYS_USB_CONNECTED: |
@@ -309,8 +379,13 @@ int sd_init(void) | |||
309 | queue_init(&sd_queue, true); | 379 | queue_init(&sd_queue, true); |
310 | create_thread(sd_thread, sd_stack, sizeof(sd_stack), 0, | 380 | create_thread(sd_thread, sd_stack, sizeof(sd_stack), 0, |
311 | sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); | 381 | sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); |
312 | sd_enable(false); | 382 | |
313 | imx233_ssp_sdmmc_setup_detect(SD_SSP, true, sd_detect_callback, false); | 383 | for(unsigned drive = 0; drive < SD_NUM_DRIVES; drive++) |
384 | { | ||
385 | if(SD_FLAGS(drive) & REMOVABLE) | ||
386 | imx233_ssp_sdmmc_setup_detect(SD_SSP(drive), true, sd_detect_callback, | ||
387 | false, SD_FLAGS(drive) & DETECT_INVERTED); | ||
388 | } | ||
314 | 389 | ||
315 | return 0; | 390 | return 0; |
316 | } | 391 | } |
@@ -324,21 +399,28 @@ static int transfer_sectors(IF_MD2(int drive,) unsigned long start, int count, v | |||
324 | last_disk_activity = current_tick; | 399 | last_disk_activity = current_tick; |
325 | 400 | ||
326 | mutex_lock(&sd_mutex); | 401 | mutex_lock(&sd_mutex); |
327 | sd_enable(true); | ||
328 | 402 | ||
329 | if(card_info.initialized <= 0) | 403 | if(card_info[drive].initialized <= 0) |
330 | { | 404 | { |
331 | ret = sd_init_card(); | 405 | ret = sd_init_card(drive); |
332 | if(card_info.initialized <= 0) | 406 | if(card_info[drive].initialized <= 0) |
333 | goto Lend; | 407 | goto Lend; |
334 | } | 408 | } |
409 | |||
410 | /* check window */ | ||
411 | start += sd_window_start[drive]; | ||
412 | if((start + count) > sd_window_end[drive]) | ||
413 | { | ||
414 | ret = -201; | ||
415 | goto Lend; | ||
416 | } | ||
335 | 417 | ||
336 | if(!send_cmd(SD_SELECT_CARD, card_info.rca, MCI_NO_RESP, NULL)) | 418 | if(!send_cmd(drive, SD_SELECT_CARD, card_info[drive].rca, MCI_NO_RESP, NULL)) |
337 | { | 419 | { |
338 | ret = -20; | 420 | ret = -20; |
339 | goto Lend; | 421 | goto Lend; |
340 | } | 422 | } |
341 | ret = sd_wait_for_tran_state(); | 423 | ret = sd_wait_for_tran_state(drive); |
342 | if(ret < 0) | 424 | if(ret < 0) |
343 | goto Ldeselect; | 425 | goto Ldeselect; |
344 | while(count != 0) | 426 | while(count != 0) |
@@ -346,13 +428,14 @@ static int transfer_sectors(IF_MD2(int drive,) unsigned long start, int count, v | |||
346 | int this_count = MIN(count, IMX233_MAX_SSP_XFER_SIZE / 512); | 428 | int this_count = MIN(count, IMX233_MAX_SSP_XFER_SIZE / 512); |
347 | /* Set bank_start to the correct unit (blocks or bytes) */ | 429 | /* Set bank_start to the correct unit (blocks or bytes) */ |
348 | int bank_start = start; | 430 | int bank_start = start; |
349 | if(!(card_info.ocr & (1<<30))) /* not SDHC */ | 431 | if(!(card_info[drive].ocr & (1<<30))) /* not SDHC */ |
350 | bank_start *= SD_BLOCK_SIZE; | 432 | bank_start *= SD_BLOCK_SIZE; |
351 | ret = imx233_ssp_sd_mmc_transfer(SD_SSP, read ? SD_READ_MULTIPLE_BLOCK : SD_WRITE_MULTIPLE_BLOCK, | 433 | ret = imx233_ssp_sd_mmc_transfer(SD_SSP(drive), |
434 | read ? SD_READ_MULTIPLE_BLOCK : SD_WRITE_MULTIPLE_BLOCK, | ||
352 | bank_start, SSP_SHORT_RESP, buf, this_count, false, read, &resp); | 435 | bank_start, SSP_SHORT_RESP, buf, this_count, false, read, &resp); |
353 | if(ret != SSP_SUCCESS) | 436 | if(ret != SSP_SUCCESS) |
354 | break; | 437 | break; |
355 | if(!send_cmd(SD_STOP_TRANSMISSION, 0, MCI_RESP|MCI_BUSY, &resp)) | 438 | if(!send_cmd(drive, SD_STOP_TRANSMISSION, 0, MCI_RESP|MCI_BUSY, &resp)) |
356 | { | 439 | { |
357 | ret = -15; | 440 | ret = -15; |
358 | break; | 441 | break; |
@@ -364,51 +447,48 @@ static int transfer_sectors(IF_MD2(int drive,) unsigned long start, int count, v | |||
364 | 447 | ||
365 | Ldeselect: | 448 | Ldeselect: |
366 | /* CMD7 w/rca =0 : deselects card & puts it in STBY state */ | 449 | /* CMD7 w/rca =0 : deselects card & puts it in STBY state */ |
367 | if(!send_cmd(SD_DESELECT_CARD, 0, MCI_NO_RESP, NULL)) | 450 | if(!send_cmd(drive, SD_DESELECT_CARD, 0, MCI_NO_RESP, NULL)) |
368 | ret = -23; | 451 | ret = -23; |
369 | Lend: | 452 | Lend: |
370 | mutex_unlock(&sd_mutex); | 453 | mutex_unlock(&sd_mutex); |
371 | return ret; | 454 | return ret; |
372 | } | 455 | } |
373 | 456 | ||
374 | int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count, | 457 | int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf) |
375 | void* buf) | ||
376 | { | 458 | { |
377 | return transfer_sectors(IF_MD2(drive,) start, count, buf, true); | 459 | return transfer_sectors(IF_MD2(drive,) start, count, buf, true); |
378 | } | 460 | } |
379 | 461 | ||
380 | int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count, | 462 | int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf) |
381 | const void* buf) | ||
382 | { | 463 | { |
383 | return transfer_sectors(IF_MD2(drive,) start, count, (void *)buf, false); | 464 | return transfer_sectors(IF_MD2(drive,) start, count, (void *)buf, false); |
384 | } | 465 | } |
385 | 466 | ||
386 | tCardInfo *card_get_info_target(int card_no) | 467 | tCardInfo *card_get_info_target(int card_no) |
387 | { | 468 | { |
388 | (void)card_no; | 469 | return &card_info[card_no]; |
389 | return &card_info; | ||
390 | } | 470 | } |
391 | 471 | ||
392 | int sd_num_drives(int first_drive) | 472 | int sd_num_drives(int first_drive) |
393 | { | 473 | { |
394 | sd_first_drive = first_drive; | 474 | sd_first_drive = first_drive; |
395 | return 1; | 475 | return SD_NUM_DRIVES; |
396 | } | 476 | } |
397 | 477 | ||
398 | bool sd_present(IF_MD(int drive)) | 478 | bool sd_present(IF_MV_NONVOID(int drive)) |
399 | { | 479 | { |
400 | IF_MD((void) drive); | 480 | if(SD_FLAGS(drive) & REMOVABLE) |
401 | return imx233_ssp_sdmmc_detect(SD_SSP); | 481 | return imx233_ssp_sdmmc_detect(SD_SSP(drive)); |
482 | else | ||
483 | return true; | ||
402 | } | 484 | } |
403 | 485 | ||
404 | bool sd_removable(IF_MD(int drive)) | 486 | bool sd_removable(IF_MV_NONVOID(int drive)) |
405 | { | 487 | { |
406 | IF_MD((void) drive); | 488 | return SD_FLAGS(drive) & REMOVABLE; |
407 | return true; | ||
408 | } | 489 | } |
409 | 490 | ||
410 | long sd_last_disk_activity(void) | 491 | long sd_last_disk_activity(void) |
411 | { | 492 | { |
412 | return last_disk_activity; | 493 | return last_disk_activity; |
413 | } | 494 | } |
414 | |||
diff --git a/firmware/target/arm/imx233/ssp-imx233.c b/firmware/target/arm/imx233/ssp-imx233.c index 1dd2d767ba..21dcba67aa 100644 --- a/firmware/target/arm/imx233/ssp-imx233.c +++ b/firmware/target/arm/imx233/ssp-imx233.c | |||
@@ -28,6 +28,13 @@ | |||
28 | #include "pinctrl-imx233.h" | 28 | #include "pinctrl-imx233.h" |
29 | #include "dma-imx233.h" | 29 | #include "dma-imx233.h" |
30 | 30 | ||
31 | /* for debug purpose */ | ||
32 | #if 0 | ||
33 | #define ASSERT_SSP(ssp) if(ssp < 1 || ssp > 2) panicf("ssp=%d in %s", ssp, __func__); | ||
34 | #else | ||
35 | #define ASSERT_SSP(ssp) | ||
36 | #endif | ||
37 | |||
31 | /* Used for DMA */ | 38 | /* Used for DMA */ |
32 | struct ssp_dma_command_t | 39 | struct ssp_dma_command_t |
33 | { | 40 | { |
@@ -46,6 +53,7 @@ static struct ssp_dma_command_t ssp_dma_cmd[2]; | |||
46 | static uint32_t ssp_bus_width[2]; | 53 | static uint32_t ssp_bus_width[2]; |
47 | static unsigned ssp_log_block_size[2]; | 54 | static unsigned ssp_log_block_size[2]; |
48 | static ssp_detect_cb_t ssp_detect_cb[2]; | 55 | static ssp_detect_cb_t ssp_detect_cb[2]; |
56 | static bool ssp_detect_invert[2]; | ||
49 | 57 | ||
50 | void INT_SSP(int ssp) | 58 | void INT_SSP(int ssp) |
51 | { | 59 | { |
@@ -93,6 +101,7 @@ void imx233_ssp_init(void) | |||
93 | 101 | ||
94 | void imx233_ssp_start(int ssp) | 102 | void imx233_ssp_start(int ssp) |
95 | { | 103 | { |
104 | ASSERT_SSP(ssp) | ||
96 | if(ssp_in_use[ssp - 1]) | 105 | if(ssp_in_use[ssp - 1]) |
97 | return; | 106 | return; |
98 | ssp_in_use[ssp - 1] = true; | 107 | ssp_in_use[ssp - 1] = true; |
@@ -117,6 +126,7 @@ void imx233_ssp_start(int ssp) | |||
117 | 126 | ||
118 | void imx233_ssp_stop(int ssp) | 127 | void imx233_ssp_stop(int ssp) |
119 | { | 128 | { |
129 | ASSERT_SSP(ssp) | ||
120 | if(!ssp_in_use[ssp - 1]) | 130 | if(!ssp_in_use[ssp - 1]) |
121 | return; | 131 | return; |
122 | ssp_in_use[ssp - 1] = false; | 132 | ssp_in_use[ssp - 1] = false; |
@@ -135,11 +145,13 @@ void imx233_ssp_stop(int ssp) | |||
135 | 145 | ||
136 | void imx233_ssp_softreset(int ssp) | 146 | void imx233_ssp_softreset(int ssp) |
137 | { | 147 | { |
148 | ASSERT_SSP(ssp) | ||
138 | imx233_reset_block(&HW_SSP_CTRL0(ssp)); | 149 | imx233_reset_block(&HW_SSP_CTRL0(ssp)); |
139 | } | 150 | } |
140 | 151 | ||
141 | void imx233_ssp_set_timings(int ssp, int divide, int rate, int timeout) | 152 | void imx233_ssp_set_timings(int ssp, int divide, int rate, int timeout) |
142 | { | 153 | { |
154 | ASSERT_SSP(ssp) | ||
143 | HW_SSP_TIMING(ssp) = divide << HW_SSP_TIMING__CLOCK_DIVIDE_BP | rate | | 155 | HW_SSP_TIMING(ssp) = divide << HW_SSP_TIMING__CLOCK_DIVIDE_BP | rate | |
144 | timeout << HW_SSP_TIMING__CLOCK_TIMEOUT_BP; | 156 | timeout << HW_SSP_TIMING__CLOCK_TIMEOUT_BP; |
145 | } | 157 | } |
@@ -209,6 +221,7 @@ void imx233_ssp_setup_ssp2_sd_mmc_pins(bool enable_pullups, unsigned bus_width, | |||
209 | 221 | ||
210 | void imx233_ssp_set_mode(int ssp, unsigned mode) | 222 | void imx233_ssp_set_mode(int ssp, unsigned mode) |
211 | { | 223 | { |
224 | ASSERT_SSP(ssp) | ||
212 | switch(mode) | 225 | switch(mode) |
213 | { | 226 | { |
214 | case HW_SSP_CTRL1__SSP_MODE__SD_MMC: | 227 | case HW_SSP_CTRL1__SSP_MODE__SD_MMC: |
@@ -226,6 +239,7 @@ void imx233_ssp_set_mode(int ssp, unsigned mode) | |||
226 | 239 | ||
227 | void imx233_ssp_set_bus_width(int ssp, unsigned width) | 240 | void imx233_ssp_set_bus_width(int ssp, unsigned width) |
228 | { | 241 | { |
242 | ASSERT_SSP(ssp) | ||
229 | switch(width) | 243 | switch(width) |
230 | { | 244 | { |
231 | case 1: ssp_bus_width[ssp - 1] = HW_SSP_CTRL0__BUS_WIDTH__ONE_BIT; break; | 245 | case 1: ssp_bus_width[ssp - 1] = HW_SSP_CTRL0__BUS_WIDTH__ONE_BIT; break; |
@@ -236,6 +250,7 @@ void imx233_ssp_set_bus_width(int ssp, unsigned width) | |||
236 | 250 | ||
237 | void imx233_ssp_set_block_size(int ssp, unsigned log_block_size) | 251 | void imx233_ssp_set_block_size(int ssp, unsigned log_block_size) |
238 | { | 252 | { |
253 | ASSERT_SSP(ssp) | ||
239 | ssp_log_block_size[ssp - 1] = log_block_size; | 254 | ssp_log_block_size[ssp - 1] = log_block_size; |
240 | } | 255 | } |
241 | 256 | ||
@@ -243,6 +258,7 @@ enum imx233_ssp_error_t imx233_ssp_sd_mmc_transfer(int ssp, uint8_t cmd, | |||
243 | uint32_t cmd_arg, enum imx233_ssp_resp_t resp, void *buffer, unsigned block_count, | 258 | uint32_t cmd_arg, enum imx233_ssp_resp_t resp, void *buffer, unsigned block_count, |
244 | bool wait4irq, bool read, uint32_t *resp_ptr) | 259 | bool wait4irq, bool read, uint32_t *resp_ptr) |
245 | { | 260 | { |
261 | ASSERT_SSP(ssp) | ||
246 | mutex_lock(&ssp_mutex[ssp - 1]); | 262 | mutex_lock(&ssp_mutex[ssp - 1]); |
247 | /* Enable all interrupts */ | 263 | /* Enable all interrupts */ |
248 | imx233_icoll_enable_interrupt(INT_SRC_SSP_DMA(ssp), true); | 264 | imx233_icoll_enable_interrupt(INT_SRC_SSP_DMA(ssp), true); |
@@ -312,6 +328,7 @@ enum imx233_ssp_error_t imx233_ssp_sd_mmc_transfer(int ssp, uint8_t cmd, | |||
312 | 328 | ||
313 | void imx233_ssp_sd_mmc_power_up_sequence(int ssp) | 329 | void imx233_ssp_sd_mmc_power_up_sequence(int ssp) |
314 | { | 330 | { |
331 | ASSERT_SSP(ssp) | ||
315 | __REG_CLR(HW_SSP_CMD0(ssp)) = HW_SSP_CMD0__SLOW_CLKING_EN; | 332 | __REG_CLR(HW_SSP_CMD0(ssp)) = HW_SSP_CMD0__SLOW_CLKING_EN; |
316 | __REG_SET(HW_SSP_CMD0(ssp)) = HW_SSP_CMD0__CONT_CLKING_EN; | 333 | __REG_SET(HW_SSP_CMD0(ssp)) = HW_SSP_CMD0__CONT_CLKING_EN; |
317 | mdelay(1); | 334 | mdelay(1); |
@@ -320,6 +337,7 @@ void imx233_ssp_sd_mmc_power_up_sequence(int ssp) | |||
320 | 337 | ||
321 | static int ssp_detect_oneshot_callback(int ssp) | 338 | static int ssp_detect_oneshot_callback(int ssp) |
322 | { | 339 | { |
340 | ASSERT_SSP(ssp) | ||
323 | if(ssp_detect_cb[ssp - 1]) | 341 | if(ssp_detect_cb[ssp - 1]) |
324 | ssp_detect_cb[ssp - 1](ssp); | 342 | ssp_detect_cb[ssp - 1](ssp); |
325 | 343 | ||
@@ -348,11 +366,14 @@ static void detect_irq(int bank, int pin) | |||
348 | timeout_register(&ssp2_detect_oneshot, ssp2_detect_oneshot_callback, (3*HZ/10), 0); | 366 | timeout_register(&ssp2_detect_oneshot, ssp2_detect_oneshot_callback, (3*HZ/10), 0); |
349 | } | 367 | } |
350 | 368 | ||
351 | void imx233_ssp_sdmmc_setup_detect(int ssp, bool enable, ssp_detect_cb_t fn, bool first_time) | 369 | void imx233_ssp_sdmmc_setup_detect(int ssp, bool enable, ssp_detect_cb_t fn, |
370 | bool first_time, bool invert) | ||
352 | { | 371 | { |
372 | ASSERT_SSP(ssp) | ||
353 | int bank = ssp == 1 ? 2 : 0; | 373 | int bank = ssp == 1 ? 2 : 0; |
354 | int pin = ssp == 1 ? 1 : 19; | 374 | int pin = ssp == 1 ? 1 : 19; |
355 | ssp_detect_cb[ssp - 1] = fn; | 375 | ssp_detect_cb[ssp - 1] = fn; |
376 | ssp_detect_invert[ssp - 1] = invert; | ||
356 | if(enable) | 377 | if(enable) |
357 | { | 378 | { |
358 | imx233_pinctrl_acquire_pin(bank, pin, ssp == 1 ? "ssp1 detect" : "ssp2 detect"); | 379 | imx233_pinctrl_acquire_pin(bank, pin, ssp == 1 ? "ssp1 detect" : "ssp2 detect"); |
@@ -361,10 +382,23 @@ void imx233_ssp_sdmmc_setup_detect(int ssp, bool enable, ssp_detect_cb_t fn, boo | |||
361 | } | 382 | } |
362 | if(first_time && imx233_ssp_sdmmc_detect(ssp)) | 383 | if(first_time && imx233_ssp_sdmmc_detect(ssp)) |
363 | detect_irq(bank, pin); | 384 | detect_irq(bank, pin); |
364 | imx233_setup_pin_irq(bank, pin, enable, true, !imx233_ssp_sdmmc_detect(ssp), detect_irq); | 385 | imx233_setup_pin_irq(bank, pin, enable, true, !imx233_ssp_sdmmc_detect_raw(ssp), detect_irq); |
365 | } | 386 | } |
366 | 387 | ||
367 | bool imx233_ssp_sdmmc_detect(int ssp) | 388 | bool imx233_ssp_sdmmc_is_detect_inverted(int ssp) |
389 | { | ||
390 | ASSERT_SSP(ssp) | ||
391 | return ssp_detect_invert[ssp - 1]; | ||
392 | } | ||
393 | |||
394 | bool imx233_ssp_sdmmc_detect_raw(int ssp) | ||
368 | { | 395 | { |
396 | ASSERT_SSP(ssp) | ||
369 | return !!(HW_SSP_STATUS(ssp) & HW_SSP_STATUS__CARD_DETECT); | 397 | return !!(HW_SSP_STATUS(ssp) & HW_SSP_STATUS__CARD_DETECT); |
370 | } | 398 | } |
399 | |||
400 | bool imx233_ssp_sdmmc_detect(int ssp) | ||
401 | { | ||
402 | ASSERT_SSP(ssp) | ||
403 | return imx233_ssp_sdmmc_detect_raw(ssp) != ssp_detect_invert[ssp - 1]; | ||
404 | } | ||
diff --git a/firmware/target/arm/imx233/ssp-imx233.h b/firmware/target/arm/imx233/ssp-imx233.h index a463c04a20..c168d5997c 100644 --- a/firmware/target/arm/imx233/ssp-imx233.h +++ b/firmware/target/arm/imx233/ssp-imx233.h | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2011 by amaury Pouly | 10 | * Copyright (C) 2011 by Amaury Pouly |
11 | * | 11 | * |
12 | * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing | 12 | * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing |
13 | * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach | 13 | * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach |
@@ -170,8 +170,15 @@ void imx233_ssp_setup_ssp2_sd_mmc_pins(bool enable_pullups, unsigned bus_width, | |||
170 | /* after callback is fired, imx233_ssp_sdmmc_setup_detect needs to be called | 170 | /* after callback is fired, imx233_ssp_sdmmc_setup_detect needs to be called |
171 | * to enable detection again. If first_time is true, the callback will | 171 | * to enable detection again. If first_time is true, the callback will |
172 | * be called if the sd card is inserted when the function is called, otherwise | 172 | * be called if the sd card is inserted when the function is called, otherwise |
173 | * it will be called on the next insertion change. */ | 173 | * it will be called on the next insertion change. |
174 | void imx233_ssp_sdmmc_setup_detect(int ssp, bool enable, ssp_detect_cb_t fn, bool first_time); | 174 | * By default, sd_detect=1 means sd inserted; invert reverses this behaviour */ |
175 | void imx233_ssp_sdmmc_setup_detect(int ssp, bool enable, ssp_detect_cb_t fn, | ||
176 | bool first_time, bool invert); | ||
177 | /* needs prior setup with imx233_ssp_sdmmc_setup_detect */ | ||
178 | bool imx233_ssp_sdmmc_is_detect_inverted(int spp); | ||
179 | /* raw value of the detect pin */ | ||
180 | bool imx233_ssp_sdmmc_detect_raw(int ssp); | ||
181 | /* corrected value given the invert setting */ | ||
175 | bool imx233_ssp_sdmmc_detect(int ssp); | 182 | bool imx233_ssp_sdmmc_detect(int ssp); |
176 | /* SD/MMC requires that the card be provided the clock during an init sequence of | 183 | /* SD/MMC requires that the card be provided the clock during an init sequence of |
177 | * at least 1msec (or 74 clocks). Does NOT touch the clock so it has to be correct. */ | 184 | * at least 1msec (or 74 clocks). Does NOT touch the clock so it has to be correct. */ |