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