From b12c69bac7a02ea161ebc02ce7323e82bebe7b23 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Sun, 13 Apr 2008 20:03:08 +0000 Subject: ADC driver for Gigabeat S - a bit on the general side for now. Needs to have scales set properly (what physical value a reading represents isn't clear from the docs or I'm just lazy atm). Throw-in a _bunch_ more reg defines for the PMIC. Show all 16 raw channels values in debug menu. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17100 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/imx31/gigabeat-s/adc-imx31.c | 103 ++++++++++++++++++----- 1 file changed, 81 insertions(+), 22 deletions(-) (limited to 'firmware/target/arm/imx31/gigabeat-s/adc-imx31.c') diff --git a/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c b/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c index 1fd2247ef1..b1b79a7989 100644 --- a/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c @@ -7,7 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Copyright (C) 2006 by Wade Brown + * Copyright (C) 2008 by Michael Sevakis * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. @@ -16,37 +16,96 @@ * KIND, either express or implied. * ****************************************************************************/ -#include "cpu.h" +#include "config.h" +#include "system.h" +#include "mc13783.h" #include "adc-target.h" #include "kernel.h" -/* prototypes */ -static unsigned short __adc_read(int channel); -static void adc_tick(void); - -void adc_init(void) +/* Do this so we may read all channels in a single SPI message */ +static const unsigned char reg_array[NUM_ADC_CHANNELS/2] = { -} + MC13783_ADC2, + MC13783_ADC2, + MC13783_ADC2, + MC13783_ADC2, + MC13783_ADC2, + MC13783_ADC2, + MC13783_ADC2, + MC13783_ADC2, +}; -/* Called to get the recent ADC reading */ -inline unsigned short adc_read(int channel) +static uint32_t channels[2][NUM_ADC_CHANNELS/2]; +static struct wakeup adc_wake; +static struct mutex adc_mtx; +static long last_adc_read[2]; /* One for each input group */ + +/* Read 10-bit ADC channel */ +unsigned short adc_read(int channel) { - (void)channel; - return 0; + uint32_t data; + int input_select; + + if ((unsigned)channel >= NUM_ADC_CHANNELS) + return ADC_READ_ERROR; + + mutex_lock(&adc_mtx); + + input_select = channel >> 3; + + /* Limit the traffic through here */ + if (TIME_AFTER(current_tick, last_adc_read[input_select])) + { + /* Keep enable, start conversion, increment from channel 0, + * increment from channel 4 */ + uint32_t adc1 = MC13783_ADEN | MC13783_ASC | MC13783_ADA1w(0) | + MC13783_ADA2w(4); + + if (input_select == 1) + adc1 |= MC13783_ADSEL; /* 2nd set of inputs */ + + /* Start conversion */ + mc13783_write(MC13783_ADC1, adc1); + + /* Wait for done signal */ + wakeup_wait(&adc_wake, TIMEOUT_BLOCK); + + /* Read all 8 channels that are converted - two channels in each + * word. */ + mc13783_read_regset(reg_array, channels[input_select], + NUM_ADC_CHANNELS/2); + + last_adc_read[input_select] = current_tick; + } + + data = channels[input_select][channel & 7]; + + mutex_unlock(&adc_mtx); + + /* Extract the bitfield depending on even or odd channel number */ + return (channel & 1) ? MC13783_ADD2r(data) : MC13783_ADD1r(data); } -/** - * Read the ADC by polling - * @param channel The ADC channel to read - * @return 10bit reading from ADC channel or ADC_READ_ERROR if timeout - */ -static unsigned short __adc_read(int channel) +/* Called when conversion is complete */ +void adc_done(void) { - (void)channel; - return 0; + wakeup_signal(&adc_wake); } -/* add this to the tick so that the ADC converts are done in the background */ -static void adc_tick(void) +void adc_init(void) { + wakeup_init(&adc_wake); + mutex_init(&adc_mtx); + + /* Init so first reads get data */ + last_adc_read[0] = last_adc_read[1] = current_tick-1; + + /* Enable increment-by-read, thermistor */ + mc13783_write(MC13783_ADC0, MC13783_ADINC2 | MC13783_ADINC1 | + MC13783_RTHEN); + /* Enable ADC, set multi-channel mode */ + mc13783_write(MC13783_ADC1, MC13783_ADEN); + /* Enable the ADCDONE interrupt - notifications are dispatched by + * event handler. */ + mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_ADCDONE); } -- cgit v1.2.3