xref: /OK3568_Linux_fs/kernel/drivers/mfd/twl4030-power.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * Handle TWL4030 Power initialization
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2008 Nokia Corporation
6*4882a593Smuzhiyun  * Copyright (C) 2006 Texas Instruments, Inc
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Written by 	Kalle Jokiniemi
9*4882a593Smuzhiyun  *		Peter De Schrijver <peter.de-schrijver@nokia.com>
10*4882a593Smuzhiyun  * Several fixes by Amit Kucheria <amit.kucheria@verdurent.com>
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * This file is subject to the terms and conditions of the GNU General
13*4882a593Smuzhiyun  * Public License. See the file "COPYING" in the main directory of this
14*4882a593Smuzhiyun  * archive for more details.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful,
17*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19*4882a593Smuzhiyun  * GNU General Public License for more details.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * You should have received a copy of the GNU General Public License
22*4882a593Smuzhiyun  * along with this program; if not, write to the Free Software
23*4882a593Smuzhiyun  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include <linux/module.h>
27*4882a593Smuzhiyun #include <linux/pm.h>
28*4882a593Smuzhiyun #include <linux/mfd/twl.h>
29*4882a593Smuzhiyun #include <linux/platform_device.h>
30*4882a593Smuzhiyun #include <linux/of.h>
31*4882a593Smuzhiyun #include <linux/of_device.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include <asm/mach-types.h>
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static u8 twl4030_start_script_address = 0x2b;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /* Register bits for P1, P2 and P3_SW_EVENTS */
38*4882a593Smuzhiyun #define PWR_STOPON_PRWON	BIT(6)
39*4882a593Smuzhiyun #define PWR_STOPON_SYSEN	BIT(5)
40*4882a593Smuzhiyun #define PWR_ENABLE_WARMRESET	BIT(4)
41*4882a593Smuzhiyun #define PWR_LVL_WAKEUP		BIT(3)
42*4882a593Smuzhiyun #define PWR_DEVACT		BIT(2)
43*4882a593Smuzhiyun #define PWR_DEVSLP		BIT(1)
44*4882a593Smuzhiyun #define PWR_DEVOFF		BIT(0)
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /* Register bits for CFG_P1_TRANSITION (also for P2 and P3) */
47*4882a593Smuzhiyun #define STARTON_SWBUG		BIT(7)	/* Start on watchdog */
48*4882a593Smuzhiyun #define STARTON_VBUS		BIT(5)	/* Start on VBUS */
49*4882a593Smuzhiyun #define STARTON_VBAT		BIT(4)	/* Start on battery insert */
50*4882a593Smuzhiyun #define STARTON_RTC		BIT(3)	/* Start on RTC */
51*4882a593Smuzhiyun #define STARTON_USB		BIT(2)	/* Start on USB host */
52*4882a593Smuzhiyun #define STARTON_CHG		BIT(1)	/* Start on charger */
53*4882a593Smuzhiyun #define STARTON_PWON		BIT(0)	/* Start on PWRON button */
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define SEQ_OFFSYNC		(1 << 0)
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #define PHY_TO_OFF_PM_MASTER(p)		(p - 0x36)
58*4882a593Smuzhiyun #define PHY_TO_OFF_PM_RECEIVER(p)	(p - 0x5b)
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun /* resource - hfclk */
61*4882a593Smuzhiyun #define R_HFCLKOUT_DEV_GRP 	PHY_TO_OFF_PM_RECEIVER(0xe6)
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun /* PM events */
64*4882a593Smuzhiyun #define R_P1_SW_EVENTS		PHY_TO_OFF_PM_MASTER(0x46)
65*4882a593Smuzhiyun #define R_P2_SW_EVENTS		PHY_TO_OFF_PM_MASTER(0x47)
66*4882a593Smuzhiyun #define R_P3_SW_EVENTS		PHY_TO_OFF_PM_MASTER(0x48)
67*4882a593Smuzhiyun #define R_CFG_P1_TRANSITION	PHY_TO_OFF_PM_MASTER(0x36)
68*4882a593Smuzhiyun #define R_CFG_P2_TRANSITION	PHY_TO_OFF_PM_MASTER(0x37)
69*4882a593Smuzhiyun #define R_CFG_P3_TRANSITION	PHY_TO_OFF_PM_MASTER(0x38)
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun #define END_OF_SCRIPT		0x3f
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #define R_SEQ_ADD_A2S		PHY_TO_OFF_PM_MASTER(0x55)
74*4882a593Smuzhiyun #define R_SEQ_ADD_S2A12		PHY_TO_OFF_PM_MASTER(0x56)
75*4882a593Smuzhiyun #define	R_SEQ_ADD_S2A3		PHY_TO_OFF_PM_MASTER(0x57)
76*4882a593Smuzhiyun #define	R_SEQ_ADD_WARM		PHY_TO_OFF_PM_MASTER(0x58)
77*4882a593Smuzhiyun #define R_MEMORY_ADDRESS	PHY_TO_OFF_PM_MASTER(0x59)
78*4882a593Smuzhiyun #define R_MEMORY_DATA		PHY_TO_OFF_PM_MASTER(0x5a)
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun /* resource configuration registers
81*4882a593Smuzhiyun    <RESOURCE>_DEV_GRP   at address 'n+0'
82*4882a593Smuzhiyun    <RESOURCE>_TYPE      at address 'n+1'
83*4882a593Smuzhiyun    <RESOURCE>_REMAP     at address 'n+2'
84*4882a593Smuzhiyun    <RESOURCE>_DEDICATED at address 'n+3'
85*4882a593Smuzhiyun */
86*4882a593Smuzhiyun #define DEV_GRP_OFFSET		0
87*4882a593Smuzhiyun #define TYPE_OFFSET		1
88*4882a593Smuzhiyun #define REMAP_OFFSET		2
89*4882a593Smuzhiyun #define DEDICATED_OFFSET	3
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun /* Bit positions in the registers */
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* <RESOURCE>_DEV_GRP */
94*4882a593Smuzhiyun #define DEV_GRP_SHIFT		5
95*4882a593Smuzhiyun #define DEV_GRP_MASK		(7 << DEV_GRP_SHIFT)
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun /* <RESOURCE>_TYPE */
98*4882a593Smuzhiyun #define TYPE_SHIFT		0
99*4882a593Smuzhiyun #define TYPE_MASK		(7 << TYPE_SHIFT)
100*4882a593Smuzhiyun #define TYPE2_SHIFT		3
101*4882a593Smuzhiyun #define TYPE2_MASK		(3 << TYPE2_SHIFT)
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /* <RESOURCE>_REMAP */
104*4882a593Smuzhiyun #define SLEEP_STATE_SHIFT	0
105*4882a593Smuzhiyun #define SLEEP_STATE_MASK	(0xf << SLEEP_STATE_SHIFT)
106*4882a593Smuzhiyun #define OFF_STATE_SHIFT		4
107*4882a593Smuzhiyun #define OFF_STATE_MASK		(0xf << OFF_STATE_SHIFT)
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun static u8 res_config_addrs[] = {
110*4882a593Smuzhiyun 	[RES_VAUX1]	= 0x17,
111*4882a593Smuzhiyun 	[RES_VAUX2]	= 0x1b,
112*4882a593Smuzhiyun 	[RES_VAUX3]	= 0x1f,
113*4882a593Smuzhiyun 	[RES_VAUX4]	= 0x23,
114*4882a593Smuzhiyun 	[RES_VMMC1]	= 0x27,
115*4882a593Smuzhiyun 	[RES_VMMC2]	= 0x2b,
116*4882a593Smuzhiyun 	[RES_VPLL1]	= 0x2f,
117*4882a593Smuzhiyun 	[RES_VPLL2]	= 0x33,
118*4882a593Smuzhiyun 	[RES_VSIM]	= 0x37,
119*4882a593Smuzhiyun 	[RES_VDAC]	= 0x3b,
120*4882a593Smuzhiyun 	[RES_VINTANA1]	= 0x3f,
121*4882a593Smuzhiyun 	[RES_VINTANA2]	= 0x43,
122*4882a593Smuzhiyun 	[RES_VINTDIG]	= 0x47,
123*4882a593Smuzhiyun 	[RES_VIO]	= 0x4b,
124*4882a593Smuzhiyun 	[RES_VDD1]	= 0x55,
125*4882a593Smuzhiyun 	[RES_VDD2]	= 0x63,
126*4882a593Smuzhiyun 	[RES_VUSB_1V5]	= 0x71,
127*4882a593Smuzhiyun 	[RES_VUSB_1V8]	= 0x74,
128*4882a593Smuzhiyun 	[RES_VUSB_3V1]	= 0x77,
129*4882a593Smuzhiyun 	[RES_VUSBCP]	= 0x7a,
130*4882a593Smuzhiyun 	[RES_REGEN]	= 0x7f,
131*4882a593Smuzhiyun 	[RES_NRES_PWRON] = 0x82,
132*4882a593Smuzhiyun 	[RES_CLKEN]	= 0x85,
133*4882a593Smuzhiyun 	[RES_SYSEN]	= 0x88,
134*4882a593Smuzhiyun 	[RES_HFCLKOUT]	= 0x8b,
135*4882a593Smuzhiyun 	[RES_32KCLKOUT]	= 0x8e,
136*4882a593Smuzhiyun 	[RES_RESET]	= 0x91,
137*4882a593Smuzhiyun 	[RES_MAIN_REF]	= 0x94,
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun /*
141*4882a593Smuzhiyun  * Usable values for .remap_sleep and .remap_off
142*4882a593Smuzhiyun  * Based on table "5.3.3 Resource Operating modes"
143*4882a593Smuzhiyun  */
144*4882a593Smuzhiyun enum {
145*4882a593Smuzhiyun 	TWL_REMAP_OFF = 0,
146*4882a593Smuzhiyun 	TWL_REMAP_SLEEP = 8,
147*4882a593Smuzhiyun 	TWL_REMAP_ACTIVE = 9,
148*4882a593Smuzhiyun };
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun  * Macros to configure the PM register states for various resources.
152*4882a593Smuzhiyun  * Note that we can make MSG_SINGULAR etc private to this driver once
153*4882a593Smuzhiyun  * omap3 has been made DT only.
154*4882a593Smuzhiyun  */
155*4882a593Smuzhiyun #define TWL_DFLT_DELAY		2	/* typically 2 32 KiHz cycles */
156*4882a593Smuzhiyun #define TWL_DEV_GRP_P123	(DEV_GRP_P1 | DEV_GRP_P2 | DEV_GRP_P3)
157*4882a593Smuzhiyun #define TWL_RESOURCE_SET(res, state)					\
158*4882a593Smuzhiyun 	{ MSG_SINGULAR(DEV_GRP_NULL, (res), (state)), TWL_DFLT_DELAY }
159*4882a593Smuzhiyun #define TWL_RESOURCE_ON(res)	TWL_RESOURCE_SET(res, RES_STATE_ACTIVE)
160*4882a593Smuzhiyun #define TWL_RESOURCE_OFF(res)	TWL_RESOURCE_SET(res, RES_STATE_OFF)
161*4882a593Smuzhiyun #define TWL_RESOURCE_RESET(res)	TWL_RESOURCE_SET(res, RES_STATE_WRST)
162*4882a593Smuzhiyun /*
163*4882a593Smuzhiyun  * It seems that type1 and type2 is just the resource init order
164*4882a593Smuzhiyun  * number for the type1 and type2 group.
165*4882a593Smuzhiyun  */
166*4882a593Smuzhiyun #define TWL_RESOURCE_SET_ACTIVE(res, state)			       	\
167*4882a593Smuzhiyun 	{ MSG_SINGULAR(DEV_GRP_NULL, (res), RES_STATE_ACTIVE), (state) }
168*4882a593Smuzhiyun #define TWL_RESOURCE_GROUP_RESET(group, type1, type2)			\
169*4882a593Smuzhiyun 	{ MSG_BROADCAST(DEV_GRP_NULL, (group), (type1), (type2),	\
170*4882a593Smuzhiyun 		RES_STATE_WRST), TWL_DFLT_DELAY }
171*4882a593Smuzhiyun #define TWL_RESOURCE_GROUP_SLEEP(group, type, type2)			\
172*4882a593Smuzhiyun 	{ MSG_BROADCAST(DEV_GRP_NULL, (group), (type), (type2),		\
173*4882a593Smuzhiyun 		RES_STATE_SLEEP), TWL_DFLT_DELAY }
174*4882a593Smuzhiyun #define TWL_RESOURCE_GROUP_ACTIVE(group, type, type2)			\
175*4882a593Smuzhiyun 	{ MSG_BROADCAST(DEV_GRP_NULL, (group), (type), (type2),		\
176*4882a593Smuzhiyun 		RES_STATE_ACTIVE), TWL_DFLT_DELAY }
177*4882a593Smuzhiyun #define TWL_REMAP_SLEEP(res, devgrp, typ, typ2)				\
178*4882a593Smuzhiyun 	{ .resource = (res), .devgroup = (devgrp),			\
179*4882a593Smuzhiyun 	  .type = (typ), .type2 = (typ2),				\
180*4882a593Smuzhiyun 	  .remap_off = TWL_REMAP_OFF,					\
181*4882a593Smuzhiyun 	  .remap_sleep = TWL_REMAP_SLEEP, }
182*4882a593Smuzhiyun #define TWL_REMAP_OFF(res, devgrp, typ, typ2)				\
183*4882a593Smuzhiyun 	{ .resource = (res), .devgroup = (devgrp),			\
184*4882a593Smuzhiyun 	  .type = (typ), .type2 = (typ2),				\
185*4882a593Smuzhiyun 	  .remap_off = TWL_REMAP_OFF, .remap_sleep = TWL_REMAP_OFF, }
186*4882a593Smuzhiyun 
twl4030_write_script_byte(u8 address,u8 byte)187*4882a593Smuzhiyun static int twl4030_write_script_byte(u8 address, u8 byte)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	int err;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_MEMORY_ADDRESS);
192*4882a593Smuzhiyun 	if (err)
193*4882a593Smuzhiyun 		goto out;
194*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, byte, R_MEMORY_DATA);
195*4882a593Smuzhiyun out:
196*4882a593Smuzhiyun 	return err;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
twl4030_write_script_ins(u8 address,u16 pmb_message,u8 delay,u8 next)199*4882a593Smuzhiyun static int twl4030_write_script_ins(u8 address, u16 pmb_message,
200*4882a593Smuzhiyun 					   u8 delay, u8 next)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	int err;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	address *= 4;
205*4882a593Smuzhiyun 	err = twl4030_write_script_byte(address++, pmb_message >> 8);
206*4882a593Smuzhiyun 	if (err)
207*4882a593Smuzhiyun 		goto out;
208*4882a593Smuzhiyun 	err = twl4030_write_script_byte(address++, pmb_message & 0xff);
209*4882a593Smuzhiyun 	if (err)
210*4882a593Smuzhiyun 		goto out;
211*4882a593Smuzhiyun 	err = twl4030_write_script_byte(address++, delay);
212*4882a593Smuzhiyun 	if (err)
213*4882a593Smuzhiyun 		goto out;
214*4882a593Smuzhiyun 	err = twl4030_write_script_byte(address++, next);
215*4882a593Smuzhiyun out:
216*4882a593Smuzhiyun 	return err;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
twl4030_write_script(u8 address,struct twl4030_ins * script,int len)219*4882a593Smuzhiyun static int twl4030_write_script(u8 address, struct twl4030_ins *script,
220*4882a593Smuzhiyun 				       int len)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	int err = -EINVAL;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	for (; len; len--, address++, script++) {
225*4882a593Smuzhiyun 		if (len == 1) {
226*4882a593Smuzhiyun 			err = twl4030_write_script_ins(address,
227*4882a593Smuzhiyun 						script->pmb_message,
228*4882a593Smuzhiyun 						script->delay,
229*4882a593Smuzhiyun 						END_OF_SCRIPT);
230*4882a593Smuzhiyun 			if (err)
231*4882a593Smuzhiyun 				break;
232*4882a593Smuzhiyun 		} else {
233*4882a593Smuzhiyun 			err = twl4030_write_script_ins(address,
234*4882a593Smuzhiyun 						script->pmb_message,
235*4882a593Smuzhiyun 						script->delay,
236*4882a593Smuzhiyun 						address + 1);
237*4882a593Smuzhiyun 			if (err)
238*4882a593Smuzhiyun 				break;
239*4882a593Smuzhiyun 		}
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 	return err;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
twl4030_config_wakeup3_sequence(u8 address)244*4882a593Smuzhiyun static int twl4030_config_wakeup3_sequence(u8 address)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	int err;
247*4882a593Smuzhiyun 	u8 data;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	/* Set SLEEP to ACTIVE SEQ address for P3 */
250*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_S2A3);
251*4882a593Smuzhiyun 	if (err)
252*4882a593Smuzhiyun 		goto out;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* P3 LVL_WAKEUP should be on LEVEL */
255*4882a593Smuzhiyun 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, R_P3_SW_EVENTS);
256*4882a593Smuzhiyun 	if (err)
257*4882a593Smuzhiyun 		goto out;
258*4882a593Smuzhiyun 	data |= PWR_LVL_WAKEUP;
259*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, R_P3_SW_EVENTS);
260*4882a593Smuzhiyun out:
261*4882a593Smuzhiyun 	if (err)
262*4882a593Smuzhiyun 		pr_err("TWL4030 wakeup sequence for P3 config error\n");
263*4882a593Smuzhiyun 	return err;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun static int
twl4030_config_wakeup12_sequence(const struct twl4030_power_data * pdata,u8 address)267*4882a593Smuzhiyun twl4030_config_wakeup12_sequence(const struct twl4030_power_data *pdata,
268*4882a593Smuzhiyun 				 u8 address)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	int err = 0;
271*4882a593Smuzhiyun 	u8 data;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	/* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
274*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_S2A12);
275*4882a593Smuzhiyun 	if (err)
276*4882a593Smuzhiyun 		goto out;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	/* P1/P2 LVL_WAKEUP should be on LEVEL */
279*4882a593Smuzhiyun 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, R_P1_SW_EVENTS);
280*4882a593Smuzhiyun 	if (err)
281*4882a593Smuzhiyun 		goto out;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	data |= PWR_LVL_WAKEUP;
284*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, R_P1_SW_EVENTS);
285*4882a593Smuzhiyun 	if (err)
286*4882a593Smuzhiyun 		goto out;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, R_P2_SW_EVENTS);
289*4882a593Smuzhiyun 	if (err)
290*4882a593Smuzhiyun 		goto out;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	data |= PWR_LVL_WAKEUP;
293*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, R_P2_SW_EVENTS);
294*4882a593Smuzhiyun 	if (err)
295*4882a593Smuzhiyun 		goto out;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	if (pdata->ac_charger_quirk || machine_is_omap_3430sdp() ||
298*4882a593Smuzhiyun 	    machine_is_omap_ldp()) {
299*4882a593Smuzhiyun 		/* Disabling AC charger effect on sleep-active transitions */
300*4882a593Smuzhiyun 		err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data,
301*4882a593Smuzhiyun 				      R_CFG_P1_TRANSITION);
302*4882a593Smuzhiyun 		if (err)
303*4882a593Smuzhiyun 			goto out;
304*4882a593Smuzhiyun 		data &= ~STARTON_CHG;
305*4882a593Smuzhiyun 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data,
306*4882a593Smuzhiyun 				       R_CFG_P1_TRANSITION);
307*4882a593Smuzhiyun 		if (err)
308*4882a593Smuzhiyun 			goto out;
309*4882a593Smuzhiyun 	}
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun out:
312*4882a593Smuzhiyun 	if (err)
313*4882a593Smuzhiyun 		pr_err("TWL4030 wakeup sequence for P1 and P2" \
314*4882a593Smuzhiyun 			"config error\n");
315*4882a593Smuzhiyun 	return err;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
twl4030_config_sleep_sequence(u8 address)318*4882a593Smuzhiyun static int twl4030_config_sleep_sequence(u8 address)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun 	int err;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	/* Set ACTIVE to SLEEP SEQ address in T2 memory*/
323*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_A2S);
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	if (err)
326*4882a593Smuzhiyun 		pr_err("TWL4030 sleep sequence config error\n");
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	return err;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
twl4030_config_warmreset_sequence(u8 address)331*4882a593Smuzhiyun static int twl4030_config_warmreset_sequence(u8 address)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	int err;
334*4882a593Smuzhiyun 	u8 rd_data;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	/* Set WARM RESET SEQ address for P1 */
337*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_WARM);
338*4882a593Smuzhiyun 	if (err)
339*4882a593Smuzhiyun 		goto out;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	/* P1/P2/P3 enable WARMRESET */
342*4882a593Smuzhiyun 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &rd_data, R_P1_SW_EVENTS);
343*4882a593Smuzhiyun 	if (err)
344*4882a593Smuzhiyun 		goto out;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	rd_data |= PWR_ENABLE_WARMRESET;
347*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, rd_data, R_P1_SW_EVENTS);
348*4882a593Smuzhiyun 	if (err)
349*4882a593Smuzhiyun 		goto out;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &rd_data, R_P2_SW_EVENTS);
352*4882a593Smuzhiyun 	if (err)
353*4882a593Smuzhiyun 		goto out;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	rd_data |= PWR_ENABLE_WARMRESET;
356*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, rd_data, R_P2_SW_EVENTS);
357*4882a593Smuzhiyun 	if (err)
358*4882a593Smuzhiyun 		goto out;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &rd_data, R_P3_SW_EVENTS);
361*4882a593Smuzhiyun 	if (err)
362*4882a593Smuzhiyun 		goto out;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	rd_data |= PWR_ENABLE_WARMRESET;
365*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, rd_data, R_P3_SW_EVENTS);
366*4882a593Smuzhiyun out:
367*4882a593Smuzhiyun 	if (err)
368*4882a593Smuzhiyun 		pr_err("TWL4030 warmreset seq config error\n");
369*4882a593Smuzhiyun 	return err;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
twl4030_configure_resource(struct twl4030_resconfig * rconfig)372*4882a593Smuzhiyun static int twl4030_configure_resource(struct twl4030_resconfig *rconfig)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	int rconfig_addr;
375*4882a593Smuzhiyun 	int err;
376*4882a593Smuzhiyun 	u8 type;
377*4882a593Smuzhiyun 	u8 grp;
378*4882a593Smuzhiyun 	u8 remap;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	if (rconfig->resource > TOTAL_RESOURCES) {
381*4882a593Smuzhiyun 		pr_err("TWL4030 Resource %d does not exist\n",
382*4882a593Smuzhiyun 			rconfig->resource);
383*4882a593Smuzhiyun 		return -EINVAL;
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	rconfig_addr = res_config_addrs[rconfig->resource];
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	/* Set resource group */
389*4882a593Smuzhiyun 	err = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &grp,
390*4882a593Smuzhiyun 			      rconfig_addr + DEV_GRP_OFFSET);
391*4882a593Smuzhiyun 	if (err) {
392*4882a593Smuzhiyun 		pr_err("TWL4030 Resource %d group could not be read\n",
393*4882a593Smuzhiyun 			rconfig->resource);
394*4882a593Smuzhiyun 		return err;
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) {
398*4882a593Smuzhiyun 		grp &= ~DEV_GRP_MASK;
399*4882a593Smuzhiyun 		grp |= rconfig->devgroup << DEV_GRP_SHIFT;
400*4882a593Smuzhiyun 		err = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER,
401*4882a593Smuzhiyun 				       grp, rconfig_addr + DEV_GRP_OFFSET);
402*4882a593Smuzhiyun 		if (err < 0) {
403*4882a593Smuzhiyun 			pr_err("TWL4030 failed to program devgroup\n");
404*4882a593Smuzhiyun 			return err;
405*4882a593Smuzhiyun 		}
406*4882a593Smuzhiyun 	}
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	/* Set resource types */
409*4882a593Smuzhiyun 	err = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &type,
410*4882a593Smuzhiyun 				rconfig_addr + TYPE_OFFSET);
411*4882a593Smuzhiyun 	if (err < 0) {
412*4882a593Smuzhiyun 		pr_err("TWL4030 Resource %d type could not be read\n",
413*4882a593Smuzhiyun 			rconfig->resource);
414*4882a593Smuzhiyun 		return err;
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	if (rconfig->type != TWL4030_RESCONFIG_UNDEF) {
418*4882a593Smuzhiyun 		type &= ~TYPE_MASK;
419*4882a593Smuzhiyun 		type |= rconfig->type << TYPE_SHIFT;
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) {
423*4882a593Smuzhiyun 		type &= ~TYPE2_MASK;
424*4882a593Smuzhiyun 		type |= rconfig->type2 << TYPE2_SHIFT;
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER,
428*4882a593Smuzhiyun 				type, rconfig_addr + TYPE_OFFSET);
429*4882a593Smuzhiyun 	if (err < 0) {
430*4882a593Smuzhiyun 		pr_err("TWL4030 failed to program resource type\n");
431*4882a593Smuzhiyun 		return err;
432*4882a593Smuzhiyun 	}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	/* Set remap states */
435*4882a593Smuzhiyun 	err = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &remap,
436*4882a593Smuzhiyun 			      rconfig_addr + REMAP_OFFSET);
437*4882a593Smuzhiyun 	if (err < 0) {
438*4882a593Smuzhiyun 		pr_err("TWL4030 Resource %d remap could not be read\n",
439*4882a593Smuzhiyun 			rconfig->resource);
440*4882a593Smuzhiyun 		return err;
441*4882a593Smuzhiyun 	}
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) {
444*4882a593Smuzhiyun 		remap &= ~OFF_STATE_MASK;
445*4882a593Smuzhiyun 		remap |= rconfig->remap_off << OFF_STATE_SHIFT;
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
449*4882a593Smuzhiyun 		remap &= ~SLEEP_STATE_MASK;
450*4882a593Smuzhiyun 		remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT;
451*4882a593Smuzhiyun 	}
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER,
454*4882a593Smuzhiyun 			       remap,
455*4882a593Smuzhiyun 			       rconfig_addr + REMAP_OFFSET);
456*4882a593Smuzhiyun 	if (err < 0) {
457*4882a593Smuzhiyun 		pr_err("TWL4030 failed to program remap\n");
458*4882a593Smuzhiyun 		return err;
459*4882a593Smuzhiyun 	}
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	return 0;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun 
load_twl4030_script(const struct twl4030_power_data * pdata,struct twl4030_script * tscript,u8 address)464*4882a593Smuzhiyun static int load_twl4030_script(const struct twl4030_power_data *pdata,
465*4882a593Smuzhiyun 			       struct twl4030_script *tscript,
466*4882a593Smuzhiyun 			       u8 address)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	int err;
469*4882a593Smuzhiyun 	static int order;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	/* Make sure the script isn't going beyond last valid address (0x3f) */
472*4882a593Smuzhiyun 	if ((address + tscript->size) > END_OF_SCRIPT) {
473*4882a593Smuzhiyun 		pr_err("TWL4030 scripts too big error\n");
474*4882a593Smuzhiyun 		return -EINVAL;
475*4882a593Smuzhiyun 	}
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	err = twl4030_write_script(address, tscript->script, tscript->size);
478*4882a593Smuzhiyun 	if (err)
479*4882a593Smuzhiyun 		goto out;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	if (tscript->flags & TWL4030_WRST_SCRIPT) {
482*4882a593Smuzhiyun 		err = twl4030_config_warmreset_sequence(address);
483*4882a593Smuzhiyun 		if (err)
484*4882a593Smuzhiyun 			goto out;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 	if (tscript->flags & TWL4030_WAKEUP12_SCRIPT) {
487*4882a593Smuzhiyun 		/* Reset any existing sleep script to avoid hangs on reboot */
488*4882a593Smuzhiyun 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT,
489*4882a593Smuzhiyun 				       R_SEQ_ADD_A2S);
490*4882a593Smuzhiyun 		if (err)
491*4882a593Smuzhiyun 			goto out;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 		err = twl4030_config_wakeup12_sequence(pdata, address);
494*4882a593Smuzhiyun 		if (err)
495*4882a593Smuzhiyun 			goto out;
496*4882a593Smuzhiyun 		order = 1;
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 	if (tscript->flags & TWL4030_WAKEUP3_SCRIPT) {
499*4882a593Smuzhiyun 		err = twl4030_config_wakeup3_sequence(address);
500*4882a593Smuzhiyun 		if (err)
501*4882a593Smuzhiyun 			goto out;
502*4882a593Smuzhiyun 	}
503*4882a593Smuzhiyun 	if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
504*4882a593Smuzhiyun 		if (!order)
505*4882a593Smuzhiyun 			pr_warn("TWL4030: Bad order of scripts (sleep script before wakeup) Leads to boot failure on some boards\n");
506*4882a593Smuzhiyun 		err = twl4030_config_sleep_sequence(address);
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun out:
509*4882a593Smuzhiyun 	return err;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun 
twl4030_remove_script(u8 flags)512*4882a593Smuzhiyun int twl4030_remove_script(u8 flags)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun 	int err = 0;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
517*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_PROTECT_KEY);
518*4882a593Smuzhiyun 	if (err) {
519*4882a593Smuzhiyun 		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
520*4882a593Smuzhiyun 		return err;
521*4882a593Smuzhiyun 	}
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2,
524*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_PROTECT_KEY);
525*4882a593Smuzhiyun 	if (err) {
526*4882a593Smuzhiyun 		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
527*4882a593Smuzhiyun 		return err;
528*4882a593Smuzhiyun 	}
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	if (flags & TWL4030_WRST_SCRIPT) {
531*4882a593Smuzhiyun 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT,
532*4882a593Smuzhiyun 				       R_SEQ_ADD_WARM);
533*4882a593Smuzhiyun 		if (err)
534*4882a593Smuzhiyun 			return err;
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 	if (flags & TWL4030_WAKEUP12_SCRIPT) {
537*4882a593Smuzhiyun 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT,
538*4882a593Smuzhiyun 				       R_SEQ_ADD_S2A12);
539*4882a593Smuzhiyun 		if (err)
540*4882a593Smuzhiyun 			return err;
541*4882a593Smuzhiyun 	}
542*4882a593Smuzhiyun 	if (flags & TWL4030_WAKEUP3_SCRIPT) {
543*4882a593Smuzhiyun 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT,
544*4882a593Smuzhiyun 				       R_SEQ_ADD_S2A3);
545*4882a593Smuzhiyun 		if (err)
546*4882a593Smuzhiyun 			return err;
547*4882a593Smuzhiyun 	}
548*4882a593Smuzhiyun 	if (flags & TWL4030_SLEEP_SCRIPT) {
549*4882a593Smuzhiyun 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT,
550*4882a593Smuzhiyun 				       R_SEQ_ADD_A2S);
551*4882a593Smuzhiyun 		if (err)
552*4882a593Smuzhiyun 			return err;
553*4882a593Smuzhiyun 	}
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
556*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_PROTECT_KEY);
557*4882a593Smuzhiyun 	if (err)
558*4882a593Smuzhiyun 		pr_err("TWL4030 Unable to relock registers\n");
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	return err;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun static int
twl4030_power_configure_scripts(const struct twl4030_power_data * pdata)564*4882a593Smuzhiyun twl4030_power_configure_scripts(const struct twl4030_power_data *pdata)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun 	int err;
567*4882a593Smuzhiyun 	int i;
568*4882a593Smuzhiyun 	u8 address = twl4030_start_script_address;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	for (i = 0; i < pdata->num; i++) {
571*4882a593Smuzhiyun 		err = load_twl4030_script(pdata, pdata->scripts[i], address);
572*4882a593Smuzhiyun 		if (err)
573*4882a593Smuzhiyun 			return err;
574*4882a593Smuzhiyun 		address += pdata->scripts[i]->size;
575*4882a593Smuzhiyun 	}
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	return 0;
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun 
twl4030_patch_rconfig(struct twl4030_resconfig * common,struct twl4030_resconfig * board)580*4882a593Smuzhiyun static void twl4030_patch_rconfig(struct twl4030_resconfig *common,
581*4882a593Smuzhiyun 				  struct twl4030_resconfig *board)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun 	while (common->resource) {
584*4882a593Smuzhiyun 		struct twl4030_resconfig *b = board;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 		while (b->resource) {
587*4882a593Smuzhiyun 			if (b->resource == common->resource) {
588*4882a593Smuzhiyun 				*common = *b;
589*4882a593Smuzhiyun 				break;
590*4882a593Smuzhiyun 			}
591*4882a593Smuzhiyun 			b++;
592*4882a593Smuzhiyun 		}
593*4882a593Smuzhiyun 		common++;
594*4882a593Smuzhiyun 	}
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun static int
twl4030_power_configure_resources(const struct twl4030_power_data * pdata)598*4882a593Smuzhiyun twl4030_power_configure_resources(const struct twl4030_power_data *pdata)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun 	struct twl4030_resconfig *resconfig = pdata->resource_config;
601*4882a593Smuzhiyun 	struct twl4030_resconfig *boardconf = pdata->board_config;
602*4882a593Smuzhiyun 	int err;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	if (resconfig) {
605*4882a593Smuzhiyun 		if (boardconf)
606*4882a593Smuzhiyun 			twl4030_patch_rconfig(resconfig, boardconf);
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 		while (resconfig->resource) {
609*4882a593Smuzhiyun 			err = twl4030_configure_resource(resconfig);
610*4882a593Smuzhiyun 			if (err)
611*4882a593Smuzhiyun 				return err;
612*4882a593Smuzhiyun 			resconfig++;
613*4882a593Smuzhiyun 		}
614*4882a593Smuzhiyun 	}
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	return 0;
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun 
twl4030_starton_mask_and_set(u8 bitmask,u8 bitvalues)619*4882a593Smuzhiyun static int twl4030_starton_mask_and_set(u8 bitmask, u8 bitvalues)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	u8 regs[3] = { TWL4030_PM_MASTER_CFG_P1_TRANSITION,
622*4882a593Smuzhiyun 		       TWL4030_PM_MASTER_CFG_P2_TRANSITION,
623*4882a593Smuzhiyun 		       TWL4030_PM_MASTER_CFG_P3_TRANSITION, };
624*4882a593Smuzhiyun 	u8 val;
625*4882a593Smuzhiyun 	int i, err;
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
628*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_PROTECT_KEY);
629*4882a593Smuzhiyun 	if (err)
630*4882a593Smuzhiyun 		goto relock;
631*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
632*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_KEY_CFG2,
633*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_PROTECT_KEY);
634*4882a593Smuzhiyun 	if (err)
635*4882a593Smuzhiyun 		goto relock;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	for (i = 0; i < sizeof(regs); i++) {
638*4882a593Smuzhiyun 		err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER,
639*4882a593Smuzhiyun 				      &val, regs[i]);
640*4882a593Smuzhiyun 		if (err)
641*4882a593Smuzhiyun 			break;
642*4882a593Smuzhiyun 		val = (~bitmask & val) | (bitmask & bitvalues);
643*4882a593Smuzhiyun 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
644*4882a593Smuzhiyun 				       val, regs[i]);
645*4882a593Smuzhiyun 		if (err)
646*4882a593Smuzhiyun 			break;
647*4882a593Smuzhiyun 	}
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	if (err)
650*4882a593Smuzhiyun 		pr_err("TWL4030 Register access failed: %i\n", err);
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun relock:
653*4882a593Smuzhiyun 	return twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
654*4882a593Smuzhiyun 				TWL4030_PM_MASTER_PROTECT_KEY);
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun /*
658*4882a593Smuzhiyun  * In master mode, start the power off sequence.
659*4882a593Smuzhiyun  * After a successful execution, TWL shuts down the power to the SoC
660*4882a593Smuzhiyun  * and all peripherals connected to it.
661*4882a593Smuzhiyun  */
twl4030_power_off(void)662*4882a593Smuzhiyun void twl4030_power_off(void)
663*4882a593Smuzhiyun {
664*4882a593Smuzhiyun 	int err;
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	/* Disable start on charger or VBUS as it can break poweroff */
667*4882a593Smuzhiyun 	err = twl4030_starton_mask_and_set(STARTON_VBUS | STARTON_CHG, 0);
668*4882a593Smuzhiyun 	if (err)
669*4882a593Smuzhiyun 		pr_err("TWL4030 Unable to configure start-up\n");
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, PWR_DEVOFF,
672*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_P1_SW_EVENTS);
673*4882a593Smuzhiyun 	if (err)
674*4882a593Smuzhiyun 		pr_err("TWL4030 Unable to power off\n");
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun 
twl4030_power_use_poweroff(const struct twl4030_power_data * pdata,struct device_node * node)677*4882a593Smuzhiyun static bool twl4030_power_use_poweroff(const struct twl4030_power_data *pdata,
678*4882a593Smuzhiyun 					struct device_node *node)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	if (pdata && pdata->use_poweroff)
681*4882a593Smuzhiyun 		return true;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	if (of_property_read_bool(node, "ti,system-power-controller"))
684*4882a593Smuzhiyun 		return true;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	if (of_property_read_bool(node, "ti,use_poweroff"))
687*4882a593Smuzhiyun 		return true;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	return false;
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun #ifdef CONFIG_OF
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun /* Generic warm reset configuration for omap3 */
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun static struct twl4030_ins omap3_wrst_seq[] = {
697*4882a593Smuzhiyun 	TWL_RESOURCE_OFF(RES_NRES_PWRON),
698*4882a593Smuzhiyun 	TWL_RESOURCE_OFF(RES_RESET),
699*4882a593Smuzhiyun 	TWL_RESOURCE_RESET(RES_MAIN_REF),
700*4882a593Smuzhiyun 	TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2),
701*4882a593Smuzhiyun 	TWL_RESOURCE_RESET(RES_VUSB_3V1),
702*4882a593Smuzhiyun 	TWL_RESOURCE_RESET(RES_VMMC1),
703*4882a593Smuzhiyun 	TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1),
704*4882a593Smuzhiyun 	TWL_RESOURCE_GROUP_RESET(RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0),
705*4882a593Smuzhiyun 	TWL_RESOURCE_ON(RES_RESET),
706*4882a593Smuzhiyun 	TWL_RESOURCE_ON(RES_NRES_PWRON),
707*4882a593Smuzhiyun };
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun static struct twl4030_script omap3_wrst_script = {
710*4882a593Smuzhiyun 	.script	= omap3_wrst_seq,
711*4882a593Smuzhiyun 	.size	= ARRAY_SIZE(omap3_wrst_seq),
712*4882a593Smuzhiyun 	.flags	= TWL4030_WRST_SCRIPT,
713*4882a593Smuzhiyun };
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun static struct twl4030_script *omap3_reset_scripts[] = {
716*4882a593Smuzhiyun 	&omap3_wrst_script,
717*4882a593Smuzhiyun };
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun static struct twl4030_resconfig omap3_rconfig[] = {
720*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_HFCLKOUT, DEV_GRP_P3, -1, -1),
721*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VDD1, DEV_GRP_P1, -1, -1),
722*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VDD2, DEV_GRP_P1, -1, -1),
723*4882a593Smuzhiyun 	{ 0, 0 },
724*4882a593Smuzhiyun };
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun static struct twl4030_power_data omap3_reset = {
727*4882a593Smuzhiyun 	.scripts		= omap3_reset_scripts,
728*4882a593Smuzhiyun 	.num			= ARRAY_SIZE(omap3_reset_scripts),
729*4882a593Smuzhiyun 	.resource_config	= omap3_rconfig,
730*4882a593Smuzhiyun };
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun /* Recommended generic default idle configuration for off-idle */
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun /* Broadcast message to put res to sleep */
735*4882a593Smuzhiyun static struct twl4030_ins omap3_idle_sleep_on_seq[] = {
736*4882a593Smuzhiyun 	TWL_RESOURCE_GROUP_SLEEP(RES_GRP_ALL, RES_TYPE_ALL, 0),
737*4882a593Smuzhiyun };
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun static struct twl4030_script omap3_idle_sleep_on_script = {
740*4882a593Smuzhiyun 	.script	= omap3_idle_sleep_on_seq,
741*4882a593Smuzhiyun 	.size	= ARRAY_SIZE(omap3_idle_sleep_on_seq),
742*4882a593Smuzhiyun 	.flags	= TWL4030_SLEEP_SCRIPT,
743*4882a593Smuzhiyun };
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun /* Broadcast message to put res to active */
746*4882a593Smuzhiyun static struct twl4030_ins omap3_idle_wakeup_p12_seq[] = {
747*4882a593Smuzhiyun 	TWL_RESOURCE_GROUP_ACTIVE(RES_GRP_ALL, RES_TYPE_ALL, 0),
748*4882a593Smuzhiyun };
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun static struct twl4030_script omap3_idle_wakeup_p12_script = {
751*4882a593Smuzhiyun 	.script	= omap3_idle_wakeup_p12_seq,
752*4882a593Smuzhiyun 	.size	= ARRAY_SIZE(omap3_idle_wakeup_p12_seq),
753*4882a593Smuzhiyun 	.flags	= TWL4030_WAKEUP12_SCRIPT,
754*4882a593Smuzhiyun };
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun /* Broadcast message to put res to active */
757*4882a593Smuzhiyun static struct twl4030_ins omap3_idle_wakeup_p3_seq[] = {
758*4882a593Smuzhiyun 	TWL_RESOURCE_SET_ACTIVE(RES_CLKEN, 0x37),
759*4882a593Smuzhiyun 	TWL_RESOURCE_GROUP_ACTIVE(RES_GRP_ALL, RES_TYPE_ALL, 0),
760*4882a593Smuzhiyun };
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun static struct twl4030_script omap3_idle_wakeup_p3_script = {
763*4882a593Smuzhiyun 	.script	= omap3_idle_wakeup_p3_seq,
764*4882a593Smuzhiyun 	.size	= ARRAY_SIZE(omap3_idle_wakeup_p3_seq),
765*4882a593Smuzhiyun 	.flags	= TWL4030_WAKEUP3_SCRIPT,
766*4882a593Smuzhiyun };
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun static struct twl4030_script *omap3_idle_scripts[] = {
769*4882a593Smuzhiyun 	&omap3_idle_wakeup_p12_script,
770*4882a593Smuzhiyun 	&omap3_idle_wakeup_p3_script,
771*4882a593Smuzhiyun 	&omap3_wrst_script,
772*4882a593Smuzhiyun 	&omap3_idle_sleep_on_script,
773*4882a593Smuzhiyun };
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun /*
776*4882a593Smuzhiyun  * Recommended configuration based on "Recommended Sleep
777*4882a593Smuzhiyun  * Sequences for the Zoom Platform":
778*4882a593Smuzhiyun  * http://omappedia.com/wiki/File:Recommended_Sleep_Sequences_Zoom.pdf
779*4882a593Smuzhiyun  * Note that the type1 and type2 seem to be just the init order number
780*4882a593Smuzhiyun  * for type1 and type2 groups as specified in the document mentioned
781*4882a593Smuzhiyun  * above.
782*4882a593Smuzhiyun  */
783*4882a593Smuzhiyun static struct twl4030_resconfig omap3_idle_rconfig[] = {
784*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VAUX1, TWL4030_RESCONFIG_UNDEF, 0, 0),
785*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VAUX2, TWL4030_RESCONFIG_UNDEF, 0, 0),
786*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VAUX3, TWL4030_RESCONFIG_UNDEF, 0, 0),
787*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VAUX4, TWL4030_RESCONFIG_UNDEF, 0, 0),
788*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VMMC1, TWL4030_RESCONFIG_UNDEF, 0, 0),
789*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VMMC2, TWL4030_RESCONFIG_UNDEF, 0, 0),
790*4882a593Smuzhiyun 	TWL_REMAP_OFF(RES_VPLL1, DEV_GRP_P1, 3, 1),
791*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VPLL2, DEV_GRP_P1, 0, 0),
792*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VSIM, TWL4030_RESCONFIG_UNDEF, 0, 0),
793*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VDAC, TWL4030_RESCONFIG_UNDEF, 0, 0),
794*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VINTANA1, TWL_DEV_GRP_P123, 1, 2),
795*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VINTANA2, TWL_DEV_GRP_P123, 0, 2),
796*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VINTDIG, TWL_DEV_GRP_P123, 1, 2),
797*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VIO, TWL_DEV_GRP_P123, 2, 2),
798*4882a593Smuzhiyun 	TWL_REMAP_OFF(RES_VDD1, DEV_GRP_P1, 4, 1),
799*4882a593Smuzhiyun 	TWL_REMAP_OFF(RES_VDD2, DEV_GRP_P1, 3, 1),
800*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VUSB_1V5, TWL4030_RESCONFIG_UNDEF, 0, 0),
801*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VUSB_1V8, TWL4030_RESCONFIG_UNDEF, 0, 0),
802*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_VUSB_3V1, TWL_DEV_GRP_P123, 0, 0),
803*4882a593Smuzhiyun 	/* Resource #20 USB charge pump skipped */
804*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_REGEN, TWL_DEV_GRP_P123, 2, 1),
805*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_NRES_PWRON, TWL_DEV_GRP_P123, 0, 1),
806*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_CLKEN, TWL_DEV_GRP_P123, 3, 2),
807*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_SYSEN, TWL_DEV_GRP_P123, 6, 1),
808*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_HFCLKOUT, DEV_GRP_P3, 0, 2),
809*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_32KCLKOUT, TWL_DEV_GRP_P123, 0, 0),
810*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_RESET, TWL_DEV_GRP_P123, 6, 0),
811*4882a593Smuzhiyun 	TWL_REMAP_SLEEP(RES_MAIN_REF, TWL_DEV_GRP_P123, 0, 0),
812*4882a593Smuzhiyun 	{ /* Terminator */ },
813*4882a593Smuzhiyun };
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun static struct twl4030_power_data omap3_idle = {
816*4882a593Smuzhiyun 	.scripts		= omap3_idle_scripts,
817*4882a593Smuzhiyun 	.num			= ARRAY_SIZE(omap3_idle_scripts),
818*4882a593Smuzhiyun 	.resource_config	= omap3_idle_rconfig,
819*4882a593Smuzhiyun };
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun /* Disable 32 KiHz oscillator during idle */
822*4882a593Smuzhiyun static struct twl4030_resconfig osc_off_rconfig[] = {
823*4882a593Smuzhiyun 	TWL_REMAP_OFF(RES_CLKEN, DEV_GRP_P1 | DEV_GRP_P3, 3, 2),
824*4882a593Smuzhiyun 	{ /* Terminator */ },
825*4882a593Smuzhiyun };
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun static struct twl4030_power_data osc_off_idle = {
828*4882a593Smuzhiyun 	.scripts		= omap3_idle_scripts,
829*4882a593Smuzhiyun 	.num			= ARRAY_SIZE(omap3_idle_scripts),
830*4882a593Smuzhiyun 	.resource_config	= omap3_idle_rconfig,
831*4882a593Smuzhiyun 	.board_config		= osc_off_rconfig,
832*4882a593Smuzhiyun };
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun static struct twl4030_power_data omap3_idle_ac_quirk = {
835*4882a593Smuzhiyun 	.scripts		= omap3_idle_scripts,
836*4882a593Smuzhiyun 	.num			= ARRAY_SIZE(omap3_idle_scripts),
837*4882a593Smuzhiyun 	.resource_config	= omap3_idle_rconfig,
838*4882a593Smuzhiyun 	.ac_charger_quirk	= true,
839*4882a593Smuzhiyun };
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun static struct twl4030_power_data omap3_idle_ac_quirk_osc_off = {
842*4882a593Smuzhiyun 	.scripts		= omap3_idle_scripts,
843*4882a593Smuzhiyun 	.num			= ARRAY_SIZE(omap3_idle_scripts),
844*4882a593Smuzhiyun 	.resource_config	= omap3_idle_rconfig,
845*4882a593Smuzhiyun 	.board_config		= osc_off_rconfig,
846*4882a593Smuzhiyun 	.ac_charger_quirk	= true,
847*4882a593Smuzhiyun };
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun static const struct of_device_id twl4030_power_of_match[] = {
850*4882a593Smuzhiyun 	{
851*4882a593Smuzhiyun 		.compatible = "ti,twl4030-power",
852*4882a593Smuzhiyun 	},
853*4882a593Smuzhiyun 	{
854*4882a593Smuzhiyun 		.compatible = "ti,twl4030-power-reset",
855*4882a593Smuzhiyun 		.data = &omap3_reset,
856*4882a593Smuzhiyun 	},
857*4882a593Smuzhiyun 	{
858*4882a593Smuzhiyun 		.compatible = "ti,twl4030-power-idle",
859*4882a593Smuzhiyun 		.data = &omap3_idle,
860*4882a593Smuzhiyun 	},
861*4882a593Smuzhiyun 	{
862*4882a593Smuzhiyun 		.compatible = "ti,twl4030-power-idle-osc-off",
863*4882a593Smuzhiyun 		.data = &osc_off_idle,
864*4882a593Smuzhiyun 	},
865*4882a593Smuzhiyun 	{
866*4882a593Smuzhiyun 		.compatible = "ti,twl4030-power-omap3-sdp",
867*4882a593Smuzhiyun 		.data = &omap3_idle_ac_quirk,
868*4882a593Smuzhiyun 	},
869*4882a593Smuzhiyun 	{
870*4882a593Smuzhiyun 		.compatible = "ti,twl4030-power-omap3-ldp",
871*4882a593Smuzhiyun 		.data = &omap3_idle_ac_quirk_osc_off,
872*4882a593Smuzhiyun 	},
873*4882a593Smuzhiyun 	{
874*4882a593Smuzhiyun 		.compatible = "ti,twl4030-power-omap3-evm",
875*4882a593Smuzhiyun 		.data = &omap3_idle_ac_quirk,
876*4882a593Smuzhiyun 	},
877*4882a593Smuzhiyun 	{ },
878*4882a593Smuzhiyun };
879*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, twl4030_power_of_match);
880*4882a593Smuzhiyun #endif	/* CONFIG_OF */
881*4882a593Smuzhiyun 
twl4030_power_probe(struct platform_device * pdev)882*4882a593Smuzhiyun static int twl4030_power_probe(struct platform_device *pdev)
883*4882a593Smuzhiyun {
884*4882a593Smuzhiyun 	const struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev);
885*4882a593Smuzhiyun 	struct device_node *node = pdev->dev.of_node;
886*4882a593Smuzhiyun 	const struct of_device_id *match;
887*4882a593Smuzhiyun 	int err = 0;
888*4882a593Smuzhiyun 	int err2 = 0;
889*4882a593Smuzhiyun 	u8 val;
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun 	if (!pdata && !node) {
892*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Platform data is missing\n");
893*4882a593Smuzhiyun 		return -EINVAL;
894*4882a593Smuzhiyun 	}
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
897*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_PROTECT_KEY);
898*4882a593Smuzhiyun 	err |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
899*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_KEY_CFG2,
900*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_PROTECT_KEY);
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	if (err) {
903*4882a593Smuzhiyun 		pr_err("TWL4030 Unable to unlock registers\n");
904*4882a593Smuzhiyun 		return err;
905*4882a593Smuzhiyun 	}
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	match = of_match_device(of_match_ptr(twl4030_power_of_match),
908*4882a593Smuzhiyun 				&pdev->dev);
909*4882a593Smuzhiyun 	if (match && match->data)
910*4882a593Smuzhiyun 		pdata = match->data;
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	if (pdata) {
913*4882a593Smuzhiyun 		err = twl4030_power_configure_scripts(pdata);
914*4882a593Smuzhiyun 		if (err) {
915*4882a593Smuzhiyun 			pr_err("TWL4030 failed to load scripts\n");
916*4882a593Smuzhiyun 			goto relock;
917*4882a593Smuzhiyun 		}
918*4882a593Smuzhiyun 		err = twl4030_power_configure_resources(pdata);
919*4882a593Smuzhiyun 		if (err) {
920*4882a593Smuzhiyun 			pr_err("TWL4030 failed to configure resource\n");
921*4882a593Smuzhiyun 			goto relock;
922*4882a593Smuzhiyun 		}
923*4882a593Smuzhiyun 	}
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	/* Board has to be wired properly to use this feature */
926*4882a593Smuzhiyun 	if (twl4030_power_use_poweroff(pdata, node) && !pm_power_off) {
927*4882a593Smuzhiyun 		/* Default for SEQ_OFFSYNC is set, lets ensure this */
928*4882a593Smuzhiyun 		err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
929*4882a593Smuzhiyun 				      TWL4030_PM_MASTER_CFG_P123_TRANSITION);
930*4882a593Smuzhiyun 		if (err) {
931*4882a593Smuzhiyun 			pr_warn("TWL4030 Unable to read registers\n");
932*4882a593Smuzhiyun 		} else if (!(val & SEQ_OFFSYNC)) {
933*4882a593Smuzhiyun 			val |= SEQ_OFFSYNC;
934*4882a593Smuzhiyun 			err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val,
935*4882a593Smuzhiyun 					TWL4030_PM_MASTER_CFG_P123_TRANSITION);
936*4882a593Smuzhiyun 			if (err) {
937*4882a593Smuzhiyun 				pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n");
938*4882a593Smuzhiyun 				goto relock;
939*4882a593Smuzhiyun 			}
940*4882a593Smuzhiyun 		}
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 		pm_power_off = twl4030_power_off;
943*4882a593Smuzhiyun 	}
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun relock:
946*4882a593Smuzhiyun 	err2 = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
947*4882a593Smuzhiyun 			       TWL4030_PM_MASTER_PROTECT_KEY);
948*4882a593Smuzhiyun 	if (err2) {
949*4882a593Smuzhiyun 		pr_err("TWL4030 Unable to relock registers\n");
950*4882a593Smuzhiyun 		return err2;
951*4882a593Smuzhiyun 	}
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	return err;
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun 
twl4030_power_remove(struct platform_device * pdev)956*4882a593Smuzhiyun static int twl4030_power_remove(struct platform_device *pdev)
957*4882a593Smuzhiyun {
958*4882a593Smuzhiyun 	return 0;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun static struct platform_driver twl4030_power_driver = {
962*4882a593Smuzhiyun 	.driver = {
963*4882a593Smuzhiyun 		.name	= "twl4030_power",
964*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(twl4030_power_of_match),
965*4882a593Smuzhiyun 	},
966*4882a593Smuzhiyun 	.probe		= twl4030_power_probe,
967*4882a593Smuzhiyun 	.remove		= twl4030_power_remove,
968*4882a593Smuzhiyun };
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun module_platform_driver(twl4030_power_driver);
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun MODULE_AUTHOR("Nokia Corporation");
973*4882a593Smuzhiyun MODULE_AUTHOR("Texas Instruments, Inc.");
974*4882a593Smuzhiyun MODULE_DESCRIPTION("Power management for TWL4030");
975*4882a593Smuzhiyun MODULE_LICENSE("GPL");
976*4882a593Smuzhiyun MODULE_ALIAS("platform:twl4030_power");
977