2005-11-13 13:07:46 +03:00
/*
* Battery and Power Management code for the Sharp SL - C7xx
*
* Copyright ( c ) 2005 Richard Purdie
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
*/
# include <linux/module.h>
# include <linux/stat.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/delay.h>
2010-01-08 08:32:46 +03:00
# include <linux/gpio.h>
2011-12-08 11:07:19 +04:00
# include <linux/gpio-pxa.h>
2005-11-13 13:07:46 +03:00
# include <linux/interrupt.h>
# include <linux/platform_device.h>
2007-02-27 15:10:07 +03:00
# include <linux/apm-emulation.h>
2012-03-20 23:33:19 +04:00
# include <linux/io.h>
2007-02-27 15:10:07 +03:00
2005-11-13 13:07:46 +03:00
# include <asm/irq.h>
# include <asm/mach-types.h>
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2005-11-13 13:07:46 +03:00
2008-08-05 19:14:15 +04:00
# include <mach/corgi.h>
# include <mach/pxa2xx-regs.h>
2010-07-04 20:03:34 +04:00
# include <mach/sharpsl_pm.h>
2010-01-08 08:32:46 +03:00
# include "generic.h"
2005-11-13 13:07:46 +03:00
2006-06-19 22:58:52 +04:00
# define SHARPSL_CHARGE_ON_VOLT 0x99 /* 2.9V */
# define SHARPSL_CHARGE_ON_TEMP 0xe0 /* 2.9V */
# define SHARPSL_CHARGE_ON_ACIN_HIGH 0x9b /* 6V */
# define SHARPSL_CHARGE_ON_ACIN_LOW 0x34 /* 2V */
# define SHARPSL_FATAL_ACIN_VOLT 182 /* 3.45V */
# define SHARPSL_FATAL_NOACIN_VOLT 170 /* 3.40V */
2010-01-08 08:32:46 +03:00
static struct gpio charger_gpios [ ] = {
{ CORGI_GPIO_ADC_TEMP_ON , GPIOF_OUT_INIT_LOW , " ADC Temp On " } ,
{ CORGI_GPIO_CHRG_ON , GPIOF_OUT_INIT_LOW , " Charger On " } ,
{ CORGI_GPIO_CHRG_UKN , GPIOF_OUT_INIT_LOW , " Charger Unknown " } ,
2011-10-17 09:37:23 +04:00
{ CORGI_GPIO_AC_IN , GPIOF_IN , " Charger Detection " } ,
2010-01-08 08:32:46 +03:00
{ CORGI_GPIO_KEY_INT , GPIOF_IN , " Key Interrupt " } ,
2011-10-17 09:37:23 +04:00
{ CORGI_GPIO_WAKEUP , GPIOF_IN , " System wakeup notification " } ,
2010-01-08 08:32:46 +03:00
} ;
2005-11-13 13:07:46 +03:00
static void corgi_charger_init ( void )
{
2010-01-08 08:32:46 +03:00
gpio_request_array ( ARRAY_AND_SIZE ( charger_gpios ) ) ;
2005-11-13 13:07:46 +03:00
}
static void corgi_measure_temp ( int on )
{
2010-01-08 08:32:46 +03:00
gpio_set_value ( CORGI_GPIO_ADC_TEMP_ON , on ) ;
2005-11-13 13:07:46 +03:00
}
static void corgi_charge ( int on )
{
if ( on ) {
if ( machine_is_corgi ( ) & & ( sharpsl_pm . flags & SHARPSL_SUSPENDED ) ) {
2010-01-08 08:32:46 +03:00
gpio_set_value ( CORGI_GPIO_CHRG_ON , 0 ) ;
gpio_set_value ( CORGI_GPIO_CHRG_UKN , 1 ) ;
2005-11-13 13:07:46 +03:00
} else {
2010-01-08 08:32:46 +03:00
gpio_set_value ( CORGI_GPIO_CHRG_ON , 1 ) ;
gpio_set_value ( CORGI_GPIO_CHRG_UKN , 0 ) ;
2005-11-13 13:07:46 +03:00
}
} else {
2010-01-08 08:32:46 +03:00
gpio_set_value ( CORGI_GPIO_CHRG_ON , 0 ) ;
gpio_set_value ( CORGI_GPIO_CHRG_UKN , 0 ) ;
2005-11-13 13:07:46 +03:00
}
}
static void corgi_discharge ( int on )
{
2010-01-08 08:32:46 +03:00
gpio_set_value ( CORGI_GPIO_DISCHARGE_ON , on ) ;
2005-11-13 13:07:46 +03:00
}
static void corgi_presuspend ( void )
{
}
static void corgi_postsuspend ( void )
{
}
/*
* Check what brought us out of the suspend .
* Return : 0 to sleep , otherwise wake
*/
static int corgi_should_wakeup ( unsigned int resume_on_alarm )
{
int is_resume = 0 ;
2011-10-17 09:37:23 +04:00
dev_dbg ( sharpsl_pm . dev , " PEDR = %x, GPIO_AC_IN = %d, "
" GPIO_CHRG_FULL = %d, GPIO_KEY_INT = %d, GPIO_WAKEUP = %d \n " ,
PEDR , gpio_get_value ( CORGI_GPIO_AC_IN ) ,
gpio_get_value ( CORGI_GPIO_CHRG_FULL ) ,
gpio_get_value ( CORGI_GPIO_KEY_INT ) ,
gpio_get_value ( CORGI_GPIO_WAKEUP ) ) ;
2005-11-13 13:07:46 +03:00
if ( ( PEDR & GPIO_bit ( CORGI_GPIO_AC_IN ) ) ) {
2006-01-05 23:44:55 +03:00
if ( sharpsl_pm . machinfo - > read_devdata ( SHARPSL_STATUS_ACIN ) ) {
2005-11-13 13:07:46 +03:00
/* charge on */
dev_dbg ( sharpsl_pm . dev , " ac insert \n " ) ;
sharpsl_pm . flags | = SHARPSL_DO_OFFLINE_CHRG ;
} else {
/* charge off */
dev_dbg ( sharpsl_pm . dev , " ac remove \n " ) ;
2006-01-05 23:44:55 +03:00
sharpsl_pm_led ( SHARPSL_LED_OFF ) ;
sharpsl_pm . machinfo - > charge ( 0 ) ;
2005-11-13 13:07:46 +03:00
sharpsl_pm . charge_mode = CHRG_OFF ;
}
}
if ( ( PEDR & GPIO_bit ( CORGI_GPIO_CHRG_FULL ) ) )
dev_dbg ( sharpsl_pm . dev , " Charge full interrupt \n " ) ;
if ( PEDR & GPIO_bit ( CORGI_GPIO_KEY_INT ) )
is_resume | = GPIO_bit ( CORGI_GPIO_KEY_INT ) ;
if ( PEDR & GPIO_bit ( CORGI_GPIO_WAKEUP ) )
is_resume | = GPIO_bit ( CORGI_GPIO_WAKEUP ) ;
if ( resume_on_alarm & & ( PEDR & PWER_RTC ) )
is_resume | = PWER_RTC ;
dev_dbg ( sharpsl_pm . dev , " is_resume: %x \n " , is_resume ) ;
return is_resume ;
}
static unsigned long corgi_charger_wakeup ( void )
{
2011-10-17 09:37:23 +04:00
unsigned long ret ;
ret = ( ! gpio_get_value ( CORGI_GPIO_AC_IN ) < < GPIO_bit ( CORGI_GPIO_AC_IN ) )
| ( ! gpio_get_value ( CORGI_GPIO_KEY_INT )
< < GPIO_bit ( CORGI_GPIO_KEY_INT ) )
| ( ! gpio_get_value ( CORGI_GPIO_WAKEUP )
< < GPIO_bit ( CORGI_GPIO_WAKEUP ) ) ;
return ret ;
2005-11-13 13:07:46 +03:00
}
2006-01-05 23:44:55 +03:00
unsigned long corgipm_read_devdata ( int type )
2005-11-13 13:07:46 +03:00
{
2006-01-05 23:44:55 +03:00
switch ( type ) {
case SHARPSL_STATUS_ACIN :
2011-10-17 09:37:23 +04:00
return ! gpio_get_value ( CORGI_GPIO_AC_IN ) ;
2006-01-05 23:44:55 +03:00
case SHARPSL_STATUS_LOCK :
2010-07-04 19:45:36 +04:00
return gpio_get_value ( sharpsl_pm . machinfo - > gpio_batlock ) ;
2006-01-05 23:44:55 +03:00
case SHARPSL_STATUS_CHRGFULL :
2010-07-04 19:45:36 +04:00
return gpio_get_value ( sharpsl_pm . machinfo - > gpio_batfull ) ;
2006-01-05 23:44:55 +03:00
case SHARPSL_STATUS_FATAL :
2010-07-04 19:45:36 +04:00
return gpio_get_value ( sharpsl_pm . machinfo - > gpio_fatal ) ;
2006-01-05 23:44:55 +03:00
case SHARPSL_ACIN_VOLT :
return sharpsl_pm_pxa_read_max1111 ( MAX1111_ACIN_VOLT ) ;
case SHARPSL_BATT_TEMP :
return sharpsl_pm_pxa_read_max1111 ( MAX1111_BATT_TEMP ) ;
case SHARPSL_BATT_VOLT :
default :
return sharpsl_pm_pxa_read_max1111 ( MAX1111_BATT_VOLT ) ;
}
2005-11-13 13:07:46 +03:00
}
static struct sharpsl_charger_machinfo corgi_pm_machinfo = {
. init = corgi_charger_init ,
2009-03-28 18:18:52 +03:00
. exit = NULL ,
2005-11-13 13:07:46 +03:00
. gpio_batlock = CORGI_GPIO_BAT_COVER ,
. gpio_acin = CORGI_GPIO_AC_IN ,
. gpio_batfull = CORGI_GPIO_CHRG_FULL ,
. discharge = corgi_discharge ,
. charge = corgi_charge ,
. measure_temp = corgi_measure_temp ,
. presuspend = corgi_presuspend ,
. postsuspend = corgi_postsuspend ,
2006-01-05 23:44:55 +03:00
. read_devdata = corgipm_read_devdata ,
2005-11-13 13:07:46 +03:00
. charger_wakeup = corgi_charger_wakeup ,
. should_wakeup = corgi_should_wakeup ,
2008-10-28 20:26:40 +03:00
# if defined(CONFIG_LCD_CORGI)
. backlight_limit = corgi_lcd_limit_intensity ,
2008-04-20 20:15:32 +04:00
# endif
2006-06-19 22:58:52 +04:00
. charge_on_volt = SHARPSL_CHARGE_ON_VOLT ,
. charge_on_temp = SHARPSL_CHARGE_ON_TEMP ,
. charge_acin_high = SHARPSL_CHARGE_ON_ACIN_HIGH ,
. charge_acin_low = SHARPSL_CHARGE_ON_ACIN_LOW ,
. fatal_acin_volt = SHARPSL_FATAL_ACIN_VOLT ,
. fatal_noacin_volt = SHARPSL_FATAL_NOACIN_VOLT ,
. bat_levels = 40 ,
2009-10-23 00:16:34 +04:00
. bat_levels_noac = sharpsl_battery_levels_noac ,
. bat_levels_acin = sharpsl_battery_levels_acin ,
2005-11-13 13:07:46 +03:00
. status_high_acin = 188 ,
. status_low_acin = 178 ,
. status_high_noac = 185 ,
. status_low_noac = 175 ,
} ;
static struct platform_device * corgipm_device ;
2012-12-22 02:02:24 +04:00
static int corgipm_init ( void )
2005-11-13 13:07:46 +03:00
{
int ret ;
2008-05-31 19:16:54 +04:00
if ( ! machine_is_corgi ( ) & & ! machine_is_shepherd ( )
& & ! machine_is_husky ( ) )
return - ENODEV ;
2005-11-13 13:07:46 +03:00
corgipm_device = platform_device_alloc ( " sharpsl-pm " , - 1 ) ;
if ( ! corgipm_device )
return - ENOMEM ;
2006-06-19 22:58:52 +04:00
if ( ! machine_is_corgi ( ) )
corgi_pm_machinfo . batfull_irq = 1 ;
2005-11-13 13:07:46 +03:00
corgipm_device - > dev . platform_data = & corgi_pm_machinfo ;
ret = platform_device_add ( corgipm_device ) ;
if ( ret )
platform_device_put ( corgipm_device ) ;
return ret ;
}
static void corgipm_exit ( void )
{
platform_device_unregister ( corgipm_device ) ;
}
module_init ( corgipm_init ) ;
module_exit ( corgipm_exit ) ;