1 /**
2  * \file
3  *
4  * \brief SAM Serial Peripheral Interface Driver
5  *
6  * Copyright (C) 2012-2016 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 #include "sercom.h"
47 
48 #define SHIFT 32
49 #define BAUD_INT_MAX   8192
50 #define BAUD_FP_MAX     8
51 
52 #if !defined(__DOXYGEN__)
53 /**
54  * \internal Configuration structure to save current gclk status.
55  */
56 struct _sercom_conf {
57 	/* Status of gclk generator initialization */
58 	bool generator_is_set;
59 	/* Sercom gclk generator used */
60 	enum gclk_generator generator_source;
61 };
62 
63 static struct _sercom_conf _sercom_config;
64 
65 
66 /**
67  * \internal Calculate 64 bit division, ref can be found in
68  * http://en.wikipedia.org/wiki/Division_algorithm#Long_division
69  */
long_division(uint64_t n,uint64_t d)70 static uint64_t long_division(uint64_t n, uint64_t d)
71 {
72 	int32_t i;
73 	uint64_t q = 0, r = 0, bit_shift;
74 	for (i = 63; i >= 0; i--) {
75 		bit_shift = (uint64_t)1 << i;
76 
77 		r = r << 1;
78 
79 		if (n & bit_shift) {
80 			r |= 0x01;
81 		}
82 
83 		if (r >= d) {
84 			r = r - d;
85 			q |= bit_shift;
86 		}
87 	}
88 
89 	return q;
90 }
91 
92 /**
93  * \internal Calculate synchronous baudrate value (SPI/UART)
94  */
_sercom_get_sync_baud_val(const uint32_t baudrate,const uint32_t external_clock,uint16_t * const baudvalue)95 enum status_code _sercom_get_sync_baud_val(
96 		const uint32_t baudrate,
97 		const uint32_t external_clock,
98 		uint16_t *const baudvalue)
99 {
100 	/* Baud value variable */
101 	uint16_t baud_calculated = 0;
102 	uint32_t clock_value = external_clock;
103 
104 
105 	/* Check if baudrate is outside of valid range */
106 	if (baudrate > (external_clock / 2)) {
107 		/* Return with error code */
108 		return STATUS_ERR_BAUDRATE_UNAVAILABLE;
109 	}
110 
111 	/* Calculate BAUD value from clock frequency and baudrate */
112 	clock_value = external_clock / 2;
113 	while (clock_value >= baudrate) {
114 		clock_value = clock_value - baudrate;
115 		baud_calculated++;
116 	}
117 	baud_calculated = baud_calculated - 1;
118 
119 	/* Check if BAUD value is more than 255, which is maximum
120 	 * for synchronous mode */
121 	if (baud_calculated > 0xFF) {
122 		/* Return with an error code */
123 		return STATUS_ERR_BAUDRATE_UNAVAILABLE;
124 	} else {
125 		*baudvalue = baud_calculated;
126 		return STATUS_OK;
127 	}
128 }
129 
130 /**
131  * \internal Calculate asynchronous baudrate value (UART)
132 */
_sercom_get_async_baud_val(const uint32_t baudrate,const uint32_t peripheral_clock,uint16_t * const baudval,enum sercom_asynchronous_operation_mode mode,enum sercom_asynchronous_sample_num sample_num)133 enum status_code _sercom_get_async_baud_val(
134 		const uint32_t baudrate,
135 		const uint32_t peripheral_clock,
136 		uint16_t *const baudval,
137 		enum sercom_asynchronous_operation_mode mode,
138 		enum sercom_asynchronous_sample_num sample_num)
139 {
140 	/* Temporary variables  */
141 	uint64_t ratio = 0;
142 	uint64_t scale = 0;
143 	uint64_t baud_calculated = 0;
144 	uint8_t baud_fp;
145 	uint32_t baud_int = 0;
146 	uint64_t temp1;
147 
148 	/* Check if the baudrate is outside of valid range */
149 	if ((baudrate * sample_num) > peripheral_clock) {
150 		/* Return with error code */
151 		return STATUS_ERR_BAUDRATE_UNAVAILABLE;
152 	}
153 
154 	if(mode == SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC) {
155 		/* Calculate the BAUD value */
156 		temp1 = ((sample_num * (uint64_t)baudrate) << SHIFT);
157 		ratio = long_division(temp1, peripheral_clock);
158 		scale = ((uint64_t)1 << SHIFT) - ratio;
159 		baud_calculated = (65536 * scale) >> SHIFT;
160 	} else if(mode == SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL) {
161 		temp1 = ((uint64_t)baudrate * sample_num);
162 		baud_int = long_division( peripheral_clock, temp1);
163 		if(baud_int > BAUD_INT_MAX) {
164 				return STATUS_ERR_BAUDRATE_UNAVAILABLE;
165 		}
166 		temp1 = long_division( 8 * (uint64_t)peripheral_clock, temp1);
167 		baud_fp = temp1 - 8 * baud_int;
168 		baud_calculated = baud_int | (baud_fp << 13);
169 	}
170 
171 	*baudval = baud_calculated;
172 	return STATUS_OK;
173 }
174 #endif
175 
176 /**
177  * \brief Set GCLK channel to generator.
178  *
179  * This will set the appropriate GCLK channel to the requested GCLK generator.
180  * This will set the generator for all SERCOM instances, and the user will thus
181  * only be able to set the same generator that has previously been set, if any.
182  *
183  * After the generator has been set the first time, the generator can be changed
184  * using the \c force_change flag.
185  *
186  * \param[in]  generator_source The generator to use for SERCOM.
187  * \param[in]  force_change     Force change the generator.
188  *
189  * \return Status code indicating the GCLK generator change operation.
190  * \retval STATUS_OK                       If the generator update request was
191  *                                         successful.
192  * \retval STATUS_ERR_ALREADY_INITIALIZED  If a generator was already configured
193  *                                         and the new configuration was not
194  *                                         forced.
195  */
sercom_set_gclk_generator(const enum gclk_generator generator_source,const bool force_change)196 enum status_code sercom_set_gclk_generator(
197 		const enum gclk_generator generator_source,
198 		const bool force_change)
199 {
200 	/* Check if valid option */
201 	if (!_sercom_config.generator_is_set || force_change) {
202 		/* Create and fill a GCLK configuration structure for the new config */
203 		struct system_gclk_chan_config gclk_chan_conf;
204 		system_gclk_chan_get_config_defaults(&gclk_chan_conf);
205 		gclk_chan_conf.source_generator = generator_source;
206 		system_gclk_chan_set_config(SERCOM_GCLK_ID, &gclk_chan_conf);
207 		system_gclk_chan_enable(SERCOM_GCLK_ID);
208 
209 		/* Save config */
210 		_sercom_config.generator_source = generator_source;
211 		_sercom_config.generator_is_set = true;
212 
213 		return STATUS_OK;
214 	} else if (generator_source == _sercom_config.generator_source) {
215 		/* Return status OK if same config */
216 		return STATUS_OK;
217 	}
218 
219 	/* Return invalid config to already initialized GCLK */
220 	return STATUS_ERR_ALREADY_INITIALIZED;
221 }
222 
223 /** \internal
224  * Creates a switch statement case entry to convert a SERCOM instance and pad
225  * index to the default SERCOM pad MUX setting.
226  */
227 #define _SERCOM_PAD_DEFAULTS_CASE(n, pad) \
228 		case (uintptr_t)SERCOM##n: \
229 			switch (pad) { \
230 				case 0: \
231 					return SERCOM##n##_PAD0_DEFAULT; \
232 				case 1: \
233 					return SERCOM##n##_PAD1_DEFAULT; \
234 				case 2: \
235 					return SERCOM##n##_PAD2_DEFAULT; \
236 				case 3: \
237 					return SERCOM##n##_PAD3_DEFAULT; \
238 			} \
239 			break;
240 
241 /**
242  * \internal Gets the default PAD pinout for a given SERCOM.
243  *
244  * Returns the pinmux settings for the given SERCOM and pad. This is used
245  * for default configuration of pins.
246  *
247  * \param[in]  sercom_module   Pointer to the SERCOM module
248  * \param[in]  pad             PAD to get default pinout for
249  *
250  * \returns The default pinmux for the given SERCOM instance and PAD
251  *
252  */
_sercom_get_default_pad(Sercom * const sercom_module,const uint8_t pad)253 uint32_t _sercom_get_default_pad(
254 		Sercom *const sercom_module,
255 		const uint8_t pad)
256 {
257 	switch ((uintptr_t)sercom_module) {
258 		/* Auto-generate a lookup table for the default SERCOM pad defaults */
259 		MREPEAT(SERCOM_INST_NUM, _SERCOM_PAD_DEFAULTS_CASE, pad)
260 	}
261 
262 	Assert(false);
263 	return 0;
264 }
265 
266 /**
267  * \internal
268  * Find index of given instance.
269  *
270  * \param[in] sercom_instance  Instance pointer.
271  *
272  * \return Index of given instance.
273  */
_sercom_get_sercom_inst_index(Sercom * const sercom_instance)274 uint8_t _sercom_get_sercom_inst_index(
275 		Sercom *const sercom_instance)
276 {
277 	/* Save all available SERCOM instances for compare */
278 	Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS;
279 
280 	/* Find index for sercom instance */
281 	for (uint32_t i = 0; i < SERCOM_INST_NUM; i++) {
282 		if ((uintptr_t)sercom_instance == (uintptr_t)sercom_instances[i]) {
283 			return i;
284 		}
285 	}
286 
287 	/* Invalid data given */
288 	Assert(false);
289 	return 0;
290 }
291