From 696b9d146b69b36fc309233f62d43f4f57f26823 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Tue, 13 Sep 2011 23:40:09 +0000 Subject: imx233/fuze+: implement lradc function and adc on top of it git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30534 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/imx233/adc-imx233.c | 64 ++++++++- firmware/target/arm/imx233/adc-imx233.h | 38 ++++++ firmware/target/arm/imx233/lradc-imx233.c | 146 +++++++++++++++++++++ firmware/target/arm/imx233/lradc-imx233.h | 128 ++++++++++++++++++ .../arm/imx233/sansa-fuzeplus/adc-fuzeplus.c | 37 ++++++ .../target/arm/imx233/sansa-fuzeplus/adc-target.h | 35 +++++ 6 files changed, 446 insertions(+), 2 deletions(-) create mode 100644 firmware/target/arm/imx233/adc-imx233.h create mode 100644 firmware/target/arm/imx233/lradc-imx233.c create mode 100644 firmware/target/arm/imx233/lradc-imx233.h create mode 100644 firmware/target/arm/imx233/sansa-fuzeplus/adc-fuzeplus.c create mode 100644 firmware/target/arm/imx233/sansa-fuzeplus/adc-target.h (limited to 'firmware/target') diff --git a/firmware/target/arm/imx233/adc-imx233.c b/firmware/target/arm/imx233/adc-imx233.c index 8236f58767..4f183ac531 100644 --- a/firmware/target/arm/imx233/adc-imx233.c +++ b/firmware/target/arm/imx233/adc-imx233.c @@ -23,12 +23,72 @@ #include "adc.h" #include "adc-target.h" +/* dedicate two channels to temperature sensing + * dedicate channel 7 to battery + * and channel 6 to vddio */ +static int pmos_chan, nmos_chan; +static int battery_chan, vddio_chan; + void adc_init(void) { + imx233_lradc_init(); + battery_chan = 7; + imx233_lradc_reserve_channel(7); + vddio_chan = 6; + imx233_lradc_reserve_channel(6); + + pmos_chan = imx233_lradc_acquire_channel(0); + if(pmos_chan < 0) panicf("No LRADC channel for PMOS !"); + nmos_chan = imx233_lradc_acquire_channel(0); + if(nmos_chan < 0) panicf("No LRADC channel for NMOS !"); + + // setup them + imx233_lradc_setup_channel(battery_chan, false, false, 0, HW_LRADC_CHANNEL_BATTERY); + imx233_lradc_setup_channel(vddio_chan, false, false, 0, HW_LRADC_CHANNEL_VDDIO); + imx233_lradc_setup_channel(nmos_chan, false, false, 0, HW_LRADC_CHANNEL_NMOS_THIN); + imx233_lradc_setup_channel(pmos_chan, false, false, 0, HW_LRADC_CHANNEL_PMOS_THIN); +} + +int adc_read_physical_ex(int virt) +{ + imx233_lradc_clear_channel(virt); + imx233_lradc_kick_channel(virt); + imx233_lradc_wait_channel(virt); + int v = imx233_lradc_read_channel(virt); + return v; +} + +int adc_read_physical(int src) +{ + int virt = imx233_lradc_acquire_channel(TIMEOUT_BLOCK); + // divide by two for wider ranger + imx233_lradc_setup_channel(virt, false, false, 0, src); + int val = adc_read_physical_ex(virt); + imx233_lradc_release_channel(virt); + return val; +} + +unsigned short adc_read_virtual(int c) +{ + switch(c) + { + case IMX233_ADC_BATTERY: + return adc_read_physical_ex(battery_chan); + case IMX233_ADC_VDDIO: + return adc_read_physical_ex(vddio_chan); + case IMX233_ADC_DIE_TEMP: + // do kelvin to celsius conversion + return imx233_lradc_sense_die_temperature(nmos_chan, pmos_chan) - 273; + default: + return 0; + } } unsigned short adc_read(int channel) { - (void) channel; - return 0; + int c = imx233_adc_mapping[channel]; + if(c < 0) + return adc_read_virtual(c); + else + return adc_read_physical(c); } diff --git a/firmware/target/arm/imx233/adc-imx233.h b/firmware/target/arm/imx233/adc-imx233.h new file mode 100644 index 0000000000..6025fdcdf8 --- /dev/null +++ b/firmware/target/arm/imx233/adc-imx233.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef _ADC_IMX233_H_ +#define _ADC_IMX233_H_ + +#include "system.h" +#include "lradc-imx233.h" +#include "adc-imx233.h" + +/* Virtual channels */ +#define IMX233_ADC_BATTERY -1 /* Battery voltage (mV) */ +#define IMX233_ADC_DIE_TEMP -2 /* Die temperature (°C) */ +#define IMX233_ADC_VDDIO -3 /* VddIO voltage (mV) */ + +/* Channel mapping */ +extern int imx233_adc_mapping[]; +/* Channel names */ +extern const char *imx233_adc_channel_name[]; + +#endif diff --git a/firmware/target/arm/imx233/lradc-imx233.c b/firmware/target/arm/imx233/lradc-imx233.c new file mode 100644 index 0000000000..7da58c64b3 --- /dev/null +++ b/firmware/target/arm/imx233/lradc-imx233.c @@ -0,0 +1,146 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "system-target.h" +#include "lradc-imx233.h" + +static struct semaphore free_bm_sema; +static struct mutex free_bm_mutex; +static unsigned free_bm; + +void imx233_lradc_setup_channel(int channel, bool div2, bool acc, int nr_samples, int src) +{ + __REG_CLR(HW_LRADC_CHx(channel)) =HW_LRADC_CHx__NUM_SAMPLES_BM | HW_LRADC_CHx__ACCUMULATE; + __REG_SET(HW_LRADC_CHx(channel)) = nr_samples << HW_LRADC_CHx__NUM_SAMPLES_BP | + acc << HW_LRADC_CHx__ACCUMULATE; + if(div2) + __REG_SET(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__DIVIDE_BY_TWO(channel); + else + __REG_CLR(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__DIVIDE_BY_TWO(channel); + __REG_CLR(HW_LRADC_CTRL4) = HW_LRADC_CTRL4__LRADCxSELECT_BM(channel); + __REG_SET(HW_LRADC_CTRL4) = src << HW_LRADC_CTRL4__LRADCxSELECT_BP(channel); +} + +void imx233_lradc_setup_delay(int dchan, int trigger_lradc, int trigger_delays, + int loop_count, int delay) +{ + HW_LRADC_DELAYx(dchan) = + trigger_lradc << HW_LRADC_DELAYx__TRIGGER_LRADCS_BP | + trigger_delays << HW_LRADC_DELAYx__TRIGGER_DELAYS_BP | + loop_count << HW_LRADC_DELAYx__LOOP_COUNT_BP | + delay << HW_LRADC_DELAYx__DELAY_BP; +} + +void imx233_lradc_kick_channel(int channel) +{ + __REG_CLR(HW_LRADC_CTRL1) = HW_LRADC_CTRL1__LRADCx_IRQ(channel); + __REG_SET(HW_LRADC_CTRL0) = HW_LRADC_CTRL0__SCHEDULE(channel); +} + +void imx233_lradc_kick_delay(int dchan) +{ + __REG_SET(HW_LRADC_DELAYx(dchan)) = HW_LRADC_DELAYx__KICK; +} + +void imx233_lradc_wait_channel(int channel) +{ + /* wait for completion */ + while(!(HW_LRADC_CTRL1 & HW_LRADC_CTRL1__LRADCx_IRQ(channel))) + yield(); +} + +int imx233_lradc_read_channel(int channel) +{ + return __XTRACT_EX(HW_LRADC_CHx(channel), HW_LRADC_CHx__VALUE); +} + +void imx233_lradc_clear_channel(int channel) +{ + __REG_CLR(HW_LRADC_CHx(channel)) = HW_LRADC_CHx__VALUE_BM; +} + +int imx233_lradc_acquire_channel(int timeout) +{ + int w = semaphore_wait(&free_bm_sema, timeout); + if(w == OBJ_WAIT_TIMEDOUT) + return w; + mutex_lock(&free_bm_mutex); + int chan = find_first_set_bit(free_bm); + if(chan >= HW_LRADC_NUM_CHANNELS) + panicf("imx233_lradc_acquire_channel cannot find a free channel !"); + free_bm &= ~(1 << chan); + mutex_unlock(&free_bm_mutex); + return chan; +} + +void imx233_lradc_release_channel(int chan) +{ + mutex_lock(&free_bm_mutex); + free_bm |= 1 << chan; + mutex_unlock(&free_bm_mutex); + semaphore_release(&free_bm_sema); +} + +void imx233_lradc_reserve_channel(int channel) +{ + semaphore_wait(&free_bm_sema, TIMEOUT_NOBLOCK); + mutex_lock(&free_bm_mutex); + free_bm &= ~(1 << channel); + mutex_unlock(&free_bm_mutex); +} + +int imx233_lradc_sense_die_temperature(int nmos_chan, int pmos_chan) +{ + // mux sensors + __REG_CLR(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__TEMPSENSE_PWD; + imx233_lradc_clear_channel(nmos_chan); + imx233_lradc_clear_channel(pmos_chan); + // schedule both channels + imx233_lradc_kick_channel(nmos_chan); + imx233_lradc_kick_channel(pmos_chan); + // wait completion + imx233_lradc_wait_channel(nmos_chan); + imx233_lradc_wait_channel(pmos_chan); + // mux sensors + __REG_SET(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__TEMPSENSE_PWD; + // do the computation + int diff = imx233_lradc_read_channel(nmos_chan) - imx233_lradc_read_channel(pmos_chan); + // return diff * 1.012 / 4 + return (diff * 1012) / 4000; +} + +void imx233_lradc_init(void) +{ + mutex_init(&free_bm_mutex); + semaphore_init(&free_bm_sema, HW_LRADC_NUM_CHANNELS, HW_LRADC_NUM_CHANNELS); + free_bm = (1 << HW_LRADC_NUM_CHANNELS) - 1; + // enable block + imx233_reset_block(&HW_LRADC_CTRL0); + // disable ground ref + __REG_CLR(HW_LRADC_CTRL0) = HW_LRADC_CTRL0__ONCHIP_GROUNDREF; + // disable temperature sensors + __REG_CLR(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__TEMP_SENSOR_IENABLE0 | + HW_LRADC_CTRL2__TEMP_SENSOR_IENABLE1; + __REG_SET(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__TEMPSENSE_PWD; + // set frequency + __REG_CLR(HW_LRADC_CTRL3) = HW_LRADC_CTRL3__CYCLE_TIME_BM; + __REG_SET(HW_LRADC_CTRL3) = HW_LRADC_CTRL3__CYCLE_TIME__6MHz; +} diff --git a/firmware/target/arm/imx233/lradc-imx233.h b/firmware/target/arm/imx233/lradc-imx233.h new file mode 100644 index 0000000000..a72916054a --- /dev/null +++ b/firmware/target/arm/imx233/lradc-imx233.h @@ -0,0 +1,128 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __lradc_imx233__ +#define __lradc_imx233__ + +#include "config.h" +#include "cpu.h" + +#include "cpu.h" +#include "system.h" +#include "system-target.h" + +#define HW_LRADC_BASE 0x80050000 + +#define HW_LRADC_CTRL0 (*(volatile uint32_t *)(HW_LRADC_BASE + 0x0)) +#define HW_LRADC_CTRL0__ONCHIP_GROUNDREF (1 << 21) +#define HW_LRADC_CTRL0__SCHEDULE(x) (1 << (x)) + +#define HW_LRADC_CTRL1 (*(volatile uint32_t *)(HW_LRADC_BASE + 0x10)) +#define HW_LRADC_CTRL1__LRADCx_IRQ(x) (1 << (x)) +#define HW_LRADC_CTRL1__LRADCx_IRQ_EN(x) (1 << ((x) + 16)) + +#define HW_LRADC_CTRL2 (*(volatile uint32_t *)(HW_LRADC_BASE + 0x20)) +#define HW_LRADC_CTRL2__TEMP_ISRC1_BP 4 +#define HW_LRADC_CTRL2__TEMP_ISRC1_BM 0xf0 +#define HW_LRADC_CTRL2__TEMP_ISRC0_BP 0 +#define HW_LRADC_CTRL2__TEMP_ISRC0_BM 0xf +#define HW_LRADC_CTRL2__TEMP_SENSOR_IENABLE0 (1 << 8) +#define HW_LRADC_CTRL2__TEMP_SENSOR_IENABLE1 (1 << 9) +#define HW_LRADC_CTRL2__TEMPSENSE_PWD (1 << 15) +#define HW_LRADC_CTRL2__DIVIDE_BY_TWO(x) (1 << ((x) + 24)) + +#define HW_LRADC_CTRL3 (*(volatile uint32_t *)(HW_LRADC_BASE + 0x30)) +#define HW_LRADC_CTRL3__CYCLE_TIME_BM 0x300 +#define HW_LRADC_CTRL3__CYCLE_TIME_BP 8 +#define HW_LRADC_CTRL3__CYCLE_TIME__6MHz (0 << 8) +#define HW_LRADC_CTRL3__CYCLE_TIME__4MHz (1 << 8) +#define HW_LRADC_CTRL3__CYCLE_TIME__3MHz (2 << 8) +#define HW_LRADC_CTRL3__CYCLE_TIME__2MHz (3 << 8) + +#define HW_LRADC_STATUS (*(volatile uint32_t *)(HW_LRADC_BASE + 0x40)) + +#define HW_LRADC_CHx(x) (*(volatile uint32_t *)(HW_LRADC_BASE + 0x50 + (x) * 0x10)) +#define HW_LRADC_CHx__NUM_SAMPLES_BM (0xf << 24) +#define HW_LRADC_CHx__NUM_SAMPLES_BP 24 +#define HW_LRADC_CHx__ACCUMULATE 29 +#define HW_LRADC_CHx__VALUE_BM 0x3ffff +#define HW_LRADC_CHx__VALUE_BP 0 + +#define HW_LRADC_DELAYx(x) (*(volatile uint32_t *)(HW_LRADC_BASE + 0xD0 + (x) * 0x10)) +#define HW_LRADC_DELAYx__DELAY_BP 0 +#define HW_LRADC_DELAYx__DELAY_BM 0x7ff +#define HW_LRADC_DELAYx__LOOP_COUNT_BP 11 +#define HW_LRADC_DELAYx__LOOP_COUNT_BM (0x1f << 11) +#define HW_LRADC_DELAYx__TRIGGER_DELAYS_BP 16 +#define HW_LRADC_DELAYx__TRIGGER_DELAYS_BM (0xf << 16) +#define HW_LRADC_DELAYx__KICK (1 << 20) +#define HW_LRADC_DELAYx__TRIGGER_LRADCS_BP 24 +#define HW_LRADC_DELAYx__TRIGGER_LRADCS_BM (0xff << 24) + +#define HW_LRADC_CONVERSION (*(volatile uint32_t *)(HW_LRADC_BASE + 0x130)) +#define HW_LRADC_CONVERSION__SCALED_BATT_VOLTAGE_BP 0 +#define HW_LRADC_CONVERSION__SCALED_BATT_VOLTAGE_BM 0x3ff +#define HW_LRADC_CONVERSION__SCALE_FACTOR_BM (3 << 16) +#define HW_LRADC_CONVERSION__SCALE_FACTOR_BP 16 +#define HW_LRADC_CONVERSION__SCALE_FACTOR__LI_ION (2 << 16) +#define HW_LRADC_CONVERSION__AUTOMATIC (1 << 20) + +#define HW_LRADC_CTRL4 (*(volatile uint32_t *)(HW_LRADC_BASE + 0x140)) +#define HW_LRADC_CTRL4__LRADCxSELECT_BM(x) (0xf << ((x) * 4)) +#define HW_LRADC_CTRL4__LRADCxSELECT_BP(x) ((x) * 4) + +#define HW_LRADC_VERSION (*(volatile uint32_t *)(HW_LRADC_BASE + 0x150)) + +#define HW_LRADC_NUM_CHANNELS 8 +#define HW_LRADC_NUM_DELAYS 4 + +#define HW_LRADC_CHANNEL(x) (x) +#define HW_LRADC_CHANNEL_VDDIO HW_LRADC_CHANNEL(6) +#define HW_LRADC_CHANNEL_BATTERY HW_LRADC_CHANNEL(7) +#define HW_LRADC_CHANNEL_PMOS_THIN HW_LRADC_CHANNEL(8) +#define HW_LRADC_CHANNEL_NMOS_THIN HW_LRADC_CHANNEL(9) +#define HW_LRADC_CHANNEL_NMOS_THICK HW_LRADC_CHANNEL(10) +#define HW_LRADC_CHANNEL_PMOS_THICK HW_LRADC_CHANNEL(11) +#define HW_LRADC_CHANNEL_PMOS_THICK HW_LRADC_CHANNEL(11) +#define HW_LRADC_CHANNEL_USB_DP HW_LRADC_CHANNEL(12) +#define HW_LRADC_CHANNEL_USB_DN HW_LRADC_CHANNEL(13) +#define HW_LRADC_CHANNEL_VBG HW_LRADC_CHANNEL(14) +#define HW_LRADC_CHANNEL_5V HW_LRADC_CHANNEL(15) + +void imx233_lradc_init(void); +void imx233_lradc_setup_channel(int channel, bool div2, bool acc, int nr_samples, int src); +void imx233_lradc_setup_delay(int dchan, int trigger_lradc, int trigger_delays, + int loop_count, int delay); +void imx233_lradc_kick_channel(int channel); +void imx233_lradc_kick_delay(int dchan); +void imx233_lradc_wait_channel(int channel); +int imx233_lradc_read_channel(int channel); +void imx233_lradc_clear_channel(int channel); +// acquire a virtual channel, returns -1 on timeout, channel otherwise */ +int imx233_lradc_acquire_channel(int timeout); +void imx233_lradc_release_channel(int chan); +// doesn't check that channel is in use! +void imx233_lradc_reserve_channel(int channel); + +/* enable sensing and return temperature in kelvin, + * channels must already be configured as nmos and pmos */ +int imx233_lradc_sense_die_temperature(int nmos_chan, int pmos_chan); + +#endif /* __lradc_imx233__ */ diff --git a/firmware/target/arm/imx233/sansa-fuzeplus/adc-fuzeplus.c b/firmware/target/arm/imx233/sansa-fuzeplus/adc-fuzeplus.c new file mode 100644 index 0000000000..8a99d19323 --- /dev/null +++ b/firmware/target/arm/imx233/sansa-fuzeplus/adc-fuzeplus.c @@ -0,0 +1,37 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "adc-target.h" + +int imx233_adc_mapping[] = +{ + [ADC_BATTERY] = IMX233_ADC_BATTERY, + [ADC_DIE_TEMP] = IMX233_ADC_DIE_TEMP, + [ADC_VDDIO] = IMX233_ADC_VDDIO, + [ADC_5V] = HW_LRADC_CHANNEL_5V, +}; + +const char *imx233_adc_channel_name[] = +{ + "Battery(mV)", + "Die temperature(°C)", + "VddIO", + "5V", +}; diff --git a/firmware/target/arm/imx233/sansa-fuzeplus/adc-target.h b/firmware/target/arm/imx233/sansa-fuzeplus/adc-target.h new file mode 100644 index 0000000000..ea0102d5c1 --- /dev/null +++ b/firmware/target/arm/imx233/sansa-fuzeplus/adc-target.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef _ADC_TARGET_H_ +#define _ADC_TARGET_H_ + +#include "system.h" +#include "lradc-imx233.h" +#include "adc-imx233.h" + +#define NUM_ADC_CHANNELS 4 + +#define ADC_BATTERY 0 +#define ADC_DIE_TEMP 1 +#define ADC_VDDIO 2 +#define ADC_5V 3 + +#endif -- cgit v1.2.3