1 /**
2 * \file
3 *
4 * \brief SAM I<SUP>2</SUP>S - Inter-IC Sound Controller
5 *
6 * Copyright (C) 2014-2015 Atmel Corporation. All rights reserved.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * 3. The name of Atmel may not be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 * \asf_license_stop
41 *
42 */
43 /*
44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45 */
46
47 #include "i2s_callback.h"
48
49 struct i2s_module *_i2s_instances[I2S_INST_NUM];
50
_i2s_interrupt_handler(const uint8_t instance)51 static void _i2s_interrupt_handler(const uint8_t instance)
52 {
53 struct i2s_module *module = _i2s_instances[instance];
54 struct i2s_serializer_module *data_module;
55
56 /* Get interrupt flags */
57 uint32_t intflag = module->hw->INTFLAG.reg;
58 uint32_t inten = intflag & module->hw->INTENSET.reg;
59 uint32_t run_flags = (I2S_INTFLAG_TXUR0 | I2S_INTFLAG_RXOR0);
60 uint32_t ready_flags = (I2S_INTFLAG_TXRDY0 | I2S_INTFLAG_RXRDY0);
61 uint32_t call_mask;
62 uint8_t serializer;
63
64 for (serializer = 0; serializer < 2; serializer ++) {
65 data_module = &module->serializer[serializer];
66 call_mask = data_module->registered_callback_mask &
67 data_module->enabled_callback_mask;
68
69 if (intflag & (run_flags | ready_flags)) {
70 /* Serializer Tx ready */
71 if ((I2S_INTFLAG_TXRDY0 << serializer) & inten) {
72
73 if (data_module->transferred_words <
74 data_module->requested_words) {
75
76 /* Write data word */
77 while (module->hw->SYNCBUSY.reg &
78 (I2S_SYNCBUSY_DATA0 << serializer)) {
79 /* Wait sync */
80 }
81 switch(data_module->data_size) {
82 case I2S_DATA_SIZE_32BIT:
83 case I2S_DATA_SIZE_24BIT:
84 case I2S_DATA_SIZE_20BIT:
85 case I2S_DATA_SIZE_18BIT:
86 module->hw->DATA[serializer].reg =
87 ((uint32_t*)data_module->job_buffer) \
88 [data_module->transferred_words];
89 break;
90 case I2S_DATA_SIZE_16BIT:
91 case I2S_DATA_SIZE_16BIT_COMPACT:
92 module->hw->DATA[serializer].reg =
93 ((uint16_t*)data_module->job_buffer) \
94 [data_module->transferred_words];
95 break;
96 default:
97 module->hw->DATA[serializer].reg =
98 ((uint8_t*)data_module->job_buffer) \
99 [data_module->transferred_words];
100 }
101 /* Clear interrupt status */
102 module->hw->INTFLAG.reg = I2S_INTFLAG_TXRDY0 << serializer;
103
104 /* Count data */
105 data_module->transferred_words ++;
106 }
107
108 /* Check if the buffer is done */
109 if (data_module->transferred_words >=
110 data_module->requested_words) {
111 /* It's done */
112 data_module->job_status = STATUS_OK;
113 /* Disable interrupt */
114 module->hw->INTENCLR.reg =
115 I2S_INTFLAG_TXRDY0 << serializer;
116 /* Invoke callback */
117 if ((1 << I2S_SERIALIZER_CALLBACK_BUFFER_DONE) &
118 call_mask) {
119 (data_module->callback \
120 [I2S_SERIALIZER_CALLBACK_BUFFER_DONE])(module);
121 }
122 }
123 return;
124 }
125 /* Serializer Rx ready */
126 if ((I2S_INTFLAG_RXRDY0 << serializer) & inten) {
127 /* Read data word */
128 switch(data_module->data_size) {
129 case I2S_DATA_SIZE_32BIT:
130 case I2S_DATA_SIZE_24BIT:
131 case I2S_DATA_SIZE_20BIT:
132 case I2S_DATA_SIZE_18BIT:
133 ((uint32_t*)data_module->job_buffer) \
134 [data_module->transferred_words] =
135 module->hw->DATA[serializer].reg;
136 break;
137 case I2S_DATA_SIZE_16BIT:
138 case I2S_DATA_SIZE_16BIT_COMPACT:
139 ((uint16_t*)data_module->job_buffer) \
140 [data_module->transferred_words] =
141 (uint16_t)module->hw->DATA[serializer].reg;
142 break;
143 default:
144 ((uint8_t*)data_module->job_buffer) \
145 [data_module->transferred_words] =
146 (uint8_t)module->hw->DATA[serializer].reg;
147
148 }
149 /* Clear interrupt status */
150 module->hw->INTFLAG.reg = I2S_INTFLAG_RXRDY0 << serializer;
151
152 /* Count data */
153 data_module->transferred_words ++;
154
155 /* Check if the buffer is done */
156 if (data_module->transferred_words >=
157 data_module->requested_words) {
158 if (data_module->job_status == STATUS_BUSY) {
159 data_module->job_status = STATUS_OK;
160 /* Disable interrupt */
161 module->hw->INTENCLR.reg =
162 I2S_INTFLAG_RXRDY0 << serializer;
163 /* Invoke callback */
164 if ((1 << I2S_SERIALIZER_CALLBACK_BUFFER_DONE) &
165 call_mask) {
166 (data_module->callback \
167 [I2S_SERIALIZER_CALLBACK_BUFFER_DONE])(module);
168 }
169 }
170 }
171 return;
172 }
173 /* Serializer Tx undrerun or Rx overrun */
174 if (run_flags & inten) {
175 module->hw->INTFLAG.reg = I2S_INTFLAG_TXUR0 << serializer;
176 if ((1 << I2S_SERIALIZER_CALLBACK_OVER_UNDER_RUN) &
177 call_mask) {
178 (data_module->callback \
179 [I2S_SERIALIZER_CALLBACK_OVER_UNDER_RUN])(module);
180 }
181 return;
182 }
183 }
184 run_flags <<= 1;
185 ready_flags <<= 1;
186 }
187
188 }
189
190 /** Interrupt handler for the I<SUP>2</SUP>S module */
I2S_Handler(void)191 void I2S_Handler(void)
192 {
193 _i2s_interrupt_handler(0);
194 }
195
196 /**
197 * \brief Write buffer to the specified Serializer of I<SUP>2</SUP>S module
198 *
199 * \param[in] module_inst Pointer to the software module instance struct
200 * \param[in] serializer The serializer to write to
201 * \param[in] buffer The data buffer to write
202 * \param[in] size Number of data words to write
203 *
204 * \return Status of the initialization procedure.
205 *
206 * \retval STATUS_OK The data was sent successfully
207 * \retval STATUS_ERR_DENIED The serializer is not in transmit mode
208 * \retval STATUS_ERR_INVALID_ARG An invalid buffer pointer was supplied
209 */
i2s_serializer_write_buffer_job(struct i2s_module * const module_inst,const enum i2s_serializer serializer,const void * buffer,const uint32_t size)210 enum status_code i2s_serializer_write_buffer_job(
211 struct i2s_module *const module_inst,
212 const enum i2s_serializer serializer,
213 const void *buffer,
214 const uint32_t size)
215 {
216 struct i2s_serializer_module *data_module;
217
218 /* Sanity check arguments */
219 Assert(module_inst);
220 Assert(module_inst->hw);
221 Assert(serializer < I2S_SERIALIZER_N);
222
223 data_module = &module_inst->serializer[serializer];
224
225 /* Serializer must in transmit mode */
226 if (data_module->mode != I2S_SERIALIZER_TRANSMIT) {
227 return STATUS_ERR_DENIED;
228 }
229
230 /* Buffer should be aligned */
231 switch(data_module->data_size) {
232 case I2S_DATA_SIZE_32BIT:
233 case I2S_DATA_SIZE_24BIT:
234 case I2S_DATA_SIZE_20BIT:
235 case I2S_DATA_SIZE_18BIT:
236 if ((uint32_t)buffer & 0x3) {
237 return STATUS_ERR_INVALID_ARG;
238 }
239 break;
240 case I2S_DATA_SIZE_16BIT:
241 case I2S_DATA_SIZE_16BIT_COMPACT:
242 if ((uint32_t)buffer & 0x1) {
243 return STATUS_ERR_INVALID_ARG;
244 }
245 break;
246 default:
247 break;
248 }
249
250 data_module = &module_inst->serializer[serializer];
251 if (data_module->job_status == STATUS_BUSY) {
252 return STATUS_BUSY;
253 }
254
255 data_module->job_status = STATUS_BUSY;
256 data_module->requested_words = size;
257 data_module->transferred_words = 0;
258 data_module->job_buffer = (void*)buffer;
259
260 module_inst->hw->INTENSET.reg = (I2S_INTENSET_TXRDY0 << serializer);
261
262 return STATUS_OK;
263 }
264
265 /**
266 * \brief Read from the specified Serializer of I<SUP>2</SUP>S module to a buffer
267 *
268 * \param[in] module_inst Pointer to the software module instance struct
269 * \param[in] serializer The serializer to write to
270 * \param[out] buffer The buffer to fill read data
271 * \param[in] size Number of data words to read
272 *
273 * \return Status of the initialization procedure.
274 *
275 * \retval STATUS_OK The data was sent successfully
276 * \retval STATUS_ERR_DENIED The serializer is not in receive mode
277 * \retval STATUS_ERR_INVALID_ARG An invalid buffer pointer was supplied
278 */
i2s_serializer_read_buffer_job(struct i2s_module * const module_inst,const enum i2s_serializer serializer,void * buffer,const uint32_t size)279 enum status_code i2s_serializer_read_buffer_job(
280 struct i2s_module *const module_inst,
281 const enum i2s_serializer serializer,
282 void *buffer,
283 const uint32_t size)
284 {
285 struct i2s_serializer_module *data_module;
286
287 /* Sanity check arguments */
288 Assert(module_inst);
289 Assert(module_inst->hw);
290 Assert(serializer < I2S_SERIALIZER_N);
291
292 data_module = &module_inst->serializer[serializer];
293
294 /* Serializer must in receive mode */
295 if (data_module->mode == I2S_SERIALIZER_TRANSMIT) {
296 return STATUS_ERR_DENIED;
297 }
298
299 /* Data buffer must be aligned */
300 switch(data_module->data_size) {
301 case I2S_DATA_SIZE_32BIT:
302 case I2S_DATA_SIZE_24BIT:
303 case I2S_DATA_SIZE_20BIT:
304 case I2S_DATA_SIZE_18BIT:
305 if ((uint32_t)buffer & 0x3) {
306 return STATUS_ERR_INVALID_ARG;
307 }
308 break;
309 case I2S_DATA_SIZE_16BIT:
310 case I2S_DATA_SIZE_16BIT_COMPACT:
311 if ((uint32_t)buffer & 0x1) {
312 return STATUS_ERR_INVALID_ARG;
313 }
314 break;
315 default:
316 break;
317 }
318
319 data_module = &module_inst->serializer[serializer];
320 if (data_module->job_status == STATUS_BUSY) {
321 return STATUS_BUSY;
322 }
323
324 data_module->job_status = STATUS_BUSY;
325 data_module->requested_words = size;
326 data_module->transferred_words = 0;
327 data_module->job_buffer = (void*)buffer;
328
329 module_inst->hw->INTENCLR.reg = (I2S_INTENSET_RXRDY0 << serializer);
330 module_inst->hw->INTENSET.reg = (I2S_INTENSET_RXRDY0 << serializer);
331
332 return STATUS_OK;
333 }
334
335 /**
336 * \brief Aborts an ongoing job running on serializer
337 *
338 * Aborts an ongoing job.
339 *
340 * \param[in] module_inst Pointer to the software module instance struct
341 * \param[in] serializer The serializer which runs the job
342 * \param[in] job_type Type of job to abort
343 */
i2s_serializer_abort_job(struct i2s_module * const module_inst,const enum i2s_serializer serializer,const enum i2s_job_type job_type)344 void i2s_serializer_abort_job(
345 struct i2s_module *const module_inst,
346 const enum i2s_serializer serializer,
347 const enum i2s_job_type job_type)
348 {
349 /* Sanity check arguments */
350 Assert(module_inst);
351 Assert(module_inst->hw);
352 Assert(serializer < I2S_SERIALIZER_N);
353
354 if (job_type == I2S_JOB_WRITE_BUFFER) {
355 /* Disable interrupt */
356 module_inst->hw->INTENCLR.reg = (I2S_INTENCLR_TXRDY0 << serializer);
357 /* Mark job as aborted */
358 module_inst->serializer[serializer].job_status = STATUS_ABORTED;
359 } else if (job_type == I2S_JOB_READ_BUFFER) {
360 /* Disable interrupt */
361 module_inst->hw->INTENCLR.reg = (I2S_INTENCLR_RXRDY0 << serializer);
362 /* Mark job as aborted */
363 module_inst->serializer[serializer].job_status = STATUS_ABORTED;
364 }
365 }
366
367 /**
368 * \brief Gets the status of a job running on serializer
369 *
370 * Gets the status of an ongoing or the last job.
371 *
372 * \param[in] module_inst Pointer to the software module instance struct
373 * \param[in] serializer The serializer which runs the job
374 * \param[in] job_type Type of job to abort
375 *
376 * \return Status of the job.
377 */
i2s_serializer_get_job_status(const struct i2s_module * const module_inst,const enum i2s_serializer serializer,const enum i2s_job_type job_type)378 enum status_code i2s_serializer_get_job_status(
379 const struct i2s_module *const module_inst,
380 const enum i2s_serializer serializer,
381 const enum i2s_job_type job_type)
382 {
383 /* Sanity check arguments */
384 Assert(module_inst);
385 Assert(serializer < I2S_SERIALIZER_N);
386
387 if (job_type == I2S_JOB_WRITE_BUFFER || job_type == I2S_JOB_READ_BUFFER) {
388 return module_inst->serializer[serializer].job_status;
389 } else {
390 return STATUS_ERR_INVALID_ARG;
391 }
392 }
393