2005-11-13 10:07:47 +00:00
/*
* Battery and Power Management code for the Sharp SL - Cxx00
*
* 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>
2011-06-14 17:06:02 -07:00
# include <linux/gpio.h>
2011-12-08 15:07:18 +08:00
# include <linux/gpio-pxa.h>
2005-11-13 10:07:47 +00:00
# include <linux/interrupt.h>
# include <linux/platform_device.h>
2007-02-27 12:10:07 +00:00
# include <linux/apm-emulation.h>
2005-11-13 10:07:47 +00:00
# include <asm/irq.h>
# include <asm/mach-types.h>
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2005-11-13 10:07:47 +00:00
2008-08-05 16:14:15 +01:00
# include <mach/spitz.h>
2010-01-11 16:17:25 +08:00
# include <mach/pxa27x.h>
2010-07-05 00:03:34 +08:00
# include <mach/sharpsl_pm.h>
2010-01-11 16:17:25 +08:00
# include "generic.h"
2005-11-13 10:07:47 +00:00
2006-06-19 19:58:52 +01: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 */
2005-11-13 10:07:47 +00:00
static int spitz_last_ac_status ;
2010-01-11 16:17:25 +08:00
static struct gpio spitz_charger_gpios [ ] = {
{ SPITZ_GPIO_KEY_INT , GPIOF_IN , " Keyboard Interrupt " } ,
{ SPITZ_GPIO_SYNC , GPIOF_IN , " Sync " } ,
2011-10-17 13:37:23 +08:00
{ SPITZ_GPIO_AC_IN , GPIOF_IN , " Charger Detection " } ,
2010-01-11 16:17:25 +08:00
{ SPITZ_GPIO_ADC_TEMP_ON , GPIOF_OUT_INIT_LOW , " ADC Temp On " } ,
{ SPITZ_GPIO_JK_B , GPIOF_OUT_INIT_LOW , " JK B " } ,
{ SPITZ_GPIO_CHRG_ON , GPIOF_OUT_INIT_LOW , " Charger On " } ,
} ;
2005-11-13 10:07:47 +00:00
static void spitz_charger_init ( void )
{
2010-01-11 16:17:25 +08:00
gpio_request_array ( ARRAY_AND_SIZE ( spitz_charger_gpios ) ) ;
2005-11-13 10:07:47 +00:00
}
static void spitz_measure_temp ( int on )
{
2008-09-05 22:15:23 +08:00
gpio_set_value ( SPITZ_GPIO_ADC_TEMP_ON , on ) ;
2005-11-13 10:07:47 +00:00
}
static void spitz_charge ( int on )
{
if ( on ) {
if ( sharpsl_pm . flags & SHARPSL_SUSPENDED ) {
2008-09-05 22:15:23 +08:00
gpio_set_value ( SPITZ_GPIO_JK_B , 1 ) ;
gpio_set_value ( SPITZ_GPIO_CHRG_ON , 0 ) ;
2005-11-13 10:07:47 +00:00
} else {
2008-09-05 22:15:23 +08:00
gpio_set_value ( SPITZ_GPIO_JK_B , 0 ) ;
gpio_set_value ( SPITZ_GPIO_CHRG_ON , 0 ) ;
2005-11-13 10:07:47 +00:00
}
} else {
2008-09-05 22:15:23 +08:00
gpio_set_value ( SPITZ_GPIO_JK_B , 0 ) ;
gpio_set_value ( SPITZ_GPIO_CHRG_ON , 1 ) ;
2005-11-13 10:07:47 +00:00
}
}
static void spitz_discharge ( int on )
{
2008-09-05 22:15:23 +08:00
gpio_set_value ( SPITZ_GPIO_JK_A , on ) ;
2005-11-13 10:07:47 +00:00
}
/* HACK - For unknown reasons, accurate voltage readings are only made with a load
on the power bus which the green led on spitz provides */
static void spitz_discharge1 ( int on )
{
2008-09-05 22:15:23 +08:00
gpio_set_value ( SPITZ_GPIO_LED_GREEN , on ) ;
2005-11-13 10:07:47 +00:00
}
2012-10-25 18:51:38 +02:00
static unsigned long gpio18_config = GPIO18_GPIO ;
2010-01-11 16:17:25 +08:00
2005-11-13 10:07:47 +00:00
static void spitz_presuspend ( void )
{
2006-01-05 20:44:55 +00:00
spitz_last_ac_status = sharpsl_pm . machinfo - > read_devdata ( SHARPSL_STATUS_ACIN ) ;
2005-11-13 10:07:47 +00:00
/* GPIO Sleep Register */
PGSR0 = 0x00144018 ;
PGSR1 = 0x00EF0000 ;
if ( machine_is_akita ( ) ) {
PGSR2 = 0x2121C000 ;
PGSR3 = 0x00600400 ;
} else {
PGSR2 = 0x0121C000 ;
PGSR3 = 0x00600000 ;
}
PGSR0 & = ~ SPITZ_GPIO_G0_STROBE_BIT ;
PGSR1 & = ~ SPITZ_GPIO_G1_STROBE_BIT ;
PGSR2 & = ~ SPITZ_GPIO_G2_STROBE_BIT ;
PGSR3 & = ~ SPITZ_GPIO_G3_STROBE_BIT ;
PGSR2 | = GPIO_bit ( SPITZ_GPIO_KEY_STROBE0 ) ;
2012-10-25 18:51:38 +02:00
pxa2xx_mfp_config ( & gpio18_config , 1 ) ;
2010-01-11 16:17:25 +08:00
gpio_request_one ( 18 , GPIOF_OUT_INIT_HIGH , " Unknown " ) ;
gpio_free ( 18 ) ;
2005-11-13 10:07:47 +00:00
PRER = GPIO_bit ( SPITZ_GPIO_KEY_INT ) ;
PFER = GPIO_bit ( SPITZ_GPIO_KEY_INT ) | GPIO_bit ( SPITZ_GPIO_RESET ) ;
PWER = GPIO_bit ( SPITZ_GPIO_KEY_INT ) | GPIO_bit ( SPITZ_GPIO_RESET ) | PWER_RTC ;
PKWR = GPIO_bit ( SPITZ_GPIO_SYNC ) | GPIO_bit ( SPITZ_GPIO_KEY_INT ) | GPIO_bit ( SPITZ_GPIO_RESET ) ;
2009-10-22 21:35:33 +02:00
PKSR = 0xffffffff ; /* clear */
2005-11-13 10:07:47 +00:00
/* nRESET_OUT Disable */
PSLR | = PSLR_SL_ROD ;
/* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
PCFR = PCFR_GPR_EN | PCFR_OPDE ;
}
static void spitz_postsuspend ( void )
{
}
static int spitz_should_wakeup ( unsigned int resume_on_alarm )
{
int is_resume = 0 ;
2006-01-05 20:44:55 +00:00
int acin = sharpsl_pm . machinfo - > read_devdata ( SHARPSL_STATUS_ACIN ) ;
2005-11-13 10:07:47 +00:00
if ( spitz_last_ac_status ! = acin ) {
if ( acin ) {
/* charge on */
sharpsl_pm . flags | = SHARPSL_DO_OFFLINE_CHRG ;
dev_dbg ( sharpsl_pm . dev , " AC Inserted \n " ) ;
} else {
/* charge off */
dev_dbg ( sharpsl_pm . dev , " AC Removed \n " ) ;
2006-01-05 20:44:55 +00:00
sharpsl_pm_led ( SHARPSL_LED_OFF ) ;
sharpsl_pm . machinfo - > charge ( 0 ) ;
2005-11-13 10:07:47 +00:00
sharpsl_pm . charge_mode = CHRG_OFF ;
}
spitz_last_ac_status = acin ;
/* Return to suspend as this must be what we were woken for */
return 0 ;
}
if ( PEDR & GPIO_bit ( SPITZ_GPIO_KEY_INT ) )
is_resume | = GPIO_bit ( SPITZ_GPIO_KEY_INT ) ;
if ( PKSR & GPIO_bit ( SPITZ_GPIO_SYNC ) )
is_resume | = GPIO_bit ( SPITZ_GPIO_SYNC ) ;
if ( resume_on_alarm & & ( PEDR & PWER_RTC ) )
is_resume | = PWER_RTC ;
2009-10-22 21:35:33 +02:00
dev_dbg ( sharpsl_pm . dev , " is_resume: %x \n " , is_resume ) ;
2005-11-13 10:07:47 +00:00
return is_resume ;
}
static unsigned long spitz_charger_wakeup ( void )
{
2011-10-17 13:37:23 +08:00
unsigned long ret ;
2012-02-06 15:33:22 +08:00
ret = ( ( ! gpio_get_value ( SPITZ_GPIO_KEY_INT )
2011-10-17 13:37:23 +08:00
< < GPIO_bit ( SPITZ_GPIO_KEY_INT ) )
2012-02-06 15:33:22 +08:00
| gpio_get_value ( SPITZ_GPIO_SYNC ) ) ;
2011-10-17 13:37:23 +08:00
return ret ;
2005-11-13 10:07:47 +00:00
}
2006-01-05 20:44:55 +00:00
unsigned long spitzpm_read_devdata ( int type )
2005-11-13 10:07:47 +00:00
{
2009-10-22 21:35:33 +02:00
switch ( type ) {
2006-01-05 20:44:55 +00:00
case SHARPSL_STATUS_ACIN :
2011-10-17 13:37:23 +08:00
return ! gpio_get_value ( SPITZ_GPIO_AC_IN ) ;
2006-01-05 20:44:55 +00:00
case SHARPSL_STATUS_LOCK :
2010-07-04 23:45:36 +08:00
return gpio_get_value ( sharpsl_pm . machinfo - > gpio_batlock ) ;
2006-01-05 20:44:55 +00:00
case SHARPSL_STATUS_CHRGFULL :
2010-07-04 23:45:36 +08:00
return gpio_get_value ( sharpsl_pm . machinfo - > gpio_batfull ) ;
2006-01-05 20:44:55 +00:00
case SHARPSL_STATUS_FATAL :
2010-07-04 23:45:36 +08:00
return gpio_get_value ( sharpsl_pm . machinfo - > gpio_fatal ) ;
2006-01-05 20:44:55 +00: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 10:07:47 +00:00
}
struct sharpsl_charger_machinfo spitz_pm_machinfo = {
. init = spitz_charger_init ,
2009-03-28 18:18:52 +03:00
. exit = NULL ,
2005-11-13 10:07:47 +00:00
. gpio_batlock = SPITZ_GPIO_BAT_COVER ,
. gpio_acin = SPITZ_GPIO_AC_IN ,
. gpio_batfull = SPITZ_GPIO_CHRG_FULL ,
2006-06-19 19:58:52 +01:00
. batfull_irq = 1 ,
2005-11-13 10:07:47 +00:00
. gpio_fatal = SPITZ_GPIO_FATAL_BAT ,
. discharge = spitz_discharge ,
. discharge1 = spitz_discharge1 ,
. charge = spitz_charge ,
. measure_temp = spitz_measure_temp ,
. presuspend = spitz_presuspend ,
. postsuspend = spitz_postsuspend ,
2006-01-05 20:44:55 +00:00
. read_devdata = spitzpm_read_devdata ,
2005-11-13 10:07:47 +00:00
. charger_wakeup = spitz_charger_wakeup ,
. should_wakeup = spitz_should_wakeup ,
2008-10-28 20:26:40 +03:00
# if defined(CONFIG_LCD_CORGI)
. backlight_limit = corgi_lcd_limit_intensity ,
2008-04-20 17:15:32 +01:00
# endif
2006-06-19 19:58:52 +01: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 ,
2005-11-13 10:07:47 +00:00
. bat_levels = 40 ,
2009-10-22 22:16:34 +02:00
. bat_levels_noac = sharpsl_battery_levels_noac ,
. bat_levels_acin = sharpsl_battery_levels_acin ,
2005-11-13 10:07:47 +00:00
. status_high_acin = 188 ,
. status_low_acin = 178 ,
. status_high_noac = 185 ,
. status_low_noac = 175 ,
} ;
static struct platform_device * spitzpm_device ;
2012-12-21 14:02:24 -08:00
static int spitzpm_init ( void )
2005-11-13 10:07:47 +00:00
{
int ret ;
2008-05-31 16:17:32 +01:00
if ( ! machine_is_spitz ( ) & & ! machine_is_akita ( )
& & ! machine_is_borzoi ( ) )
return - ENODEV ;
2005-11-13 10:07:47 +00:00
spitzpm_device = platform_device_alloc ( " sharpsl-pm " , - 1 ) ;
if ( ! spitzpm_device )
return - ENOMEM ;
spitzpm_device - > dev . platform_data = & spitz_pm_machinfo ;
ret = platform_device_add ( spitzpm_device ) ;
if ( ret )
platform_device_put ( spitzpm_device ) ;
return ret ;
}
static void spitzpm_exit ( void )
{
2009-10-22 21:35:33 +02:00
platform_device_unregister ( spitzpm_device ) ;
2005-11-13 10:07:47 +00:00
}
module_init ( spitzpm_init ) ;
module_exit ( spitzpm_exit ) ;