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
This commit is contained in:
parent
a25d0c58aa
commit
adbd2969e6
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
@ -133,12 +135,20 @@ bool dbg_hw_info(void)
|
|||
_DEBUG_PRINTF("accessory present: %s",
|
||||
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];
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
@ -142,18 +112,87 @@ void pmu_write_rtc(unsigned char* buffer)
|
|||
pmu_write_multiple(0x59, 7, 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) */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue