From 05f12e08772d1ca03101b176e329bfd313daf673 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Sat, 31 Dec 2011 13:34:56 +0000 Subject: [PATCH] ypr0: Enable battery voltage read-out, charging monitoring and charger detection. Voltage can be read using as3543 adc (i.e. ascodec api, on this target implemented via ioctl()). TODO: Look into possibly controlling charging more by re-using powermgmt-ascodec.c. However, charging seems to be controlled by the kernel, so may not be needed. Charger state can be read using /dev/minivet. It allows to differentiate between wall charger and usb charging, but that's not implemented (is it even worthwhile?) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31470 a1c6a512-1295-4272-9138-f99709370657 --- apps/debug_menu.c | 6 +- apps/plugin.c | 2 +- apps/plugin.h | 2 +- firmware/SOURCES | 2 +- firmware/export/config/samsungypr0.h | 18 +-- firmware/export/power.h | 3 + firmware/export/powermgmt.h | 2 +- firmware/export/storage.h | 2 +- firmware/powermgmt.c | 4 +- firmware/target/hosted/ypr0/powermgmt-ypr0.c | 117 +++++----------- firmware/target/hosted/ypr0/sc900776.h | 134 +++++++++++++++++++ firmware/target/hosted/ypr0/system-ypr0.c | 11 +- 12 files changed, 195 insertions(+), 108 deletions(-) create mode 100644 firmware/target/hosted/ypr0/sc900776.h diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 5773374d36..b4d917a3eb 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -58,7 +58,6 @@ #if (CONFIG_PLATFORM & PLATFORM_NATIVE) #include "disk.h" #include "adc.h" -#include "power.h" #include "usb.h" #include "rtc.h" #include "storage.h" @@ -75,6 +74,7 @@ #include "radio.h" #endif #endif +#include "power.h" #ifdef HAVE_LCD_BITMAP #include "scrollbar.h" @@ -900,7 +900,7 @@ static bool tsc2100_debug(void) return simplelist_show_list(&info); } #endif -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) +#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) #ifdef HAVE_LCD_BITMAP /* * view_battery() shows a automatically scaled graph of the battery voltage @@ -2168,7 +2168,7 @@ static const struct the_menu_item menuitems[] = { { "View CPU stats", dbg_cpuinfo }, #endif #ifdef HAVE_LCD_BITMAP -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) +#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) { "View battery", view_battery }, #endif #ifndef APPLICATION diff --git a/apps/plugin.c b/apps/plugin.c index 6dd84af775..f17ad3c57a 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -664,7 +664,7 @@ static const struct plugin_api rockbox_api = { battery_level, battery_level_safe, battery_time, -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) +#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) battery_voltage, #endif #if CONFIG_CHARGING diff --git a/apps/plugin.h b/apps/plugin.h index 3644e6468d..0bb7262bd8 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -794,7 +794,7 @@ struct plugin_api { int (*battery_level)(void); bool (*battery_level_safe)(void); int (*battery_time)(void); -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) +#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) unsigned int (*battery_voltage)(void); #endif #if CONFIG_CHARGING diff --git a/firmware/SOURCES b/firmware/SOURCES index e80a7492b1..46ef51beea 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -13,8 +13,8 @@ powermgmt.c target/hosted/cpuinfo-linux.c #endif -target/hosted/powermgmt.c #ifndef SAMSUNG_YPR0 /* uses as3514 rtc */ +target/hosted/powermgmt.c target/hosted/rtc.c #endif #endif diff --git a/firmware/export/config/samsungypr0.h b/firmware/export/config/samsungypr0.h index 25e1906a80..8d133c4e24 100644 --- a/firmware/export/config/samsungypr0.h +++ b/firmware/export/config/samsungypr0.h @@ -21,7 +21,7 @@ #define USB_NONE /* Hardware controlled charging with monitoring */ -//#define CONFIG_CHARGING CHARGING_MONITOR +#define CONFIG_CHARGING CHARGING_MONITOR /* There is only USB charging */ //#define HAVE_USB_POWER @@ -127,16 +127,16 @@ /* Define current usage levels. */ /* TODO: to be filled with correct values after implementing power management */ -#define CURRENT_NORMAL 88 /* 18 hours from a 1600 mAh battery */ -#define CURRENT_BACKLIGHT 30 /* TBD */ -#define CURRENT_RECORD 0 /* no recording yet */ +//#define CURRENT_NORMAL 88 /* 18 hours from a 1600 mAh battery */ +//#define CURRENT_BACKLIGHT 30 /* TBD */ +//#define CURRENT_RECORD 0 /* no recording yet */ /* TODO: We need to do battery handling */ -//#define BATTERY_CAPACITY_DEFAULT 600 /* default battery capacity */ -//#define BATTERY_CAPACITY_MIN 600 /* min. capacity selectable */ -//#define BATTERY_CAPACITY_MAX 700 /* max. capacity selectable */ -//#define BATTERY_CAPACITY_INC 50 /* capacity increment */ -//#define BATTERY_TYPES_COUNT 1 /* only one type */ +#define BATTERY_CAPACITY_DEFAULT 600 /* default battery capacity */ +#define BATTERY_CAPACITY_MIN 600 /* min. capacity selectable */ +#define BATTERY_CAPACITY_MAX 600 /* max. capacity selectable */ +#define BATTERY_CAPACITY_INC 0 /* capacity increment */ +#define BATTERY_TYPES_COUNT 1 /* only one type */ /* TODO: We possibly can only watch linux charging */ //#define CONFIG_CHARGING CHARGING_TARGET diff --git a/firmware/export/power.h b/firmware/export/power.h index d46b9ba924..4937705910 100644 --- a/firmware/export/power.h +++ b/firmware/export/power.h @@ -23,6 +23,7 @@ #include "config.h" +#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) #if CONFIG_CHARGING enum power_input_flags { /* No external power source? Default. */ @@ -100,4 +101,6 @@ bool tuner_power(bool status); bool tuner_powered(void); #endif +#endif + #endif /* _POWER_H_ */ diff --git a/firmware/export/powermgmt.h b/firmware/export/powermgmt.h index d54f1d5a18..837767f56b 100644 --- a/firmware/export/powermgmt.h +++ b/firmware/export/powermgmt.h @@ -78,7 +78,7 @@ extern unsigned int power_thread_inputs; /* Start up power management thread */ void powermgmt_init(void) INIT_ATTR; -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) +#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) /* Generic current values that are intentionally meaningless - config header * should define proper numbers.*/ diff --git a/firmware/export/storage.h b/firmware/export/storage.h index 58d8d32b6d..6c875bc847 100644 --- a/firmware/export/storage.h +++ b/firmware/export/storage.h @@ -71,7 +71,7 @@ static inline void stub_storage_spindown(int timeout) { (void)timeout; } #define storage_enable(on) #define storage_sleepnow() - #define storage_disk_is_active() + #define storage_disk_is_active() 0 #define storage_soft_reset() #define storage_init() #define storage_close() diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index 4d554d6d3c..6027414b71 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c @@ -86,7 +86,7 @@ void handle_auto_poweroff(void); static int poweroff_timeout = 0; static long last_event_tick = 0; -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) +#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) /* * Average battery voltage and charger voltage, filtered via a digital * exponential filter (aka. exponential moving average, scaled): @@ -108,7 +108,7 @@ static int battery_type = 0; /* Power history: power_history[0] is the newest sample */ unsigned short power_history[POWER_HISTORY_LEN] = {0}; -#if CONFIG_CPU == JZ4732 /* FIXME! */ +#if CONFIG_CPU == JZ4732 /* FIXME! */ || (CONFIG_PLATFORM & PLATFORM_HOSTED) static char power_stack[DEFAULT_STACK_SIZE + POWERMGMT_DEBUG_STACK]; #else static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK]; diff --git a/firmware/target/hosted/ypr0/powermgmt-ypr0.c b/firmware/target/hosted/ypr0/powermgmt-ypr0.c index 5701e9f02f..3a97331083 100644 --- a/firmware/target/hosted/ypr0/powermgmt-ypr0.c +++ b/firmware/target/hosted/ypr0/powermgmt-ypr0.c @@ -17,117 +17,72 @@ * ****************************************************************************/ #include "config.h" -#include "system.h" -#include +#include #include "kernel.h" #include "powermgmt.h" +#include "power.h" +#include "file.h" #include "ascodec-target.h" -#include "stdio.h" +#include "as3514.h" +#include "sc900776.h" -#if 0 /*still unused*/ -/* The battery manufacturer's website shows discharge curves down to 3.0V, - so 'dangerous' and 'shutoff' levels of 3.4V and 3.3V should be safe. - */ const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = { - 3550 + 3500 }; +/* the OF shuts down at this voltage */ const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = { 3450 }; /* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ +/* FIXME: This is guessed. Make proper curve using battery_bench */ const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = { - { 3300, 3692, 3740, 3772, 3798, 3828, 3876, 3943, 4013, 4094, 4194 } + { 3450, 3692, 3740, 3772, 3798, 3828, 3876, 3943, 4013, 4094, 4194 } }; #if CONFIG_CHARGING /* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ -const unsigned short percent_to_volt_charge[11] = +/* FIXME: This is guessed. Make proper curve using battery_bench */ +const unsigned short const percent_to_volt_charge[11] = { - 3417, 3802, 3856, 3888, 3905, 3931, 3973, 4025, 4084, 4161, 4219 + 3600, 3802, 3856, 3888, 3905, 3931, 3973, 4025, 4084, 4161, 4219 }; -#endif /* CONFIG_CHARGING */ -#endif -#define BATT_MINMVOLT 3450 /* minimum millivolts of battery */ -#define BATT_MAXMVOLT 4150 /* maximum millivolts of battery */ -#define BATT_MAXRUNTIME (10 * 60) /* maximum runtime with full battery in - minutes */ - -extern void send_battery_level_event(void); -extern int last_sent_battery_level; -extern int battery_percent; - -static unsigned int battery_millivolts = BATT_MAXMVOLT; -/* estimated remaining time in minutes */ -static int powermgmt_est_runningtime_min = BATT_MAXRUNTIME; - -static void battery_status_update(void) +unsigned int power_input_status(void) { - static time_t last_change = 0; - time_t now; - - time(&now); - - if (last_change < now) { - last_change = now; - - battery_percent = 100 * (battery_millivolts - BATT_MINMVOLT) / - (BATT_MAXMVOLT - BATT_MINMVOLT); - - powermgmt_est_runningtime_min = - battery_percent * BATT_MAXRUNTIME / 100; + unsigned status = POWER_INPUT_NONE; + int fd = open("/dev/minivet", O_RDONLY); + if (fd >= 0) + { + if (ioctl(fd, IOCTL_MINIVET_DET_VBUS, NULL) > 0) + status = POWER_INPUT_MAIN_CHARGER; + close(fd); } - - send_battery_level_event(); + return status; } -void battery_read_info(int *voltage, int *level) +#endif /* CONFIG_CHARGING */ + + +/* Returns battery voltage from ADC [millivolts], + * adc returns voltage in 5mV steps */ +unsigned int battery_adc_voltage(void) { - battery_status_update(); - - if (voltage) - *voltage = battery_millivolts; - - if (level) - *level = battery_percent; + return adc_read(3) * 5; } -unsigned int battery_voltage(void) +bool charging_state(void) { - battery_status_update(); - return battery_millivolts; -} + /* cannot make this static (initializer not constant error), but gcc + * seems to calculate at compile time anyway */ + const unsigned short charged_thres = + ((percent_to_volt_charge[9] + percent_to_volt_charge[10]) / 2); -int battery_level(void) -{ - battery_status_update(); - return battery_percent; + bool ret = (power_input_status() == POWER_INPUT_MAIN_CHARGER); + /* dont indicate for > ~95% */ + return ret && (battery_adc_voltage() <= charged_thres); } - -int battery_time(void) -{ - battery_status_update(); - return powermgmt_est_runningtime_min; -} - -bool battery_level_safe(void) -{ - return battery_level() >= 10; -} - -void set_battery_capacity(int capacity) -{ - (void)capacity; -} - -#if BATTERY_TYPES_COUNT > 1 -void set_battery_type(int type) -{ - (void)type; -} -#endif diff --git a/firmware/target/hosted/ypr0/sc900776.h b/firmware/target/hosted/ypr0/sc900776.h new file mode 100644 index 0000000000..32eb90f797 --- /dev/null +++ b/firmware/target/hosted/ypr0/sc900776.h @@ -0,0 +1,134 @@ +/* This file originates from the linux kernel provided in Samsung's YP-R0 Open + * Source package. + */ + +/* +* Bigbang project +* Copyright (c) 2009 VPS R&D Group, Samsung Electronics, Inc. +* All rights reserved. +*/ + +/** +* This file defines data structures and APIs for Freescale SC900776 +* +* @name sc900776.h +* @author Eung Chan Kim (eungchan.kim@samsung.com) +* @version 0.1 +* @see +*/ + +#ifndef __SC900776_H__ +#define __SC900776_H__ + + +typedef enum +{ + SC900776_DEVICE_ID = 0x01, /* 01h R */ + SC900776_CONTROL, /* 02h R/W */ + SC900776_INTERRUPT1, /* 03h R/C */ + SC900776_INTERRUPT2, /* 04h R/C */ + SC900776_INTERRUPT_MASK1, /* 05h R/W */ + SC900776_INTERRUPT_MASK2, /* 06h R/W */ + SC900776_ADC_RESULT, /* 07h R */ + SC900776_TIMING_SET1, /* 08h R/W */ + SC900776_TIMING_SET2, /* 09h R/W */ + SC900776_DEVICE_TYPE1, /* 0Ah R */ + SC900776_DEVICE_TYPE2, /* 0Bh R */ + SC900776_BUTTON1, /* 0Ch R/C */ + SC900776_BUTTON2, /* 0Dh R/C */ + /* 0Eh ~ 12h : reserved */ + SC900776_MANUAL_SWITCH1 = 0x13, /* 13h R/W */ + SC900776_MANUAL_SWITCH2, /* 14h R/W */ + /* 15h ~ 1Fh : reserved */ + SC900776_FSL_STATUS = 0x20, /* 20h R */ + SC900776_FSL_CONTROL, /* 21h R/W */ + SC900776_TIME_DELAY, /* 22h R/W */ + SC900776_DEVICE_MODE, /* 23h R/W */ + + SC900776_REG_MAX +} eSc900776_register_t; + +typedef enum +{ + DEVICETYPE1_UNDEFINED = 0, + DEVICETYPE1_USB, // 0x04 0x00 // normal usb cable & ad200 + DEVICETYPE1_DEDICATED, // 0x40 0x00 // dedicated charger cable + DEVICETYPE2_JIGUARTON, // 0x00 0x08 // Anygate_UART jig + DEVICETYPE2_JIGUSBOFF, // 0x00 0x01 // USB jig(AS center) + DEVICETYPE2_JIGUSBON, // 0x00 0x02 // Anygate_USB jig with boot-on, not tested +} eMinivet_device_t; + +/* + * sc900776 register bit definitions + */ +#define MINIVET_DEVICETYPE1_USBOTG 0x80 /* 1: a USBOTG device is attached */ +#define MINIVET_DEVICETYPE1_DEDICATED 0x40 /* 1: a dedicated charger is attached */ +#define MINIVET_DEVICETYPE1_USBCHG 0x20 /* 1: a USB charger is attached */ +#define MINIVET_DEVICETYPE1_5WCHG 0x10 /* 1: a 5-wire charger (type 1 or 2) is attached */ +#define MINIVET_DEVICETYPE1_UART 0x08 /* 1: a UART cable is attached */ +#define MINIVET_DEVICETYPE1_USB 0x04 /* 1: a USB host is attached */ +#define MINIVET_DEVICETYPE1_AUDIO2 0x02 /* 1: an audio accessory type 2 is attached */ +#define MINIVET_DEVICETYPE1_AUDIO1 0x01 /* 1: an audio accessory type 1 is attached */ + +#define MINIVET_DEVICETYPE2_AV 0x40 /* 1: an audio/video cable is attached */ +#define MINIVET_DEVICETYPE2_TTY 0x20 /* 1: a TTY converter is attached */ +#define MINIVET_DEVICETYPE2_PPD 0x10 /* 1: a phone powered device is attached */ +#define MINIVET_DEVICETYPE2_JIGUARTON 0x08 /* 1: a UART jig cable with the BOOT-on option is attached */ +#define MINIVET_DEVICETYPE2_JIGUARTOFF 0x04 /* 1: a UART jig cable with the BOOT-off option is attached */ +#define MINIVET_DEVICETYPE2_JIGUSBON 0x02 /* 1: a USB jig cable with the BOOT-on option is attached */ +#define MINIVET_DEVICETYPE2_JIGUSBOFF 0x01 /* 1: a USB jig cable with the BOOT-off option is attached */ + +#define MINIVET_FSLSTATUS_FETSTATUS 0x40 /* 1: The on status of the power MOSFET */ +#define MINIVET_FSLSTATUS_IDDETEND 0x20 /* 1: ID resistance detection finished */ +#define MINIVET_FSLSTATUS_VBUSDETEND 0x10 /* 1: VBUS power supply type identification completed */ +#define MINIVET_FSLSTATUS_IDGND 0x08 /* 1: ID pin is shorted to ground */ +#define MINIVET_FSLSTATUS_IDFLOAT 0x04 /* 1: ID line is floating */ +#define MINIVET_FSLSTATUS_VBUSDET 0x02 /* 1: VBUS voltage is higher than the POR */ +#define MINIVET_FSLSTATUS_ADCSTATUS 0x01 /* 1: ADC conversion completed */ + + +#define SC900776_I2C_SLAVE_ADDR 0x25 + +typedef struct { + unsigned char addr; + unsigned char value; +}__attribute__((packed)) sMinivet_t; + + +#define DRV_IOCTL_MINIVET_MAGIC 'M' + + +typedef enum +{ + E_IOCTL_MINIVET_INIT = 0, + E_IOCTL_MINIVET_WRITE_BYTE, + E_IOCTL_MINIVET_READ_BYTE, + E_IOCTL_MINIVET_DET_VBUS, + E_IOCTL_MINIVET_MANUAL_USB, + E_IOCTL_MINIVET_MANUAL_UART, + + E_IOCTL_MINIVET_MAX +} eSc900776_ioctl_t; + +#define IOCTL_MINIVET_INIT _IO(DRV_IOCTL_MINIVET_MAGIC, E_IOCTL_MINIVET_INIT) +#define IOCTL_MINIVET_WRITE_BYTE _IOW(DRV_IOCTL_MINIVET_MAGIC, E_IOCTL_MINIVET_WRITE_BYTE, sMinivet_t) +#define IOCTL_MINIVET_READ_BYTE _IOR(DRV_IOCTL_MINIVET_MAGIC, E_IOCTL_MINIVET_READ_BYTE, sMinivet_t) +#define IOCTL_MINIVET_DET_VBUS _IO(DRV_IOCTL_MINIVET_MAGIC, E_IOCTL_MINIVET_DET_VBUS) +#define IOCTL_MINIVET_MANUAL_USB _IO(DRV_IOCTL_MINIVET_MAGIC, E_IOCTL_MINIVET_MANUAL_USB) +#define IOCTL_MINIVET_MANUAL_UART _IO(DRV_IOCTL_MINIVET_MAGIC, E_IOCTL_MINIVET_MANUAL_UART) + + +#ifndef __MINIVET_ENUM__ +#define __MINIVET_ENUM__ +enum +{ + EXT_PWR_UNPLUGGED = 0, + EXT_PWR_PLUGGED, + EXT_PWR_NOT_OVP, + EXT_PWR_OVP, +}; + +#endif /* __MINIVET_ENUM__ */ + + +#endif /* __MINIVET_IOCTL_H__ */ diff --git a/firmware/target/hosted/ypr0/system-ypr0.c b/firmware/target/hosted/ypr0/system-ypr0.c index 3a2b30339f..bf3b1cd4c9 100644 --- a/firmware/target/hosted/ypr0/system-ypr0.c +++ b/firmware/target/hosted/ypr0/system-ypr0.c @@ -32,16 +32,11 @@ #include "ascodec-target.h" -void sim_do_exit(void) -{ - exit(EXIT_SUCCESS); -} - -void shutdown_hw(void) +void power_off(void) { /* Something that we need to do before exit on our platform YPR0 */ ascodec_close(); - sim_do_exit(); + exit(EXIT_SUCCESS); } uintptr_t *stackbegin; @@ -62,7 +57,7 @@ void system_init(void) void system_reboot(void) { - sim_do_exit(); + power_off(); } void system_exception_wait(void)