pxa2x0_i2s.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /* $OpenBSD: pxa2x0_i2s.c,v 1.8 2014/07/12 18:44:41 tedu Exp $ */
  2. /*
  3. * Copyright (c) 2005 Christopher Pascoe <pascoe@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/param.h>
  18. #include <sys/systm.h>
  19. #include <sys/device.h>
  20. #include <sys/malloc.h>
  21. #include <arm/xscale/pxa2x0reg.h>
  22. #include <arm/xscale/pxa2x0var.h>
  23. #include <arm/xscale/pxa2x0_gpio.h>
  24. #include <arm/xscale/pxa2x0_i2s.h>
  25. #include <arm/xscale/pxa2x0_dmac.h>
  26. struct pxa2x0_i2s_dma {
  27. struct pxa2x0_i2s_dma *next;
  28. caddr_t addr;
  29. size_t size;
  30. bus_dmamap_t map;
  31. bus_dma_segment_t seg;
  32. };
  33. void
  34. pxa2x0_i2s_init(struct pxa2x0_i2s_softc *sc)
  35. {
  36. bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR0, SACR0_RST);
  37. delay(100);
  38. bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR0,
  39. SACR0_BCKD | SACR0_SET_TFTH(7) | SACR0_SET_RFTH(7));
  40. bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR1, 0);
  41. bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADR, 0);
  42. bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADIV, sc->sc_sadiv);
  43. bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR0,
  44. SACR0_BCKD | SACR0_SET_TFTH(7) | SACR0_SET_RFTH(7) | SACR0_ENB);
  45. }
  46. int
  47. pxa2x0_i2s_attach_sub(struct pxa2x0_i2s_softc *sc)
  48. {
  49. if (bus_space_map(sc->sc_iot, PXA2X0_I2S_BASE, PXA2X0_I2S_SIZE, 0,
  50. &sc->sc_ioh)) {
  51. sc->sc_size = 0;
  52. return 1;
  53. }
  54. sc->sc_sadiv = SADIV_3_058MHz;
  55. bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, sc->sc_size,
  56. BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
  57. pxa2x0_gpio_set_function(28, GPIO_ALT_FN_1_OUT); /* I2S_BITCLK */
  58. pxa2x0_gpio_set_function(113, GPIO_ALT_FN_1_OUT); /* I2S_SYSCLK */
  59. pxa2x0_gpio_set_function(31, GPIO_ALT_FN_1_OUT); /* I2S_SYNC */
  60. pxa2x0_gpio_set_function(30, GPIO_ALT_FN_1_OUT); /* I2S_SDATA_OUT */
  61. pxa2x0_gpio_set_function(29, GPIO_ALT_FN_2_IN); /* I2S_SDATA_IN */
  62. pxa2x0_i2s_init(sc);
  63. return 0;
  64. }
  65. void pxa2x0_i2s_open(struct pxa2x0_i2s_softc *sc)
  66. {
  67. sc->sc_open++;
  68. pxa2x0_clkman_config(CKEN_I2S, 1);
  69. }
  70. void pxa2x0_i2s_close(struct pxa2x0_i2s_softc *sc)
  71. {
  72. pxa2x0_clkman_config(CKEN_I2S, 0);
  73. sc->sc_open--;
  74. }
  75. int
  76. pxa2x0_i2s_detach_sub(struct pxa2x0_i2s_softc *sc)
  77. {
  78. if (sc->sc_size > 0) {
  79. bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
  80. sc->sc_size = 0;
  81. }
  82. pxa2x0_clkman_config(CKEN_I2S, 0);
  83. return (0);
  84. }
  85. void pxa2x0_i2s_write(struct pxa2x0_i2s_softc *sc, u_int32_t data)
  86. {
  87. if (! sc->sc_open)
  88. return;
  89. /* Clear intr and underrun bit if set. */
  90. if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, I2S_SASR0) & SASR0_TUR)
  91. bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SAICR, SAICR_TUR);
  92. /* Wait for transmit fifo to have space. */
  93. while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, I2S_SASR0) & SASR0_TNF)
  94. == 0)
  95. ; /* nothing */
  96. /* Queue data */
  97. bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADR, data);
  98. }
  99. void
  100. pxa2x0_i2s_setspeed(struct pxa2x0_i2s_softc *sc, u_long *argp)
  101. {
  102. /*
  103. * The available speeds are in the following table.
  104. * Keep the speeds in increasing order.
  105. */
  106. typedef struct {
  107. int speed;
  108. int div;
  109. } speed_struct;
  110. u_long arg = *argp;
  111. static speed_struct speed_table[] = {
  112. {8000, SADIV_513_25kHz},
  113. {11025, SADIV_702_75kHz},
  114. {16000, SADIV_1_026MHz},
  115. {22050, SADIV_1_405MHz},
  116. {44100, SADIV_2_836MHz},
  117. {48000, SADIV_3_058MHz},
  118. };
  119. int i, n, selected = -1;
  120. n = sizeof(speed_table) / sizeof(speed_struct);
  121. if (arg < speed_table[0].speed)
  122. selected = 0;
  123. if (arg > speed_table[n - 1].speed)
  124. selected = n - 1;
  125. for (i = 1; selected == -1 && i < n; i++) {
  126. if (speed_table[i].speed == arg)
  127. selected = i;
  128. else if (speed_table[i].speed > arg) {
  129. int diff1, diff2;
  130. diff1 = arg - speed_table[i - 1].speed;
  131. diff2 = speed_table[i].speed - arg;
  132. if (diff1 < diff2)
  133. selected = i - 1;
  134. else
  135. selected = i;
  136. }
  137. }
  138. if (selected == -1)
  139. selected = 0;
  140. *argp = speed_table[selected].speed;
  141. sc->sc_sadiv = speed_table[selected].div;
  142. bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADIV, sc->sc_sadiv);
  143. }
  144. void *
  145. pxa2x0_i2s_allocm(void *hdl, int direction, size_t size, int type, int flags)
  146. {
  147. struct device *sc_dev = hdl;
  148. struct pxa2x0_i2s_softc *sc =
  149. (struct pxa2x0_i2s_softc *)((struct device *)hdl + 1);
  150. struct pxa2x0_i2s_dma *p;
  151. int error;
  152. int rseg;
  153. p = malloc(sizeof(*p), type, flags);
  154. if (!p)
  155. return 0;
  156. p->size = size;
  157. if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &p->seg, 1,
  158. &rseg, BUS_DMA_NOWAIT)) != 0) {
  159. printf("%s: unable to allocate dma, error = %d\n",
  160. sc_dev->dv_xname, error);
  161. goto fail_alloc;
  162. }
  163. if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
  164. BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
  165. printf("%s: unable to map dma, error = %d\n",
  166. sc_dev->dv_xname, error);
  167. goto fail_map;
  168. }
  169. if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
  170. BUS_DMA_NOWAIT, &p->map)) != 0) {
  171. printf("%s: unable to create dma map, error = %d\n",
  172. sc_dev->dv_xname, error);
  173. goto fail_create;
  174. }
  175. if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
  176. BUS_DMA_NOWAIT)) != 0) {
  177. printf("%s: unable to load dma map, error = %d\n",
  178. sc_dev->dv_xname, error);
  179. goto fail_load;
  180. }
  181. p->next = sc->sc_dmas;
  182. sc->sc_dmas = p;
  183. return p->addr;
  184. fail_load:
  185. bus_dmamap_destroy(sc->sc_dmat, p->map);
  186. fail_create:
  187. bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
  188. fail_map:
  189. bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
  190. fail_alloc:
  191. free(p, type, 0);
  192. return 0;
  193. }
  194. void
  195. pxa2x0_i2s_freem(void *hdl, void *ptr, int type)
  196. {
  197. struct pxa2x0_i2s_softc *sc =
  198. (struct pxa2x0_i2s_softc *)((struct device *)hdl + 1);
  199. struct pxa2x0_i2s_dma **pp, *p;
  200. for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
  201. if (p->addr == ptr) {
  202. bus_dmamap_unload(sc->sc_dmat, p->map);
  203. bus_dmamap_destroy(sc->sc_dmat, p->map);
  204. bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
  205. bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
  206. *pp = p->next;
  207. free(p, type, 0);
  208. return;
  209. }
  210. panic("pxa2x0_i2s_freem: trying to free unallocated memory");
  211. }
  212. paddr_t
  213. pxa2x0_i2s_mappage(void *hdl, void *mem, off_t off, int prot)
  214. {
  215. struct pxa2x0_i2s_softc *sc =
  216. (struct pxa2x0_i2s_softc *)((struct device *)hdl + 1);
  217. struct pxa2x0_i2s_dma *p;
  218. if (off < 0)
  219. return -1;
  220. for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
  221. ;
  222. if (!p)
  223. return -1;
  224. if (off > p->size)
  225. return -1;
  226. return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot,
  227. BUS_DMA_WAITOK);
  228. }
  229. int
  230. pxa2x0_i2s_round_blocksize(void *hdl, int bs)
  231. {
  232. /* Enforce individual DMA block size limit */
  233. if (bs > DCMD_LENGTH_MASK)
  234. return (DCMD_LENGTH_MASK & ~0x03);
  235. return (bs + 0x03) & ~0x03; /* 32-bit multiples */
  236. }
  237. size_t
  238. pxa2x0_i2s_round_buffersize(void *hdl, int direction, size_t bufsize)
  239. {
  240. return bufsize;
  241. }
  242. int
  243. pxa2x0_i2s_start_output(struct pxa2x0_i2s_softc *sc, void *block, int bsize,
  244. void (*intr)(void *), void *intrarg)
  245. {
  246. struct pxa2x0_i2s_dma *p;
  247. int offset;
  248. /* Find mapping which contains block completely */
  249. for (p = sc->sc_dmas; p && (((caddr_t)block < p->addr) ||
  250. ((caddr_t)block + bsize > p->addr + p->size)); p = p->next)
  251. ; /* Nothing */
  252. if (!p) {
  253. printf("pxa2x0_i2s_start_output: request with bad start "
  254. "address: %p, size: %d)\n", block, bsize);
  255. return ENXIO;
  256. }
  257. /* Offset into block to use in mapped block */
  258. offset = (caddr_t)block - p->addr;
  259. /* Start DMA */
  260. pxa2x0_dma_to_fifo(3, 1, 0x40400080, 4, 32,
  261. p->map->dm_segs[0].ds_addr + offset, bsize, intr, intrarg);
  262. return 0;
  263. }
  264. int
  265. pxa2x0_i2s_start_input(struct pxa2x0_i2s_softc *sc, void *block, int bsize,
  266. void (*intr)(void *), void *intrarg)
  267. {
  268. struct pxa2x0_i2s_dma *p;
  269. int offset;
  270. /* Find mapping which contains block completely */
  271. for (p = sc->sc_dmas; p && (((caddr_t)block < p->addr) ||
  272. ((caddr_t)block + bsize > p->addr + p->size)); p = p->next)
  273. ; /* Nothing */
  274. if (!p) {
  275. printf("pxa2x0_i2s_start_input: request with bad start "
  276. "address: %p, size: %d)\n", block, bsize);
  277. return ENXIO;
  278. }
  279. /* Offset into block to use in mapped block */
  280. offset = (caddr_t)block - p->addr;
  281. /* Start DMA */
  282. pxa2x0_dma_from_fifo(2, 2, 0x40400080, 4, 32,
  283. p->map->dm_segs[0].ds_addr + offset, bsize, intr, intrarg);
  284. return 0;
  285. }