iPod Classic: introduce PMU interrupts

PMU interrupts are used to detect USB Vbus, wall adaptor, accessories
and holdswitch. A thread is needed to poll the PMU throught I2C, ATM
it does nothing but showing the state of the inputs on the HW debug
menu, funcionallity for each individual input will be added in next
patches.

Change-Id: If93bf2044d1052729237a7fd1431c8493e09f1c7
This commit is contained in:
Cástor Muñoz 2016-05-22 02:33:58 +02:00
parent 88caf222ed
commit 98bd2231ec
6 changed files with 214 additions and 16 deletions

View file

@ -159,6 +159,17 @@ enum pcf5063X_reg_oocwake {
PCF5063X_OOCWAKE_ADP = 0x80,
};
enum pcf5063X_reg_oocstat {
PCF5063X_OOCSTAT_ONKEY = 0x01,
PCF5063X_OOCSTAT_EXTON1 = 0x02,
PCF5063X_OOCSTAT_EXTON2 = 0x04,
PCF5063X_OOCSTAT_EXTON3 = 0x08,
PCF5063X_OOCSTAT_BUBPRES = 0x10,
PCF5063X_OOCSTAT_SYSOK = 0x20,
PCF5063X_OOCSTAT_BATOK = 0x40,
PCF5063X_OOCSTAT_TMPOK = 0x80,
};
enum pcf5063X_reg_mbcc1 {
PCF5063X_MBCC1_CHGENA = 0x01, /* Charger enable */
PCF5063X_MBCC1_AUTOSTOP = 0x02,

View file

@ -102,14 +102,14 @@ bool dbg_hw_info(void)
_DEBUG_PRINTF("PMU:");
for(i=0;i<7;i++)
{
char *device[] = {"(unknown)",
"(unknown)",
"(unknown)",
"(unknown)",
"(unknown)",
"(unknown)",
"(unknown)"};
_DEBUG_PRINTF("ldo%d %s: %dmV %s",i,
char *device[] = {"unknown",
"unknown",
"LCD",
"AUDIO",
"unknown",
"CLICKWHEEL",
"ACCESSORY"};
_DEBUG_PRINTF("ldo%d %s: %dmV (%s)",i,
pmu_read(0x2e + (i << 1))?" on":"off",
900 + pmu_read(0x2d + (i << 1))*100,
device[i]);
@ -120,6 +120,19 @@ bool dbg_hw_info(void)
_DEBUG_PRINTF("charging: %s", charging_state() ? "true" : "false");
_DEBUG_PRINTF("backlight: %s", pmu_read(0x29) ? "on" : "off");
_DEBUG_PRINTF("brightness value: %d", pmu_read(0x28));
line++;
_DEBUG_PRINTF("USB present: %s",
pmu_usb_present() ? "true" : "false");
#if CONFIG_CHARGING
_DEBUG_PRINTF("FW present: %s",
pmu_firewire_present() ? "true" : "false");
#endif
_DEBUG_PRINTF("holdswitch locked: %s",
pmu_holdswitch_locked() ? "true" : "false");
#ifdef IPOD_ACCESSORY_PROTOCOL
_DEBUG_PRINTF("accessory present: %s",
pmu_accessory_present() ? "true" : "false");
#endif
}
#ifdef UC870X_DEBUG
else if(state==2)

View file

@ -21,8 +21,12 @@
#include "config.h"
#include "kernel.h"
#include "i2c-s5l8702.h"
#include "thread.h"
#include "pmu-target.h"
#include "i2c-s5l8702.h"
#include "gpio-s5l8702.h"
static struct mutex pmu_adc_mutex;
@ -50,11 +54,6 @@ int pmu_write(int address, unsigned char val)
return pmu_write_multiple(address, 1, &val);
}
void pmu_init(void)
{
mutex_init(&pmu_adc_mutex);
}
int pmu_read_adc(unsigned int adc)
{
int data = 0;
@ -143,6 +142,157 @@ void pmu_write_rtc(unsigned char* buffer)
pmu_write_multiple(0x59, 7, buffer);
}
/*
* eINT
*/
#define Q_EINT 0
static char pmu_thread_stack[DEFAULT_STACK_SIZE/4];
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 = {
.gpio_n = GPIO_EINT_PMU,
.type = EIC_INTTYPE_LEVEL,
.level = EIC_INTLEVEL_LOW,
.isr = pmu_eint_isr,
};
static int pmu_input_holdswitch;
static int pmu_input_usb;
int pmu_holdswitch_locked(void)
{
return pmu_input_holdswitch;
}
int pmu_usb_present(void)
{
return pmu_input_usb;
}
#ifdef IPOD_ACCESSORY_PROTOCOL
static int pmu_input_accessory;
int pmu_accessory_present(void)
{
return pmu_input_accessory;
}
#endif
#if CONFIG_CHARGING
static int pmu_input_firewire;
int pmu_firewire_present(void)
{
return pmu_input_firewire;
}
static void pmu_read_inputs_mbcs(void)
{
pmu_input_firewire = !!(pmu_read(PCF5063X_REG_MBCS1)
& PCF5063X_MBCS1_ADAPTPRES);
}
#endif
static void pmu_read_inputs_gpio(void)
{
pmu_input_holdswitch = !(pmu_read(PCF50635_REG_GPIOSTAT)
& PCF50635_GPIOSTAT_GPIO2);
}
static void pmu_read_inputs_ooc(void)
{
unsigned char oocstat = pmu_read(PCF5063X_REG_OOCSTAT);
pmu_input_usb = !!(oocstat & PCF5063X_OOCSTAT_EXTON2);
#ifdef IPOD_ACCESSORY_PROTOCOL
pmu_input_accessory = !(oocstat & PCF5063X_OOCSTAT_EXTON3);
#endif
}
static void pmu_eint_isr(struct eint_handler *h)
{
eint_unregister(h);
queue_post(&pmu_queue, Q_EINT, 0);
}
static void NORETURN_ATTR pmu_thread(void)
{
struct queue_event ev;
unsigned char ints[6];
while (true)
{
queue_wait_w_tmo(&pmu_queue, &ev, TIMEOUT_BLOCK);
switch (ev.id)
{
case Q_EINT:
/* read (clear) PMU interrupts, this will also
raise the PMU IRQ pin */
pmu_read_multiple(PCF5063X_REG_INT1, 2, ints);
ints[5] = pmu_read(PCF50635_REG_INT6);
#if CONFIG_CHARGING
if (ints[0] & ~ints_msk[0]) pmu_read_inputs_mbcs();
#endif
if (ints[1] & ~ints_msk[1]) pmu_read_inputs_ooc();
if (ints[5] & ~ints_msk[5]) pmu_read_inputs_gpio();
eint_register(&pmu_eint);
break;
case SYS_TIMEOUT:
break;
}
}
}
/* main init */
void pmu_init(void)
{
mutex_init(&pmu_adc_mutex);
queue_init(&pmu_queue, false);
create_thread(pmu_thread,
pmu_thread_stack, sizeof(pmu_thread_stack), 0,
"PMU" IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU));
/* configure PMU interrutps */
for (int i = 0; i < 6; i++)
ints_msk[i] = 0xff;
#if CONFIG_CHARGING
ints_msk[0] &= ~PCF5063X_INT1_ADPINS & /* FireWire */
~PCF5063X_INT1_ADPREM;
#endif
ints_msk[1] &= ~PCF5063X_INT2_EXTON2R & /* USB */
~PCF5063X_INT2_EXTON2F;
#ifdef IPOD_ACCESSORY_PROTOCOL
ints_msk[1] &= ~PCF5063X_INT2_EXTON3R & /* Accessory */
~PCF5063X_INT2_EXTON3F;
#endif
ints_msk[5] &= ~PCF50635_INT6_GPIO2; /* Holdswitch */
pmu_write_multiple(PCF5063X_REG_INT1M, 5, ints_msk);
pmu_write(PCF50635_REG_INT6M, ints_msk[5]);
/* clear all */
unsigned char ints[5];
pmu_read_multiple(PCF5063X_REG_INT1, 5, ints);
pmu_read(PCF50635_REG_INT6);
/* get initial values */
#if CONFIG_CHARGING
pmu_read_inputs_mbcs();
#endif
pmu_read_inputs_ooc();
pmu_read_inputs_gpio();
eint_register(&pmu_eint);
}
/*
* preinit
*/

