aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/smb349-charger.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/smb349-charger.c')
-rw-r--r--drivers/power/smb349-charger.c588
1 files changed, 588 insertions, 0 deletions
diff --git a/drivers/power/smb349-charger.c b/drivers/power/smb349-charger.c
new file mode 100644
index 00000000000..1f230baadcb
--- /dev/null
+++ b/drivers/power/smb349-charger.c
@@ -0,0 +1,588 @@
1/*
2 * drivers/power/smb349-charger.c
3 *
4 * Battery charger driver for smb349 from summit microelectronics
5 *
6 * Copyright (c) 2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation;
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/platform_device.h>
25#include <linux/mutex.h>
26#include <linux/err.h>
27#include <linux/i2c.h>
28#include <linux/delay.h>
29#include <linux/power_supply.h>
30#include <linux/platform_device.h>
31#include <linux/regulator/driver.h>
32#include <linux/regulator/machine.h>
33#include <linux/smb349-charger.h>
34#include <linux/slab.h>
35#include <linux/gpio.h>
36#include <linux/interrupt.h>
37#include <linux/irq.h>
38#include <linux/usb/otg.h>
39
40#define SMB349_CHARGE 0x00
41#define SMB349_CHRG_CRNTS 0x01
42#define SMB349_VRS_FUNC 0x02
43#define SMB349_FLOAT_VLTG 0x03
44#define SMB349_CHRG_CTRL 0x04
45#define SMB349_STAT_TIME_CTRL 0x05
46#define SMB349_PIN_CTRL 0x06
47#define SMB349_THERM_CTRL 0x07
48#define SMB349_CTRL_REG 0x09
49
50#define SMB349_OTG_TLIM_REG 0x0A
51#define SMB349_HRD_SFT_TEMP 0x0B
52#define SMB349_FAULT_INTR 0x0C
53#define SMB349_STS_INTR_1 0x0D
54#define SMB349_SYSOK_USB3 0x0E
55#define SMB349_IN_CLTG_DET 0x10
56#define SMB349_STS_INTR_2 0x11
57
58#define SMB349_CMD_REG 0x30
59#define SMB349_CMD_REG_B 0x31
60#define SMB349_CMD_REG_c 0x33
61
62#define SMB349_INTR_STS_A 0x35
63#define SMB349_INTR_STS_B 0x36
64#define SMB349_INTR_STS_C 0x37
65#define SMB349_INTR_STS_D 0x38
66#define SMB349_INTR_STS_E 0x39
67#define SMB349_INTR_STS_F 0x3A
68
69#define SMB349_STS_REG_A 0x3B
70#define SMB349_STS_REG_B 0x3C
71#define SMB349_STS_REG_C 0x3D
72#define SMB349_STS_REG_D 0x3E
73#define SMB349_STS_REG_E 0x3F
74
75#define SMB349_ENABLE_WRITE 1
76#define SMB349_DISABLE_WRITE 0
77#define ENABLE_WRT_ACCESS 0x80
78#define THERM_CTRL 0x10
79#define BATTERY_MISSING 0x10
80#define CHARGING 0x06
81#define DEDICATED_CHARGER 0x04
82#define CHRG_DOWNSTRM_PORT 0x08
83#define ENABLE_CHARGE 0x02
84
85static struct smb349_charger *charger;
86static int smb349_configure_charger(struct i2c_client *client, int value);
87static int smb349_configure_interrupts(struct i2c_client *client);
88
89static int smb349_read(struct i2c_client *client, int reg)
90{
91 int ret;
92
93 ret = i2c_smbus_read_byte_data(client, reg);
94
95 if (ret < 0)
96 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
97
98 return ret;
99}
100
101static int smb349_write(struct i2c_client *client, int reg, u8 value)
102{
103 int ret;
104
105 ret = i2c_smbus_write_byte_data(client, reg, value);
106
107 if (ret < 0)
108 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
109
110 return ret;
111}
112
113static int smb349_update_reg(struct i2c_client *client, int reg, u8 value)
114{
115 int ret, retval;
116
117 retval = smb349_read(client, reg);
118 if (retval < 0) {
119 dev_err(&client->dev, "%s: err %d\n", __func__, retval);
120 return retval;
121 }
122
123 ret = smb349_write(client, reg, retval | value);
124 if (ret < 0) {
125 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
126 return ret;
127 }
128
129 return ret;
130}
131
132int smb349_volatile_writes(struct i2c_client *client, uint8_t value)
133{
134 int ret = 0;
135
136 if (value == SMB349_ENABLE_WRITE) {
137 /* Enable volatile write to config registers */
138 ret = smb349_update_reg(client, SMB349_CMD_REG,
139 ENABLE_WRT_ACCESS);
140 if (ret < 0) {
141 dev_err(&client->dev, "%s(): Failed in writing"
142 "register 0x%02x\n", __func__, SMB349_CMD_REG);
143 return ret;
144 }
145 } else {
146 ret = smb349_read(client, SMB349_CMD_REG);
147 if (ret < 0) {
148 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
149 return ret;
150 }
151
152 ret = smb349_write(client, SMB349_CMD_REG, ret & (~(1<<7)));
153 if (ret < 0) {
154 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
155 return ret;
156 }
157 }
158 return ret;
159}
160
161static void smb349_clear_interrupts(struct i2c_client *client)
162{
163 uint8_t val, buf[6];
164
165 val = i2c_smbus_read_i2c_block_data(client, SMB349_INTR_STS_A, 6, buf);
166 if (val < 0)
167 dev_err(&client->dev, "%s(): Failed in clearing interrupts\n",
168 __func__);
169}
170
171static int smb349_configure_otg(struct i2c_client *client, int enable)
172{
173 int ret = 0;
174
175 /*Enable volatile writes to registers*/
176 ret = smb349_volatile_writes(client, SMB349_ENABLE_WRITE);
177 if (ret < 0) {
178 dev_err(&client->dev, "%s error in configuring otg..\n",
179 __func__);
180 goto error;
181 }
182
183 if (enable) {
184 /* Configure PGOOD to be active low */
185 ret = smb349_read(client, SMB349_SYSOK_USB3);
186 if (ret < 0) {
187 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
188 goto error;
189 }
190
191 ret = smb349_write(client, SMB349_SYSOK_USB3, (ret & (~(1))));
192 if (ret < 0) {
193 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
194 goto error;
195 }
196
197 /* Enable OTG */
198 ret = smb349_update_reg(client, SMB349_CMD_REG, 0x10);
199 if (ret < 0) {
200 dev_err(&client->dev, "%s: Failed in writing register"
201 "0x%02x\n", __func__, SMB349_CMD_REG);
202 goto error;
203 }
204 } else {
205 /* Disable OTG */
206 ret = smb349_read(client, SMB349_CMD_REG);
207 if (ret < 0) {
208 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
209 goto error;
210 }
211
212 ret = smb349_write(client, SMB349_CMD_REG, (ret & (~(1<<4))));
213 if (ret < 0) {
214 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
215 goto error;
216 }
217