imx23_ssp.c revision 1.2.2.3 1 /* $Id: imx23_ssp.c,v 1.2.2.3 2013/01/23 00:05:41 yamt Exp $ */
2
3 /*
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Petri Laakso.
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, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/bus.h>
35 #include <sys/cdefs.h>
36 #include <sys/device.h>
37 #include <sys/errno.h>
38 #include <sys/systm.h>
39
40 #include <arm/imx/imx23_sspreg.h>
41 #include <arm/imx/imx23var.h>
42
43 #include <dev/sdmmc/sdmmcchip.h>
44 #include <dev/sdmmc/sdmmcreg.h>
45 #include <dev/sdmmc/sdmmcvar.h>
46
47 /*
48 * SD/MMC host controller driver for i.MX23.
49 */
50
51 struct issp_softc {
52 device_t sc_dev;
53 bus_space_tag_t sc_iot;
54 bus_space_handle_t sc_hdl;
55 device_t sc_sdmmc;
56 device_t dmac;
57 };
58
59 static int issp_match(device_t, cfdata_t, void *);
60 static void issp_attach(device_t, device_t, void *);
61 static int issp_activate(device_t, enum devact);
62
63 static void issp_reset(struct issp_softc *);
64 static void issp_init(struct issp_softc *);
65 static uint32_t issp_set_sck(struct issp_softc *, uint32_t target);
66
67 /* sdmmc(4) driver chip function prototypes. */
68 static int issp_host_reset(sdmmc_chipset_handle_t);
69 static uint32_t issp_host_ocr(sdmmc_chipset_handle_t);
70 static int issp_host_maxblklen(sdmmc_chipset_handle_t);
71 static int issp_card_detect(sdmmc_chipset_handle_t);
72 static int issp_write_protect(sdmmc_chipset_handle_t);
73 static int issp_bus_power(sdmmc_chipset_handle_t, uint32_t);
74 static int issp_bus_clock(sdmmc_chipset_handle_t, int);
75 static int issp_bus_width(sdmmc_chipset_handle_t, int);
76 static int issp_bus_rod(sdmmc_chipset_handle_t, int);
77 static void issp_exec_command(sdmmc_chipset_handle_t,
78 struct sdmmc_command *);
79 static void issp_card_enable_intr(sdmmc_chipset_handle_t, int);
80 static void issp_card_intr_ack(sdmmc_chipset_handle_t);
81
82 static struct sdmmc_chip_functions issp_functions = {
83 .host_reset = issp_host_reset,
84 .host_ocr = issp_host_ocr,
85 .host_maxblklen = issp_host_maxblklen,
86 .card_detect = issp_card_detect,
87 .write_protect = issp_write_protect,
88 .bus_power = issp_bus_power,
89 .bus_clock = issp_bus_clock,
90 .bus_width = issp_bus_width,
91 .bus_rod = issp_bus_rod,
92 .exec_command = issp_exec_command,
93 .card_enable_intr = issp_card_enable_intr,
94 .card_intr_ack = issp_card_intr_ack
95 };
96
97 CFATTACH_DECL3_NEW(ssp,
98 sizeof(struct issp_softc),
99 issp_match,
100 issp_attach,
101 NULL,
102 issp_activate,
103 NULL,
104 NULL,
105 0);
106
107 #define SSP_SOFT_RST_LOOP 455 /* At least 1 us ... */
108
109 #define SSP_RD(sc, reg) \
110 bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
111 #define SSP_WR(sc, reg, val) \
112 bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
113
114 #define SSP_CLK 96000000 /* CLK_SSP from PLL is 96 MHz */
115 #define SSP_CLK_MIN 400 /* 400 kHz */
116 #define SSP_CLK_MAX 48000 /* 48 MHz */
117
118 #define SSP_BUSY (HW_SSP_STATUS_CMD_BUSY | \
119 HW_SSP_STATUS_DATA_BUSY | \
120 HW_SSP_STATUS_BUSY)
121
122 #define SSP_RUN_ERR (HW_SSP_STATUS_RESP_CRC_ERR | \
123 HW_SSP_STATUS_RESP_ERR | \
124 HW_SSP_STATUS_RESP_TIMEOUT | \
125 HW_SSP_STATUS_DATA_CRC_ERR | \
126 HW_SSP_STATUS_TIMEOUT)
127
128 #define BLKIO_NONE 0
129 #define BLKIO_RD 1
130 #define BLKIO_WR 2
131
132 #define BUS_WIDTH_1_BIT 0x0
133 #define BUS_WIDTH_4_BIT 0x1
134 #define BUS_WIDTH_8_BIT 0x2
135
136 static int
137 issp_match(device_t parent, cfdata_t match, void *aux)
138 {
139 struct apb_attach_args *aa = aux;
140
141 if ((aa->aa_addr == HW_SSP1_BASE) && (aa->aa_size == HW_SSP1_SIZE))
142 return 1;
143
144 if ((aa->aa_addr == HW_SSP2_BASE) && (aa->aa_size == HW_SSP2_SIZE))
145 return 1;
146
147 return 0;
148 }
149
150 static void
151 issp_attach(device_t parent, device_t self, void *aux)
152 {
153 struct issp_softc *sc = device_private(self);
154 struct apb_softc *sc_parent = device_private(parent);
155 struct apb_attach_args *aa = aux;
156 struct sdmmcbus_attach_args saa;
157 static int issp_attached = 0;
158
159 if (issp_attached)
160 return;
161
162 sc->sc_dev = self;
163 sc->sc_iot = aa->aa_iot;
164 sc->dmac = sc_parent->dmac;
165
166 if (bus_space_map(sc->sc_iot,
167 aa->aa_addr, aa->aa_size, 0, &(sc->sc_hdl))) {
168 aprint_error_dev(sc->sc_dev, "unable to map bus space\n");
169 return;
170 }
171
172 issp_reset(sc);
173 issp_init(sc);
174
175 uint32_t issp_vers = SSP_RD(sc, HW_SSP_VERSION);
176 aprint_normal(": SSP Block v%" __PRIuBIT ".%" __PRIuBIT "\n",
177 __SHIFTOUT(issp_vers, HW_SSP_VERSION_MAJOR),
178 __SHIFTOUT(issp_vers, HW_SSP_VERSION_MINOR));
179
180 saa.saa_busname = "sdmmc";
181 saa.saa_sct = &issp_functions;
182 saa.saa_spi_sct = NULL;
183 saa.saa_sch = sc;
184 saa.saa_dmat = aa->aa_dmat;
185 saa.saa_clkmin = SSP_CLK_MIN;
186 saa.saa_clkmax = SSP_CLK_MAX;
187 /* Add SMC_CAPS_DMA capability when DMA funtionality is implemented. */
188 saa.saa_caps = SMC_CAPS_4BIT_MODE | SMC_CAPS_SINGLE_ONLY;
189
190 sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL);
191 if (sc->sc_sdmmc == NULL) {
192 aprint_error_dev(sc->sc_dev, "unable to attach sdmmc\n");
193 return;
194 }
195
196 issp_attached = 1;
197
198 return;
199 }
200
201 static int
202 issp_activate(device_t self, enum devact act)
203 {
204 return EOPNOTSUPP;
205 }
206
207 /*
208 * sdmmc chip functions.
209 */
210 static int
211 issp_host_reset(sdmmc_chipset_handle_t sch)
212 {
213 struct issp_softc *sc = sch;
214
215 issp_reset(sc);
216
217 return 0;
218 }
219
220 static uint32_t
221 issp_host_ocr(sdmmc_chipset_handle_t sch)
222 {
223 /* SSP supports at least 3.2-3.3v */
224 return MMC_OCR_3_2V_3_3V;
225 }
226
227 static int
228 issp_host_maxblklen(sdmmc_chipset_handle_t sch)
229 {
230 return 512;
231 }
232
233 /*
234 * Called at the beginning of sdmmc_task_thread to detect the presence
235 * of the SD card.
236 */
237 static int
238 issp_card_detect(sdmmc_chipset_handle_t sch)
239 {
240 /* struct issp_softc *sc = sch;
241 *
242 * In the perfect world I'll just:
243 * return SSP_RD(sc, HW_SSP_STATUS) & HW_SSP_STATUS_CARD_DETECT;
244 * and call it a day.
245 *
246 * But on i.MX23 OLinuXino MAXI, SSP1_DETECT is not used for the SD
247 * card detection but SSP1_DATA3 is, as Tsvetan put it:
248 *
249 * < Tsvetan> if you want to know if SD card is inserted watch
250 * CD/DAT3/CS port
251 * < Tsvetan> without card there is R20 weak pulldown
252 * < Tsvetan> all cards have 40K pullup to this pin
253 * < Tsvetan> so when card is inserted you will read it high
254 *
255 * Which means I should to do something like this:
256 * #if BOARDTYPE == MAXI (Possibly MINI & MICRO)
257 * return GPIO_READ(PIN_125) & PIN_125
258 * #else
259 * return SSP_RD(sc, STATUS) & CARD_DETECT;
260 * #endif
261 * Until GPIO functionality is not present I am just going to */
262
263 return 1;
264 }
265
266 static int
267 issp_write_protect(sdmmc_chipset_handle_t sch)
268 {
269 /* The device is not write protected. */
270 return 0;
271 }
272
273 static int
274 issp_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
275 {
276 /* i.MX23 SSP does not support setting bus power. */
277 return 0;
278 }
279
280 static int
281 issp_bus_clock(sdmmc_chipset_handle_t sch, int clock)
282 {
283 struct issp_softc *sc = sch;
284 uint32_t sck;
285
286 sck = issp_set_sck(sc, clock * 1000);
287
288 /* Notify user if we didn't get exact clock rate from SSP that was
289 * requested. */
290 if (sck != clock * 1000)
291 aprint_normal_dev(sc->sc_dev, "requested clock %dHz, "
292 "but got %dHz\n", clock * 1000, sck);
293
294 return 0;
295 }
296
297 static int
298 issp_bus_width(sdmmc_chipset_handle_t sch, int width)
299 {
300 struct issp_softc *sc = sch;
301 uint32_t reg;
302
303 reg = SSP_RD(sc, HW_SSP_CTRL0);
304 reg &= ~(HW_SSP_CTRL0_BUS_WIDTH);
305
306 switch(width) {
307 case(1):
308 reg |= __SHIFTIN(BUS_WIDTH_1_BIT, HW_SSP_CTRL0_BUS_WIDTH);
309 break;
310 case(4):
311 reg |= __SHIFTIN(BUS_WIDTH_4_BIT, HW_SSP_CTRL0_BUS_WIDTH);
312 break;
313 case(8):
314 reg |= __SHIFTIN(BUS_WIDTH_8_BIT, HW_SSP_CTRL0_BUS_WIDTH);
315 break;
316 default:
317 return 1;
318 }
319
320 SSP_WR(sc, HW_SSP_CTRL0, reg);
321
322 return 0;
323 }
324
325 static int
326 issp_bus_rod(sdmmc_chipset_handle_t sch, int rod)
327 {
328 /* Go to data transfer mode. */
329 return 0;
330 }
331
332 static void
333 issp_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
334 {
335 struct issp_softc *sc = sch;
336 uint32_t reg;
337 uint32_t do_blkio;
338 uint32_t i;
339
340 do_blkio = 0;
341
342 /* Wait until SSP done. (data I/O error + retry...) */
343 while (SSP_RD(sc, HW_SSP_STATUS) & SSP_BUSY)
344 ;
345
346 /* Set expected response type. */
347 SSP_WR(sc, HW_SSP_CTRL0_CLR,
348 HW_SSP_CTRL0_GET_RESP | HW_SSP_CTRL0_LONG_RESP);
349
350 if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
351 SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_GET_RESP);
352 if (ISSET(cmd->c_flags, SCF_RSP_136))
353 SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_LONG_RESP);
354 }
355
356 /* If CMD does not need CRC validation, tell it to SSP. */
357 if (ISSET(cmd->c_flags, SCF_RSP_CRC))
358 SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_IGNORE_CRC);
359 else
360 SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_IGNORE_CRC);
361
362 /* Set command. */
363 SSP_WR(sc, HW_SSP_CMD0_CLR, HW_SSP_CMD0_CMD);
364 SSP_WR(sc, HW_SSP_CMD0_SET,
365 __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD));
366
367 /* Set command argument. */
368 SSP_WR(sc, HW_SSP_CMD1, cmd->c_arg);
369
370 /* Is data to be transferred? */
371 if (cmd->c_datalen > 0 && cmd->c_data != NULL) {
372 SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_DATA_XFER);
373 /* Transfer XFER_COUNT of 8-bit words. */
374 SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_XFER_COUNT);
375 SSP_WR(sc, HW_SSP_CTRL0_SET,
376 __SHIFTIN(cmd->c_datalen, HW_SSP_CTRL0_XFER_COUNT));
377
378 /* XXX: why 8CYC? Bit is never cleaned. */
379 SSP_WR(sc, HW_SSP_CMD0_SET, HW_SSP_CMD0_APPEND_8CYC);
380
381 if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
382 /* Read mode. */
383 do_blkio |= BLKIO_RD;
384 SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_READ);
385 } else {
386 /* Write mode. */
387 do_blkio |= BLKIO_WR;
388 SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_READ);
389 }
390 } else {
391 /* No data to be transferred. */
392 SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_DATA_XFER);
393 }
394
395 /* Run the command. */
396 SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_RUN);
397
398 if (ISSET(do_blkio, BLKIO_RD)) {
399 for (i = 0; i < cmd->c_datalen / 4; i++) {
400 /* Wait until data arrives to FIFO. */
401 while (SSP_RD(sc, HW_SSP_STATUS)
402 & HW_SSP_STATUS_FIFO_EMPTY) {
403 /* Abort if error while waiting. */
404 if (SSP_RD(sc, HW_SSP_STATUS) & SSP_RUN_ERR) {
405 aprint_normal_dev(sc->sc_dev,
406 "RD_ERR: %x\n",
407 SSP_RD(sc, HW_SSP_STATUS));
408 cmd->c_error = 1;
409 goto pioerr;
410 }
411 }
412 *((uint32_t *)cmd->c_data+i) = SSP_RD(sc, HW_SSP_DATA);
413 }
414 } else if (ISSET(do_blkio, BLKIO_WR)) {
415 for (i = 0; i < (cmd->c_datalen / 4); i++) {
416 while (SSP_RD(sc, HW_SSP_STATUS)
417 & HW_SSP_STATUS_FIFO_FULL) {
418 /* Abort if error while waiting. */
419 if (SSP_RD(sc, HW_SSP_STATUS) & SSP_RUN_ERR) {
420 aprint_normal_dev(sc->sc_dev,
421 "WR_ERR: %x\n",
422 SSP_RD(sc, HW_SSP_STATUS));
423 cmd->c_error = 1;
424 goto pioerr;
425 }
426 }
427 SSP_WR(sc, HW_SSP_DATA, *((uint32_t *)cmd->c_data+i));
428 }
429 }
430
431 /* Wait until SSP is done. */
432 while (SSP_RD(sc, HW_SSP_STATUS) & SSP_BUSY)
433 ;
434
435 /* Check if the command ran successfully. */
436 reg = SSP_RD(sc, HW_SSP_STATUS);
437 if (reg & SSP_RUN_ERR)
438 cmd->c_error = reg & SSP_RUN_ERR;
439
440 /* Read response if such was requested. */
441 if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
442 cmd->c_resp[0] = SSP_RD(sc, HW_SSP_SDRESP0);
443 if (ISSET(cmd->c_flags, SCF_RSP_136)) {
444 cmd->c_resp[1] = SSP_RD(sc, HW_SSP_SDRESP1);
445 cmd->c_resp[2] = SSP_RD(sc, HW_SSP_SDRESP2);
446 cmd->c_resp[3] = SSP_RD(sc, HW_SSP_SDRESP3);
447 /*
448 * Remove CRC7 + LSB by rotating all bits right by 8 to
449 * make sdmmc __bitfield() happy.
450 */
451 cmd->c_resp[0] >>= 8; /* Remove CRC7 + LSB. */
452 cmd->c_resp[0] |= (0x000000FF & cmd->c_resp[1]) << 24;
453 cmd->c_resp[1] >>= 8;
454 cmd->c_resp[1] |= (0x000000FF & cmd->c_resp[2]) << 24;
455 cmd->c_resp[2] >>= 8;
456 cmd->c_resp[2] |= (0x000000FF & cmd->c_resp[3]) << 24;
457 cmd->c_resp[3] >>= 8;
458 }
459 }
460 pioerr:
461 return;
462 }
463
464 static void
465 issp_card_enable_intr(sdmmc_chipset_handle_t sch, int irq)
466 {
467 struct issp_softc *sc = sch;
468
469 aprint_normal_dev(sc->sc_dev,
470 "issp_card_enable_intr NOT IMPLEMENTED!\n");
471
472 return;
473 }
474
475 static void
476 issp_card_intr_ack(sdmmc_chipset_handle_t sch)
477 {
478 struct issp_softc *sc = sch;
479
480 aprint_normal_dev(sc->sc_dev, "issp_card_intr_ack NOT IMPLEMENTED!\n");
481
482 return;
483 }
484
485 /*
486 * Reset the SSP block.
487 *
488 * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
489 */
490 static void
491 issp_reset(struct issp_softc *sc)
492 {
493 unsigned int loop;
494
495 /* Prepare for soft-reset by making sure that SFTRST is not currently
496 * asserted. Also clear CLKGATE so we can wait for its assertion below.
497 */
498 SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
499
500 /* Wait at least a microsecond for SFTRST to deassert. */
501 loop = 0;
502 while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
503 (loop < SSP_SOFT_RST_LOOP))
504 loop++;
505
506 /* Clear CLKGATE so we can wait for its assertion below. */
507 SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
508
509 /* Soft-reset the block. */
510 SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_SFTRST);
511
512 /* Wait until clock is in the gated state. */
513 while (!(SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE));
514
515 /* Bring block out of reset. */
516 SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
517
518 loop = 0;
519 while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
520 (loop < SSP_SOFT_RST_LOOP))
521 loop++;
522
523 SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
524
525 /* Wait until clock is in the NON-gated state. */
526 while (SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE);
527
528 return;
529 }
530
531
532 /*
533 * DATA_TIMEOUT is calculated as:
534 * (1 / SSP_CLK) * (DATA_TIMEOUT * 4096)
535 */
536 #define DATA_TIMEOUT 0x4240 /* 723ms */
537
538 /*
539 * Initialize SSP controller to SD/MMC mode.
540 */
541 static void
542 issp_init(struct issp_softc *sc)
543 {
544 uint32_t reg;
545
546 /* Initial data bus width is 1-bit. */
547 reg = SSP_RD(sc, HW_SSP_CTRL0);
548 reg &= ~(HW_SSP_CTRL0_BUS_WIDTH);
549 reg |= __SHIFTIN(BUS_WIDTH_1_BIT, HW_SSP_CTRL0_BUS_WIDTH) |
550 HW_SSP_CTRL0_WAIT_FOR_IRQ | HW_SSP_CTRL0_ENABLE;
551 SSP_WR(sc, HW_SSP_CTRL0, reg);
552
553 /* Set data timeout. */
554 reg = SSP_RD(sc, HW_SSP_TIMING);
555 reg &= ~(HW_SSP_TIMING_TIMEOUT);
556 reg |= __SHIFTIN(DATA_TIMEOUT, HW_SSP_TIMING_TIMEOUT);
557
558 /* Set initial clock rate to minimum. */
559 issp_set_sck(sc, SSP_CLK_MIN * 1000);
560
561 SSP_WR(sc, HW_SSP_TIMING, reg);
562 /* Enable SD/MMC mode and use use 8-bits per word. */
563 reg = SSP_RD(sc, HW_SSP_CTRL1);
564 reg &= ~(HW_SSP_CTRL1_WORD_LENGTH | HW_SSP_CTRL1_SSP_MODE);
565 reg |= HW_SSP_CTRL1_POLARITY |
566 __SHIFTIN(0x7, HW_SSP_CTRL1_WORD_LENGTH) |
567 __SHIFTIN(0x3, HW_SSP_CTRL1_SSP_MODE);
568 SSP_WR(sc, HW_SSP_CTRL1, reg);
569
570 return;
571 }
572
573 /*
574 * Set SSP_SCK clock rate to the value specified in target.
575 *
576 * SSP_SCK is calculated as: SSP_CLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE))
577 *
578 * issp_set_sck find the most suitable CLOCK_DIVIDE and CLOCK_RATE register
579 * values for the target clock rate by iterating through all possible register
580 * values.
581 */
582 static uint32_t
583 issp_set_sck(struct issp_softc *sc, uint32_t target)
584 {
585 uint32_t newclk, found, reg;
586 uint8_t div, rate, d, r;
587
588 found = div = rate = 0;
589
590 for (d = 2; d < 254; d++) {
591 for (r = 0; r < 255; r++) {
592 newclk = SSP_CLK / (d * (1 + r));
593 if (newclk == target) {
594 found = newclk;
595 div = d;
596 rate = r;
597 goto out;
598 }
599 if (newclk < target && newclk > found) {
600 found = newclk;
601 div = d;
602 rate = r;
603 }
604 }
605 }
606 out:
607 reg = SSP_RD(sc, HW_SSP_TIMING);
608 reg &= ~(HW_SSP_TIMING_CLOCK_DIVIDE | HW_SSP_TIMING_CLOCK_RATE);
609 reg |= __SHIFTIN(div, HW_SSP_TIMING_CLOCK_DIVIDE) |
610 __SHIFTIN(rate, HW_SSP_TIMING_CLOCK_RATE);
611 SSP_WR(sc, HW_SSP_TIMING, reg);
612
613 return SSP_CLK / (div * (1 + rate));
614 }
615