summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCástor Muñoz <cmvidal@gmail.com>2016-08-12 02:37:45 +0200
committerCástor Muñoz <cmvidal@gmail.com>2016-08-12 14:17:46 +0200
commitadbd2969e6e6fd584d46ef60a3fa40bf878d7e00 (patch)
tree628a89d0e63cd338bbd741702c9b36010f679437
parenta25d0c58aa801087e80b479a7f536d519a422891 (diff)
downloadrockbox-adbd2969e6e6fd584d46ef60a3fa40bf878d7e00.tar.gz
rockbox-adbd2969e6e6fd584d46ef60a3fa40bf878d7e00.tar.bz2
rockbox-adbd2969e6e6fd584d46ef60a3fa40bf878d7e00.zip
iPod Classic: ADC updates
Add code to read USB D+/D- and accessory ADCs, it is shown in HW debug menu, might be useful in future for RB and/or the bootloader to identify external USB chargers. Change-Id: Ia48ca5e06bb7ddc52bb55abedde6734653ce8dba
-rw-r--r--firmware/export/pcf5063x.h8
-rw-r--r--firmware/target/arm/s5l8702/debug-s5l8702.c12
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/adc-ipod6g.c84
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/adc-target.h20
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c108
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/pmu-target.h15
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c11
7 files changed, 201 insertions, 57 deletions
diff --git a/firmware/export/pcf5063x.h b/firmware/export/pcf5063x.h
index f5f177ace7..2751b67b57 100644
--- a/firmware/export/pcf5063x.h
+++ b/firmware/export/pcf5063x.h
@@ -198,12 +198,12 @@ enum pcf5063X_reg_mbcc2 {
enum pcf5063X_reg_adcc1 {
PCF5063X_ADCC1_ADCSTART = 0x01,
- PCF5063X_ADCC1_RES_10BIT = 0x02,
+ PCF5063X_ADCC1_RES_10BIT = 0x00,
+ PCF5063X_ADCC1_RES_8BIT = 0x02,
PCF5063X_ADCC1_AVERAGE_NO = 0x00,
PCF5063X_ADCC1_AVERAGE_4 = 0x04,
PCF5063X_ADCC1_AVERAGE_8 = 0x08,
PCF5063X_ADCC1_AVERAGE_16 = 0x0c,
-
PCF5063X_ADCC1_MUX_BATSNS_RES = 0x00,
PCF5063X_ADCC1_MUX_BATSNS_SUBTR = 0x10,
PCF5063X_ADCC1_MUX_ADCIN2_RES = 0x20,
@@ -211,6 +211,7 @@ enum pcf5063X_reg_adcc1 {
PCF5063X_ADCC1_MUX_BATTEMP = 0x60,
PCF5063X_ADCC1_MUX_ADCIN1 = 0x70,
};
+#define PCF5063X_ADCC1_RES_MASK 0x02
#define PCF5063X_ADCC1_AVERAGE_MASK 0x0c
#define PCF5063X_ADCC1_ADCMUX_MASK 0xf0
@@ -219,9 +220,11 @@ enum pcf5063X_reg_adcc2 {
PCF5063X_ADCC2_RATIO_BATTEMP = 0x01,
PCF5063X_ADCC2_RATIO_ADCIN1 = 0x02,
PCF5063X_ADCC2_RATIO_BOTH = 0x03,
+ PCF5063X_ADCC2_RATIOSETTL_10US = 0x00,
PCF5063X_ADCC2_RATIOSETTL_100US = 0x04,
};
#define PCF5063X_ADCC2_RATIO_MASK 0x03
+#define PCF5063X_ADCC2_RATIOSETTL_MASK 0x04
enum pcf5063X_reg_adcc3 {
PCF5063X_ADCC3_ACCSW_EN = 0x01,
@@ -229,6 +232,7 @@ enum pcf5063X_reg_adcc3 {
PCF5063X_ADCC3_RES_DIV_TWO = 0x10,
PCF5063X_ADCC3_RES_DIV_THREE = 0x00,
};
+#define PCF5063X_ADCC3_RES_DIV_MASK 0x10
enum pcf5063X_reg_adcs3 {
PCF5063X_ADCS3_REF_NTCSW = 0x00,
diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c
index a61a728d43..1bf59e94fe 100644
--- a/firmware/target/arm/s5l8702/debug-s5l8702.c
+++ b/firmware/target/arm/s5l8702/debug-s5l8702.c
@@ -19,6 +19,7 @@
*
****************************************************************************/
+#include <stdio.h>
#include <stdbool.h>
#include "system.h"
#include "config.h"
@@ -28,6 +29,7 @@
#include "font.h"
#include "storage.h"
#include "power.h"
+#include "adc.h"
#include "pmu-target.h"
#include "pcm-target.h"
#ifdef HAVE_SERIAL
@@ -134,11 +136,19 @@ bool dbg_hw_info(void)
pmu_accessory_present() ? "true" : "false");
#endif
line++;
+ _DEBUG_PRINTF("ADC:");
+ _DEBUG_PRINTF("%s: %d mV", adc_name(ADC_BATTERY),
+ adc_read_battery_voltage());
+ _DEBUG_PRINTF("%s: %d Ohms", adc_name(ADC_ACCESSORY),
+ adc_read_accessory_resistor());
+ _DEBUG_PRINTF("USB D+: %d mV", adc_read_usbdata_voltage(true));
+ _DEBUG_PRINTF("USB D-: %d mV", adc_read_usbdata_voltage(false));
+ line++;
extern unsigned long i2c_rd_err, i2c_wr_err;
_DEBUG_PRINTF("i2c rd/wr errors: %lu/%lu", i2c_rd_err, i2c_wr_err);
}
#ifdef UC870X_DEBUG
- else if(state==2)
+ else if(state==(max_states-1))
{
extern struct uartc_port ser_port;
bool opened = !!ser_port.uartc->port_l[ser_port.id];
diff --git a/firmware/target/arm/s5l8702/ipod6g/adc-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/adc-ipod6g.c
index 201af5ee00..fbe5ef805e 100644
--- a/firmware/target/arm/s5l8702/ipod6g/adc-ipod6g.c
+++ b/firmware/target/arm/s5l8702/ipod6g/adc-ipod6g.c
@@ -18,7 +18,7 @@
* KIND, either express or implied.
*
****************************************************************************/
-
+
#include "config.h"
#include "inttypes.h"
@@ -28,12 +28,90 @@
#include "pmu-target.h"
#include "kernel.h"
+
+/* MS_TO_TICKS converts a milisecond time period into the
+ * corresponding amount of ticks. If the time period cannot
+ * be accurately measured in ticks it will round up.
+ */
+#define MS_PER_HZ (1000/HZ)
+#define MS_TO_TICKS(x) (((x)+MS_PER_HZ-1)/MS_PER_HZ)
+
+static const struct pmu_adc_channel adc_channels[] =
+{
+ [ADC_BATTERY] =
+ {
+ .name = "Battery",
+ .adcc1 = PCF5063X_ADCC1_MUX_BATSNS_SUBTR
+ | PCF5063X_ADCC1_AVERAGE_4
+ | PCF5063X_ADCC1_RES_10BIT,
+ },
+
+ [ADC_USBDATA] =
+ {
+ .name = "USB D+/D-",
+ .adcc1 = PCF5063X_ADCC1_MUX_ADCIN2_RES
+ | PCF5063X_ADCC1_AVERAGE_16
+ | PCF5063X_ADCC1_RES_10BIT,
+ .adcc3 = PCF5063X_ADCC3_RES_DIV_THREE,
+ },
+
+ [ADC_ACCESSORY] =
+ {
+ .name = "Accessory",
+ .adcc1 = PCF5063X_ADCC1_MUX_ADCIN1
+ | PCF5063X_ADCC1_AVERAGE_16
+ | PCF5063X_ADCC1_RES_10BIT,
+ .adcc2 = PCF5063X_ADCC2_RATIO_ADCIN1
+ | PCF5063X_ADCC2_RATIOSETTL_10US,
+ .adcc3 = PCF5063X_ADCC3_ACCSW_EN,
+ .bias_dly = MS_TO_TICKS(50),
+ },
+};
+
+const char *adc_name(int channel)
+{
+ return adc_channels[channel].name;
+}
+
+unsigned short adc_read_millivolts(int channel)
+{
+ const struct pmu_adc_channel *ch = &adc_channels[channel];
+ return pmu_adc_raw2mv(ch, pmu_read_adc(ch));
+}
+
+/* Returns battery voltage [millivolts] */
+unsigned int adc_read_battery_voltage(void)
+{
+ return adc_read_millivolts(ADC_BATTERY);
+}
+
+/* Returns USB D+/D- voltage from ADC [millivolts] */
+unsigned int adc_read_usbdata_voltage(bool dp)
+{
+ unsigned int mvolts;
+ int gpio = dp ? 0xb0300 : 0xb0200; /* select D+/D- */
+ GPIOCMD = gpio | 0xf; /* route to ADCIN2 */
+ mvolts = adc_read_millivolts(ADC_USBDATA);
+ GPIOCMD = gpio | 0xe; /* unroute */
+ return mvolts;
+}
+
+/* Returns resistor connected to "Accessory identify" pin [ohms] */
+#define IAP_DEVICE_RESISTOR 100000 /* ohms */
+int adc_read_accessory_resistor(void)
+{
+ int raw = pmu_read_adc(&adc_channels[ADC_ACCESSORY]);
+ return (1023-raw) ? raw * IAP_DEVICE_RESISTOR / (1023-raw)
+ : -1 /* open circuit */;
+}
+
+
+/* API functions */
unsigned short adc_read(int channel)
{
- return pmu_read_adc(channel);
+ return pmu_read_adc(&adc_channels[channel]);
}
void adc_init(void)
{
}
-
diff --git a/firmware/target/arm/s5l8702/ipod6g/adc-target.h b/firmware/target/arm/s5l8702/ipod6g/adc-target.h
index d4dce3d31f..bedc0a8447 100644
--- a/firmware/target/arm/s5l8702/ipod6g/adc-target.h
+++ b/firmware/target/arm/s5l8702/ipod6g/adc-target.h
@@ -21,13 +21,23 @@
#ifndef _ADC_TARGET_H_
#define _ADC_TARGET_H_
-#define NUM_ADC_CHANNELS 4
+#include <stdbool.h>
+#include "config.h"
-#define ADC_UNKNOWN_0 0
-#define ADC_UNKNOWN_1 1
-#define ADC_BATTERY 2
-#define ADC_UNKNOWN_3 3
+enum
+{
+ ADC_BATTERY = 0,
+ ADC_USBDATA,
+ ADC_ACCESSORY,
+ NUM_ADC_CHANNELS
+};
#define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */
+unsigned short adc_read_millivolts(int channel);
+unsigned int adc_read_battery_voltage(void);
+unsigned int adc_read_usbdata_voltage(bool dp);
+int adc_read_accessory_resistor(void);
+const char *adc_name(int channel);
+
#endif
diff --git a/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c
index c439a30fc1..d282a48d5b 100644
--- a/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c
+++ b/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c
@@ -24,12 +24,11 @@
#include "thread.h"
#include "pmu-target.h"
+#include "adc-target.h"
#include "i2c-s5l8702.h"
#include "gpio-s5l8702.h"
-static struct mutex pmu_adc_mutex;
-
int pmu_read_multiple(int address, int count, unsigned char* buffer)
{
return i2c_read(0, 0xe6, address, count, buffer);
@@ -54,35 +53,6 @@ int pmu_write(int address, unsigned char val)
return pmu_write_multiple(address, 1, &val);
}
-int pmu_read_adc(unsigned int adc)
-{
- int data = 0;
- mutex_lock(&pmu_adc_mutex);
- pmu_write(0x54, 5 | (adc << 4));
- while ((data & 0x80) == 0)
- {
- yield();
- data = pmu_read(0x57);
- }
- int value = (pmu_read(0x55) << 2) | (data & 3);
- mutex_unlock(&pmu_adc_mutex);
- return value;
-}
-
-/* millivolts */
-int pmu_read_battery_voltage(void)
-{
- return (pmu_read_adc(1) * 2000 / 1023) + 2250;
-}
-
-/* milliamps */
-int pmu_read_battery_current(void)
-{
-//TODO: Figure out how to read the battery current
-// return pmu_read_adc(2);
- return 0;
-}
-
void pmu_ldo_on_in_standby(unsigned int ldo, int onoff)
{
if (ldo < 4)
@@ -143,17 +113,86 @@ void pmu_write_rtc(unsigned char* buffer)
}
/*
+ * ADC
+ */
+#define ADC_FULL_SCALE 2000
+#define ADC_FULL_SCALE_VISA 2400
+#define ADC_SUBTR_OFFSET 2250
+
+static struct mutex pmu_adc_mutex;
+
+/* converts raw 8/10-bit value to millivolts */
+unsigned short pmu_adc_raw2mv(
+ const struct pmu_adc_channel *ch, unsigned short raw)
+{
+ int full_scale = ADC_FULL_SCALE;
+ int offset = 0;
+
+ switch (ch->adcc1 & PCF5063X_ADCC1_ADCMUX_MASK)
+ {
+ case PCF5063X_ADCC1_MUX_BATSNS_RES:
+ case PCF5063X_ADCC1_MUX_ADCIN2_RES:
+ full_scale *= ((ch->adcc1 & PCF5063X_ADCC3_RES_DIV_MASK) ==
+ PCF5063X_ADCC3_RES_DIV_TWO) ? 2 : 3;
+ break;
+ case PCF5063X_ADCC1_MUX_BATSNS_SUBTR:
+ case PCF5063X_ADCC1_MUX_ADCIN2_SUBTR:
+ offset = ADC_SUBTR_OFFSET;
+ break;
+ case PCF5063X_ADCC1_MUX_BATTEMP:
+ if (ch->adcc2 & PCF5063X_ADCC2_RATIO_BATTEMP)
+ full_scale = ADC_FULL_SCALE_VISA;
+ break;
+ case PCF5063X_ADCC1_MUX_ADCIN1:
+ if (ch->adcc2 & PCF5063X_ADCC2_RATIO_ADCIN1)
+ full_scale = ADC_FULL_SCALE_VISA;
+ break;
+ }
+
+ int nrb = ((ch->adcc1 & PCF5063X_ADCC1_RES_MASK) ==
+ PCF5063X_ADCC1_RES_8BIT) ? 8 : 10;
+ return (raw * full_scale / ((1<<nrb)-1)) + offset;
+}
+
+/* returns raw value, 8 or 10-bit resolution */
+unsigned short pmu_read_adc(const struct pmu_adc_channel *ch)
+{
+ mutex_lock(&pmu_adc_mutex);
+
+ pmu_write(PCF5063X_REG_ADCC3, ch->adcc3);
+ if (ch->bias_dly)
+ sleep(ch->bias_dly);
+ uint8_t buf[2] = { ch->adcc2, ch->adcc1 | PCF5063X_ADCC1_ADCSTART };
+ pmu_write_multiple(PCF5063X_REG_ADCC2, 2, buf);
+
+ int adcs3 = 0;
+ while (!(adcs3 & PCF5063X_ADCS3_ADCRDY))
+ {
+ yield();
+ adcs3 = pmu_read(PCF5063X_REG_ADCS3);
+ }
+
+ int raw = pmu_read(PCF5063X_REG_ADCS1);
+ if ((ch->adcc1 & PCF5063X_ADCC1_RES_MASK) == PCF5063X_ADCC1_RES_10BIT)
+ raw = (raw << 2) | (adcs3 & PCF5063X_ADCS3_ADCDAT1L_MASK);
+
+ mutex_unlock(&pmu_adc_mutex);
+ return raw;
+}
+
+/*
* eINT
*/
#define Q_EINT 0
-static char pmu_thread_stack[DEFAULT_STACK_SIZE/4];
+static char pmu_thread_stack[DEFAULT_STACK_SIZE/2];
static struct event_queue pmu_queue;
static unsigned char ints_msk[6];
static void pmu_eint_isr(struct eint_handler*);
-static struct eint_handler pmu_eint = {
+static struct eint_handler pmu_eint =
+{
.gpio_n = GPIO_EINT_PMU,
.type = EIC_INTTYPE_LEVEL,
.level = EIC_INTLEVEL_LOW,
@@ -355,10 +394,11 @@ void pmu_preinit(void)
PCF5063X_REG_STBYCTL1, 0x0,
PCF5063X_REG_STBYCTL2, 0x8c,
- /* GPIO1,2 = input, GPIO3 = output */
+ /* GPIO1,2 = input, GPIO3 = output High (NoPower default) */
PCF5063X_REG_GPIOCTL, 0x3,
PCF5063X_REG_GPIO1CFG, 0x0,
PCF5063X_REG_GPIO2CFG, 0x0,
+ PCF5063X_REG_GPIO3CFG, 0x7,
/* DOWN2 converter (SDRAM): 1800 mV, enabled,
startup current limit = 15mA*0x10 (TBC) */
diff --git a/firmware/target/arm/s5l8702/ipod6g/pmu-target.h b/firmware/target/arm/s5l8702/ipod6g/pmu-target.h
index 5552e2196a..d33db42717 100644
--- a/firmware/target/arm/s5l8702/ipod6g/pmu-target.h
+++ b/firmware/target/arm/s5l8702/ipod6g/pmu-target.h
@@ -22,6 +22,7 @@
#ifndef __PMU_TARGET_H__
#define __PMU_TARGET_H__
+#include <stdint.h>
#include <stdbool.h>
#include "config.h"
@@ -72,14 +73,22 @@ enum pcf50635_reg_gpiostat {
* GPIO3: output, unknown
*/
+struct pmu_adc_channel
+{
+ const char *name;
+ uint8_t adcc1;
+ uint8_t adcc2;
+ uint8_t adcc3;
+ uint8_t bias_dly; /* RB ticks */
+};
unsigned char pmu_read(int address);
int pmu_write(int address, unsigned char val);
int pmu_read_multiple(int address, int count, unsigned char* buffer);
int pmu_write_multiple(int address, int count, unsigned char* buffer);
-int pmu_read_adc(unsigned int adc);
-int pmu_read_battery_voltage(void);
-int pmu_read_battery_current(void);
+unsigned short pmu_read_adc(const struct pmu_adc_channel *ch);
+unsigned short pmu_adc_raw2mv(
+ const struct pmu_adc_channel *ch, unsigned short raw);
void pmu_init(void);
void pmu_ldo_on_in_standby(unsigned int ldo, int onoff);
void pmu_ldo_set_voltage(unsigned int ldo, unsigned char voltage);
diff --git a/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c
index 4553b03685..c5f9c9b9f5 100644
--- a/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c
+++ b/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c
@@ -24,6 +24,7 @@
#include "pmu-target.h"
#include "power.h"
#include "audiohw.h"
+#include "adc-target.h"
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
{
@@ -49,20 +50,12 @@ const unsigned short percent_to_volt_charge[11] =
};
#endif /* CONFIG_CHARGING */
-/* ADC should read 0x3ff=6.00V */
-#define BATTERY_SCALE_FACTOR 6000
-/* full-scale ADC readout (2^10) in millivolt */
-
-
/* Returns battery voltage from ADC [millivolts] */
int _battery_voltage(void)
{
- int compensation = (10 * (pmu_read_battery_current() - 7)) / 12;
- if (charging_state()) return pmu_read_battery_voltage() - compensation;
- return pmu_read_battery_voltage() + compensation;
+ return adc_read_battery_voltage();
}
-
#ifdef HAVE_ACCESSORY_SUPPLY
void accessory_supply_set(bool enable)
{