summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx5/pm_da9053.c
blob: 1313aa78d8c332d7ff3402a72f777b2dcc7aced4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/*
 * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */


#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/mfd/da9052/reg.h>

#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/i2c.h>
#include "pmic.h"

/** Defines ********************************************************************
*******************************************************************************/
/* have to hard-code the preset voltage here for they share the register
as the normal setting on Da9053 */
/* preset buck core to 850 mv */
#define BUCKCORE_SUSPEND_PRESET 0xCE
/* preset buck core to 950 mv */
#define BUCKPRO_SUSPEND_PRESET 0xD2
/* preset ldo6 to 1200 mv */
#define LDO6_SUSPEND_PRESET 0xC0
/* preset ldo10 to 1200 mv */
#define iLDO10_SUSPEND_PRESET 0xC0
/* set VUSB 2V5 active during suspend */
#define BUCKPERI_SUSPEND_SW_STEP 0x50
/* restore VUSB 2V5 active after suspend */
#define BUCKPERI_RESTORE_SW_STEP 0x55
/* restore VUSB 2V5 power supply after suspend */
#define SUPPLY_RESTORE_VPERISW_EN 0x20
#define CONF_BIT 0x80

#define DA9053_SLEEP_DELAY 0x1f
#define DA9052_CONTROLC_SMD_SET 0x62
#define DA9052_GPIO0809_SMD_SET 0x18
#define DA9052_ID1415_SMD_SET   0x1
#define DA9052_GPI9_IRQ_MASK    0x2
#define DA9052_ALARM_IRQ_EN     (0x1<<6)
#define DA9052_SEQ_RDY_IRQ_MASK (0x1<<6)

static u8 volt_settings[DA9052_LDO10_REG - DA9052_BUCKCORE_REG + 1];

static void pm_da9053_read_reg(u8 reg, u8 *value)
{
	unsigned char buf[2] = {0, 0};
	struct i2c_msg i2cmsg[2];
	buf[0] = reg;
	i2cmsg[0].addr  = 0x48 ;
	i2cmsg[0].len   = 1;
	i2cmsg[0].buf   = &buf[0];

	i2cmsg[0].flags = 0;

	i2cmsg[1].addr  = 0x48 ;
	i2cmsg[1].len   = 1;
	i2cmsg[1].buf   = &buf[1];

	i2cmsg[1].flags = I2C_M_RD;

	pm_i2c_imx_xfer(i2cmsg, 2);
	*value = buf[1];
}

static void pm_da9053_write_reg(u8 reg, u8 value)
{
	unsigned char buf[2] = {0, 0};
	struct i2c_msg i2cmsg[2];
	buf[0] = reg;
	buf[1] = value;
	i2cmsg[0].addr  = 0x48 ;
	i2cmsg[0].len   = 2;
	i2cmsg[0].buf   = &buf[0];
	i2cmsg[0].flags = 0;
	pm_i2c_imx_xfer(i2cmsg, 1);
}

static void pm_da9053_preset_voltage(void)
{
	u8 reg, data;
	for (reg = DA9052_BUCKCORE_REG;
		reg <= DA9052_LDO10_REG; reg++) {
		pm_da9053_read_reg(reg, &data);
		volt_settings[reg - DA9052_BUCKCORE_REG] = data;
		data |= CONF_BIT;
		pm_da9053_write_reg(reg, data);
	}
	pm_da9053_write_reg(DA9052_BUCKCORE_REG, BUCKCORE_SUSPEND_PRESET);
	pm_da9053_write_reg(DA9052_BUCKPRO_REG, BUCKPRO_SUSPEND_PRESET);
	pm_da9053_write_reg(DA9052_LDO6_REG, LDO6_SUSPEND_PRESET);
	pm_da9053_write_reg(DA9052_LDO10_REG, iLDO10_SUSPEND_PRESET);
	pm_da9053_write_reg(DA9052_ID1213_REG, BUCKPERI_SUSPEND_SW_STEP);
}

#if 0
static void pm_da9053_dump(int start, int end)
{
	u8 reg, data;
	for (reg = start; reg <= end; reg++) {
		pm_da9053_read_reg(reg, &data);
		pr_info("reg %u = 0x%2x\n",
			reg, data);
	}
}
#endif

