diff --git a/firmware/export/pcf5063x.h b/firmware/export/pcf5063x.h index 164417f483..f5f177ace7 100644 --- a/firmware/export/pcf5063x.h +++ b/firmware/export/pcf5063x.h @@ -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, diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c index 614019bac1..48a20a97c2 100644 --- a/firmware/target/arm/s5l8702/debug-s5l8702.c +++ b/firmware/target/arm/s5l8702/debug-s5l8702.c @@ -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) diff --git a/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c index 920c93ad5d..4200308861 100644 --- a/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c @@ -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 */ diff --git a/firmware/target/arm/s5l8702/ipod6g/pmu-target.h b/firmware/target/arm/s5l8702/ipod6g/pmu-target.h index d090f72a67..2274b4061f 100644 --- a/firmware/target/arm/s5l8702/ipod6g/pmu-target.h +++ b/firmware/target/arm/s5l8702/ipod6g/pmu-target.h @@ -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); diff --git a/firmware/target/arm/s5l8702/ipod6g/power-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/power-ipod6g.c index 57358b8cb6..d3224d2a66 100644 --- a/firmware/target/arm/s5l8702/ipod6g/power-ipod6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/power-ipod6g.c @@ -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) */ diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c index cbe8bfcaf7..459f4c36c6 100644 --- a/firmware/target/arm/s5l8702/system-s5l8702.c +++ b/firmware/target/arm/s5l8702/system-s5l8702.c @@ -207,7 +207,6 @@ void system_init(void) #endif gpio_init(); eint_init(); - pmu_init(); dma_init(); #ifdef HAVE_SERIAL uart_init();