2009-08-31 20:32:18 +04:00
/*
* linux / drivers / i2c / chips / twl4030 - power . c
*
* Handle TWL4030 Power initialization
*
* Copyright ( C ) 2008 Nokia Corporation
* Copyright ( C ) 2006 Texas Instruments , Inc
*
* Written by Kalle Jokiniemi
* Peter De Schrijver < peter . de - schrijver @ nokia . com >
* Several fixes by Amit Kucheria < amit . kucheria @ verdurent . com >
*
* This file is subject to the terms and conditions of the GNU General
* Public License . See the file " COPYING " in the main directory of this
* archive for more details .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/module.h>
# include <linux/pm.h>
2009-12-13 22:05:51 +03:00
# include <linux/i2c/twl.h>
2009-08-31 20:32:18 +04:00
# include <linux/platform_device.h>
2013-06-18 17:17:58 +04:00
# include <linux/of.h>
2014-05-20 22:17:54 +04:00
# include <linux/of_device.h>
2009-08-31 20:32:18 +04:00
# include <asm/mach-types.h>
static u8 twl4030_start_script_address = 0x2b ;
2014-05-20 22:17:53 +04:00
/* Register bits for P1, P2 and P3_SW_EVENTS */
# define PWR_STOPON_PRWON BIT(6)
# define PWR_STOPON_SYSEN BIT(5)
# define PWR_ENABLE_WARMRESET BIT(4)
# define PWR_LVL_WAKEUP BIT(3)
# define PWR_DEVACT BIT(2)
# define PWR_DEVSLP BIT(1)
# define PWR_DEVOFF BIT(0)
2014-11-02 21:07:56 +03:00
/* Register bits for CFG_P1_TRANSITION (also for P2 and P3) */
# define STARTON_SWBUG BIT(7) /* Start on watchdog */
# define STARTON_VBUS BIT(5) /* Start on VBUS */
# define STARTON_VBAT BIT(4) /* Start on battery insert */
# define STARTON_RTC BIT(3) /* Start on RTC */
# define STARTON_USB BIT(2) /* Start on USB host */
# define STARTON_CHG BIT(1) /* Start on charger */
# define STARTON_PWON BIT(0) /* Start on PWRON button */
2011-11-13 13:49:50 +04:00
# define SEQ_OFFSYNC (1 << 0)
2009-08-31 20:32:18 +04:00
# define PHY_TO_OFF_PM_MASTER(p) (p - 0x36)
# define PHY_TO_OFF_PM_RECEIVER(p) (p - 0x5b)
/* resource - hfclk */
# define R_HFCLKOUT_DEV_GRP PHY_TO_OFF_PM_RECEIVER(0xe6)
/* PM events */
# define R_P1_SW_EVENTS PHY_TO_OFF_PM_MASTER(0x46)
# define R_P2_SW_EVENTS PHY_TO_OFF_PM_MASTER(0x47)
# define R_P3_SW_EVENTS PHY_TO_OFF_PM_MASTER(0x48)
# define R_CFG_P1_TRANSITION PHY_TO_OFF_PM_MASTER(0x36)
# define R_CFG_P2_TRANSITION PHY_TO_OFF_PM_MASTER(0x37)
# define R_CFG_P3_TRANSITION PHY_TO_OFF_PM_MASTER(0x38)
# define END_OF_SCRIPT 0x3f
# define R_SEQ_ADD_A2S PHY_TO_OFF_PM_MASTER(0x55)
# define R_SEQ_ADD_S2A12 PHY_TO_OFF_PM_MASTER(0x56)
# define R_SEQ_ADD_S2A3 PHY_TO_OFF_PM_MASTER(0x57)
# define R_SEQ_ADD_WARM PHY_TO_OFF_PM_MASTER(0x58)
# define R_MEMORY_ADDRESS PHY_TO_OFF_PM_MASTER(0x59)
# define R_MEMORY_DATA PHY_TO_OFF_PM_MASTER(0x5a)
2009-10-19 16:10:48 +04:00
/* resource configuration registers
< RESOURCE > _DEV_GRP at address ' n + 0 '
< RESOURCE > _TYPE at address ' n + 1 '
< RESOURCE > _REMAP at address ' n + 2 '
< RESOURCE > _DEDICATED at address ' n + 3 '
*/
2009-10-19 16:10:44 +04:00
# define DEV_GRP_OFFSET 0
2009-08-31 20:32:18 +04:00
# define TYPE_OFFSET 1
2009-10-19 16:11:00 +04:00
# define REMAP_OFFSET 2
# define DEDICATED_OFFSET 3
2009-08-31 20:32:18 +04:00
2009-10-19 16:10:44 +04:00
/* Bit positions in the registers */
2009-10-19 16:10:48 +04:00
/* <RESOURCE>_DEV_GRP */
2009-10-19 16:10:44 +04:00
# define DEV_GRP_SHIFT 5
# define DEV_GRP_MASK (7 << DEV_GRP_SHIFT)
2009-10-19 16:10:48 +04:00
/* <RESOURCE>_TYPE */
2009-08-31 20:32:18 +04:00
# define TYPE_SHIFT 0
# define TYPE_MASK (7 << TYPE_SHIFT)
# define TYPE2_SHIFT 3
# define TYPE2_MASK (3 << TYPE2_SHIFT)
2009-10-19 16:11:00 +04:00
/* <RESOURCE>_REMAP */
# define SLEEP_STATE_SHIFT 0
# define SLEEP_STATE_MASK (0xf << SLEEP_STATE_SHIFT)
# define OFF_STATE_SHIFT 4
# define OFF_STATE_MASK (0xf << OFF_STATE_SHIFT)
2009-08-31 20:32:18 +04:00
static u8 res_config_addrs [ ] = {
[ RES_VAUX1 ] = 0x17 ,
[ RES_VAUX2 ] = 0x1b ,
[ RES_VAUX3 ] = 0x1f ,
[ RES_VAUX4 ] = 0x23 ,
[ RES_VMMC1 ] = 0x27 ,
[ RES_VMMC2 ] = 0x2b ,
[ RES_VPLL1 ] = 0x2f ,
[ RES_VPLL2 ] = 0x33 ,
[ RES_VSIM ] = 0x37 ,
[ RES_VDAC ] = 0x3b ,
[ RES_VINTANA1 ] = 0x3f ,
[ RES_VINTANA2 ] = 0x43 ,
[ RES_VINTDIG ] = 0x47 ,
[ RES_VIO ] = 0x4b ,
[ RES_VDD1 ] = 0x55 ,
[ RES_VDD2 ] = 0x63 ,
[ RES_VUSB_1V5 ] = 0x71 ,
[ RES_VUSB_1V8 ] = 0x74 ,
[ RES_VUSB_3V1 ] = 0x77 ,
[ RES_VUSBCP ] = 0x7a ,
[ RES_REGEN ] = 0x7f ,
[ RES_NRES_PWRON ] = 0x82 ,
[ RES_CLKEN ] = 0x85 ,
[ RES_SYSEN ] = 0x88 ,
[ RES_HFCLKOUT ] = 0x8b ,
[ RES_32KCLKOUT ] = 0x8e ,
[ RES_RESET ] = 0x91 ,
2011-04-14 16:27:51 +04:00
[ RES_MAIN_REF ] = 0x94 ,
2009-08-31 20:32:18 +04:00
} ;
2014-05-20 22:17:54 +04:00
/*
* Usable values for . remap_sleep and . remap_off
* Based on table " 5.3.3 Resource Operating modes "
*/
enum {
TWL_REMAP_OFF = 0 ,
TWL_REMAP_SLEEP = 8 ,
TWL_REMAP_ACTIVE = 9 ,
} ;
/*
* Macros to configure the PM register states for various resources .
* Note that we can make MSG_SINGULAR etc private to this driver once
* omap3 has been made DT only .
*/
# define TWL_DFLT_DELAY 2 /* typically 2 32 KiHz cycles */
2014-05-20 22:17:54 +04:00
# define TWL_DEV_GRP_P123 (DEV_GRP_P1 | DEV_GRP_P2 | DEV_GRP_P3)
2014-05-20 22:17:54 +04:00
# define TWL_RESOURCE_SET(res, state) \
{ MSG_SINGULAR ( DEV_GRP_NULL , ( res ) , ( state ) ) , TWL_DFLT_DELAY }
# define TWL_RESOURCE_ON(res) TWL_RESOURCE_SET(res, RES_STATE_ACTIVE)
# define TWL_RESOURCE_OFF(res) TWL_RESOURCE_SET(res, RES_STATE_OFF)
# define TWL_RESOURCE_RESET(res) TWL_RESOURCE_SET(res, RES_STATE_WRST)
/*
* It seems that type1 and type2 is just the resource init order
* number for the type1 and type2 group .
*/
2014-05-20 22:17:54 +04:00
# define TWL_RESOURCE_SET_ACTIVE(res, state) \
{ MSG_SINGULAR ( DEV_GRP_NULL , ( res ) , RES_STATE_ACTIVE ) , ( state ) }
2014-05-20 22:17:54 +04:00
# define TWL_RESOURCE_GROUP_RESET(group, type1, type2) \
{ MSG_BROADCAST ( DEV_GRP_NULL , ( group ) , ( type1 ) , ( type2 ) , \
RES_STATE_WRST ) , TWL_DFLT_DELAY }
2014-05-20 22:17:54 +04:00
# define TWL_RESOURCE_GROUP_SLEEP(group, type, type2) \
{ MSG_BROADCAST ( DEV_GRP_NULL , ( group ) , ( type ) , ( type2 ) , \
RES_STATE_SLEEP ) , TWL_DFLT_DELAY }
# define TWL_RESOURCE_GROUP_ACTIVE(group, type, type2) \
{ MSG_BROADCAST ( DEV_GRP_NULL , ( group ) , ( type ) , ( type2 ) , \
RES_STATE_ACTIVE ) , TWL_DFLT_DELAY }
2014-05-20 22:17:54 +04:00
# define TWL_REMAP_SLEEP(res, devgrp, typ, typ2) \
{ . resource = ( res ) , . devgroup = ( devgrp ) , \
. type = ( typ ) , . type2 = ( typ2 ) , \
. remap_off = TWL_REMAP_OFF , \
. remap_sleep = TWL_REMAP_SLEEP , }
2014-05-20 22:17:54 +04:00
# define TWL_REMAP_OFF(res, devgrp, typ, typ2) \
{ . resource = ( res ) , . devgroup = ( devgrp ) , \
. type = ( typ ) , . type2 = ( typ2 ) , \
. remap_off = TWL_REMAP_OFF , . remap_sleep = TWL_REMAP_OFF , }
2014-05-20 22:17:54 +04:00
2012-11-19 22:23:04 +04:00
static int twl4030_write_script_byte ( u8 address , u8 byte )
2009-08-31 20:32:18 +04:00
{
int err ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , address , R_MEMORY_ADDRESS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , byte , R_MEMORY_DATA ) ;
2009-08-31 20:32:18 +04:00
out :
return err ;
}
2012-11-19 22:23:04 +04:00
static int twl4030_write_script_ins ( u8 address , u16 pmb_message ,
2009-08-31 20:32:18 +04:00
u8 delay , u8 next )
{
int err ;
address * = 4 ;
err = twl4030_write_script_byte ( address + + , pmb_message > > 8 ) ;
if ( err )
goto out ;
err = twl4030_write_script_byte ( address + + , pmb_message & 0xff ) ;
if ( err )
goto out ;
err = twl4030_write_script_byte ( address + + , delay ) ;
if ( err )
goto out ;
err = twl4030_write_script_byte ( address + + , next ) ;
out :
return err ;
}
2012-11-19 22:23:04 +04:00
static int twl4030_write_script ( u8 address , struct twl4030_ins * script ,
2009-08-31 20:32:18 +04:00
int len )
{
2013-01-25 18:14:26 +04:00
int err = - EINVAL ;
2009-08-31 20:32:18 +04:00
for ( ; len ; len - - , address + + , script + + ) {
if ( len = = 1 ) {
err = twl4030_write_script_ins ( address ,
script - > pmb_message ,
script - > delay ,
END_OF_SCRIPT ) ;
if ( err )
break ;
} else {
err = twl4030_write_script_ins ( address ,
script - > pmb_message ,
script - > delay ,
address + 1 ) ;
if ( err )
break ;
}
}
return err ;
}
2012-11-19 22:23:04 +04:00
static int twl4030_config_wakeup3_sequence ( u8 address )
2009-08-31 20:32:18 +04:00
{
int err ;
u8 data ;
/* Set SLEEP to ACTIVE SEQ address for P3 */
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , address , R_SEQ_ADD_S2A3 ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
/* P3 LVL_WAKEUP should be on LEVEL */
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_MASTER , & data , R_P3_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
2014-05-20 22:17:53 +04:00
data | = PWR_LVL_WAKEUP ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , data , R_P3_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
out :
if ( err )
pr_err ( " TWL4030 wakeup sequence for P3 config error \n " ) ;
return err ;
}
2012-11-19 22:23:04 +04:00
static int twl4030_config_wakeup12_sequence ( u8 address )
2009-08-31 20:32:18 +04:00
{
int err = 0 ;
u8 data ;
/* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , address , R_SEQ_ADD_S2A12 ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
/* P1/P2 LVL_WAKEUP should be on LEVEL */
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_MASTER , & data , R_P1_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
2014-05-20 22:17:53 +04:00
data | = PWR_LVL_WAKEUP ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , data , R_P1_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_MASTER , & data , R_P2_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
2014-05-20 22:17:53 +04:00
data | = PWR_LVL_WAKEUP ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , data , R_P2_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
if ( machine_is_omap_3430sdp ( ) | | machine_is_omap_ldp ( ) ) {
/* Disabling AC charger effect on sleep-active transitions */
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_MASTER , & data ,
R_CFG_P1_TRANSITION ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
data & = ~ ( 1 < < 1 ) ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , data ,
R_CFG_P1_TRANSITION ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
}
out :
if ( err )
pr_err ( " TWL4030 wakeup sequence for P1 and P2 " \
" config error \n " ) ;
return err ;
}
2012-11-19 22:23:04 +04:00
static int twl4030_config_sleep_sequence ( u8 address )
2009-08-31 20:32:18 +04:00
{
int err ;
/* Set ACTIVE to SLEEP SEQ address in T2 memory*/
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , address , R_SEQ_ADD_A2S ) ;
2009-08-31 20:32:18 +04:00
if ( err )
pr_err ( " TWL4030 sleep sequence config error \n " ) ;
return err ;
}
2012-11-19 22:23:04 +04:00
static int twl4030_config_warmreset_sequence ( u8 address )
2009-08-31 20:32:18 +04:00
{
int err ;
u8 rd_data ;
/* Set WARM RESET SEQ address for P1 */
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , address , R_SEQ_ADD_WARM ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
/* P1/P2/P3 enable WARMRESET */
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_MASTER , & rd_data , R_P1_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
2014-05-20 22:17:53 +04:00
rd_data | = PWR_ENABLE_WARMRESET ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , rd_data , R_P1_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_MASTER , & rd_data , R_P2_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
2014-05-20 22:17:53 +04:00
rd_data | = PWR_ENABLE_WARMRESET ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , rd_data , R_P2_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_MASTER , & rd_data , R_P3_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
if ( err )
goto out ;
2014-05-20 22:17:53 +04:00
rd_data | = PWR_ENABLE_WARMRESET ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , rd_data , R_P3_SW_EVENTS ) ;
2009-08-31 20:32:18 +04:00
out :
if ( err )
pr_err ( " TWL4030 warmreset seq config error \n " ) ;
return err ;
}
2012-11-19 22:23:04 +04:00
static int twl4030_configure_resource ( struct twl4030_resconfig * rconfig )
2009-08-31 20:32:18 +04:00
{
int rconfig_addr ;
int err ;
u8 type ;
u8 grp ;
2009-10-19 16:11:00 +04:00
u8 remap ;
2009-08-31 20:32:18 +04:00
if ( rconfig - > resource > TOTAL_RESOURCES ) {
pr_err ( " TWL4030 Resource %d does not exist \n " ,
rconfig - > resource ) ;
return - EINVAL ;
}
rconfig_addr = res_config_addrs [ rconfig - > resource ] ;
/* Set resource group */
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_RECEIVER , & grp ,
2009-12-13 23:23:33 +03:00
rconfig_addr + DEV_GRP_OFFSET ) ;
2009-08-31 20:32:18 +04:00
if ( err ) {
pr_err ( " TWL4030 Resource %d group could not be read \n " ,
rconfig - > resource ) ;
return err ;
}
2009-10-19 23:24:02 +04:00
if ( rconfig - > devgroup ! = TWL4030_RESCONFIG_UNDEF ) {
2009-10-19 16:10:44 +04:00
grp & = ~ DEV_GRP_MASK ;
grp | = rconfig - > devgroup < < DEV_GRP_SHIFT ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_RECEIVER ,
2009-12-13 23:23:33 +03:00
grp , rconfig_addr + DEV_GRP_OFFSET ) ;
2009-08-31 20:32:18 +04:00
if ( err < 0 ) {
pr_err ( " TWL4030 failed to program devgroup \n " ) ;
return err ;
}
}
/* Set resource types */
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_RECEIVER , & type ,
2009-08-31 20:32:18 +04:00
rconfig_addr + TYPE_OFFSET ) ;
if ( err < 0 ) {
pr_err ( " TWL4030 Resource %d type could not be read \n " ,
rconfig - > resource ) ;
return err ;
}
2009-10-19 23:24:02 +04:00
if ( rconfig - > type ! = TWL4030_RESCONFIG_UNDEF ) {
2009-08-31 20:32:18 +04:00
type & = ~ TYPE_MASK ;
type | = rconfig - > type < < TYPE_SHIFT ;
}
2009-10-19 23:24:02 +04:00
if ( rconfig - > type2 ! = TWL4030_RESCONFIG_UNDEF ) {
2009-08-31 20:32:18 +04:00
type & = ~ TYPE2_MASK ;
type | = rconfig - > type2 < < TYPE2_SHIFT ;
}
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_RECEIVER ,
2009-08-31 20:32:18 +04:00
type , rconfig_addr + TYPE_OFFSET ) ;
if ( err < 0 ) {
pr_err ( " TWL4030 failed to program resource type \n " ) ;
return err ;
}
2009-10-19 16:11:00 +04:00
/* Set remap states */
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_RECEIVER , & remap ,
2009-12-13 23:23:33 +03:00
rconfig_addr + REMAP_OFFSET ) ;
2009-10-19 16:11:00 +04:00
if ( err < 0 ) {
pr_err ( " TWL4030 Resource %d remap could not be read \n " ,
rconfig - > resource ) ;
return err ;
}
2009-10-21 15:49:22 +04:00
if ( rconfig - > remap_off ! = TWL4030_RESCONFIG_UNDEF ) {
2009-10-19 16:11:00 +04:00
remap & = ~ OFF_STATE_MASK ;
remap | = rconfig - > remap_off < < OFF_STATE_SHIFT ;
}
2009-10-21 15:49:22 +04:00
if ( rconfig - > remap_sleep ! = TWL4030_RESCONFIG_UNDEF ) {
2009-10-19 16:11:00 +04:00
remap & = ~ SLEEP_STATE_MASK ;
2010-02-05 11:51:37 +03:00
remap | = rconfig - > remap_sleep < < SLEEP_STATE_SHIFT ;
2009-10-19 16:11:00 +04:00
}
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_RECEIVER ,
2009-12-13 23:23:33 +03:00
remap ,
rconfig_addr + REMAP_OFFSET ) ;
2009-10-19 16:11:00 +04:00
if ( err < 0 ) {
pr_err ( " TWL4030 failed to program remap \n " ) ;
return err ;
}
2009-08-31 20:32:18 +04:00
return 0 ;
}
2012-11-19 22:23:04 +04:00
static int load_twl4030_script ( struct twl4030_script * tscript ,
2009-08-31 20:32:18 +04:00
u8 address )
{
int err ;
2009-08-17 18:01:56 +04:00
static int order ;
2009-08-31 20:32:18 +04:00
/* Make sure the script isn't going beyond last valid address (0x3f) */
if ( ( address + tscript - > size ) > END_OF_SCRIPT ) {
pr_err ( " TWL4030 scripts too big error \n " ) ;
return - EINVAL ;
}
err = twl4030_write_script ( address , tscript - > script , tscript - > size ) ;
if ( err )
goto out ;
if ( tscript - > flags & TWL4030_WRST_SCRIPT ) {
err = twl4030_config_warmreset_sequence ( address ) ;
if ( err )
goto out ;
}
if ( tscript - > flags & TWL4030_WAKEUP12_SCRIPT ) {
2014-05-14 05:34:04 +04:00
/* Reset any existing sleep script to avoid hangs on reboot */
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , END_OF_SCRIPT ,
R_SEQ_ADD_A2S ) ;
if ( err )
goto out ;
2009-08-31 20:32:18 +04:00
err = twl4030_config_wakeup12_sequence ( address ) ;
if ( err )
goto out ;
2009-08-17 18:01:56 +04:00
order = 1 ;
2009-08-31 20:32:18 +04:00
}
if ( tscript - > flags & TWL4030_WAKEUP3_SCRIPT ) {
err = twl4030_config_wakeup3_sequence ( address ) ;
if ( err )
goto out ;
}
2011-04-14 16:27:49 +04:00
if ( tscript - > flags & TWL4030_SLEEP_SCRIPT ) {
2011-04-14 16:27:50 +04:00
if ( ! order )
2009-08-17 18:01:56 +04:00
pr_warning ( " TWL4030: Bad order of scripts (sleep " \
" script before wakeup) Leads to boot " \
" failure on some boards \n " ) ;
2009-08-31 20:32:18 +04:00
err = twl4030_config_sleep_sequence ( address ) ;
2011-04-14 16:27:49 +04:00
}
2009-08-31 20:32:18 +04:00
out :
return err ;
}
2010-02-22 20:16:30 +03:00
int twl4030_remove_script ( u8 flags )
{
int err = 0 ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , TWL4030_PM_MASTER_KEY_CFG1 ,
TWL4030_PM_MASTER_PROTECT_KEY ) ;
2010-02-22 20:16:30 +03:00
if ( err ) {
pr_err ( " twl4030: unable to unlock PROTECT_KEY \n " ) ;
return err ;
}
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , TWL4030_PM_MASTER_KEY_CFG2 ,
TWL4030_PM_MASTER_PROTECT_KEY ) ;
2010-02-22 20:16:30 +03:00
if ( err ) {
pr_err ( " twl4030: unable to unlock PROTECT_KEY \n " ) ;
return err ;
}
if ( flags & TWL4030_WRST_SCRIPT ) {
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , END_OF_SCRIPT ,
R_SEQ_ADD_WARM ) ;
2010-02-22 20:16:30 +03:00
if ( err )
return err ;
}
if ( flags & TWL4030_WAKEUP12_SCRIPT ) {
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , END_OF_SCRIPT ,
R_SEQ_ADD_S2A12 ) ;
2011-05-04 16:08:53 +04:00
if ( err )
2010-02-22 20:16:30 +03:00
return err ;
}
if ( flags & TWL4030_WAKEUP3_SCRIPT ) {
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , END_OF_SCRIPT ,
R_SEQ_ADD_S2A3 ) ;
2010-02-22 20:16:30 +03:00
if ( err )
return err ;
}
if ( flags & TWL4030_SLEEP_SCRIPT ) {
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , END_OF_SCRIPT ,
R_SEQ_ADD_A2S ) ;
2010-02-22 20:16:30 +03:00
if ( err )
return err ;
}
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , 0 ,
TWL4030_PM_MASTER_PROTECT_KEY ) ;
2010-02-22 20:16:30 +03:00
if ( err )
pr_err ( " TWL4030 Unable to relock registers \n " ) ;
return err ;
}
2014-05-20 22:17:54 +04:00
static int
twl4030_power_configure_scripts ( const struct twl4030_power_data * pdata )
2013-06-18 17:17:57 +04:00
{
int err ;
int i ;
u8 address = twl4030_start_script_address ;
for ( i = 0 ; i < pdata - > num ; i + + ) {
err = load_twl4030_script ( pdata - > scripts [ i ] , address ) ;
if ( err )
return err ;
address + = pdata - > scripts [ i ] - > size ;
}
return 0 ;
}
2014-05-20 22:17:54 +04:00
static void twl4030_patch_rconfig ( struct twl4030_resconfig * common ,
struct twl4030_resconfig * board )
{
while ( common - > resource ) {
struct twl4030_resconfig * b = board ;
while ( b - > resource ) {
if ( b - > resource = = common - > resource ) {
* common = * b ;
break ;
}
b + + ;
}
common + + ;
}
}
2014-05-20 22:17:54 +04:00
static int
twl4030_power_configure_resources ( const struct twl4030_power_data * pdata )
2013-06-18 17:17:57 +04:00
{
struct twl4030_resconfig * resconfig = pdata - > resource_config ;
2014-05-20 22:17:54 +04:00
struct twl4030_resconfig * boardconf = pdata - > board_config ;
2013-06-18 17:17:57 +04:00
int err ;
if ( resconfig ) {
2014-05-20 22:17:54 +04:00
if ( boardconf )
twl4030_patch_rconfig ( resconfig , boardconf ) ;
2013-06-18 17:17:57 +04:00
while ( resconfig - > resource ) {
err = twl4030_configure_resource ( resconfig ) ;
if ( err )
return err ;
resconfig + + ;
}
}
return 0 ;
}
2014-11-02 21:07:56 +03:00
static int twl4030_starton_mask_and_set ( u8 bitmask , u8 bitvalues )
{
u8 regs [ 3 ] = { TWL4030_PM_MASTER_CFG_P1_TRANSITION ,
TWL4030_PM_MASTER_CFG_P2_TRANSITION ,
TWL4030_PM_MASTER_CFG_P3_TRANSITION , } ;
u8 val ;
int i , err ;
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , TWL4030_PM_MASTER_KEY_CFG1 ,
TWL4030_PM_MASTER_PROTECT_KEY ) ;
if ( err )
goto relock ;
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER ,
TWL4030_PM_MASTER_KEY_CFG2 ,
TWL4030_PM_MASTER_PROTECT_KEY ) ;
if ( err )
goto relock ;
for ( i = 0 ; i < sizeof ( regs ) ; i + + ) {
err = twl_i2c_read_u8 ( TWL_MODULE_PM_MASTER ,
& val , regs [ i ] ) ;
if ( err )
break ;
val = ( ~ bitmask & val ) | ( bitmask & bitvalues ) ;
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER ,
val , regs [ i ] ) ;
if ( err )
break ;
}
if ( err )
pr_err ( " TWL4030 Register access failed: %i \n " , err ) ;
relock :
return twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , 0 ,
TWL4030_PM_MASTER_PROTECT_KEY ) ;
}
2011-11-13 13:49:50 +04:00
/*
* In master mode , start the power off sequence .
* After a successful execution , TWL shuts down the power to the SoC
* and all peripherals connected to it .
*/
void twl4030_power_off ( void )
{
int err ;
2014-11-02 21:07:56 +03:00
/* Disable start on charger or VBUS as it can break poweroff */
err = twl4030_starton_mask_and_set ( STARTON_VBUS | STARTON_CHG , 0 ) ;
if ( err )
pr_err ( " TWL4030 Unable to configure start-up \n " ) ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , PWR_DEVOFF ,
2011-11-13 13:49:50 +04:00
TWL4030_PM_MASTER_P1_SW_EVENTS ) ;
if ( err )
pr_err ( " TWL4030 Unable to power off \n " ) ;
}
2014-05-20 22:17:54 +04:00
static bool twl4030_power_use_poweroff ( const struct twl4030_power_data * pdata ,
2013-06-18 17:17:58 +04:00
struct device_node * node )
{
if ( pdata & & pdata - > use_poweroff )
return true ;
2014-09-17 16:34:12 +04:00
if ( of_property_read_bool ( node , " ti,system-power-controller " ) )
return true ;
2013-06-18 17:17:58 +04:00
if ( of_property_read_bool ( node , " ti,use_poweroff " ) )
return true ;
return false ;
}
2014-05-20 22:17:54 +04:00
# ifdef CONFIG_OF
/* Generic warm reset configuration for omap3 */
static struct twl4030_ins omap3_wrst_seq [ ] = {
TWL_RESOURCE_OFF ( RES_NRES_PWRON ) ,
TWL_RESOURCE_OFF ( RES_RESET ) ,
TWL_RESOURCE_RESET ( RES_MAIN_REF ) ,
TWL_RESOURCE_GROUP_RESET ( RES_GRP_ALL , RES_TYPE_R0 , RES_TYPE2_R2 ) ,
TWL_RESOURCE_RESET ( RES_VUSB_3V1 ) ,
TWL_RESOURCE_GROUP_RESET ( RES_GRP_ALL , RES_TYPE_R0 , RES_TYPE2_R1 ) ,
TWL_RESOURCE_GROUP_RESET ( RES_GRP_RC , RES_TYPE_ALL , RES_TYPE2_R0 ) ,
TWL_RESOURCE_ON ( RES_RESET ) ,
TWL_RESOURCE_ON ( RES_NRES_PWRON ) ,
} ;
static struct twl4030_script omap3_wrst_script = {
. script = omap3_wrst_seq ,
. size = ARRAY_SIZE ( omap3_wrst_seq ) ,
. flags = TWL4030_WRST_SCRIPT ,
} ;
static struct twl4030_script * omap3_reset_scripts [ ] = {
& omap3_wrst_script ,
} ;
static struct twl4030_resconfig omap3_rconfig [ ] = {
TWL_REMAP_SLEEP ( RES_HFCLKOUT , DEV_GRP_P3 , - 1 , - 1 ) ,
TWL_REMAP_SLEEP ( RES_VDD1 , DEV_GRP_P1 , - 1 , - 1 ) ,
TWL_REMAP_SLEEP ( RES_VDD2 , DEV_GRP_P1 , - 1 , - 1 ) ,
{ 0 , 0 } ,
} ;
static struct twl4030_power_data omap3_reset = {
. scripts = omap3_reset_scripts ,
. num = ARRAY_SIZE ( omap3_reset_scripts ) ,
. resource_config = omap3_rconfig ,
} ;
2014-05-20 22:17:54 +04:00
/* Recommended generic default idle configuration for off-idle */
/* Broadcast message to put res to sleep */
static struct twl4030_ins omap3_idle_sleep_on_seq [ ] = {
TWL_RESOURCE_GROUP_SLEEP ( RES_GRP_ALL , RES_TYPE_ALL , 0 ) ,
} ;
static struct twl4030_script omap3_idle_sleep_on_script = {
. script = omap3_idle_sleep_on_seq ,
. size = ARRAY_SIZE ( omap3_idle_sleep_on_seq ) ,
. flags = TWL4030_SLEEP_SCRIPT ,
} ;
/* Broadcast message to put res to active */
static struct twl4030_ins omap3_idle_wakeup_p12_seq [ ] = {
TWL_RESOURCE_GROUP_ACTIVE ( RES_GRP_ALL , RES_TYPE_ALL , 0 ) ,
} ;
static struct twl4030_script omap3_idle_wakeup_p12_script = {
. script = omap3_idle_wakeup_p12_seq ,
. size = ARRAY_SIZE ( omap3_idle_wakeup_p12_seq ) ,
. flags = TWL4030_WAKEUP12_SCRIPT ,
} ;
/* Broadcast message to put res to active */
static struct twl4030_ins omap3_idle_wakeup_p3_seq [ ] = {
TWL_RESOURCE_SET_ACTIVE ( RES_CLKEN , 0x37 ) ,
TWL_RESOURCE_GROUP_ACTIVE ( RES_GRP_ALL , RES_TYPE_ALL , 0 ) ,
} ;
static struct twl4030_script omap3_idle_wakeup_p3_script = {
. script = omap3_idle_wakeup_p3_seq ,
. size = ARRAY_SIZE ( omap3_idle_wakeup_p3_seq ) ,
. flags = TWL4030_WAKEUP3_SCRIPT ,
} ;
static struct twl4030_script * omap3_idle_scripts [ ] = {
& omap3_idle_wakeup_p12_script ,
& omap3_idle_wakeup_p3_script ,
& omap3_wrst_script ,
& omap3_idle_sleep_on_script ,
} ;
/*
* Recommended configuration based on " Recommended Sleep
* Sequences for the Zoom Platform " :
* http : //omappedia.com/wiki/File:Recommended_Sleep_Sequences_Zoom.pdf
* Note that the type1 and type2 seem to be just the init order number
* for type1 and type2 groups as specified in the document mentioned
* above .
*/
static struct twl4030_resconfig omap3_idle_rconfig [ ] = {
2014-08-19 19:24:05 +04:00
TWL_REMAP_SLEEP ( RES_VAUX1 , TWL4030_RESCONFIG_UNDEF , 0 , 0 ) ,
TWL_REMAP_SLEEP ( RES_VAUX2 , TWL4030_RESCONFIG_UNDEF , 0 , 0 ) ,
TWL_REMAP_SLEEP ( RES_VAUX3 , TWL4030_RESCONFIG_UNDEF , 0 , 0 ) ,
TWL_REMAP_SLEEP ( RES_VAUX4 , TWL4030_RESCONFIG_UNDEF , 0 , 0 ) ,
TWL_REMAP_SLEEP ( RES_VMMC1 , TWL4030_RESCONFIG_UNDEF , 0 , 0 ) ,
TWL_REMAP_SLEEP ( RES_VMMC2 , TWL4030_RESCONFIG_UNDEF , 0 , 0 ) ,
2014-05-20 22:17:54 +04:00
TWL_REMAP_OFF ( RES_VPLL1 , DEV_GRP_P1 , 3 , 1 ) ,
TWL_REMAP_SLEEP ( RES_VPLL2 , DEV_GRP_P1 , 0 , 0 ) ,
2014-08-19 19:24:05 +04:00
TWL_REMAP_SLEEP ( RES_VSIM , TWL4030_RESCONFIG_UNDEF , 0 , 0 ) ,
TWL_REMAP_SLEEP ( RES_VDAC , TWL4030_RESCONFIG_UNDEF , 0 , 0 ) ,
2014-05-20 22:17:54 +04:00
TWL_REMAP_SLEEP ( RES_VINTANA1 , TWL_DEV_GRP_P123 , 1 , 2 ) ,
TWL_REMAP_SLEEP ( RES_VINTANA2 , TWL_DEV_GRP_P123 , 0 , 2 ) ,
TWL_REMAP_SLEEP ( RES_VINTDIG , TWL_DEV_GRP_P123 , 1 , 2 ) ,
TWL_REMAP_SLEEP ( RES_VIO , TWL_DEV_GRP_P123 , 2 , 2 ) ,
TWL_REMAP_OFF ( RES_VDD1 , DEV_GRP_P1 , 4 , 1 ) ,
TWL_REMAP_OFF ( RES_VDD2 , DEV_GRP_P1 , 3 , 1 ) ,
2014-08-19 19:24:05 +04:00
TWL_REMAP_SLEEP ( RES_VUSB_1V5 , TWL4030_RESCONFIG_UNDEF , 0 , 0 ) ,
TWL_REMAP_SLEEP ( RES_VUSB_1V8 , TWL4030_RESCONFIG_UNDEF , 0 , 0 ) ,
2014-05-20 22:17:54 +04:00
TWL_REMAP_SLEEP ( RES_VUSB_3V1 , TWL_DEV_GRP_P123 , 0 , 0 ) ,
/* Resource #20 USB charge pump skipped */
TWL_REMAP_SLEEP ( RES_REGEN , TWL_DEV_GRP_P123 , 2 , 1 ) ,
TWL_REMAP_SLEEP ( RES_NRES_PWRON , TWL_DEV_GRP_P123 , 0 , 1 ) ,
TWL_REMAP_SLEEP ( RES_CLKEN , TWL_DEV_GRP_P123 , 3 , 2 ) ,
TWL_REMAP_SLEEP ( RES_SYSEN , TWL_DEV_GRP_P123 , 6 , 1 ) ,
TWL_REMAP_SLEEP ( RES_HFCLKOUT , DEV_GRP_P3 , 0 , 2 ) ,
TWL_REMAP_SLEEP ( RES_32KCLKOUT , TWL_DEV_GRP_P123 , 0 , 0 ) ,
TWL_REMAP_SLEEP ( RES_RESET , TWL_DEV_GRP_P123 , 6 , 0 ) ,
TWL_REMAP_SLEEP ( RES_MAIN_REF , TWL_DEV_GRP_P123 , 0 , 0 ) ,
{ /* Terminator */ } ,
} ;
static struct twl4030_power_data omap3_idle = {
. scripts = omap3_idle_scripts ,
. num = ARRAY_SIZE ( omap3_idle_scripts ) ,
. resource_config = omap3_idle_rconfig ,
} ;
2014-05-14 05:34:09 +04:00
/* Disable 32 KiHz oscillator during idle */
static struct twl4030_resconfig osc_off_rconfig [ ] = {
TWL_REMAP_OFF ( RES_CLKEN , DEV_GRP_P1 | DEV_GRP_P3 , 3 , 2 ) ,
{ /* Terminator */ } ,
} ;
static struct twl4030_power_data osc_off_idle = {
. scripts = omap3_idle_scripts ,
. num = ARRAY_SIZE ( omap3_idle_scripts ) ,
. resource_config = omap3_idle_rconfig ,
. board_config = osc_off_rconfig ,
} ;
2014-05-20 22:17:54 +04:00
static struct of_device_id twl4030_power_of_match [ ] = {
2014-11-02 21:09:38 +03:00
{
. compatible = " ti,twl4030-power " ,
} ,
2014-05-20 22:17:54 +04:00
{
. compatible = " ti,twl4030-power-reset " ,
. data = & omap3_reset ,
} ,
2014-05-20 22:17:54 +04:00
{
. compatible = " ti,twl4030-power-idle " ,
. data = & omap3_idle ,
} ,
2014-05-14 05:34:09 +04:00
{
. compatible = " ti,twl4030-power-idle-osc-off " ,
. data = & osc_off_idle ,
} ,
2014-05-20 22:17:54 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , twl4030_power_of_match ) ;
# endif /* CONFIG_OF */
2013-08-01 05:52:55 +04:00
static int twl4030_power_probe ( struct platform_device * pdev )
2009-08-31 20:32:18 +04:00
{
2014-05-20 22:17:54 +04:00
const struct twl4030_power_data * pdata = dev_get_platdata ( & pdev - > dev ) ;
2013-06-18 17:17:58 +04:00
struct device_node * node = pdev - > dev . of_node ;
2014-05-20 22:17:54 +04:00
const struct of_device_id * match ;
2009-08-31 20:32:18 +04:00
int err = 0 ;
2013-06-18 17:18:00 +04:00
int err2 = 0 ;
2013-06-18 17:17:57 +04:00
u8 val ;
2009-08-31 20:32:18 +04:00
2013-06-18 17:17:58 +04:00
if ( ! pdata & & ! node ) {
dev_err ( & pdev - > dev , " Platform data is missing \n " ) ;
return - EINVAL ;
}
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , TWL4030_PM_MASTER_KEY_CFG1 ,
TWL4030_PM_MASTER_PROTECT_KEY ) ;
2013-06-18 17:17:59 +04:00
err | = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER ,
TWL4030_PM_MASTER_KEY_CFG2 ,
2012-11-13 12:28:52 +04:00
TWL4030_PM_MASTER_PROTECT_KEY ) ;
2013-06-18 17:17:59 +04:00
if ( err ) {
pr_err ( " TWL4030 Unable to unlock registers \n " ) ;
return err ;
}
2009-08-31 20:32:18 +04:00
2014-05-20 22:17:54 +04:00
match = of_match_device ( of_match_ptr ( twl4030_power_of_match ) ,
& pdev - > dev ) ;
if ( match & & match - > data )
pdata = match - > data ;
2013-06-18 17:17:58 +04:00
if ( pdata ) {
err = twl4030_power_configure_scripts ( pdata ) ;
2013-06-18 17:17:59 +04:00
if ( err ) {
pr_err ( " TWL4030 failed to load scripts \n " ) ;
2013-06-18 17:18:00 +04:00
goto relock ;
2013-06-18 17:17:59 +04:00
}
2013-06-18 17:17:58 +04:00
err = twl4030_power_configure_resources ( pdata ) ;
2013-06-18 17:17:59 +04:00
if ( err ) {
pr_err ( " TWL4030 failed to configure resource \n " ) ;
2013-06-18 17:18:00 +04:00
goto relock ;
2013-06-18 17:17:59 +04:00
}
2013-06-18 17:17:58 +04:00
}
2009-08-31 20:32:18 +04:00
2011-11-13 13:49:50 +04:00
/* Board has to be wired properly to use this feature */
2013-06-18 17:17:58 +04:00
if ( twl4030_power_use_poweroff ( pdata , node ) & & ! pm_power_off ) {
2011-11-13 13:49:50 +04:00
/* Default for SEQ_OFFSYNC is set, lets ensure this */
2012-11-13 12:28:52 +04:00
err = twl_i2c_read_u8 ( TWL_MODULE_PM_MASTER , & val ,
2011-11-13 13:49:50 +04:00
TWL4030_PM_MASTER_CFG_P123_TRANSITION ) ;
if ( err ) {
pr_warning ( " TWL4030 Unable to read registers \n " ) ;
} else if ( ! ( val & SEQ_OFFSYNC ) ) {
val | = SEQ_OFFSYNC ;
2012-11-13 12:28:52 +04:00
err = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , val ,
2011-11-13 13:49:50 +04:00
TWL4030_PM_MASTER_CFG_P123_TRANSITION ) ;
if ( err ) {
pr_err ( " TWL4030 Unable to setup SEQ_OFFSYNC \n " ) ;
goto relock ;
}
}
pm_power_off = twl4030_power_off ;
}
relock :
2013-06-18 17:18:00 +04:00
err2 = twl_i2c_write_u8 ( TWL_MODULE_PM_MASTER , 0 ,
2012-11-13 12:28:52 +04:00
TWL4030_PM_MASTER_PROTECT_KEY ) ;
2013-06-18 17:18:00 +04:00
if ( err2 ) {
2009-08-31 20:32:18 +04:00
pr_err ( " TWL4030 Unable to relock registers \n " ) ;
2013-06-18 17:18:00 +04:00
return err2 ;
}
2013-06-18 17:17:56 +04:00
return err ;
}
static int twl4030_power_remove ( struct platform_device * pdev )
{
return 0 ;
2009-08-31 20:32:18 +04:00
}
2013-06-18 17:17:56 +04:00
static struct platform_driver twl4030_power_driver = {
. driver = {
. name = " twl4030_power " ,
2013-06-18 17:17:58 +04:00
. of_match_table = of_match_ptr ( twl4030_power_of_match ) ,
2013-06-18 17:17:56 +04:00
} ,
. probe = twl4030_power_probe ,
. remove = twl4030_power_remove ,
} ;
module_platform_driver ( twl4030_power_driver ) ;
MODULE_AUTHOR ( " Nokia Corporation " ) ;
MODULE_AUTHOR ( " Texas Instruments, Inc. " ) ;
MODULE_DESCRIPTION ( " Power management for TWL4030 " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:twl4030_power " ) ;