xref: /openbmc/linux/drivers/mfd/twl4030-power.c (revision f791be49)
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>
31ebf0bd36SAmit Kucheria 
32ebf0bd36SAmit Kucheria #include <asm/mach-types.h>
33ebf0bd36SAmit Kucheria 
34ebf0bd36SAmit Kucheria static u8 twl4030_start_script_address = 0x2b;
35ebf0bd36SAmit Kucheria 
36ebf0bd36SAmit Kucheria #define PWR_P1_SW_EVENTS	0x10
37ebf0bd36SAmit Kucheria #define PWR_DEVOFF		(1 << 0)
3826cc3ab9SIgor Grinberg #define SEQ_OFFSYNC		(1 << 0)
39ebf0bd36SAmit Kucheria 
40ebf0bd36SAmit Kucheria #define PHY_TO_OFF_PM_MASTER(p)		(p - 0x36)
41ebf0bd36SAmit Kucheria #define PHY_TO_OFF_PM_RECEIVER(p)	(p - 0x5b)
42ebf0bd36SAmit Kucheria 
43ebf0bd36SAmit Kucheria /* resource - hfclk */
44ebf0bd36SAmit Kucheria #define R_HFCLKOUT_DEV_GRP 	PHY_TO_OFF_PM_RECEIVER(0xe6)
45ebf0bd36SAmit Kucheria 
46ebf0bd36SAmit Kucheria /* PM events */
47ebf0bd36SAmit Kucheria #define R_P1_SW_EVENTS		PHY_TO_OFF_PM_MASTER(0x46)
48ebf0bd36SAmit Kucheria #define R_P2_SW_EVENTS		PHY_TO_OFF_PM_MASTER(0x47)
49ebf0bd36SAmit Kucheria #define R_P3_SW_EVENTS		PHY_TO_OFF_PM_MASTER(0x48)
50ebf0bd36SAmit Kucheria #define R_CFG_P1_TRANSITION	PHY_TO_OFF_PM_MASTER(0x36)
51ebf0bd36SAmit Kucheria #define R_CFG_P2_TRANSITION	PHY_TO_OFF_PM_MASTER(0x37)
52ebf0bd36SAmit Kucheria #define R_CFG_P3_TRANSITION	PHY_TO_OFF_PM_MASTER(0x38)
53ebf0bd36SAmit Kucheria 
54ebf0bd36SAmit Kucheria #define LVL_WAKEUP	0x08
55ebf0bd36SAmit Kucheria 
56ebf0bd36SAmit Kucheria #define ENABLE_WARMRESET (1<<4)
57ebf0bd36SAmit Kucheria 
58ebf0bd36SAmit Kucheria #define END_OF_SCRIPT		0x3f
59ebf0bd36SAmit Kucheria 
60ebf0bd36SAmit Kucheria #define R_SEQ_ADD_A2S		PHY_TO_OFF_PM_MASTER(0x55)
61ebf0bd36SAmit Kucheria #define R_SEQ_ADD_S2A12		PHY_TO_OFF_PM_MASTER(0x56)
62ebf0bd36SAmit Kucheria #define	R_SEQ_ADD_S2A3		PHY_TO_OFF_PM_MASTER(0x57)
63ebf0bd36SAmit Kucheria #define	R_SEQ_ADD_WARM		PHY_TO_OFF_PM_MASTER(0x58)
64ebf0bd36SAmit Kucheria #define R_MEMORY_ADDRESS	PHY_TO_OFF_PM_MASTER(0x59)
65ebf0bd36SAmit Kucheria #define R_MEMORY_DATA		PHY_TO_OFF_PM_MASTER(0x5a)
66ebf0bd36SAmit Kucheria 
67890463f0SAmit Kucheria /* resource configuration registers
68890463f0SAmit Kucheria    <RESOURCE>_DEV_GRP   at address 'n+0'
69890463f0SAmit Kucheria    <RESOURCE>_TYPE      at address 'n+1'
70890463f0SAmit Kucheria    <RESOURCE>_REMAP     at address 'n+2'
71890463f0SAmit Kucheria    <RESOURCE>_DEDICATED at address 'n+3'
72890463f0SAmit Kucheria */
73e97d1546SAmit Kucheria #define DEV_GRP_OFFSET		0
74ebf0bd36SAmit Kucheria #define TYPE_OFFSET		1
75b4ead61eSAmit Kucheria #define REMAP_OFFSET		2
76b4ead61eSAmit Kucheria #define DEDICATED_OFFSET	3
77ebf0bd36SAmit Kucheria 
78e97d1546SAmit Kucheria /* Bit positions in the registers */
79890463f0SAmit Kucheria 
80890463f0SAmit Kucheria /* <RESOURCE>_DEV_GRP */
81e97d1546SAmit Kucheria #define DEV_GRP_SHIFT		5
82e97d1546SAmit Kucheria #define DEV_GRP_MASK		(7 << DEV_GRP_SHIFT)
83890463f0SAmit Kucheria 
84890463f0SAmit Kucheria /* <RESOURCE>_TYPE */
85ebf0bd36SAmit Kucheria #define TYPE_SHIFT		0
86ebf0bd36SAmit Kucheria #define TYPE_MASK		(7 << TYPE_SHIFT)
87ebf0bd36SAmit Kucheria #define TYPE2_SHIFT		3
88ebf0bd36SAmit Kucheria #define TYPE2_MASK		(3 << TYPE2_SHIFT)
89ebf0bd36SAmit Kucheria 
90b4ead61eSAmit Kucheria /* <RESOURCE>_REMAP */
91b4ead61eSAmit Kucheria #define SLEEP_STATE_SHIFT	0
92b4ead61eSAmit Kucheria #define SLEEP_STATE_MASK	(0xf << SLEEP_STATE_SHIFT)
93b4ead61eSAmit Kucheria #define OFF_STATE_SHIFT		4
94b4ead61eSAmit Kucheria #define OFF_STATE_MASK		(0xf << OFF_STATE_SHIFT)
95b4ead61eSAmit Kucheria 
96ebf0bd36SAmit Kucheria static u8 res_config_addrs[] = {
97ebf0bd36SAmit Kucheria 	[RES_VAUX1]	= 0x17,
98ebf0bd36SAmit Kucheria 	[RES_VAUX2]	= 0x1b,
99ebf0bd36SAmit Kucheria 	[RES_VAUX3]	= 0x1f,
100ebf0bd36SAmit Kucheria 	[RES_VAUX4]	= 0x23,
101ebf0bd36SAmit Kucheria 	[RES_VMMC1]	= 0x27,
102ebf0bd36SAmit Kucheria 	[RES_VMMC2]	= 0x2b,
103ebf0bd36SAmit Kucheria 	[RES_VPLL1]	= 0x2f,
104ebf0bd36SAmit Kucheria 	[RES_VPLL2]	= 0x33,
105ebf0bd36SAmit Kucheria 	[RES_VSIM]	= 0x37,
106ebf0bd36SAmit Kucheria 	[RES_VDAC]	= 0x3b,
107ebf0bd36SAmit Kucheria 	[RES_VINTANA1]	= 0x3f,
108ebf0bd36SAmit Kucheria 	[RES_VINTANA2]	= 0x43,
109ebf0bd36SAmit Kucheria 	[RES_VINTDIG]	= 0x47,
110ebf0bd36SAmit Kucheria 	[RES_VIO]	= 0x4b,
111ebf0bd36SAmit Kucheria 	[RES_VDD1]	= 0x55,
112ebf0bd36SAmit Kucheria 	[RES_VDD2]	= 0x63,
113ebf0bd36SAmit Kucheria 	[RES_VUSB_1V5]	= 0x71,
114ebf0bd36SAmit Kucheria 	[RES_VUSB_1V8]	= 0x74,
115ebf0bd36SAmit Kucheria 	[RES_VUSB_3V1]	= 0x77,
116ebf0bd36SAmit Kucheria 	[RES_VUSBCP]	= 0x7a,
117ebf0bd36SAmit Kucheria 	[RES_REGEN]	= 0x7f,
118ebf0bd36SAmit Kucheria 	[RES_NRES_PWRON] = 0x82,
119ebf0bd36SAmit Kucheria 	[RES_CLKEN]	= 0x85,
120ebf0bd36SAmit Kucheria 	[RES_SYSEN]	= 0x88,
121ebf0bd36SAmit Kucheria 	[RES_HFCLKOUT]	= 0x8b,
122ebf0bd36SAmit Kucheria 	[RES_32KCLKOUT]	= 0x8e,
123ebf0bd36SAmit Kucheria 	[RES_RESET]	= 0x91,
124d7ac829fSLesly A M 	[RES_MAIN_REF]	= 0x94,
125ebf0bd36SAmit Kucheria };
126ebf0bd36SAmit Kucheria 
127f791be49SBill Pemberton static int twl4030_write_script_byte(u8 address, u8 byte)
128ebf0bd36SAmit Kucheria {
129ebf0bd36SAmit Kucheria 	int err;
130ebf0bd36SAmit Kucheria 
131fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
132ebf0bd36SAmit Kucheria 				R_MEMORY_ADDRESS);
133ebf0bd36SAmit Kucheria 	if (err)
134ebf0bd36SAmit Kucheria 		goto out;
135fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
136ebf0bd36SAmit Kucheria 				R_MEMORY_DATA);
137ebf0bd36SAmit Kucheria out:
138ebf0bd36SAmit Kucheria 	return err;
139ebf0bd36SAmit Kucheria }
140ebf0bd36SAmit Kucheria 
141f791be49SBill Pemberton static int twl4030_write_script_ins(u8 address, u16 pmb_message,
142ebf0bd36SAmit Kucheria 					   u8 delay, u8 next)
143ebf0bd36SAmit Kucheria {
144ebf0bd36SAmit Kucheria 	int err;
145ebf0bd36SAmit Kucheria 
146ebf0bd36SAmit Kucheria 	address *= 4;
147ebf0bd36SAmit Kucheria 	err = twl4030_write_script_byte(address++, pmb_message >> 8);
148ebf0bd36SAmit Kucheria 	if (err)
149ebf0bd36SAmit Kucheria 		goto out;
150ebf0bd36SAmit Kucheria 	err = twl4030_write_script_byte(address++, pmb_message & 0xff);
151ebf0bd36SAmit Kucheria 	if (err)
152ebf0bd36SAmit Kucheria 		goto out;
153ebf0bd36SAmit Kucheria 	err = twl4030_write_script_byte(address++, delay);
154ebf0bd36SAmit Kucheria 	if (err)
155ebf0bd36SAmit Kucheria 		goto out;
156ebf0bd36SAmit Kucheria 	err = twl4030_write_script_byte(address++, next);
157ebf0bd36SAmit Kucheria out:
158ebf0bd36SAmit Kucheria 	return err;
159ebf0bd36SAmit Kucheria }
160ebf0bd36SAmit Kucheria 
161f791be49SBill Pemberton static int twl4030_write_script(u8 address, struct twl4030_ins *script,
162ebf0bd36SAmit Kucheria 				       int len)
163ebf0bd36SAmit Kucheria {
164ebf0bd36SAmit Kucheria 	int err;
165ebf0bd36SAmit Kucheria 
166ebf0bd36SAmit Kucheria 	for (; len; len--, address++, script++) {
167ebf0bd36SAmit Kucheria 		if (len == 1) {
168ebf0bd36SAmit Kucheria 			err = twl4030_write_script_ins(address,
169ebf0bd36SAmit Kucheria 						script->pmb_message,
170ebf0bd36SAmit Kucheria 						script->delay,
171ebf0bd36SAmit Kucheria 						END_OF_SCRIPT);
172ebf0bd36SAmit Kucheria 			if (err)
173ebf0bd36SAmit Kucheria 				break;
174ebf0bd36SAmit Kucheria 		} else {
175ebf0bd36SAmit Kucheria 			err = twl4030_write_script_ins(address,
176ebf0bd36SAmit Kucheria 						script->pmb_message,
177ebf0bd36SAmit Kucheria 						script->delay,
178ebf0bd36SAmit Kucheria 						address + 1);
179ebf0bd36SAmit Kucheria 			if (err)
180ebf0bd36SAmit Kucheria 				break;
181ebf0bd36SAmit Kucheria 		}
182ebf0bd36SAmit Kucheria 	}
183ebf0bd36SAmit Kucheria 	return err;
184ebf0bd36SAmit Kucheria }
185ebf0bd36SAmit Kucheria 
186f791be49SBill Pemberton static int twl4030_config_wakeup3_sequence(u8 address)
187ebf0bd36SAmit Kucheria {
188ebf0bd36SAmit Kucheria 	int err;
189ebf0bd36SAmit Kucheria 	u8 data;
190ebf0bd36SAmit Kucheria 
191ebf0bd36SAmit Kucheria 	/* Set SLEEP to ACTIVE SEQ address for P3 */
192fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
193ebf0bd36SAmit Kucheria 				R_SEQ_ADD_S2A3);
194ebf0bd36SAmit Kucheria 	if (err)
195ebf0bd36SAmit Kucheria 		goto out;
196ebf0bd36SAmit Kucheria 
197ebf0bd36SAmit Kucheria 	/* P3 LVL_WAKEUP should be on LEVEL */
198fc7b92fcSBalaji T K 	err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
199ebf0bd36SAmit Kucheria 				R_P3_SW_EVENTS);
200ebf0bd36SAmit Kucheria 	if (err)
201ebf0bd36SAmit Kucheria 		goto out;
202ebf0bd36SAmit Kucheria 	data |= LVL_WAKEUP;
203fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
204ebf0bd36SAmit Kucheria 				R_P3_SW_EVENTS);
205ebf0bd36SAmit Kucheria out:
206ebf0bd36SAmit Kucheria 	if (err)
207ebf0bd36SAmit Kucheria 		pr_err("TWL4030 wakeup sequence for P3 config error\n");
208ebf0bd36SAmit Kucheria 	return err;
209ebf0bd36SAmit Kucheria }
210ebf0bd36SAmit Kucheria 
211f791be49SBill Pemberton static int twl4030_config_wakeup12_sequence(u8 address)
212ebf0bd36SAmit Kucheria {
213ebf0bd36SAmit Kucheria 	int err = 0;
214ebf0bd36SAmit Kucheria 	u8 data;
215ebf0bd36SAmit Kucheria 
216ebf0bd36SAmit Kucheria 	/* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
217fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
218ebf0bd36SAmit Kucheria 				R_SEQ_ADD_S2A12);
219ebf0bd36SAmit Kucheria 	if (err)
220ebf0bd36SAmit Kucheria 		goto out;
221ebf0bd36SAmit Kucheria 
222ebf0bd36SAmit Kucheria 	/* P1/P2 LVL_WAKEUP should be on LEVEL */
223fc7b92fcSBalaji T K 	err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
224ebf0bd36SAmit Kucheria 				R_P1_SW_EVENTS);
225ebf0bd36SAmit Kucheria 	if (err)
226ebf0bd36SAmit Kucheria 		goto out;
227ebf0bd36SAmit Kucheria 
228ebf0bd36SAmit Kucheria 	data |= LVL_WAKEUP;
229fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
230ebf0bd36SAmit Kucheria 				R_P1_SW_EVENTS);
231ebf0bd36SAmit Kucheria 	if (err)
232ebf0bd36SAmit Kucheria 		goto out;
233ebf0bd36SAmit Kucheria 
234fc7b92fcSBalaji T K 	err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
235ebf0bd36SAmit Kucheria 				R_P2_SW_EVENTS);
236ebf0bd36SAmit Kucheria 	if (err)
237ebf0bd36SAmit Kucheria 		goto out;
238ebf0bd36SAmit Kucheria 
239ebf0bd36SAmit Kucheria 	data |= LVL_WAKEUP;
240fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
241ebf0bd36SAmit Kucheria 				R_P2_SW_EVENTS);
242ebf0bd36SAmit Kucheria 	if (err)
243ebf0bd36SAmit Kucheria 		goto out;
244ebf0bd36SAmit Kucheria 
245ebf0bd36SAmit Kucheria 	if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
246ebf0bd36SAmit Kucheria 		/* Disabling AC charger effect on sleep-active transitions */
247fc7b92fcSBalaji T K 		err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
248ebf0bd36SAmit Kucheria 					R_CFG_P1_TRANSITION);
249ebf0bd36SAmit Kucheria 		if (err)
250ebf0bd36SAmit Kucheria 			goto out;
251ebf0bd36SAmit Kucheria 		data &= ~(1<<1);
252fc7b92fcSBalaji T K 		err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
253ebf0bd36SAmit Kucheria 					R_CFG_P1_TRANSITION);
254ebf0bd36SAmit Kucheria 		if (err)
255ebf0bd36SAmit Kucheria 			goto out;
256ebf0bd36SAmit Kucheria 	}
257ebf0bd36SAmit Kucheria 
258ebf0bd36SAmit Kucheria out:
259ebf0bd36SAmit Kucheria 	if (err)
260ebf0bd36SAmit Kucheria 		pr_err("TWL4030 wakeup sequence for P1 and P2" \
261ebf0bd36SAmit Kucheria 			"config error\n");
262ebf0bd36SAmit Kucheria 	return err;
263ebf0bd36SAmit Kucheria }
264ebf0bd36SAmit Kucheria 
265f791be49SBill Pemberton static int twl4030_config_sleep_sequence(u8 address)
266ebf0bd36SAmit Kucheria {
267ebf0bd36SAmit Kucheria 	int err;
268ebf0bd36SAmit Kucheria 
269ebf0bd36SAmit Kucheria 	/* Set ACTIVE to SLEEP SEQ address in T2 memory*/
270fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
271ebf0bd36SAmit Kucheria 				R_SEQ_ADD_A2S);
272ebf0bd36SAmit Kucheria 
273ebf0bd36SAmit Kucheria 	if (err)
274ebf0bd36SAmit Kucheria 		pr_err("TWL4030 sleep sequence config error\n");
275ebf0bd36SAmit Kucheria 
276ebf0bd36SAmit Kucheria 	return err;
277ebf0bd36SAmit Kucheria }
278ebf0bd36SAmit Kucheria 
279f791be49SBill Pemberton static int twl4030_config_warmreset_sequence(u8 address)
280ebf0bd36SAmit Kucheria {
281ebf0bd36SAmit Kucheria 	int err;
282ebf0bd36SAmit Kucheria 	u8 rd_data;
283ebf0bd36SAmit Kucheria 
284ebf0bd36SAmit Kucheria 	/* Set WARM RESET SEQ address for P1 */
285fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
286ebf0bd36SAmit Kucheria 				R_SEQ_ADD_WARM);
287ebf0bd36SAmit Kucheria 	if (err)
288ebf0bd36SAmit Kucheria 		goto out;
289ebf0bd36SAmit Kucheria 
290ebf0bd36SAmit Kucheria 	/* P1/P2/P3 enable WARMRESET */
291fc7b92fcSBalaji T K 	err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
292ebf0bd36SAmit Kucheria 				R_P1_SW_EVENTS);
293ebf0bd36SAmit Kucheria 	if (err)
294ebf0bd36SAmit Kucheria 		goto out;
295ebf0bd36SAmit Kucheria 
296ebf0bd36SAmit Kucheria 	rd_data |= ENABLE_WARMRESET;
297fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
298ebf0bd36SAmit Kucheria 				R_P1_SW_EVENTS);
299ebf0bd36SAmit Kucheria 	if (err)
300ebf0bd36SAmit Kucheria 		goto out;
301ebf0bd36SAmit Kucheria 
302fc7b92fcSBalaji T K 	err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
303ebf0bd36SAmit Kucheria 				R_P2_SW_EVENTS);
304ebf0bd36SAmit Kucheria 	if (err)
305ebf0bd36SAmit Kucheria 		goto out;
306ebf0bd36SAmit Kucheria 
307ebf0bd36SAmit Kucheria 	rd_data |= ENABLE_WARMRESET;
308fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
309ebf0bd36SAmit Kucheria 				R_P2_SW_EVENTS);
310ebf0bd36SAmit Kucheria 	if (err)
311ebf0bd36SAmit Kucheria 		goto out;
312ebf0bd36SAmit Kucheria 
313fc7b92fcSBalaji T K 	err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
314ebf0bd36SAmit Kucheria 				R_P3_SW_EVENTS);
315ebf0bd36SAmit Kucheria 	if (err)
316ebf0bd36SAmit Kucheria 		goto out;
317ebf0bd36SAmit Kucheria 
318ebf0bd36SAmit Kucheria 	rd_data |= ENABLE_WARMRESET;
319fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
320ebf0bd36SAmit Kucheria 				R_P3_SW_EVENTS);
321ebf0bd36SAmit Kucheria out:
322ebf0bd36SAmit Kucheria 	if (err)
323ebf0bd36SAmit Kucheria 		pr_err("TWL4030 warmreset seq config error\n");
324ebf0bd36SAmit Kucheria 	return err;
325ebf0bd36SAmit Kucheria }
326ebf0bd36SAmit Kucheria 
327f791be49SBill Pemberton static int twl4030_configure_resource(struct twl4030_resconfig *rconfig)
328ebf0bd36SAmit Kucheria {
329ebf0bd36SAmit Kucheria 	int rconfig_addr;
330ebf0bd36SAmit Kucheria 	int err;
331ebf0bd36SAmit Kucheria 	u8 type;
332ebf0bd36SAmit Kucheria 	u8 grp;
333b4ead61eSAmit Kucheria 	u8 remap;
334ebf0bd36SAmit Kucheria 
335ebf0bd36SAmit Kucheria 	if (rconfig->resource > TOTAL_RESOURCES) {
336ebf0bd36SAmit Kucheria 		pr_err("TWL4030 Resource %d does not exist\n",
337ebf0bd36SAmit Kucheria 			rconfig->resource);
338ebf0bd36SAmit Kucheria 		return -EINVAL;
339ebf0bd36SAmit Kucheria 	}
340ebf0bd36SAmit Kucheria 
341ebf0bd36SAmit Kucheria 	rconfig_addr = res_config_addrs[rconfig->resource];
342ebf0bd36SAmit Kucheria 
343ebf0bd36SAmit Kucheria 	/* Set resource group */
344fc7b92fcSBalaji T K 	err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
345e97d1546SAmit Kucheria 			      rconfig_addr + DEV_GRP_OFFSET);
346ebf0bd36SAmit Kucheria 	if (err) {
347ebf0bd36SAmit Kucheria 		pr_err("TWL4030 Resource %d group could not be read\n",
348ebf0bd36SAmit Kucheria 			rconfig->resource);
349ebf0bd36SAmit Kucheria 		return err;
350ebf0bd36SAmit Kucheria 	}
351ebf0bd36SAmit Kucheria 
35256baa667SAaro Koskinen 	if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) {
353e97d1546SAmit Kucheria 		grp &= ~DEV_GRP_MASK;
354e97d1546SAmit Kucheria 		grp |= rconfig->devgroup << DEV_GRP_SHIFT;
355fc7b92fcSBalaji T K 		err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
356e97d1546SAmit Kucheria 				       grp, rconfig_addr + DEV_GRP_OFFSET);
357ebf0bd36SAmit Kucheria 		if (err < 0) {
358ebf0bd36SAmit Kucheria 			pr_err("TWL4030 failed to program devgroup\n");
359ebf0bd36SAmit Kucheria 			return err;
360ebf0bd36SAmit Kucheria 		}
361ebf0bd36SAmit Kucheria 	}
362ebf0bd36SAmit Kucheria 
363ebf0bd36SAmit Kucheria 	/* Set resource types */
364fc7b92fcSBalaji T K 	err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type,
365ebf0bd36SAmit Kucheria 				rconfig_addr + TYPE_OFFSET);
366ebf0bd36SAmit Kucheria 	if (err < 0) {
367ebf0bd36SAmit Kucheria 		pr_err("TWL4030 Resource %d type could not be read\n",
368ebf0bd36SAmit Kucheria 			rconfig->resource);
369ebf0bd36SAmit Kucheria 		return err;
370ebf0bd36SAmit Kucheria 	}
371ebf0bd36SAmit Kucheria 
37256baa667SAaro Koskinen 	if (rconfig->type != TWL4030_RESCONFIG_UNDEF) {
373ebf0bd36SAmit Kucheria 		type &= ~TYPE_MASK;
374ebf0bd36SAmit Kucheria 		type |= rconfig->type << TYPE_SHIFT;
375ebf0bd36SAmit Kucheria 	}
376ebf0bd36SAmit Kucheria 
37756baa667SAaro Koskinen 	if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) {
378ebf0bd36SAmit Kucheria 		type &= ~TYPE2_MASK;
379ebf0bd36SAmit Kucheria 		type |= rconfig->type2 << TYPE2_SHIFT;
380ebf0bd36SAmit Kucheria 	}
381ebf0bd36SAmit Kucheria 
382fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
383ebf0bd36SAmit Kucheria 				type, rconfig_addr + TYPE_OFFSET);
384ebf0bd36SAmit Kucheria 	if (err < 0) {
385ebf0bd36SAmit Kucheria 		pr_err("TWL4030 failed to program resource type\n");
386ebf0bd36SAmit Kucheria 		return err;
387ebf0bd36SAmit Kucheria 	}
388ebf0bd36SAmit Kucheria 
389b4ead61eSAmit Kucheria 	/* Set remap states */
390fc7b92fcSBalaji T K 	err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap,
391b4ead61eSAmit Kucheria 			      rconfig_addr + REMAP_OFFSET);
392b4ead61eSAmit Kucheria 	if (err < 0) {
393b4ead61eSAmit Kucheria 		pr_err("TWL4030 Resource %d remap could not be read\n",
394b4ead61eSAmit Kucheria 			rconfig->resource);
395b4ead61eSAmit Kucheria 		return err;
396b4ead61eSAmit Kucheria 	}
397b4ead61eSAmit Kucheria 
39853cf9a60SAmit Kucheria 	if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) {
399b4ead61eSAmit Kucheria 		remap &= ~OFF_STATE_MASK;
400b4ead61eSAmit Kucheria 		remap |= rconfig->remap_off << OFF_STATE_SHIFT;
401b4ead61eSAmit Kucheria 	}
402b4ead61eSAmit Kucheria 
40353cf9a60SAmit Kucheria 	if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
404b4ead61eSAmit Kucheria 		remap &= ~SLEEP_STATE_MASK;
4051ea933f4SMike Turquette 		remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT;
406b4ead61eSAmit Kucheria 	}
407b4ead61eSAmit Kucheria 
408fc7b92fcSBalaji T K 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
409b4ead61eSAmit Kucheria 			       remap,
410b4ead61eSAmit Kucheria 			       rconfig_addr + REMAP_OFFSET);
411b4ead61eSAmit Kucheria 	if (err < 0) {
412b4ead61eSAmit Kucheria 		pr_err("TWL4030 failed to program remap\n");
413b4ead61eSAmit Kucheria 		return err;
414b4ead61eSAmit Kucheria 	}
415b4ead61eSAmit Kucheria 
416ebf0bd36SAmit Kucheria 	return 0;
417ebf0bd36SAmit Kucheria }
418ebf0bd36SAmit Kucheria 
419f791be49SBill Pemberton static int load_twl4030_script(struct twl4030_script *tscript,
420ebf0bd36SAmit Kucheria 	       u8 address)
421ebf0bd36SAmit Kucheria {
422ebf0bd36SAmit Kucheria 	int err;
42375a74565SAmit Kucheria 	static int order;
424ebf0bd36SAmit Kucheria 
425ebf0bd36SAmit Kucheria 	/* Make sure the script isn't going beyond last valid address (0x3f) */
426ebf0bd36SAmit Kucheria 	if ((address + tscript->size) > END_OF_SCRIPT) {
427ebf0bd36SAmit Kucheria 		pr_err("TWL4030 scripts too big error\n");
428ebf0bd36SAmit Kucheria 		return -EINVAL;
429ebf0bd36SAmit Kucheria 	}
430ebf0bd36SAmit Kucheria 
431ebf0bd36SAmit Kucheria 	err = twl4030_write_script(address, tscript->script, tscript->size);
432ebf0bd36SAmit Kucheria 	if (err)
433ebf0bd36SAmit Kucheria 		goto out;
434ebf0bd36SAmit Kucheria 
435ebf0bd36SAmit Kucheria 	if (tscript->flags & TWL4030_WRST_SCRIPT) {
436ebf0bd36SAmit Kucheria 		err = twl4030_config_warmreset_sequence(address);
437ebf0bd36SAmit Kucheria 		if (err)
438ebf0bd36SAmit Kucheria 			goto out;
439ebf0bd36SAmit Kucheria 	}
440ebf0bd36SAmit Kucheria 	if (tscript->flags & TWL4030_WAKEUP12_SCRIPT) {
441ebf0bd36SAmit Kucheria 		err = twl4030_config_wakeup12_sequence(address);
442ebf0bd36SAmit Kucheria 		if (err)
443ebf0bd36SAmit Kucheria 			goto out;
44475a74565SAmit Kucheria 		order = 1;
445ebf0bd36SAmit Kucheria 	}
446ebf0bd36SAmit Kucheria 	if (tscript->flags & TWL4030_WAKEUP3_SCRIPT) {
447ebf0bd36SAmit Kucheria 		err = twl4030_config_wakeup3_sequence(address);
448ebf0bd36SAmit Kucheria 		if (err)
449ebf0bd36SAmit Kucheria 			goto out;
450ebf0bd36SAmit Kucheria 	}
451c62dd365SLesly A M 	if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
4521f968ff6SLesly A M 		if (!order)
45375a74565SAmit Kucheria 			pr_warning("TWL4030: Bad order of scripts (sleep "\
45475a74565SAmit Kucheria 					"script before wakeup) Leads to boot"\
45575a74565SAmit Kucheria 					"failure on some boards\n");
456ebf0bd36SAmit Kucheria 		err = twl4030_config_sleep_sequence(address);
457c62dd365SLesly A M 	}
458ebf0bd36SAmit Kucheria out:
459ebf0bd36SAmit Kucheria 	return err;
460ebf0bd36SAmit Kucheria }
461ebf0bd36SAmit Kucheria 
46211a441ceSMike Turquette int twl4030_remove_script(u8 flags)
46311a441ceSMike Turquette {
46411a441ceSMike Turquette 	int err = 0;
46511a441ceSMike Turquette 
46671084406SFelipe Balbi 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
46771084406SFelipe Balbi 			TWL4030_PM_MASTER_KEY_CFG1,
46871084406SFelipe Balbi 			TWL4030_PM_MASTER_PROTECT_KEY);
46911a441ceSMike Turquette 	if (err) {
47011a441ceSMike Turquette 		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
47111a441ceSMike Turquette 		return err;
47211a441ceSMike Turquette 	}
47311a441ceSMike Turquette 
47471084406SFelipe Balbi 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
47571084406SFelipe Balbi 			TWL4030_PM_MASTER_KEY_CFG2,
47671084406SFelipe Balbi 			TWL4030_PM_MASTER_PROTECT_KEY);
47711a441ceSMike Turquette 	if (err) {
47811a441ceSMike Turquette 		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
47911a441ceSMike Turquette 		return err;
48011a441ceSMike Turquette 	}
48111a441ceSMike Turquette 
48211a441ceSMike Turquette 	if (flags & TWL4030_WRST_SCRIPT) {
48311a441ceSMike Turquette 		err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
48411a441ceSMike Turquette 				R_SEQ_ADD_WARM);
48511a441ceSMike Turquette 		if (err)
48611a441ceSMike Turquette 			return err;
48711a441ceSMike Turquette 	}
48811a441ceSMike Turquette 	if (flags & TWL4030_WAKEUP12_SCRIPT) {
48911a441ceSMike Turquette 		err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
49011a441ceSMike Turquette 				R_SEQ_ADD_S2A12);
491eac78a21SLesly A M 		if (err)
49211a441ceSMike Turquette 			return err;
49311a441ceSMike Turquette 	}
49411a441ceSMike Turquette 	if (flags & TWL4030_WAKEUP3_SCRIPT) {
49511a441ceSMike Turquette 		err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
49611a441ceSMike Turquette 				R_SEQ_ADD_S2A3);
49711a441ceSMike Turquette 		if (err)
49811a441ceSMike Turquette 			return err;
49911a441ceSMike Turquette 	}
50011a441ceSMike Turquette 	if (flags & TWL4030_SLEEP_SCRIPT) {
50111a441ceSMike Turquette 		err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
50211a441ceSMike Turquette 				R_SEQ_ADD_A2S);
50311a441ceSMike Turquette 		if (err)
50411a441ceSMike Turquette 			return err;
50511a441ceSMike Turquette 	}
50611a441ceSMike Turquette 
50771084406SFelipe Balbi 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
50871084406SFelipe Balbi 			TWL4030_PM_MASTER_PROTECT_KEY);
50911a441ceSMike Turquette 	if (err)
51011a441ceSMike Turquette 		pr_err("TWL4030 Unable to relock registers\n");
51111a441ceSMike Turquette 
51211a441ceSMike Turquette 	return err;
51311a441ceSMike Turquette }
51411a441ceSMike Turquette 
51526cc3ab9SIgor Grinberg /*
51626cc3ab9SIgor Grinberg  * In master mode, start the power off sequence.
51726cc3ab9SIgor Grinberg  * After a successful execution, TWL shuts down the power to the SoC
51826cc3ab9SIgor Grinberg  * and all peripherals connected to it.
51926cc3ab9SIgor Grinberg  */
52026cc3ab9SIgor Grinberg void twl4030_power_off(void)
52126cc3ab9SIgor Grinberg {
52226cc3ab9SIgor Grinberg 	int err;
52326cc3ab9SIgor Grinberg 
52426cc3ab9SIgor Grinberg 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF,
52526cc3ab9SIgor Grinberg 			       TWL4030_PM_MASTER_P1_SW_EVENTS);
52626cc3ab9SIgor Grinberg 	if (err)
52726cc3ab9SIgor Grinberg 		pr_err("TWL4030 Unable to power off\n");
52826cc3ab9SIgor Grinberg }
52926cc3ab9SIgor Grinberg 
530f791be49SBill Pemberton void twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
531ebf0bd36SAmit Kucheria {
532ebf0bd36SAmit Kucheria 	int err = 0;
533ebf0bd36SAmit Kucheria 	int i;
534ebf0bd36SAmit Kucheria 	struct twl4030_resconfig *resconfig;
53526cc3ab9SIgor Grinberg 	u8 val, address = twl4030_start_script_address;
536ebf0bd36SAmit Kucheria 
53771084406SFelipe Balbi 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
53871084406SFelipe Balbi 			TWL4030_PM_MASTER_KEY_CFG1,
53971084406SFelipe Balbi 			TWL4030_PM_MASTER_PROTECT_KEY);
540ebf0bd36SAmit Kucheria 	if (err)
541ebf0bd36SAmit Kucheria 		goto unlock;
542ebf0bd36SAmit Kucheria 
54371084406SFelipe Balbi 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
54471084406SFelipe Balbi 			TWL4030_PM_MASTER_KEY_CFG2,
54571084406SFelipe Balbi 			TWL4030_PM_MASTER_PROTECT_KEY);
546ebf0bd36SAmit Kucheria 	if (err)
547ebf0bd36SAmit Kucheria 		goto unlock;
548ebf0bd36SAmit Kucheria 
549ebf0bd36SAmit Kucheria 	for (i = 0; i < twl4030_scripts->num; i++) {
550ebf0bd36SAmit Kucheria 		err = load_twl4030_script(twl4030_scripts->scripts[i], address);
551ebf0bd36SAmit Kucheria 		if (err)
552ebf0bd36SAmit Kucheria 			goto load;
553ebf0bd36SAmit Kucheria 		address += twl4030_scripts->scripts[i]->size;
554ebf0bd36SAmit Kucheria 	}
555ebf0bd36SAmit Kucheria 
556ebf0bd36SAmit Kucheria 	resconfig = twl4030_scripts->resource_config;
557ebf0bd36SAmit Kucheria 	if (resconfig) {
558ebf0bd36SAmit Kucheria 		while (resconfig->resource) {
559ebf0bd36SAmit Kucheria 			err = twl4030_configure_resource(resconfig);
560ebf0bd36SAmit Kucheria 			if (err)
561ebf0bd36SAmit Kucheria 				goto resource;
562ebf0bd36SAmit Kucheria 			resconfig++;
563ebf0bd36SAmit Kucheria 
564ebf0bd36SAmit Kucheria 		}
565ebf0bd36SAmit Kucheria 	}
566ebf0bd36SAmit Kucheria 
56726cc3ab9SIgor Grinberg 	/* Board has to be wired properly to use this feature */
56826cc3ab9SIgor Grinberg 	if (twl4030_scripts->use_poweroff && !pm_power_off) {
56926cc3ab9SIgor Grinberg 		/* Default for SEQ_OFFSYNC is set, lets ensure this */
57026cc3ab9SIgor Grinberg 		err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
57126cc3ab9SIgor Grinberg 				      TWL4030_PM_MASTER_CFG_P123_TRANSITION);
57226cc3ab9SIgor Grinberg 		if (err) {
57326cc3ab9SIgor Grinberg 			pr_warning("TWL4030 Unable to read registers\n");
57426cc3ab9SIgor Grinberg 
57526cc3ab9SIgor Grinberg 		} else if (!(val & SEQ_OFFSYNC)) {
57626cc3ab9SIgor Grinberg 			val |= SEQ_OFFSYNC;
57726cc3ab9SIgor Grinberg 			err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
57826cc3ab9SIgor Grinberg 					TWL4030_PM_MASTER_CFG_P123_TRANSITION);
57926cc3ab9SIgor Grinberg 			if (err) {
58026cc3ab9SIgor Grinberg 				pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n");
58126cc3ab9SIgor Grinberg 				goto relock;
58226cc3ab9SIgor Grinberg 			}
58326cc3ab9SIgor Grinberg 		}
58426cc3ab9SIgor Grinberg 
58526cc3ab9SIgor Grinberg 		pm_power_off = twl4030_power_off;
58626cc3ab9SIgor Grinberg 	}
58726cc3ab9SIgor Grinberg 
58826cc3ab9SIgor Grinberg relock:
58971084406SFelipe Balbi 	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
59071084406SFelipe Balbi 			TWL4030_PM_MASTER_PROTECT_KEY);
591ebf0bd36SAmit Kucheria 	if (err)
592ebf0bd36SAmit Kucheria 		pr_err("TWL4030 Unable to relock registers\n");
593ebf0bd36SAmit Kucheria 	return;
594ebf0bd36SAmit Kucheria 
595ebf0bd36SAmit Kucheria unlock:
596ebf0bd36SAmit Kucheria 	if (err)
597ebf0bd36SAmit Kucheria 		pr_err("TWL4030 Unable to unlock registers\n");
598ebf0bd36SAmit Kucheria 	return;
599ebf0bd36SAmit Kucheria load:
600ebf0bd36SAmit Kucheria 	if (err)
601ebf0bd36SAmit Kucheria 		pr_err("TWL4030 failed to load scripts\n");
602ebf0bd36SAmit Kucheria 	return;
603ebf0bd36SAmit Kucheria resource:
604ebf0bd36SAmit Kucheria 	if (err)
605ebf0bd36SAmit Kucheria 		pr_err("TWL4030 failed to configure resource\n");
606ebf0bd36SAmit Kucheria 	return;
607ebf0bd36SAmit Kucheria }
608