View file

@ -30,7 +30,21 @@
/* undocummented PMU registers */
#define PCF50635_REG_INT6 0x85
#define PCF50635_REG_INT6M 0x86
#define PCF50635_REG_GPIOSTAT 0x87 /* bit1: GPIO2 status (TBC) */
#define PCF50635_REG_GPIOSTAT 0x87
enum pcf50635_reg_int6 {
PCF50635_INT6_GPIO1 = 0x01, /* TBC */
PCF50635_INT6_GPIO2 = 0x02,
};
enum pcf50635_reg_gpiostat {
PCF50635_GPIOSTAT_GPIO1 = 0x01, /* TBC */
PCF50635_GPIOSTAT_GPIO2 = 0x02,
};
/* GPIO for external PMU interrupt */
#define GPIO_EINT_PMU 0x7b
/* LDOs */
#define LDO_UNK1 1 /* TBC: SoC voltage (USB) */
@ -77,6 +91,15 @@ void pmu_read_rtc(unsigned char* buffer);
void pmu_write_rtc(unsigned char* buffer);
void pmu_hdd_power(bool on);
int pmu_holdswitch_locked(void);
int pmu_usb_present(void);
#if CONFIG_CHARGING
int pmu_firewire_present(void);
#endif
#ifdef IPOD_ACCESSORY_PROTOCOL
int pmu_accessory_present(void);
#endif
void pmu_preinit(void);
#ifdef BOOTLOADER
unsigned char pmu_rd(int address);

View file

@ -41,6 +41,8 @@ void power_off(void)
void power_init(void)
{
pmu_init();
idepowered = false;
/* DOWN1CTL: CPU DVM step time = 30us (default: no DVM) */

View file

@ -207,7 +207,6 @@ void system_init(void)
#endif
gpio_init();
eint_init();
pmu_init();
dma_init();
#ifdef HAVE_SERIAL
uart_init();