int da9053_suspend_cmd_sw(void)
{
	unsigned char buf[2] = {0, 0};
	struct clk *i2c_clk;
	u8 data;
	buf[0] = 29;

	i2c_clk = clk_get(NULL, "i2c_clk");
	if (IS_ERR(i2c_clk)) {
		pr_err("unable to get i2c clk\n");
		return PTR_ERR(i2c_clk);
	}
	clk_enable(i2c_clk);

	pm_da9053_preset_voltage();

	pm_da9053_read_reg(DA9052_ID01_REG, &data);
	data &= ~(DA9052_ID01_DEFSUPPLY | DA9052_ID01_nRESMODE);
	pm_da9053_write_reg(DA9052_ID01_REG, data);

	pm_da9053_write_reg(DA9052_SEQB_REG, DA9053_SLEEP_DELAY);

	pm_da9053_read_reg(DA9052_CONTROLB_REG, &data);
	data |= DA9052_CONTROLB_DEEPSLEEP;
	pm_da9053_write_reg(DA9052_CONTROLB_REG, data);

	clk_disable(i2c_clk);
	clk_put(i2c_clk);
	return 0;
}

int da9053_suspend_cmd_hw(void)
{
	unsigned char buf[2] = {0, 0};
	struct clk *i2c_clk;
	u8 data;
	buf[0] = 29;

	i2c_clk = clk_get(NULL, "i2c_clk");
	if (IS_ERR(i2c_clk)) {
		pr_err("unable to get i2c clk\n");
		return PTR_ERR(i2c_clk);
	}
	clk_enable(i2c_clk);

	pm_da9053_preset_voltage();
	pm_da9053_write_reg(DA9052_CONTROLC_REG,
				DA9052_CONTROLC_SMD_SET);

	pm_da9053_read_reg(DA9052_ID01_REG, &data);
	data &= ~(DA9052_ID01_DEFSUPPLY | DA9052_ID01_nRESMODE);
	pm_da9053_write_reg(DA9052_ID01_REG, data);

	pm_da9053_write_reg(DA9052_GPIO0809_REG,
			DA9052_GPIO0809_SMD_SET);
	pm_da9053_read_reg(DA9052_IRQMASKD_REG, &data);
	data |= DA9052_GPI9_IRQ_MASK;
	pm_da9053_write_reg(DA9052_IRQMASKD_REG, data);
#ifdef CONFIG_RTC_DRV_DA9052
	pm_da9053_read_reg(DA9052_ALARMY_REG, &data);
	data |= DA9052_ALARM_IRQ_EN;
	pm_da9053_write_reg(DA9052_ALARMY_REG, data);
#endif
	/* Mask SEQ_RDY_IRQ to avoid some suspend/resume issues */
	pm_da9053_read_reg(DA9052_IRQMASKA_REG, &data);
	data |= DA9052_SEQ_RDY_IRQ_MASK;
	pm_da9053_write_reg(DA9052_IRQMASKA_REG, data);

	pm_da9053_read_reg(DA9052_ID1415_REG, &data);
	data &= 0xf0;
	data |= DA9052_ID1415_SMD_SET;
	pm_da9053_write_reg(DA9052_ID1415_REG, data);

	pm_da9053_write_reg(DA9052_SEQTIMER_REG, 0);
	/* pm_da9053_write_reg(DA9052_SEQB_REG, 0x1f); */

	clk_disable(i2c_clk);
	clk_put(i2c_clk);
	return 0;
}

int da9053_restore_volt_settings(void)
{
	u8 data;
	struct clk *i2c_clk;

	i2c_clk = clk_get(NULL, "i2c_clk");
	if (IS_ERR(i2c_clk)) {
		pr_err("unable to get i2c clk\n");
		return PTR_ERR(i2c_clk);
	}
	clk_enable(i2c_clk);

	pm_da9053_write_reg(DA9052_ID1213_REG, BUCKPERI_RESTORE_SW_STEP);
	pm_da9053_read_reg(DA9052_SUPPLY_REG, &data);
	data |= SUPPLY_RESTORE_VPERISW_EN;
	pm_da9053_write_reg(DA9052_SUPPLY_REG, data);

	clk_disable(i2c_clk);
	clk_put(i2c_clk);
	return 0;
}