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