1 /**
2  * \file
3  *
4  * \brief SAM QUAD DECODER Driver for SAMB11
5  *
6  * Copyright (C) 2015-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 "quad_decoder.h"
47 
48 static quad_decoder_callback_t quad_decoder0_callback = NULL;
49 static quad_decoder_callback_t quad_decoder1_callback = NULL;
50 static quad_decoder_callback_t quad_decoder2_callback = NULL;
51 
52 /**
53  * \brief Initializes config with predefined default values.
54  *
55  * This function will initialize a given QUAD DECODER configuration structure to
56  * a set of known default values. This function should be called on
57  * any new instance of the configuration structures before being
58  * modified by the user application.
59  *
60  * The default configuration is as follows:
61  *  \li Select input clock as 26MHz
62  *  \li Set counter upper threshold as 32767
63  *  \li Set counter lower threshold as -32768
64  *  \li Set pinmux_pad[0] as 0
65  *  \li Set pinmux_pad[1] as 0
66  *
67  * \param[out]  config  Pointer to a QUAD DECODER module configuration structure to set
68  */
quad_decoder_get_config_defaults(struct quad_decoder_config * config)69 void quad_decoder_get_config_defaults(struct quad_decoder_config *config)
70 {
71 	/* Axis X */
72 	config->qdec0.clock_sel = QDEC_CLK_INPUT_0;
73 	config->qdec0.threshold_upper = 32767;
74 	config->qdec0.threshold_lower = -32768;
75 	config->qdec0.pin_number_pad[0] = 0;
76 	config->qdec0.pin_number_pad[1] = 0;
77 	config->qdec0.pinmux_sel_pad[0] = 0;
78 	config->qdec0.pinmux_sel_pad[1] = 0;
79 	config->qdec_enalbe = (1 << QDEC_AXIS_X);
80 	/* Axis Y */
81 	config->qdec1.clock_sel = QDEC_CLK_INPUT_0;
82 	config->qdec1.threshold_upper = 32767;
83 	config->qdec1.threshold_lower = -32768;
84 	config->qdec1.pin_number_pad[0] = 0;
85 	config->qdec1.pin_number_pad[1] = 0;
86 	config->qdec1.pinmux_sel_pad[0] = 0;
87 	config->qdec1.pinmux_sel_pad[1] = 0;
88 	config->qdec_enalbe |= (1 << QDEC_AXIS_Y);
89 	/* Axis Z */
90 	config->qdec2.clock_sel = QDEC_CLK_INPUT_0;
91 	config->qdec2.threshold_upper = 32767;
92 	config->qdec2.threshold_lower = -32768;
93 	config->qdec2.pin_number_pad[0] = 0;
94 	config->qdec2.pin_number_pad[1] = 0;
95 	config->qdec2.pinmux_sel_pad[0] = 0;
96 	config->qdec2.pinmux_sel_pad[1] = 0;
97 	config->qdec_enalbe |= (1 << QDEC_AXIS_Z);
98 }
99 
100 /**
101  * \brief Quad Decoder ISR handler.
102  *
103  * Quad Decoder ISR handler.
104  *
105  */
quad_decoder_isr_handler(void)106 static void quad_decoder_isr_handler(void)
107 {
108 	uint8_t status = LPMCU_MISC_REGS0->QUAD_DEC_IRQS.reg;
109 
110 	if (status & LPMCU_MISC_REGS_QUAD_DEC_IRQS_QUAD_DEC0_IRQ) {
111 		LPMCU_MISC_REGS0->QUAD_DEC0_CTRL.reg |=
112 				LPMCU_MISC_REGS_QUAD_DEC0_CTRL_CLR_IRQ;
113 		if (quad_decoder0_callback) {
114 			quad_decoder0_callback();
115 		}
116 	}
117 
118 	if (status & LPMCU_MISC_REGS_QUAD_DEC_IRQS_QUAD_DEC1_IRQ) {
119 		LPMCU_MISC_REGS0->QUAD_DEC1_CTRL.reg |=
120 				LPMCU_MISC_REGS_QUAD_DEC1_CTRL_CLR_IRQ;
121 		if (quad_decoder1_callback) {
122 			quad_decoder1_callback();
123 		}
124 	}
125 
126 	if (status & LPMCU_MISC_REGS_QUAD_DEC_IRQS_QUAD_DEC2_IRQ) {
127 		LPMCU_MISC_REGS0->QUAD_DEC2_CTRL.reg |=
128 				LPMCU_MISC_REGS_QUAD_DEC2_CTRL_CLR_IRQ;
129 		if (quad_decoder2_callback) {
130 			quad_decoder2_callback();
131 		}
132 	}
133 }
134 
135 /**
136  * \brief Initializes QUAD DECODER module instance.
137  *
138  * Initializes the QUAD DECODER module, based on the given
139  * configuration values.
140  *
141  * \param[in]     qdec         Axis(x,y,z) of QUAD DECODER instance
142  * \param[in]     config       Pointer to the QAUD DECODER configuration options struct
143  */
quad_decoder_init(const struct quad_decoder_config * config)144 void quad_decoder_init(const struct quad_decoder_config *config)
145 {
146 	if (config->qdec_enalbe & (1 << QDEC_AXIS_X)) {
147 		system_peripheral_reset(PERIPHERAL_QDEC0);
148 		LPMCU_MISC_REGS0->QUAD_DEC0_CTRL.bit.CLOCK_SEL  = config->qdec0.clock_sel;
149 		LPMCU_MISC_REGS0->QUAD_DEC0_THRESHOLD.bit.UPPER = config->qdec0.threshold_upper;
150 		LPMCU_MISC_REGS0->QUAD_DEC0_THRESHOLD.bit.LOWER = config->qdec0.threshold_lower;
151 		gpio_pinmux_cofiguration(config->qdec0.pin_number_pad[0],
152 				(uint16_t)(config->qdec0.pinmux_sel_pad[0]));
153 		gpio_pinmux_cofiguration(config->qdec0.pin_number_pad[1],
154 				(uint16_t)(config->qdec0.pinmux_sel_pad[1]));
155 		quad_decoder_enable(QDEC_AXIS_X);
156 	}
157 	if (config->qdec_enalbe & (1 << QDEC_AXIS_Y)) {
158 		system_peripheral_reset(PERIPHERAL_QDEC1);
159 		LPMCU_MISC_REGS0->QUAD_DEC1_CTRL.bit.CLOCK_SEL  = config->qdec1.clock_sel;
160 		LPMCU_MISC_REGS0->QUAD_DEC1_THRESHOLD.bit.UPPER = config->qdec1.threshold_upper;
161 		LPMCU_MISC_REGS0->QUAD_DEC1_THRESHOLD.bit.LOWER = config->qdec1.threshold_lower;
162 		gpio_pinmux_cofiguration(config->qdec1.pin_number_pad[0],
163 				(uint16_t)(config->qdec1.pinmux_sel_pad[0]));
164 		gpio_pinmux_cofiguration(config->qdec1.pin_number_pad[1],
165 				(uint16_t)(config->qdec1.pinmux_sel_pad[1]));
166 		quad_decoder_enable(QDEC_AXIS_Y);
167 	}
168 	if (config->qdec_enalbe & (1 << QDEC_AXIS_Z)) {
169 		system_peripheral_reset(PERIPHERAL_QDEC2);
170 		LPMCU_MISC_REGS0->QUAD_DEC2_CTRL.bit.CLOCK_SEL  = config->qdec2.clock_sel;
171 		LPMCU_MISC_REGS0->QUAD_DEC2_THRESHOLD.bit.UPPER = config->qdec2.threshold_upper;
172 		LPMCU_MISC_REGS0->QUAD_DEC2_THRESHOLD.bit.LOWER = config->qdec2.threshold_lower;
173 		gpio_pinmux_cofiguration(config->qdec2.pin_number_pad[0],
174 				(uint16_t)(config->qdec2.pinmux_sel_pad[0]));
175 		gpio_pinmux_cofiguration(config->qdec2.pinmux_sel_pad[1],
176 				(uint16_t)(config->qdec2.pinmux_sel_pad[1]));
177 		quad_decoder_enable(QDEC_AXIS_Z);
178 	}
179 	LPMCU_MISC_REGS0->IRQ_MUX_IO_SEL_4.bit.MUX_18 =  LPMCU_MISC_REGS_IRQ_MUX_IO_SEL_4_MUX_18_19_Val;
180 	system_register_isr(33, (uint32_t)quad_decoder_isr_handler);
181 }
182 
183 /**
184  * \brief Enable QUAD DECODER module instance.
185  *
186  * Enable the QUAD DECODER module instance, based on the given axis
187  *
188  * \param[in]     qdec         Axis(x,y,z) of QUAD DECODER instance
189  */
quad_decoder_enable(enum quad_decoder_axis qdec)190 void quad_decoder_enable(enum quad_decoder_axis qdec)
191 {
192 	switch (qdec) {
193 	case QDEC_AXIS_X:
194 		LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg |=
195 				LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC0_CLK_EN;
196 		LPMCU_MISC_REGS0->QUAD_DEC0_CTRL.reg |=
197 				LPMCU_MISC_REGS_QUAD_DEC0_CTRL_ENABLE;
198 		break;
199 	case QDEC_AXIS_Y:
200 		LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg |=
201 				LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC1_CLK_EN;
202 		LPMCU_MISC_REGS0->QUAD_DEC1_CTRL.reg |=
203 				LPMCU_MISC_REGS_QUAD_DEC1_CTRL_ENABLE;
204 		break;
205 	case QDEC_AXIS_Z:
206 		LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg |=
207 				LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC2_CLK_EN;
208 		LPMCU_MISC_REGS0->QUAD_DEC2_CTRL.reg |=
209 				LPMCU_MISC_REGS_QUAD_DEC2_CTRL_ENABLE;
210 		break;
211 	}
212 }
213 
214 /**
215  * \brief Disable QUAD DECODER module instance.
216  *
217  * Disable the QUAD DECODER module instance, based on the given axis
218  *
219  * \param[in]     qdec         Axis(x,y,z) of QUAD DECODER instance
220  */
quad_decoder_disable(enum quad_decoder_axis qdec)221 void quad_decoder_disable(enum quad_decoder_axis qdec)
222 {
223 	switch (qdec) {
224 	case QDEC_AXIS_X:
225 		LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg &=
226 				~LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC0_CLK_EN;
227 		LPMCU_MISC_REGS0->QUAD_DEC0_CTRL.reg &=
228 				~LPMCU_MISC_REGS_QUAD_DEC0_CTRL_ENABLE;
229 		break;
230 	case QDEC_AXIS_Y:
231 		LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg &=
232 				~LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC1_CLK_EN;
233 		LPMCU_MISC_REGS0->QUAD_DEC1_CTRL.reg &=
234 				~LPMCU_MISC_REGS_QUAD_DEC1_CTRL_ENABLE;
235 		break;
236 	case QDEC_AXIS_Z:
237 		LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg &=
238 				~LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC2_CLK_EN;
239 		LPMCU_MISC_REGS0->QUAD_DEC2_CTRL.reg &=
240 				~LPMCU_MISC_REGS_QUAD_DEC2_CTRL_ENABLE;
241 		break;
242 	}
243 }
244 
245 /**
246  * \brief Get QUAD DECODER current counter
247  *
248  * Get the current counter of quad decoder, based on the given axis
249  *
250  * \param[in]     qdec         Axis(x,y,z) of QUAD DECODER instance
251  *
252  * \return The current counter of quad decoder instance
253  */
quad_decoder_get_counter(enum quad_decoder_axis qdec)254 int16_t quad_decoder_get_counter(enum quad_decoder_axis qdec)
255 {
256 	switch (qdec) {
257 	case QDEC_AXIS_X:
258 		return LPMCU_MISC_REGS0->QUAD_DEC0_STATUS.bit.COUNT;
259 	case QDEC_AXIS_Y:
260 		return LPMCU_MISC_REGS0->QUAD_DEC1_STATUS.bit.COUNT;
261 	case QDEC_AXIS_Z:
262 		return LPMCU_MISC_REGS0->QUAD_DEC2_STATUS.bit.COUNT;
263 	}
264 	return 0;
265 }
266 
267 /**
268  * \brief Registers a callback.
269  *
270  * Registers and enable a callback function which is implemented by the user.
271  *
272  * \param[in]     callback_func Pointer to callback function
273  */
quad_decoder_register_callback(enum quad_decoder_axis qdec,quad_decoder_callback_t fun)274 void quad_decoder_register_callback(enum quad_decoder_axis qdec, quad_decoder_callback_t fun)
275 {
276 	switch (qdec) {
277 	case QDEC_AXIS_X:
278 		quad_decoder0_callback = fun;
279 		break;
280 	case QDEC_AXIS_Y:
281 		quad_decoder1_callback = fun;
282 		break;
283 	case QDEC_AXIS_Z:
284 		quad_decoder2_callback = fun;
285 		break;
286 	}
287 }
288 
289 /**
290  * \brief Unregisters a callback.
291  *
292  * Unregisters and disable a callback function implemented by the user.
293  *
294  */
quad_decoder_unregister_callback(enum quad_decoder_axis qdec)295 void quad_decoder_unregister_callback(enum quad_decoder_axis qdec)
296 {
297 	switch (qdec) {
298 	case QDEC_AXIS_X:
299 		quad_decoder0_callback = NULL;
300 		break;
301 	case QDEC_AXIS_Y:
302 		quad_decoder1_callback = NULL;
303 		break;
304 	case QDEC_AXIS_Z:
305 		quad_decoder2_callback = NULL;
306 		break;
307 	}
308 }