xref: /openbmc/linux/drivers/mfd/twl4030-power.c (revision daebabd5)
1ebf0bd36SAmit Kucheria /*
2ebf0bd36SAmit Kucheria  * linux/drivers/i2c/chips/twl4030-power.c
3ebf0bd36SAmit Kucheria  *
4ebf0bd36SAmit Kucheria  * Handle TWL4030 Power initialization
5ebf0bd36SAmit Kucheria  *
6ebf0bd36SAmit Kucheria  * Copyright (C) 2008 Nokia Corporation
7ebf0bd36SAmit Kucheria  * Copyright (C) 2006 Texas Instruments, Inc
8ebf0bd36SAmit Kucheria  *
9ebf0bd36SAmit Kucheria  * Written by 	Kalle Jokiniemi
10ebf0bd36SAmit Kucheria  *		Peter De Schrijver <peter.de-schrijver@nokia.com>
11ebf0bd36SAmit Kucheria  * Several fixes by Amit Kucheria <amit.kucheria@verdurent.com>
12ebf0bd36SAmit Kucheria  *
13ebf0bd36SAmit Kucheria  * This file is subject to the terms and conditions of the GNU General
14ebf0bd36SAmit Kucheria  * Public License. See the file "COPYING" in the main directory of this
15ebf0bd36SAmit Kucheria  * archive for more details.
16ebf0bd36SAmit Kucheria  *
17ebf0bd36SAmit Kucheria  * This program is distributed in the hope that it will be useful,
18ebf0bd36SAmit Kucheria  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19ebf0bd36SAmit Kucheria  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20ebf0bd36SAmit Kucheria  * GNU General Public License for more details.
21ebf0bd36SAmit Kucheria  *
22ebf0bd36SAmit Kucheria  * You should have received a copy of the GNU General Public License
23ebf0bd36SAmit Kucheria  * along with this program; if not, write to the Free Software
24ebf0bd36SAmit Kucheria  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25ebf0bd36SAmit Kucheria  */
26ebf0bd36SAmit Kucheria 
27ebf0bd36SAmit Kucheria #include <linux/module.h>
28ebf0bd36SAmit Kucheria #include <linux/pm.h>
29b07682b6SSantosh Shilimkar #include <linux/i2c/twl.h>
30ebf0bd36SAmit Kucheria #include <linux/platform_device.h>
31b0fc1da4SFlorian Vaussard #include <linux/of.h>
32e7cd1d1eSTony Lindgren #include <linux/of_device.h>
33ebf0bd36SAmit Kucheria 
34ebf0bd36SAmit Kucheria #include <asm/mach-types.h>
35ebf0bd36SAmit Kucheria 
36ebf0bd36SAmit Kucheria static u8 twl4030_start_script_address = 0x2b;
37ebf0bd36SAmit Kucheria 
3832057281STony Lindgren /* Register bits for P1, P2 and P3_SW_EVENTS */
3932057281STony Lindgren #define PWR_STOPON_PRWON	BIT(6)
4032057281STony Lindgren #define PWR_STOPON_SYSEN	BIT(5)
4132057281STony Lindgren #define PWR_ENABLE_WARMRESET	BIT(4)
4232057281STony Lindgren #define PWR_LVL_WAKEUP		BIT(3)
4332057281STony Lindgren #define PWR_DEVACT		BIT(2)
4432057281STony Lindgren #define PWR_DEVSLP		BIT(1)
4532057281STony Lindgren #define PWR_DEVOFF		BIT(0)
4632057281STony Lindgren 
4726cc3ab9SIgor Grinberg #define SEQ_OFFSYNC		(1 << 0)
48ebf0bd36SAmit Kucheria 
49ebf0bd36SAmit Kucheria #define PHY_TO_OFF_PM_MASTER(p)		(p - 0x36)
50ebf0bd36SAmit Kucheria #define PHY_TO_OFF_PM_RECEIVER(p)	(p - 0x5b)
51ebf0bd36SAmit Kucheria 
52ebf0bd36SAmit Kucheria /* resource - hfclk */
53ebf0bd36SAmit Kucheria #define R_HFCLKOUT_DEV_GRP 	PHY_TO_OFF_PM_RECEIVER(0xe6)
54ebf0bd36SAmit Kucheria 
55ebf0bd36SAmit Kucheria /* PM events */
56ebf0bd36SAmit Kucheria #define R_P1_SW_EVENTS		PHY_TO_OFF_PM_MASTER(0x46)
57ebf0bd36SAmit Kucheria #define R_P2_SW_EVENTS		PHY_TO_OFF_PM_MASTER(0x47)
58ebf0bd36SAmit Kucheria #define R_P3_SW_EVENTS		PHY_TO_OFF_PM_MASTER(0x48)
59ebf0bd36SAmit Kucheria #define R_CFG_P1_TRANSITION	PHY_TO_OFF_PM_MASTER(0x36)
60ebf0bd36SAmit Kucheria #define R_CFG_P2_TRANSITION	PHY_TO_OFF_PM_MASTER(0x37)
61ebf0bd36SAmit Kucheria #define R_CFG_P3_TRANSITION	PHY_TO_OFF_PM_MASTER(0x38)
62ebf0bd36SAmit Kucheria 
63ebf0bd36SAmit Kucheria #define END_OF_SCRIPT		0x3f
64ebf0bd36SAmit Kucheria 
65ebf0bd36SAmit Kucheria #define R_SEQ_ADD_A2S		PHY_TO_OFF_PM_MASTER(0x55)
66ebf0bd36SAmit Kucheria #define R_SEQ_ADD_S2A12		PHY_TO_OFF_PM_MASTER(0x56)
67ebf0bd36SAmit Kucheria #define	R_SEQ_ADD_S2A3		PHY_TO_OFF_PM_MASTER(0x57)
68ebf0bd36SAmit Kucheria #define	R_SEQ_ADD_WARM		PHY_TO_OFF_PM_MASTER(0x58)
69ebf0bd36SAmit Kucheria #define R_MEMORY_ADDRESS	PHY_TO_OFF_PM_MASTER(0x59)
70ebf0bd36SAmit Kucheria #define R_MEMORY_DATA		PHY_TO_OFF_PM_MASTER(0x5a)
71ebf0bd36SAmit Kucheria 
72890463f0SAmit Kucheria /* resource configuration registers
73890463f0SAmit Kucheria    <RESOURCE>_DEV_GRP   at address 'n+0'
74890463f0SAmit Kucheria    <RESOURCE>_TYPE      at address 'n+1'
75890463f0SAmit Kucheria    <RESOURCE>_REMAP     at address 'n+2'
76890463f0SAmit Kucheria    <RESOURCE>_DEDICATED at address 'n+3'
77890463f0SAmit Kucheria */
78e97d1546SAmit Kucheria #define DEV_GRP_OFFSET		0
79ebf0bd36SAmit Kucheria #define TYPE_OFFSET		1
80b4ead61eSAmit Kucheria #define REMAP_OFFSET		2
81b4ead61eSAmit Kucheria #define DEDICATED_OFFSET	3
82ebf0bd36SAmit Kucheria 
83e97d1546SAmit Kucheria /* Bit positions in the registers */
84890463f0SAmit Kucheria 
85890463f0SAmit Kucheria /* <RESOURCE>_DEV_GRP */
86e97d1546SAmit Kucheria #define DEV_GRP_SHIFT		5
87e97d1546SAmit Kucheria #define DEV_GRP_MASK		(7 << DEV_GRP_SHIFT)
88890463f0SAmit Kucheria 
89890463f0SAmit Kucheria /* <RESOURCE>_TYPE */
90ebf0bd36SAmit Kucheria #define TYPE_SHIFT		0
91ebf0bd36SAmit Kucheria #define TYPE_MASK		(7 << TYPE_SHIFT)
92ebf0bd36SAmit Kucheria #define TYPE2_SHIFT		3
93ebf0bd36SAmit Kucheria #define TYPE2_MASK		(3 << TYPE2_SHIFT)
94ebf0bd36SAmit Kucheria 
95b4ead61eSAmit Kucheria /* <RESOURCE>_REMAP */
96b4ead61eSAmit Kucheria #define SLEEP_STATE_SHIFT	0
97b4ead61eSAmit Kucheria #define SLEEP_STATE_MASK	(0xf << SLEEP_STATE_SHIFT)
98b4ead61eSAmit Kucheria #define OFF_STATE_SHIFT		4
99b4ead61eSAmit Kucheria #define OFF_STATE_MASK		(0xf << OFF_STATE_SHIFT)
100b4ead61eSAmit Kucheria 
101ebf0bd36SAmit Kucheria static u8 res_config_addrs[] = {
102ebf0bd36SAmit Kucheria 	[RES_VAUX1]	= 0x17,
103ebf0bd36SAmit Kucheria 	[RES_VAUX2]	= 0x1b,
104ebf0bd36SAmit Kucheria 	[RES_VAUX3]	= 0x1f,
105ebf0bd36SAmit Kucheria 	[RES_VAUX4]	= 0x23,
106ebf0bd36SAmit Kucheria 	[RES_VMMC1]	= 0x27,
107ebf0bd36SAmit Kucheria 	[RES_VMMC2]	= 0x2b,
108ebf0bd36SAmit Kucheria 	[RES_VPLL1]	= 0x2f,
109ebf0bd36SAmit Kucheria 	[RES_VPLL2]	= 0x33,
110ebf0bd36SAmit Kucheria 	[RES_VSIM]	= 0x37,
111ebf0bd36SAmit Kucheria 	[RES_VDAC]	= 0x3b,
112ebf0bd36SAmit Kucheria 	[RES_VINTANA1]	= 0x3f,
113ebf0bd36SAmit Kucheria 	[RES_VINTANA2]	= 0x43,
114ebf0bd36SAmit Kucheria 	[RES_VINTDIG]	= 0x47,
115ebf0bd36SAmit Kucheria 	[RES_VIO]	= 0x4b,
116ebf0bd36SAmit Kucheria 	[RES_VDD1]	= 0x55,
117ebf0bd36SAmit Kucheria 	[RES_VDD2]	= 0x63,
118ebf0bd36SAmit Kucheria 	[RES_VUSB_1V5]	= 0x71,
119ebf0bd36SAmit Kucheria 	[RES_VUSB_1V8]	= 0x74,
120ebf0bd36SAmit Kucheria 	[RES_VUSB_3V1]	= 0x77,
121ebf0bd36SAmit Kucheria 	[RES_VUSBCP]	= 0x7a,
122ebf0bd36SAmit Kucheria 	[RES_REGEN]	= 0x7f,
123ebf0bd36SAmit Kucheria 	[RES_NRES_PWRON] = 0x82,
124ebf0bd36SAmit Kucheria 	[RES_CLKEN]	= 0x85,
125ebf0bd36SAmit Kucheria 	[RES_SYSEN]	= 0x88,
126ebf0bd36SAmit Kucheria 	[RES_HFCLKOUT]	= 0x8b,
127ebf0bd36SAmit Kucheria 	[RES_32KCLKOUT]	= 0x8e,
128ebf0bd36SAmit Kucheria 	[RES_RESET]	= 0x91,
129d7ac829fSLesly A M 	[RES_MAIN_REF]	= 0x94,
130ebf0bd36SAmit Kucheria };
131ebf0bd36SAmit Kucheria 
132e7cd1d1eSTony Lindgren /*
133e7cd1d1eSTony Lindgren  * Usable values for .remap_sleep and .remap_off
134e7cd1d1eSTony Lindgren  * Based on table "5.3.3 Resource Operating modes"
135e7cd1d1eSTony Lindgren  */
136e7cd1d1eSTony Lindgren enum {
137e7cd1d1eSTony Lindgren 	TWL_REMAP_OFF = 0,
138e7cd1d1eSTony Lindgren 	TWL_REMAP_SLEEP = 8,
139e7cd1d1eSTony Lindgren 	TWL_REMAP_ACTIVE = 9,
140e7cd1d1eSTony Lindgren };
141e7cd1d1eSTony Lindgren 
142e7cd1d1eSTony Lindgren /*
143e7cd1d1eSTony Lindgren  * Macros to configure the PM register states for various resources.
144e7cd1d1eSTony Lindgren  * Note that we can make MSG_SINGULAR etc private to this driver once
145e7cd1d1eSTony Lindgren  * omap3 has been made DT only.
146e7cd1d1eSTony Lindgren  */
147e7cd1d1eSTony Lindgren #define TWL_DFLT_DELAY		2	/* typically 2 32 KiHz cycles */
14876714d2cSTony Lindgren #define TWL_DEV_GRP_P123	(DEV_GRP_P1 | DEV_GRP_P2 | DEV_GRP_P3)
149e7cd1d1eSTony Lindgren #define TWL_RESOURCE_SET(res, state)					\
150e7cd1d1eSTony Lindgren 	{ MSG_SINGULAR(DEV_GRP_NULL, (res), (state)), TWL_DFLT_DELAY }
151e7cd1d1eSTony Lindgren #define TWL_RESOURCE_ON(res)	TWL_RESOURCE_SET(res, RES_STATE_ACTIVE)
152e7cd1d1eSTony Lindgren #define TWL_RESOURCE_OFF(res)	TWL_RESOURCE_SET(res, RES_STATE_OFF)
153e7cd1d1eSTony Lindgren #define TWL_RESOURCE_RESET(res)	TWL_RESOURCE_SET(res, RES_STATE_WRST)
154e7cd1d1eSTony Lindgren /*
155e7cd1d1eSTony Lindgren  * It seems that type1 and type2 is just the resource init order
156e7cd1d1eSTony Lindgren  * number for the type1 and type2 group.
157e7cd1d1eSTony Lindgren  */
15876714d2cSTony Lindgren #define TWL_RESOURCE_SET_ACTIVE(res, state)			       	\
15976714d2cSTony Lindgren 	{ MSG_SINGULAR(DEV_GRP_NULL, (res), RES_STATE_ACTIVE), (state) }
160e7cd1d1eSTony Lindgren #define TWL_RESOURCE_GROUP_RESET(group, type1, type2)			\
161e7cd1d1eSTony Lindgren 	{ MSG_BROADCAST(DEV_GRP_NULL, (group), (type1), (type2),	\
162e7cd1d1eSTony Lindgren 		RES_STATE_WRST), TWL_DFLT_DELAY }
16376714d2cSTony Lindgren #define TWL_RESOURCE_GROUP_SLEEP(group, type, type2)			\
16476714d2cSTony Lindgren 	{ MSG_BROADCAST(DEV_GRP_NULL, (group), (type), (type2),		\
16576714d2cSTony Lindgren 		RES_STATE_SLEEP), TWL_DFLT_DELAY }
16676714d2cSTony Lindgren #define TWL_RESOURCE_GROUP_ACTIVE(group, type, type2)			\
16776714d2cSTony Lindgren 	{ MSG_BROADCAST(DEV_GRP_NULL, (group), (type), (type2),		\
16876714d2cSTony Lindgren 		RES_STATE_ACTIVE), TWL_DFLT_DELAY }
169e7cd1d1eSTony Lindgren #define TWL_REMAP_SLEEP(res, devgrp, typ, typ2)				\
170e7cd1d1eSTony Lindgren 	{ .resource = (res), .devgroup = (devgrp),			\
171e7cd1d1eSTony Lindgren 	  .type = (typ), .type2 = (typ2),				\
172e7cd1d1eSTony Lindgren 	  .remap_off = TWL_REMAP_OFF,					\
173e7cd1d1eSTony Lindgren 	  .remap_sleep = TWL_REMAP_SLEEP, }
17476714d2cSTony Lindgren #define TWL_REMAP_OFF(res, devgrp, typ, typ2)				\
17576714d2cSTony Lindgren 	{ .resource = (res), .devgroup = (devgrp),			\
17676714d2cSTony Lindgren 	  .type = (typ), .type2 = (typ2),				\
17776714d2cSTony Lindgren 	  .remap_off = TWL_REMAP_OFF, .remap_sleep = TWL_REMAP_OFF, }
178e7cd1d1eSTony Lindgren 
179f791be49SBill Pemberton static int twl4030_write_script_byte(u8 address, u8 byte)
180ebf0bd36SAmit Kucheria {
181ebf0bd36SAmit Kucheria 	int err;
182ebf0bd36SAmit Kucheria 
1834850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_MEMORY_ADDRESS);
184ebf0bd36SAmit Kucheria 	if (err)
185ebf0bd36SAmit Kucheria 		goto out;
1864850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, byte, R_MEMORY_DATA);
187ebf0bd36SAmit Kucheria out:
188ebf0bd36SAmit Kucheria 	return err;
189ebf0bd36SAmit Kucheria }
190ebf0bd36SAmit Kucheria 
191f791be49SBill Pemberton static int twl4030_write_script_ins(u8 address, u16 pmb_message,
192ebf0bd36SAmit Kucheria 					   u8 delay, u8 next)
193ebf0bd36SAmit Kucheria {
194ebf0bd36SAmit Kucheria 	int err;
195ebf0bd36SAmit Kucheria 
196ebf0bd36SAmit Kucheria 	address *= 4;
197ebf0bd36SAmit Kucheria 	err = twl4030_write_script_byte(address++, pmb_message >> 8);
198ebf0bd36SAmit Kucheria 	if (err)
199ebf0bd36SAmit Kucheria 		goto out;
200ebf0bd36SAmit Kucheria 	err = twl4030_write_script_byte(address++, pmb_message & 0xff);
201ebf0bd36SAmit Kucheria 	if (err)
202ebf0bd36SAmit Kucheria 		goto out;
203ebf0bd36SAmit Kucheria 	err = twl4030_write_script_byte(address++, delay);
204ebf0bd36SAmit Kucheria 	if (err)
205ebf0bd36SAmit Kucheria 		goto out;
206ebf0bd36SAmit Kucheria 	err = twl4030_write_script_byte(address++, next);
207ebf0bd36SAmit Kucheria out:
208ebf0bd36SAmit Kucheria 	return err;
209ebf0bd36SAmit Kucheria }
210ebf0bd36SAmit Kucheria 
211f791be49SBill Pemberton static int twl4030_write_script(u8 address, struct twl4030_ins *script,
212ebf0bd36SAmit Kucheria 				       int len)
213ebf0bd36SAmit Kucheria {
214f65e9eacSArnd Bergmann 	int err = -EINVAL;
215ebf0bd36SAmit Kucheria 
216ebf0bd36SAmit Kucheria 	for (; len; len--, address++, script++) {
217ebf0bd36SAmit Kucheria 		if (len == 1) {
218ebf0bd36SAmit Kucheria 			err = twl4030_write_script_ins(address,
219ebf0bd36SAmit Kucheria 						script->pmb_message,
220ebf0bd36SAmit Kucheria 						script->delay,
221ebf0bd36SAmit Kucheria 						END_OF_SCRIPT);
222ebf0bd36SAmit Kucheria 			if (err)
223ebf0bd36SAmit Kucheria 				break;
224ebf0bd36SAmit Kucheria 		} else {
225ebf0bd36SAmit Kucheria 			err = twl4030_write_script_ins(address,
226ebf0bd36SAmit Kucheria 						script->pmb_message,
227ebf0bd36SAmit Kucheria 						script->delay,
228ebf0bd36SAmit Kucheria 						address + 1);
229ebf0bd36SAmit Kucheria 			if (err)
230ebf0bd36SAmit Kucheria 				break;
231ebf0bd36SAmit Kucheria 		}
232ebf0bd36SAmit Kucheria 	}
233ebf0bd36SAmit Kucheria 	return err;
234ebf0bd36SAmit Kucheria }
235ebf0bd36SAmit Kucheria 
236f791be49SBill Pemberton static int twl4030_config_wakeup3_sequence(u8 address)
237ebf0bd36SAmit Kucheria {
238ebf0bd36SAmit Kucheria 	int err;
239ebf0bd36SAmit Kucheria 	u8 data;
240ebf0bd36SAmit Kucheria 
241ebf0bd36SAmit Kucheria 	/* Set SLEEP to ACTIVE SEQ address for P3 */
2424850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_S2A3);
243ebf0bd36SAmit Kucheria 	if (err)
244ebf0bd36SAmit Kucheria 		goto out;
245ebf0bd36SAmit Kucheria 
246ebf0bd36SAmit Kucheria 	/* P3 LVL_WAKEUP should be on LEVEL */
2474850f124SPeter Ujfalusi 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, R_P3_SW_EVENTS);
248ebf0bd36SAmit Kucheria 	if (err)
249ebf0bd36SAmit Kucheria 		goto out;
25032057281STony Lindgren 	data |= PWR_LVL_WAKEUP;
2514850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, R_P3_SW_EVENTS);
252ebf0bd36SAmit Kucheria out:
253ebf0bd36SAmit Kucheria 	if (err)
254ebf0bd36SAmit Kucheria 		pr_err("TWL4030 wakeup sequence for P3 config error\n");
255ebf0bd36SAmit Kucheria 	return err;
256ebf0bd36SAmit Kucheria }
257ebf0bd36SAmit Kucheria 
258f791be49SBill Pemberton static int twl4030_config_wakeup12_sequence(u8 address)
259ebf0bd36SAmit Kucheria {
260ebf0bd36SAmit Kucheria 	int err = 0;
261ebf0bd36SAmit Kucheria 	u8 data;
262ebf0bd36SAmit Kucheria 
263ebf0bd36SAmit Kucheria 	/* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
2644850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_S2A12);
265ebf0bd36SAmit Kucheria 	if (err)
266ebf0bd36SAmit Kucheria 		goto out;
267ebf0bd36SAmit Kucheria 
268ebf0bd36SAmit Kucheria 	/* P1/P2 LVL_WAKEUP should be on LEVEL */
2694850f124SPeter Ujfalusi 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, R_P1_SW_EVENTS);
270ebf0bd36SAmit Kucheria 	if (err)
271ebf0bd36SAmit Kucheria 		goto out;
272ebf0bd36SAmit Kucheria 
27332057281STony Lindgren 	data |= PWR_LVL_WAKEUP;
2744850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, R_P1_SW_EVENTS);
275ebf0bd36SAmit Kucheria 	if (err)
276ebf0bd36SAmit Kucheria 		goto out;
277ebf0bd36SAmit Kucheria 
2784850f124SPeter Ujfalusi 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, R_P2_SW_EVENTS);
279ebf0bd36SAmit Kucheria 	if (err)
280ebf0bd36SAmit Kucheria 		goto out;
281ebf0bd36SAmit Kucheria 
28232057281STony Lindgren 	data |= PWR_LVL_WAKEUP;
2834850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, R_P2_SW_EVENTS);
284ebf0bd36SAmit Kucheria 	if (err)
285ebf0bd36SAmit Kucheria 		goto out;
286ebf0bd36SAmit Kucheria 
287ebf0bd36SAmit Kucheria 	if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
288ebf0bd36SAmit Kucheria 		/* Disabling AC charger effect on sleep-active transitions */
2894850f124SPeter Ujfalusi 		err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data,
290ebf0bd36SAmit Kucheria 				      R_CFG_P1_TRANSITION);
291ebf0bd36SAmit Kucheria 		if (err)
292ebf0bd36SAmit Kucheria 			goto out;
293ebf0bd36SAmit Kucheria 		data &= ~(1<<1);
2944850f124SPeter Ujfalusi 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data,
295ebf0bd36SAmit Kucheria 				       R_CFG_P1_TRANSITION);
296ebf0bd36SAmit Kucheria 		if (err)
297ebf0bd36SAmit Kucheria 			goto out;
298ebf0bd36SAmit Kucheria 	}
299ebf0bd36SAmit Kucheria 
300ebf0bd36SAmit Kucheria out:
301ebf0bd36SAmit Kucheria 	if (err)
302ebf0bd36SAmit Kucheria 		pr_err("TWL4030 wakeup sequence for P1 and P2" \
303ebf0bd36SAmit Kucheria 			"config error\n");
304ebf0bd36SAmit Kucheria 	return err;
305ebf0bd36SAmit Kucheria }
306ebf0bd36SAmit Kucheria 
307f791be49SBill Pemberton static int twl4030_config_sleep_sequence(u8 address)
308ebf0bd36SAmit Kucheria {
309ebf0bd36SAmit Kucheria 	int err;
310ebf0bd36SAmit Kucheria 
311ebf0bd36SAmit Kucheria 	/* Set ACTIVE to SLEEP SEQ address in T2 memory*/
3124850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_A2S);
313ebf0bd36SAmit Kucheria 
314ebf0bd36SAmit Kucheria 	if (err)
315ebf0bd36SAmit Kucheria 		pr_err("TWL4030 sleep sequence config error\n");
316ebf0bd36SAmit Kucheria 
317ebf0bd36SAmit Kucheria 	return err;
318ebf0bd36SAmit Kucheria }
319ebf0bd36SAmit Kucheria 
320f791be49SBill Pemberton static int twl4030_config_warmreset_sequence(u8 address)
321ebf0bd36SAmit Kucheria {
322ebf0bd36SAmit Kucheria 	int err;
323ebf0bd36SAmit Kucheria 	u8 rd_data;
324ebf0bd36SAmit Kucheria 
325ebf0bd36SAmit Kucheria 	/* Set WARM RESET SEQ address for P1 */
3264850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_WARM);
327ebf0bd36SAmit Kucheria 	if (err)
328ebf0bd36SAmit Kucheria 		goto out;
329ebf0bd36SAmit Kucheria 
330ebf0bd36SAmit Kucheria 	/* P1/P2/P3 enable WARMRESET */
3314850f124SPeter Ujfalusi 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &rd_data, R_P1_SW_EVENTS);
332ebf0bd36SAmit Kucheria 	if (err)
333ebf0bd36SAmit Kucheria 		goto out;
334ebf0bd36SAmit Kucheria 
33532057281STony Lindgren 	rd_data |= PWR_ENABLE_WARMRESET;
3364850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, rd_data, R_P1_SW_EVENTS);
337ebf0bd36SAmit Kucheria 	if (err)
338ebf0bd36SAmit Kucheria 		goto out;
339ebf0bd36SAmit Kucheria 
3404850f124SPeter Ujfalusi 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &rd_data, R_P2_SW_EVENTS);
341ebf0bd36SAmit Kucheria 	if (err)
342ebf0bd36SAmit Kucheria 		goto out;
343ebf0bd36SAmit Kucheria 
34432057281STony Lindgren 	rd_data |= PWR_ENABLE_WARMRESET;
3454850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, rd_data, R_P2_SW_EVENTS);
346ebf0bd36SAmit Kucheria 	if (err)
347ebf0bd36SAmit Kucheria 		goto out;
348ebf0bd36SAmit Kucheria 
3494850f124SPeter Ujfalusi 	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &rd_data, R_P3_SW_EVENTS);
350ebf0bd36SAmit Kucheria 	if (err)
351ebf0bd36SAmit Kucheria 		goto out;
352ebf0bd36SAmit Kucheria 
35332057281STony Lindgren 	rd_data |= PWR_ENABLE_WARMRESET;
3544850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, rd_data, R_P3_SW_EVENTS);
355ebf0bd36SAmit Kucheria out:
356ebf0bd36SAmit Kucheria 	if (err)
357ebf0bd36SAmit Kucheria 		pr_err("TWL4030 warmreset seq config error\n");
358ebf0bd36SAmit Kucheria 	return err;
359ebf0bd36SAmit Kucheria }
360ebf0bd36SAmit Kucheria 
361f791be49SBill Pemberton static int twl4030_configure_resource(struct twl4030_resconfig *rconfig)
362ebf0bd36SAmit Kucheria {
363ebf0bd36SAmit Kucheria 	int rconfig_addr;
364ebf0bd36SAmit Kucheria 	int err;
365ebf0bd36SAmit Kucheria 	u8 type;
366ebf0bd36SAmit Kucheria 	u8 grp;
367b4ead61eSAmit Kucheria 	u8 remap;
368ebf0bd36SAmit Kucheria 
369ebf0bd36SAmit Kucheria 	if (rconfig->resource > TOTAL_RESOURCES) {
370ebf0bd36SAmit Kucheria 		pr_err("TWL4030 Resource %d does not exist\n",
371ebf0bd36SAmit Kucheria 			rconfig->resource);
372ebf0bd36SAmit Kucheria 		return -EINVAL;
373ebf0bd36SAmit Kucheria 	}
374ebf0bd36SAmit Kucheria 
375ebf0bd36SAmit Kucheria 	rconfig_addr = res_config_addrs[rconfig->resource];
376ebf0bd36SAmit Kucheria 
377ebf0bd36SAmit Kucheria 	/* Set resource group */
3784850f124SPeter Ujfalusi 	err = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &grp,
379e97d1546SAmit Kucheria 			      rconfig_addr + DEV_GRP_OFFSET);
380ebf0bd36SAmit Kucheria 	if (err) {
381ebf0bd36SAmit Kucheria 		pr_err("TWL4030 Resource %d group could not be read\n",
382ebf0bd36SAmit Kucheria 			rconfig->resource);
383ebf0bd36SAmit Kucheria 		return err;
384ebf0bd36SAmit Kucheria 	}
385ebf0bd36SAmit Kucheria 
38656baa667SAaro Koskinen 	if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) {
387e97d1546SAmit Kucheria 		grp &= ~DEV_GRP_MASK;
388e97d1546SAmit Kucheria 		grp |= rconfig->devgroup << DEV_GRP_SHIFT;
3894850f124SPeter Ujfalusi 		err = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER,
390e97d1546SAmit Kucheria 				       grp, rconfig_addr + DEV_GRP_OFFSET);
391ebf0bd36SAmit Kucheria 		if (err < 0) {
392ebf0bd36SAmit Kucheria 			pr_err("TWL4030 failed to program devgroup\n");
393ebf0bd36SAmit Kucheria 			return err;
394ebf0bd36SAmit Kucheria 		}
395ebf0bd36SAmit Kucheria 	}
396ebf0bd36SAmit Kucheria 
397ebf0bd36SAmit Kucheria 	/* Set resource types */
3984850f124SPeter Ujfalusi 	err = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &type,
399ebf0bd36SAmit Kucheria 				rconfig_addr + TYPE_OFFSET);
400ebf0bd36SAmit Kucheria 	if (err < 0) {
401ebf0bd36SAmit Kucheria 		pr_err("TWL4030 Resource %d type could not be read\n",
402ebf0bd36SAmit Kucheria 			rconfig->resource);
403ebf0bd36SAmit Kucheria 		return err;
404ebf0bd36SAmit Kucheria 	}
405ebf0bd36SAmit Kucheria 
40656baa667SAaro Koskinen 	if (rconfig->type != TWL4030_RESCONFIG_UNDEF) {
407ebf0bd36SAmit Kucheria 		type &= ~TYPE_MASK;
408ebf0bd36SAmit Kucheria 		type |= rconfig->type << TYPE_SHIFT;
409ebf0bd36SAmit Kucheria 	}
410ebf0bd36SAmit Kucheria 
41156baa667SAaro Koskinen 	if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) {
412ebf0bd36SAmit Kucheria 		type &= ~TYPE2_MASK;
413ebf0bd36SAmit Kucheria 		type |= rconfig->type2 << TYPE2_SHIFT;
414ebf0bd36SAmit Kucheria 	}
415ebf0bd36SAmit Kucheria 
4164850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER,
417ebf0bd36SAmit Kucheria 				type, rconfig_addr + TYPE_OFFSET);
418ebf0bd36SAmit Kucheria 	if (err < 0) {
419ebf0bd36SAmit Kucheria 		pr_err("TWL4030 failed to program resource type\n");
420ebf0bd36SAmit Kucheria 		return err;
421ebf0bd36SAmit Kucheria 	}
422ebf0bd36SAmit Kucheria 
423b4ead61eSAmit Kucheria 	/* Set remap states */
4244850f124SPeter Ujfalusi 	err = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &remap,
425b4ead61eSAmit Kucheria 			      rconfig_addr + REMAP_OFFSET);
426b4ead61eSAmit Kucheria 	if (err < 0) {
427b4ead61eSAmit Kucheria 		pr_err("TWL4030 Resource %d remap could not be read\n",
428b4ead61eSAmit Kucheria 			rconfig->resource);
429b4ead61eSAmit Kucheria 		return err;
430b4ead61eSAmit Kucheria 	}
431b4ead61eSAmit Kucheria 
43253cf9a60SAmit Kucheria 	if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) {
433b4ead61eSAmit Kucheria 		remap &= ~OFF_STATE_MASK;
434b4ead61eSAmit Kucheria 		remap |= rconfig->remap_off << OFF_STATE_SHIFT;
435b4ead61eSAmit Kucheria 	}
436b4ead61eSAmit Kucheria 
43753cf9a60SAmit Kucheria 	if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
438b4ead61eSAmit Kucheria 		remap &= ~SLEEP_STATE_MASK;
4391ea933f4SMike Turquette 		remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT;
440b4ead61eSAmit Kucheria 	}
441b4ead61eSAmit Kucheria 
4424850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER,
443b4ead61eSAmit Kucheria 			       remap,
444b4ead61eSAmit Kucheria 			       rconfig_addr + REMAP_OFFSET);
445b4ead61eSAmit Kucheria 	if (err < 0) {
446b4ead61eSAmit Kucheria 		pr_err("TWL4030 failed to program remap\n");
447b4ead61eSAmit Kucheria 		return err;
448b4ead61eSAmit Kucheria 	}
449b4ead61eSAmit Kucheria 
450ebf0bd36SAmit Kucheria 	return 0;
451ebf0bd36SAmit Kucheria }
452ebf0bd36SAmit Kucheria 
453f791be49SBill Pemberton static int load_twl4030_script(struct twl4030_script *tscript,
454ebf0bd36SAmit Kucheria 	       u8 address)
455ebf0bd36SAmit Kucheria {
456ebf0bd36SAmit Kucheria 	int err;
45775a74565SAmit Kucheria 	static int order;
458ebf0bd36SAmit Kucheria 
459ebf0bd36SAmit Kucheria 	/* Make sure the script isn't going beyond last valid address (0x3f) */
460ebf0bd36SAmit Kucheria 	if ((address + tscript->size) > END_OF_SCRIPT) {
461ebf0bd36SAmit Kucheria 		pr_err("TWL4030 scripts too big error\n");
462ebf0bd36SAmit Kucheria 		return -EINVAL;
463ebf0bd36SAmit Kucheria 	}
464ebf0bd36SAmit Kucheria 
465ebf0bd36SAmit Kucheria 	err = twl4030_write_script(address, tscript->script, tscript->size);
466ebf0bd36SAmit Kucheria 	if (err)
467ebf0bd36SAmit Kucheria 		goto out;
468ebf0bd36SAmit Kucheria 
469ebf0bd36SAmit Kucheria 	if (tscript->flags & TWL4030_WRST_SCRIPT) {
470ebf0bd36SAmit Kucheria 		err = twl4030_config_warmreset_sequence(address);
471ebf0bd36SAmit Kucheria 		if (err)
472ebf0bd36SAmit Kucheria 			goto out;
473ebf0bd36SAmit Kucheria 	}
474ebf0bd36SAmit Kucheria 	if (tscript->flags & TWL4030_WAKEUP12_SCRIPT) {
475fc7d76e4STony Lindgren 		/* Reset any existing sleep script to avoid hangs on reboot */
476fc7d76e4STony Lindgren 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT,
477fc7d76e4STony Lindgren 				       R_SEQ_ADD_A2S);
478fc7d76e4STony Lindgren 		if (err)
479fc7d76e4STony Lindgren 			goto out;
480fc7d76e4STony Lindgren 
481ebf0bd36SAmit Kucheria 		err = twl4030_config_wakeup12_sequence(address);
482ebf0bd36SAmit Kucheria 		if (err)
483ebf0bd36SAmit Kucheria 			goto out;
48475a74565SAmit Kucheria 		order = 1;
485ebf0bd36SAmit Kucheria 	}
486ebf0bd36SAmit Kucheria 	if (tscript->flags & TWL4030_WAKEUP3_SCRIPT) {
487ebf0bd36SAmit Kucheria 		err = twl4030_config_wakeup3_sequence(address);
488ebf0bd36SAmit Kucheria 		if (err)
489ebf0bd36SAmit Kucheria 			goto out;
490ebf0bd36SAmit Kucheria 	}
491c62dd365SLesly A M 	if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
4921f968ff6SLesly A M 		if (!order)
49375a74565SAmit Kucheria 			pr_warning("TWL4030: Bad order of scripts (sleep "\
49475a74565SAmit Kucheria 					"script before wakeup) Leads to boot"\
49575a74565SAmit Kucheria 					"failure on some boards\n");
496ebf0bd36SAmit Kucheria 		err = twl4030_config_sleep_sequence(address);
497c62dd365SLesly A M 	}
498ebf0bd36SAmit Kucheria out:
499ebf0bd36SAmit Kucheria 	return err;
500ebf0bd36SAmit Kucheria }
501ebf0bd36SAmit Kucheria 
50211a441ceSMike Turquette int twl4030_remove_script(u8 flags)
50311a441ceSMike Turquette {
50411a441ceSMike Turquette 	int err = 0;
50511a441ceSMike Turquette 
5064850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
50771084406SFelipe Balbi 			       TWL4030_PM_MASTER_PROTECT_KEY);
50811a441ceSMike Turquette 	if (err) {
50911a441ceSMike Turquette 		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
51011a441ceSMike Turquette 		return err;
51111a441ceSMike Turquette 	}
51211a441ceSMike Turquette 
5134850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2,
51471084406SFelipe Balbi 			       TWL4030_PM_MASTER_PROTECT_KEY);
51511a441ceSMike Turquette 	if (err) {
51611a441ceSMike Turquette 		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
51711a441ceSMike Turquette 		return err;
51811a441ceSMike Turquette 	}
51911a441ceSMike Turquette 
52011a441ceSMike Turquette 	if (flags & TWL4030_WRST_SCRIPT) {
5214850f124SPeter Ujfalusi 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT,
52211a441ceSMike Turquette 				       R_SEQ_ADD_WARM);
52311a441ceSMike Turquette 		if (err)
52411a441ceSMike Turquette 			return err;
52511a441ceSMike Turquette 	}
52611a441ceSMike Turquette 	if (flags & TWL4030_WAKEUP12_SCRIPT) {
5274850f124SPeter Ujfalusi 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT,
52811a441ceSMike Turquette 				       R_SEQ_ADD_S2A12);
529eac78a21SLesly A M 		if (err)
53011a441ceSMike Turquette 			return err;
53111a441ceSMike Turquette 	}
53211a441ceSMike Turquette 	if (flags & TWL4030_WAKEUP3_SCRIPT) {
5334850f124SPeter Ujfalusi 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT,
53411a441ceSMike Turquette 				       R_SEQ_ADD_S2A3);
53511a441ceSMike Turquette 		if (err)
53611a441ceSMike Turquette 			return err;
53711a441ceSMike Turquette 	}
53811a441ceSMike Turquette 	if (flags & TWL4030_SLEEP_SCRIPT) {
5394850f124SPeter Ujfalusi 		err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT,
54011a441ceSMike Turquette 				       R_SEQ_ADD_A2S);
54111a441ceSMike Turquette 		if (err)
54211a441ceSMike Turquette 			return err;
54311a441ceSMike Turquette 	}
54411a441ceSMike Turquette 
5454850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
54671084406SFelipe Balbi 			       TWL4030_PM_MASTER_PROTECT_KEY);
54711a441ceSMike Turquette 	if (err)
54811a441ceSMike Turquette 		pr_err("TWL4030 Unable to relock registers\n");
54911a441ceSMike Turquette 
55011a441ceSMike Turquette 	return err;
55111a441ceSMike Turquette }
55211a441ceSMike Turquette 
553e7cd1d1eSTony Lindgren static int
554e7cd1d1eSTony Lindgren twl4030_power_configure_scripts(const struct twl4030_power_data *pdata)
555f58cb407SFlorian Vaussard {
556f58cb407SFlorian Vaussard 	int err;
557f58cb407SFlorian Vaussard 	int i;
558f58cb407SFlorian Vaussard 	u8 address = twl4030_start_script_address;
559f58cb407SFlorian Vaussard 
560f58cb407SFlorian Vaussard 	for (i = 0; i < pdata->num; i++) {
561f58cb407SFlorian Vaussard 		err = load_twl4030_script(pdata->scripts[i], address);
562f58cb407SFlorian Vaussard 		if (err)
563f58cb407SFlorian Vaussard 			return err;
564f58cb407SFlorian Vaussard 		address += pdata->scripts[i]->size;
565f58cb407SFlorian Vaussard 	}
566f58cb407SFlorian Vaussard 
567f58cb407SFlorian Vaussard 	return 0;
568f58cb407SFlorian Vaussard }
569f58cb407SFlorian Vaussard 
570482e7db1STony Lindgren static void twl4030_patch_rconfig(struct twl4030_resconfig *common,
571482e7db1STony Lindgren 				  struct twl4030_resconfig *board)
572482e7db1STony Lindgren {
573482e7db1STony Lindgren 	while (common->resource) {
574482e7db1STony Lindgren 		struct twl4030_resconfig *b = board;
575482e7db1STony Lindgren 
576482e7db1STony Lindgren 		while (b->resource) {
577482e7db1STony Lindgren 			if (b->resource == common->resource) {
578482e7db1STony Lindgren 				*common = *b;
579482e7db1STony Lindgren 				break;
580482e7db1STony Lindgren 			}
581482e7db1STony Lindgren 			b++;
582482e7db1STony Lindgren 		}
583482e7db1STony Lindgren 		common++;
584482e7db1STony Lindgren 	}
585482e7db1STony Lindgren }
586482e7db1STony Lindgren 
587e7cd1d1eSTony Lindgren static int
588e7cd1d1eSTony Lindgren twl4030_power_configure_resources(const struct twl4030_power_data *pdata)
589f58cb407SFlorian Vaussard {
590f58cb407SFlorian Vaussard 	struct twl4030_resconfig *resconfig = pdata->resource_config;
591482e7db1STony Lindgren 	struct twl4030_resconfig *boardconf = pdata->board_config;
592f58cb407SFlorian Vaussard 	int err;
593f58cb407SFlorian Vaussard 
594f58cb407SFlorian Vaussard 	if (resconfig) {
595482e7db1STony Lindgren 		if (boardconf)
596482e7db1STony Lindgren 			twl4030_patch_rconfig(resconfig, boardconf);
597482e7db1STony Lindgren 
598f58cb407SFlorian Vaussard 		while (resconfig->resource) {
599f58cb407SFlorian Vaussard 			err = twl4030_configure_resource(resconfig);
600f58cb407SFlorian Vaussard 			if (err)
601f58cb407SFlorian Vaussard 				return err;
602f58cb407SFlorian Vaussard 			resconfig++;
603f58cb407SFlorian Vaussard 		}
604f58cb407SFlorian Vaussard 	}
605f58cb407SFlorian Vaussard 
606f58cb407SFlorian Vaussard 	return 0;
607f58cb407SFlorian Vaussard }
608f58cb407SFlorian Vaussard 
60926cc3ab9SIgor Grinberg /*
61026cc3ab9SIgor Grinberg  * In master mode, start the power off sequence.
61126cc3ab9SIgor Grinberg  * After a successful execution, TWL shuts down the power to the SoC
61226cc3ab9SIgor Grinberg  * and all peripherals connected to it.
61326cc3ab9SIgor Grinberg  */
61426cc3ab9SIgor Grinberg void twl4030_power_off(void)
61526cc3ab9SIgor Grinberg {
61626cc3ab9SIgor Grinberg 	int err;
61726cc3ab9SIgor Grinberg 
6184850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, PWR_DEVOFF,
61926cc3ab9SIgor Grinberg 			       TWL4030_PM_MASTER_P1_SW_EVENTS);
62026cc3ab9SIgor Grinberg 	if (err)
62126cc3ab9SIgor Grinberg 		pr_err("TWL4030 Unable to power off\n");
62226cc3ab9SIgor Grinberg }
62326cc3ab9SIgor Grinberg 
624e7cd1d1eSTony Lindgren static bool twl4030_power_use_poweroff(const struct twl4030_power_data *pdata,
625b0fc1da4SFlorian Vaussard 					struct device_node *node)
626b0fc1da4SFlorian Vaussard {
627b0fc1da4SFlorian Vaussard 	if (pdata && pdata->use_poweroff)
628b0fc1da4SFlorian Vaussard 		return true;
629b0fc1da4SFlorian Vaussard 
630b0fc1da4SFlorian Vaussard 	if (of_property_read_bool(node, "ti,use_poweroff"))
631b0fc1da4SFlorian Vaussard 		return true;
632b0fc1da4SFlorian Vaussard 
633b0fc1da4SFlorian Vaussard 	return false;
634b0fc1da4SFlorian Vaussard }
635b0fc1da4SFlorian Vaussard 
636e7cd1d1eSTony Lindgren #ifdef CONFIG_OF
637e7cd1d1eSTony Lindgren 
638e7cd1d1eSTony Lindgren /* Generic warm reset configuration for omap3 */
639e7cd1d1eSTony Lindgren 
640e7cd1d1eSTony Lindgren static struct twl4030_ins omap3_wrst_seq[] = {
641e7cd1d1eSTony Lindgren 	TWL_RESOURCE_OFF(RES_NRES_PWRON),
642e7cd1d1eSTony Lindgren 	TWL_RESOURCE_OFF(RES_RESET),
643e7cd1d1eSTony Lindgren 	TWL_RESOURCE_RESET(RES_MAIN_REF),
644e7cd1d1eSTony Lindgren 	TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2),
645e7cd1d1eSTony Lindgren 	TWL_RESOURCE_RESET(RES_VUSB_3V1),
646e7cd1d1eSTony Lindgren 	TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1),
647e7cd1d1eSTony Lindgren 	TWL_RESOURCE_GROUP_RESET(RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0),
648e7cd1d1eSTony Lindgren 	TWL_RESOURCE_ON(RES_RESET),
649e7cd1d1eSTony Lindgren 	TWL_RESOURCE_ON(RES_NRES_PWRON),
650e7cd1d1eSTony Lindgren };
651e7cd1d1eSTony Lindgren 
652e7cd1d1eSTony Lindgren static struct twl4030_script omap3_wrst_script = {
653e7cd1d1eSTony Lindgren 	.script	= omap3_wrst_seq,
654e7cd1d1eSTony Lindgren 	.size	= ARRAY_SIZE(omap3_wrst_seq),
655e7cd1d1eSTony Lindgren 	.flags	= TWL4030_WRST_SCRIPT,
656e7cd1d1eSTony Lindgren };
657e7cd1d1eSTony Lindgren 
658e7cd1d1eSTony Lindgren static struct twl4030_script *omap3_reset_scripts[] = {
659e7cd1d1eSTony Lindgren 	&omap3_wrst_script,
660e7cd1d1eSTony Lindgren };
661e7cd1d1eSTony Lindgren 
662e7cd1d1eSTony Lindgren static struct twl4030_resconfig omap3_rconfig[] = {
663e7cd1d1eSTony Lindgren 	TWL_REMAP_SLEEP(RES_HFCLKOUT, DEV_GRP_P3, -1, -1),
664e7cd1d1eSTony Lindgren 	TWL_REMAP_SLEEP(RES_VDD1, DEV_GRP_P1, -1, -1),
665e7cd1d1eSTony Lindgren 	TWL_REMAP_SLEEP(RES_VDD2, DEV_GRP_P1, -1, -1),
666e7cd1d1eSTony Lindgren 	{ 0, 0 },
667e7cd1d1eSTony Lindgren };
668e7cd1d1eSTony Lindgren 
669e7cd1d1eSTony Lindgren static struct twl4030_power_data omap3_reset = {
670e7cd1d1eSTony Lindgren 	.scripts		= omap3_reset_scripts,
671e7cd1d1eSTony Lindgren 	.num			= ARRAY_SIZE(omap3_reset_scripts),
672e7cd1d1eSTony Lindgren 	.resource_config	= omap3_rconfig,
673e7cd1d1eSTony Lindgren };
674e7cd1d1eSTony Lindgren 
67576714d2cSTony Lindgren /* Recommended generic default idle configuration for off-idle */
67676714d2cSTony Lindgren 
67776714d2cSTony Lindgren /* Broadcast message to put res to sleep */
67876714d2cSTony Lindgren static struct twl4030_ins omap3_idle_sleep_on_seq[] = {
67976714d2cSTony Lindgren 	TWL_RESOURCE_GROUP_SLEEP(RES_GRP_ALL, RES_TYPE_ALL, 0),
68076714d2cSTony Lindgren };
68176714d2cSTony Lindgren 
68276714d2cSTony Lindgren static struct twl4030_script omap3_idle_sleep_on_script = {
68376714d2cSTony Lindgren 	.script	= omap3_idle_sleep_on_seq,
68476714d2cSTony Lindgren 	.size	= ARRAY_SIZE(omap3_idle_sleep_on_seq),
68576714d2cSTony Lindgren 	.flags	= TWL4030_SLEEP_SCRIPT,
68676714d2cSTony Lindgren };
68776714d2cSTony Lindgren 
68876714d2cSTony Lindgren /* Broadcast message to put res to active */
68976714d2cSTony Lindgren static struct twl4030_ins omap3_idle_wakeup_p12_seq[] = {
69076714d2cSTony Lindgren 	TWL_RESOURCE_GROUP_ACTIVE(RES_GRP_ALL, RES_TYPE_ALL, 0),
69176714d2cSTony Lindgren };
69276714d2cSTony Lindgren 
69376714d2cSTony Lindgren static struct twl4030_script omap3_idle_wakeup_p12_script = {
69476714d2cSTony Lindgren 	.script	= omap3_idle_wakeup_p12_seq,
69576714d2cSTony Lindgren 	.size	= ARRAY_SIZE(omap3_idle_wakeup_p12_seq),
69676714d2cSTony Lindgren 	.flags	= TWL4030_WAKEUP12_SCRIPT,
69776714d2cSTony Lindgren };
69876714d2cSTony Lindgren 
69976714d2cSTony Lindgren /* Broadcast message to put res to active */
70076714d2cSTony Lindgren static struct twl4030_ins omap3_idle_wakeup_p3_seq[] = {
70176714d2cSTony Lindgren 	TWL_RESOURCE_SET_ACTIVE(RES_CLKEN, 0x37),
70276714d2cSTony Lindgren 	TWL_RESOURCE_GROUP_ACTIVE(RES_GRP_ALL, RES_TYPE_ALL, 0),
70376714d2cSTony Lindgren };
70476714d2cSTony Lindgren 
70576714d2cSTony Lindgren static struct twl4030_script omap3_idle_wakeup_p3_script = {
70676714d2cSTony Lindgren 	.script	= omap3_idle_wakeup_p3_seq,
70776714d2cSTony Lindgren 	.size	= ARRAY_SIZE(omap3_idle_wakeup_p3_seq),
70876714d2cSTony Lindgren 	.flags	= TWL4030_WAKEUP3_SCRIPT,
70976714d2cSTony Lindgren };
71076714d2cSTony Lindgren 
71176714d2cSTony Lindgren static struct twl4030_script *omap3_idle_scripts[] = {
71276714d2cSTony Lindgren 	&omap3_idle_wakeup_p12_script,
71376714d2cSTony Lindgren 	&omap3_idle_wakeup_p3_script,
71476714d2cSTony Lindgren 	&omap3_wrst_script,
71576714d2cSTony Lindgren 	&omap3_idle_sleep_on_script,
71676714d2cSTony Lindgren };
71776714d2cSTony Lindgren 
71876714d2cSTony Lindgren /*
71976714d2cSTony Lindgren  * Recommended configuration based on "Recommended Sleep
72076714d2cSTony Lindgren  * Sequences for the Zoom Platform":
72176714d2cSTony Lindgren  * http://omappedia.com/wiki/File:Recommended_Sleep_Sequences_Zoom.pdf
72276714d2cSTony Lindgren  * Note that the type1 and type2 seem to be just the init order number
72376714d2cSTony Lindgren  * for type1 and type2 groups as specified in the document mentioned
72476714d2cSTony Lindgren  * above.
72576714d2cSTony Lindgren  */
72676714d2cSTony Lindgren static struct twl4030_resconfig omap3_idle_rconfig[] = {
727daebabd5STony Lindgren 	TWL_REMAP_SLEEP(RES_VAUX1, TWL4030_RESCONFIG_UNDEF, 0, 0),
728daebabd5STony Lindgren 	TWL_REMAP_SLEEP(RES_VAUX2, TWL4030_RESCONFIG_UNDEF, 0, 0),
729daebabd5STony Lindgren 	TWL_REMAP_SLEEP(RES_VAUX3, TWL4030_RESCONFIG_UNDEF, 0, 0),
730daebabd5STony Lindgren 	TWL_REMAP_SLEEP(RES_VAUX4, TWL4030_RESCONFIG_UNDEF, 0, 0),
731daebabd5STony Lindgren 	TWL_REMAP_SLEEP(RES_VMMC1, TWL4030_RESCONFIG_UNDEF, 0, 0),
732daebabd5STony Lindgren 	TWL_REMAP_SLEEP(RES_VMMC2, TWL4030_RESCONFIG_UNDEF, 0, 0),
73376714d2cSTony Lindgren 	TWL_REMAP_OFF(RES_VPLL1, DEV_GRP_P1, 3, 1),
73476714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_VPLL2, DEV_GRP_P1, 0, 0),
735daebabd5STony Lindgren 	TWL_REMAP_SLEEP(RES_VSIM, TWL4030_RESCONFIG_UNDEF, 0, 0),
736daebabd5STony Lindgren 	TWL_REMAP_SLEEP(RES_VDAC, TWL4030_RESCONFIG_UNDEF, 0, 0),
73776714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_VINTANA1, TWL_DEV_GRP_P123, 1, 2),
73876714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_VINTANA2, TWL_DEV_GRP_P123, 0, 2),
73976714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_VINTDIG, TWL_DEV_GRP_P123, 1, 2),
74076714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_VIO, TWL_DEV_GRP_P123, 2, 2),
74176714d2cSTony Lindgren 	TWL_REMAP_OFF(RES_VDD1, DEV_GRP_P1, 4, 1),
74276714d2cSTony Lindgren 	TWL_REMAP_OFF(RES_VDD2, DEV_GRP_P1, 3, 1),
743daebabd5STony Lindgren 	TWL_REMAP_SLEEP(RES_VUSB_1V5, TWL4030_RESCONFIG_UNDEF, 0, 0),
744daebabd5STony Lindgren 	TWL_REMAP_SLEEP(RES_VUSB_1V8, TWL4030_RESCONFIG_UNDEF, 0, 0),
74576714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_VUSB_3V1, TWL_DEV_GRP_P123, 0, 0),
74676714d2cSTony Lindgren 	/* Resource #20 USB charge pump skipped */
74776714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_REGEN, TWL_DEV_GRP_P123, 2, 1),
74876714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_NRES_PWRON, TWL_DEV_GRP_P123, 0, 1),
74976714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_CLKEN, TWL_DEV_GRP_P123, 3, 2),
75076714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_SYSEN, TWL_DEV_GRP_P123, 6, 1),
75176714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_HFCLKOUT, DEV_GRP_P3, 0, 2),
75276714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_32KCLKOUT, TWL_DEV_GRP_P123, 0, 0),
75376714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_RESET, TWL_DEV_GRP_P123, 6, 0),
75476714d2cSTony Lindgren 	TWL_REMAP_SLEEP(RES_MAIN_REF, TWL_DEV_GRP_P123, 0, 0),
75576714d2cSTony Lindgren 	{ /* Terminator */ },
75676714d2cSTony Lindgren };
75776714d2cSTony Lindgren 
75876714d2cSTony Lindgren static struct twl4030_power_data omap3_idle = {
75976714d2cSTony Lindgren 	.scripts		= omap3_idle_scripts,
76076714d2cSTony Lindgren 	.num			= ARRAY_SIZE(omap3_idle_scripts),
76176714d2cSTony Lindgren 	.resource_config	= omap3_idle_rconfig,
76276714d2cSTony Lindgren };
76376714d2cSTony Lindgren 
76443fef47fSTony Lindgren /* Disable 32 KiHz oscillator during idle */
76543fef47fSTony Lindgren static struct twl4030_resconfig osc_off_rconfig[] = {
76643fef47fSTony Lindgren 	TWL_REMAP_OFF(RES_CLKEN, DEV_GRP_P1 | DEV_GRP_P3, 3, 2),
76743fef47fSTony Lindgren 	{ /* Terminator */ },
76843fef47fSTony Lindgren };
76943fef47fSTony Lindgren 
77043fef47fSTony Lindgren static struct twl4030_power_data osc_off_idle = {
77143fef47fSTony Lindgren 	.scripts		= omap3_idle_scripts,
77243fef47fSTony Lindgren 	.num			= ARRAY_SIZE(omap3_idle_scripts),
77343fef47fSTony Lindgren 	.resource_config	= omap3_idle_rconfig,
77443fef47fSTony Lindgren 	.board_config		= osc_off_rconfig,
77543fef47fSTony Lindgren };
77643fef47fSTony Lindgren 
777e7cd1d1eSTony Lindgren static struct of_device_id twl4030_power_of_match[] = {
778e7cd1d1eSTony Lindgren 	{
779e7cd1d1eSTony Lindgren 		.compatible = "ti,twl4030-power-reset",
780e7cd1d1eSTony Lindgren 		.data = &omap3_reset,
781e7cd1d1eSTony Lindgren 	},
78276714d2cSTony Lindgren 	{
78376714d2cSTony Lindgren 		.compatible = "ti,twl4030-power-idle",
78476714d2cSTony Lindgren 		.data = &omap3_idle,
78576714d2cSTony Lindgren 	},
78643fef47fSTony Lindgren 	{
78743fef47fSTony Lindgren 		.compatible = "ti,twl4030-power-idle-osc-off",
78843fef47fSTony Lindgren 		.data = &osc_off_idle,
78943fef47fSTony Lindgren 	},
790e7cd1d1eSTony Lindgren 	{ },
791e7cd1d1eSTony Lindgren };
792e7cd1d1eSTony Lindgren MODULE_DEVICE_TABLE(of, twl4030_power_of_match);
793e7cd1d1eSTony Lindgren #endif	/* CONFIG_OF */
794e7cd1d1eSTony Lindgren 
795fae01582SJingoo Han static int twl4030_power_probe(struct platform_device *pdev)
796ebf0bd36SAmit Kucheria {
797e7cd1d1eSTony Lindgren 	const struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev);
798b0fc1da4SFlorian Vaussard 	struct device_node *node = pdev->dev.of_node;
799e7cd1d1eSTony Lindgren 	const struct of_device_id *match;
800ebf0bd36SAmit Kucheria 	int err = 0;
801cb3cabd6SFlorian Vaussard 	int err2 = 0;
802f58cb407SFlorian Vaussard 	u8 val;
803ebf0bd36SAmit Kucheria 
804b0fc1da4SFlorian Vaussard 	if (!pdata && !node) {
805b0fc1da4SFlorian Vaussard 		dev_err(&pdev->dev, "Platform data is missing\n");
806b0fc1da4SFlorian Vaussard 		return -EINVAL;
807b0fc1da4SFlorian Vaussard 	}
808b0fc1da4SFlorian Vaussard 
8094850f124SPeter Ujfalusi 	err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
81071084406SFelipe Balbi 			       TWL4030_PM_MASTER_PROTECT_KEY);
811e77a4c2fSFlorian Vaussard 	err |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
812e77a4c2fSFlorian Vaussard 			       TWL4030_PM_MASTER_KEY_CFG2,
81371084406SFelipe Balbi 			       TWL4030_PM_MASTER_PROTECT_KEY);
814e77a4c2fSFlorian Vaussard 
815e77a4c2fSFlorian Vaussard 	if (err) {
816e77a4c2fSFlorian Vaussard 		pr_err("TWL4030 Unable to unlock registers\n");
817e77a4c2fSFlorian Vaussard 		return err;
818e77a4c2fSFlorian Vaussard 	}
819ebf0bd36SAmit Kucheria 
820e7cd1d1eSTony Lindgren 	match = of_match_device(of_match_ptr(twl4030_power_of_match),
821e7cd1d1eSTony Lindgren 				&pdev->dev);
822e7cd1d1eSTony Lindgren 	if (match && match->data)
823e7cd1d1eSTony Lindgren 		pdata = match->data;
824e7cd1d1eSTony Lindgren 
825b0fc1da4SFlorian Vaussard 	if (pdata) {
826f58cb407SFlorian Vaussard 		err = twl4030_power_configure_scripts(pdata);
827e77a4c2fSFlorian Vaussard 		if (err) {
828e77a4c2fSFlorian Vaussard 			pr_err("TWL4030 failed to load scripts\n");
829cb3cabd6SFlorian Vaussard 			goto relock;
830e77a4c2fSFlorian Vaussard 		}
831f58cb407SFlorian Vaussard 		err = twl4030_power_configure_resources(pdata);
832e77a4c2fSFlorian Vaussard 		if (err) {
833e77a4c2fSFlorian Vaussard 			pr_err("TWL4030 failed to configure resource\n");
834cb3cabd6SFlorian Vaussard 			goto relock;
835e77a4c2fSFlorian Vaussard 		}
836b0fc1da4SFlorian Vaussard 	}
837ebf0bd36SAmit Kucheria 
83826cc3ab9SIgor Grinberg 	/* Board has to be wired properly to use this feature */
839b0fc1da4SFlorian Vaussard 	if (twl4030_power_use_poweroff(pdata, node) && !pm_power_off) {
84026cc3ab9SIgor Grinberg 		/* Default for SEQ_OFFSYNC is set, lets ensure this */
8414850f124SPeter Ujfalusi 		err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
84226cc3ab9SIgor Grinberg 				      TWL4030_PM_MASTER_CFG_P123_TRANSITION);
84326cc3ab9SIgor Grinberg 		if (err) {
84426cc3ab9SIgor Grinberg 			pr_warning("TWL4030 Unable to read registers\n");
84526cc3ab9SIgor Grinberg 
84626cc3ab9SIgor Grinberg 		} else if (!(val & SEQ_OFFSYNC)) {
84726cc3ab9SIgor Grinberg 			val |= SEQ_OFFSYNC;
8484850f124SPeter Ujfalusi 			err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val,
84926cc3ab9SIgor Grinberg 					TWL4030_PM_MASTER_CFG_P123_TRANSITION);
85026cc3ab9SIgor Grinberg 			if (err) {
85126cc3ab9SIgor Grinberg 				pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n");
85226cc3ab9SIgor Grinberg 				goto relock;
85326cc3ab9SIgor Grinberg 			}
85426cc3ab9SIgor Grinberg 		}
85526cc3ab9SIgor Grinberg 
85626cc3ab9SIgor Grinberg 		pm_power_off = twl4030_power_off;
85726cc3ab9SIgor Grinberg 	}
85826cc3ab9SIgor Grinberg 
85926cc3ab9SIgor Grinberg relock:
860cb3cabd6SFlorian Vaussard 	err2 = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
86171084406SFelipe Balbi 			       TWL4030_PM_MASTER_PROTECT_KEY);
862cb3cabd6SFlorian Vaussard 	if (err2) {
863ebf0bd36SAmit Kucheria 		pr_err("TWL4030 Unable to relock registers\n");
864cb3cabd6SFlorian Vaussard 		return err2;
865cb3cabd6SFlorian Vaussard 	}
866cb3cabd6SFlorian Vaussard 
867637d6895SFlorian Vaussard 	return err;
868ebf0bd36SAmit Kucheria }
869637d6895SFlorian Vaussard 
870637d6895SFlorian Vaussard static int twl4030_power_remove(struct platform_device *pdev)
871637d6895SFlorian Vaussard {
872637d6895SFlorian Vaussard 	return 0;
873637d6895SFlorian Vaussard }
874637d6895SFlorian Vaussard 
875637d6895SFlorian Vaussard static struct platform_driver twl4030_power_driver = {
876637d6895SFlorian Vaussard 	.driver = {
877637d6895SFlorian Vaussard 		.name	= "twl4030_power",
878637d6895SFlorian Vaussard 		.owner	= THIS_MODULE,
879b0fc1da4SFlorian Vaussard 		.of_match_table = of_match_ptr(twl4030_power_of_match),
880637d6895SFlorian Vaussard 	},
881637d6895SFlorian Vaussard 	.probe		= twl4030_power_probe,
882637d6895SFlorian Vaussard 	.remove		= twl4030_power_remove,
883637d6895SFlorian Vaussard };
884637d6895SFlorian Vaussard 
885637d6895SFlorian Vaussard module_platform_driver(twl4030_power_driver);
886637d6895SFlorian Vaussard 
887637d6895SFlorian Vaussard MODULE_AUTHOR("Nokia Corporation");
888637d6895SFlorian Vaussard MODULE_AUTHOR("Texas Instruments, Inc.");
889637d6895SFlorian Vaussard MODULE_DESCRIPTION("Power management for TWL4030");
890637d6895SFlorian Vaussard MODULE_LICENSE("GPL");
891637d6895SFlorian Vaussard MODULE_ALIAS("platform:twl4030_power");
892