Remove the PIO config from the clkout_on() function.
[dtplug] / drivers / adc.c
1 /****************************************************************************
2  *  drivers/adc.c
3  *
4  * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *************************************************************************** */
23 /***************************************************************************** */
24 /*                Analog to Digital Converter (ADC)                            */
25 /***************************************************************************** */
27 /* ADC driver for the integrated ADC module of the LPC176x.
28  * Refer to LPC176x documentation (UM10360.pdf) for more information.
29  */
31 #include <stdint.h>
32 #include "core/lpc_regs_17xx.h"
33 #include "core/lpc_core_cm3.h"
34 #include "core/system.h"
35 #include "core/pio.h"
36 #include "drivers/adc.h"
38 /* Should be as near to 13MHz as possible, but under. */
39 #define adc_clk_Val  13000000
43 /***************************************************************************** */
44 /* Generic ADC handler */
45 void ADC_Handler(void)
46 {
47 /*
48         volatile struct lpc_adc* adc = LPC_ADC;
49         uint32_t status = adc->status;
50 */
51         /* .... What to do ... is specific to your application */
52         /* FIXME : Add an handler callback. */
53 }
55 /* Read the conversion from the given channel (0 to 7) 
56  * This function reads the conversion value directly in the data register and
57  * always returns a value.
58  * Return 0 if the value is a new one and no overrun occured.
59  * Return -1 if channel does not exist
60  * Retuen 1 if the value is an old one
61  * Return 2 if an overrun occured
62  */
63 int adc_get_value(uint16_t * val, int channel)
64 {
65         struct lpc_adc* adc = LPC_ADC;
66         uint32_t save_reg = 0;
68         if (channel > 7)
69                 return -1;
71         /* Save the whole register as some bits are cleared when register is read */
72         save_reg = adc->data[channel];
73         *val = ((save_reg >> LPC_ADC_RESULT_SHIFT) & LPC_ADC_RESULT_MASK);
74         /* Has this conversion value been already read ? */
75         if (! (save_reg & LPC_ADC_CONV_DONE)) {
76                 return 1;
77         }
78         if (save_reg & LPC_ADC_OVERRUN) {
79                 return 2;
80         }
81         return 0;
82 }
84 /* Start a conversion on the given channel (0 to 7) */
85 void adc_start_convertion_once(unsigned int channel, int use_int)
86 {
87         struct lpc_adc* adc = LPC_ADC;
88         uint32_t reg_val = 0;
90         if (channel > 7)
91                 return;
93         /* Get a clean control register */
94         reg_val = adc->ctrl & ~(LPC_ADC_CHANNEL_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST);
96         /* Set conversion channel bit */
97         reg_val |= LPC_ADC_CHANNEL(channel);
99         /*  Use of interrupts for the specified channel ? */
100         if (use_int) {
101                 /* Set interrupt Bit */
102                 adc->int_en = LPC_ADC_CHANNEL(channel);
103         } else {
104                 adc->int_en = 0;
105         }
107         /* Start conversion */
108         reg_val |= LPC_ADC_START_CONV_NOW;
109         adc->ctrl = (reg_val & LPC_ADC_CTRL_MASK);
113 /* Start burst conversions.
114  * channels is a bit mask of requested channels.
115  * Use LPC_ADC_CHANNEL(x) (x = 0 .. 7) for channels selection.
116  */
117 void adc_start_burst_conversion(uint8_t channels)
119         struct lpc_adc* adc = LPC_ADC;
120         uint32_t reg_val = 0;
122         /* Get a clean control register */
123         reg_val = adc->ctrl & ~(LPC_ADC_CHANNEL_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST);
125         /* Set conversion channel bits and burst mode */
126         reg_val |= channels;
127         reg_val |= LPC_ADC_BURST;
129         /*  Use of interrupts for the specified channels ? */
130         /* FIXME : Need to choose between one single global interrupt or specific interrupts .... */
131         /* FIXME : Actually none. */
132         adc->int_en = 0;
134         /* Start conversion */
135         adc->ctrl = (reg_val & LPC_ADC_CTRL_MASK);
139 /* This should be used to configure conversion start on falling or rising edges of
140  * some signals, or on timer for burst conversions.
141  */
142 void adc_prepare_conversion_on_event(uint8_t channels, uint8_t event, int use_int)
144         struct lpc_adc* adc = LPC_ADC;
145         uint32_t reg_val = 0;
147         /* Get a clean control register */
148         reg_val = adc->ctrl & ~(LPC_ADC_CHANNEL_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST);
149         /* Set conversion channel bits and burst mode */
150         reg_val |= channels;
151         /* Set conversion condition bits */
152         switch (event) {
153                 case ADC_CONV_ON_CT32B0_MAT0_RISING :
154                         reg_val |= LPC_ADC_START_CONV_EVENT(LPC_ADC_START_CONV_EDGE_CT32B0_MAT0);
155                         reg_val |= LPC_ADC_START_EDGE_RISING;
156                         break;
157                 case ADC_CONV_ON_CT16B0_MAT0_RISING :
158                         reg_val |= LPC_ADC_START_CONV_EVENT(LPC_ADC_START_CONV_EDGE_CT16B0_MAT0);
159                         reg_val |= LPC_ADC_START_EDGE_RISING;
160                         break;
161                 default:
162                         break;
163         }
165         /*  Use of interrupts for the specified channel ? */
166         if (use_int) {
167                 /* FIXME : Need to choose between one single global interrupt or specific interrupts .... */
168         } else {
169                 adc->int_en = 0;
170         }
172         /* Enable conversion on selected event */
173         adc->ctrl = (reg_val & LPC_ADC_CTRL_MASK);
178 /***************************************************************************** */
179 /*   ADC Setup : private part : Clocks, Power and Mode   */
181 void adc_clk_update(void)
183         struct lpc_adc* adc = LPC_ADC;
184         uint32_t main_clock = get_main_clock();
185         uint32_t clkdiv = 0;
187         if (!subsystem_powered(LPC_ADC_POWER_ON)) {
188                 return;
189         }
190         /* Set CCLK divider for PCLK */
191         set_subsystem_clk_divider(LPC_ADC_PCLK, LPC_PCLK_CCLK);
192         /* Configure ADC clock to get the 13MHz sample clock */
193         clkdiv = (main_clock / adc_clk_Val);
194         adc->ctrl |= ((clkdiv & 0xFF) << 8);
198 void adc_on(void)
200         struct lpc_adc* adc = LPC_ADC;
202         /* Disable ADC Interrupt */
203         NVIC_DisableIRQ(ADC_IRQ);
205         /* Provide clock to ADC */
206         subsystem_power(LPC_ADC_POWER_ON, 1);
207         adc->ctrl = LPC_ADC_POWER_UP;
208         adc_clk_update();
210         /* Prevent unconfigured conversion start */
211         adc->ctrl &= ~LPC_ADC_START_CONV_MASK;
213         /* Remove the default global interrupt enabled setting */
214         adc->int_en = 0;
216         /* Enable ADC Interrupt */
217         NVIC_EnableIRQ(ADC_IRQ);
220 void adc_off(void)
222         /* Disable ADC Interrupt */
223         NVIC_DisableIRQ(ADC_IRQ);
224         /* Remove clock from ADC block */
225         subsystem_power(LPC_ADC_POWER_ON, 0);