aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorMyungJoo Ham <myungjoo.ham@samsung.com>2011-03-04 01:50:26 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2011-03-23 05:42:03 -0400
commit527e7e9a82ec95cdb8f694855004b3d262efd09f (patch)
tree5c58fb64d9efcf37c712b55c6ce993567483e2e3 /drivers/mfd
parentf77289ac25b0c81acbed6f9c17cb14809a04e18b (diff)
mfd: MAX8997/8966 support
MAX8997/MAX8966 chip is a multi-function device with I2C bussses. The chip includes PMIC, RTC, Fuel Gauge, MUIC, Haptic, Flash control, and Battery (charging) control. This patch is an initial release of a MAX8997/8966 driver that supports to enable the chip with its primary I2C bus that connects every device mentioned above except for Fuel Gauge, which uses another I2C bus. The fuel gauge is not supported by this mfd driver and is supported by a seperated driver of MAX17042 Fuel Gauge (yes, the fuel gauge part is compatible with MAX17042). Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig12
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/max8997.c427
3 files changed, 440 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 50c476964e48..642168c8d3b1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -314,6 +314,18 @@ config MFD_MAX8925
314 accessing the device, additional drivers must be enabled in order 314 accessing the device, additional drivers must be enabled in order
315 to use the functionality of the device. 315 to use the functionality of the device.
316 316
317config MFD_MAX8997
318 bool "Maxim Semiconductor MAX8997/8966 PMIC Support"
319 depends on I2C=y && GENERIC_HARDIRQS
320 select MFD_CORE
321 help
322 Say yes here to support for Maxim Semiconductor MAX8998/8966.
323 This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
324 MUIC controls on chip.
325 This driver provies common support for accessing the device,
326 additional drivers must be enabled in order to use the functionality
327 of the device.
328
317config MFD_MAX8998 329config MFD_MAX8998
318 bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" 330 bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support"
319 depends on I2C=y && GENERIC_HARDIRQS 331 depends on I2C=y && GENERIC_HARDIRQS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 25f3c7551489..0e9f0c51449d 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o
62obj-$(CONFIG_PMIC_DA903X) += da903x.o 62obj-$(CONFIG_PMIC_DA903X) += da903x.o
63max8925-objs := max8925-core.o max8925-i2c.o 63max8925-objs := max8925-core.o max8925-i2c.o
64obj-$(CONFIG_MFD_MAX8925) += max8925.o 64obj-$(CONFIG_MFD_MAX8925) += max8925.o
65obj-$(CONFIG_MFD_MAX8997) += max8997.o
65obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o 66obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o
66 67
67pcf50633-objs := pcf50633-core.o pcf50633-irq.o 68pcf50633-objs := pcf50633-core.o pcf50633-irq.o
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
new file mode 100644
index 000000000000..5d1fca0277ef
--- /dev/null
+++ b/drivers/mfd/max8997.c
@@ -0,0 +1,427 @@
1/*
2 * max8997.c - mfd core driver for the Maxim 8966 and 8997
3 *
4 * Copyright (C) 2011 Samsung Electronics
5 * MyungJoo Ham <myungjoo.ham@smasung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * This driver is based on max8998.c
22 */
23
24#include <linux/slab.h>
25#include <linux/i2c.h>
26#include <linux/pm_runtime.h>
27#include <linux/mutex.h>
28#include <linux/mfd/core.h>
29#include <linux/mfd/max8997.h>
30#include <linux/mfd/max8997-private.h>
31
32#define I2C_ADDR_PMIC (0xCC >> 1)
33#define I2C_ADDR_MUIC (0x4A >> 1)
34#define I2C_ADDR_BATTERY (0x6C >> 1)
35#define I2C_ADDR_RTC (0x0C >> 1)
36#define I2C_ADDR_HAPTIC (0x90 >> 1)
37
38static struct mfd_cell max8997_devs[] = {
39 { .name = "max8997-pmic", },
40 { .name = "max8997-rtc", },
41 { .name = "max8997-battery", },
42 { .name = "max8997-haptic", },
43 { .name = "max8997-muic", },
44 { .name = "max8997-flash", },
45};
46
47int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
48{
49 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
50 int ret;
51
52 mutex_lock(&max8997->iolock);
53 ret = i2c_smbus_read_byte_data(i2c, reg);
54 mutex_unlock(&max8997->iolock);
55 if (ret < 0)
56 return ret;
57
58 ret &= 0xff;
59 *dest = ret;
60 return 0;
61}
62EXPORT_SYMBOL_GPL(max8997_read_reg);
63
64int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
65{
66 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
67 int ret;
68
69 mutex_lock(&max8997->iolock);
70 ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf);
71 mutex_unlock(&max8997->iolock);
72 if (ret < 0)
73 return ret;
74
75 return 0;
76}
77EXPORT_SYMBOL_GPL(max8997_bulk_read);
78
79int max8997_write_reg(struct i2c_client *i2c, u8 reg, u8 value)
80{
81 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
82 int ret;
83
84 mutex_lock(&max8997->iolock);
85 ret = i2c_smbus_write_byte_data(i2c, reg, value);
86 mutex_unlock(&max8997->iolock);
87 return ret;
88}
89EXPORT_SYMBOL_GPL(max8997_write_reg);
90
91int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
92{
93 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
94 int ret;
95
96 mutex_lock(&max8997->iolock);
97 ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf);
98 mutex_unlock(&max8997->iolock);
99 if (ret < 0)
100 return ret;
101
102 return 0;
103}
104EXPORT_SYMBOL_GPL(max8997_bulk_write);
105
106int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
107{
108 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
109 int ret;
110
111 mutex_lock(&max8997->iolock);
112 ret = i2c_smbus_read_byte_data(i2c, reg);
113 if (ret >= 0) {
114 u8 old_val = ret & 0xff;
115 u8 new_val = (val & mask) | (old_val & (~mask));
116 ret = i2c_smbus_write_byte_data(i2c, reg, new_val);
117 }
118 mutex_unlock(&max8997->iolock);
119 return ret;
120}
121EXPORT_SYMBOL_GPL(max8997_update_reg);
122
123static int max8997_i2c_probe(struct i2c_client *i2c,
124 const struct i2c_device_id *id)
125{
126 struct max8997_dev *max8997;
127 struct max8997_platform_data *pdata = i2c->dev.platform_data;
128 int ret = 0;
129
130 max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL);
131 if (max8997 == NULL)
132 return -ENOMEM;
133
134 i2c_set_clientdata(i2c, max8997);
135 max8997->dev = &i2c->dev;
136 max8997->i2c = i2c;
137 max8997->type = id->driver_data;
138
139 if (!pdata)
140 goto err;
141
142 max8997->wakeup = pdata->wakeup;
143
144 mutex_init(&max8997->iolock);
145
146 max8997->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
147 i2c_set_clientdata(max8997->rtc, max8997);
148 max8997->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC);
149 i2c_set_clientdata(max8997->haptic, max8997);
150 max8997->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC);
151 i2c_set_clientdata(max8997->muic, max8997);
152
153 pm_runtime_set_active(max8997->dev);
154
155 mfd_add_devices(max8997->dev, -1, max8997_devs,
156 ARRAY_SIZE(max8997_devs),
157 NULL, 0);
158
159 /*
160 * TODO: enable others (flash, muic, rtc, battery, ...) and
161 * check the return value
162 */
163
164 if (ret < 0)
165 goto err_mfd;
166
167 return ret;
168
169err_mfd:
170 mfd_remove_devices(max8997->dev);
171 i2c_unregister_device(max8997->muic);
172 i2c_unregister_device(max8997->haptic);
173 i2c_unregister_device(max8997->rtc);
174err:
175 kfree(max8997);
176 return ret;
177}
178
179static int max8997_i2c_remove(struct i2c_client *i2c)
180{
181 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
182
183 mfd_remove_devices(max8997->dev);
184 i2c_unregister_device(max8997->muic);
185 i2c_unregister_device(max8997->haptic);
186 i2c_unregister_device(max8997->rtc);
187 kfree(max8997);
188
189 return 0;
190}
191
192static const struct i2c_device_id max8997_i2c_id[] = {
193 { "max8997", TYPE_MAX8997 },
194 { "max8966", TYPE_MAX8966 },
195 { }
196};
197MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
198
199u8 max8997_dumpaddr_pmic[] = {
200 MAX8997_REG_INT1MSK,
201 MAX8997_REG_INT2MSK,
202 MAX8997_REG_INT3MSK,
203 MAX8997_REG_INT4MSK,
204 MAX8997_REG_MAINCON1,
205 MAX8997_REG_MAINCON2,
206 MAX8997_REG_BUCKRAMP,
207 MAX8997_REG_BUCK1CTRL,
208 MAX8997_REG_BUCK1DVS1,
209 MAX8997_REG_BUCK1DVS2,
210 MAX8997_REG_BUCK1DVS3,
211 MAX8997_REG_BUCK1DVS4,
212 MAX8997_REG_BUCK1DVS5,
213 MAX8997_REG_BUCK1DVS6,
214 MAX8997_REG_BUCK1DVS7,
215 MAX8997_REG_BUCK1DVS8,
216 MAX8997_REG_BUCK2CTRL,
217 MAX8997_REG_BUCK2DVS1,
218 MAX8997_REG_BUCK2DVS2,
219 MAX8997_REG_BUCK2DVS3,
220 MAX8997_REG_BUCK2DVS4,
221 MAX8997_REG_BUCK2DVS5,
222 MAX8997_REG_BUCK2DVS6,
223 MAX8997_REG_BUCK2DVS7,
224 MAX8997_REG_BUCK2DVS8,
225 MAX8997_REG_BUCK3CTRL,
226 MAX8997_REG_BUCK3DVS,
227 MAX8997_REG_BUCK4CTRL,
228 MAX8997_REG_BUCK4DVS,
229 MAX8997_REG_BUCK5CTRL,
230 MAX8997_REG_BUCK5DVS1,
231 MAX8997_REG_BUCK5DVS2,
232 MAX8997_REG_BUCK5DVS3,
233 MAX8997_REG_BUCK5DVS4,
234 MAX8997_REG_BUCK5DVS5,
235 MAX8997_REG_BUCK5DVS6,
236 MAX8997_REG_BUCK5DVS7,
237 MAX8997_REG_BUCK5DVS8,
238 MAX8997_REG_BUCK6CTRL,
239 MAX8997_REG_BUCK6BPSKIPCTRL,
240 MAX8997_REG_BUCK7CTRL,
241 MAX8997_REG_BUCK7DVS,
242 MAX8997_REG_LDO1CTRL,
243 MAX8997_REG_LDO2CTRL,
244 MAX8997_REG_LDO3CTRL,
245 MAX8997_REG_LDO4CTRL,
246 MAX8997_REG_LDO5CTRL,
247 MAX8997_REG_LDO6CTRL,
248 MAX8997_REG_LDO7CTRL,
249 MAX8997_REG_LDO8CTRL,
250 MAX8997_REG_LDO9CTRL,
251 MAX8997_REG_LDO10CTRL,
252 MAX8997_REG_LDO11CTRL,
253 MAX8997_REG_LDO12CTRL,
254 MAX8997_REG_LDO13CTRL,
255 MAX8997_REG_LDO14CTRL,
256 MAX8997_REG_LDO15CTRL,
257 MAX8997_REG_LDO16CTRL,
258 MAX8997_REG_LDO17CTRL,
259 MAX8997_REG_LDO18CTRL,
260 MAX8997_REG_LDO21CTRL,
261 MAX8997_REG_MBCCTRL1,
262 MAX8997_REG_MBCCTRL2,
263 MAX8997_REG_MBCCTRL3,
264 MAX8997_REG_MBCCTRL4,
265 MAX8997_REG_MBCCTRL5,
266 MAX8997_REG_MBCCTRL6,
267 MAX8997_REG_OTPCGHCVS,
268 MAX8997_REG_SAFEOUTCTRL,
269 MAX8997_REG_LBCNFG1,
270 MAX8997_REG_LBCNFG2,
271 MAX8997_REG_BBCCTRL,
272
273 MAX8997_REG_FLASH1_CUR,
274 MAX8997_REG_FLASH2_CUR,
275 MAX8997_REG_MOVIE_CUR,
276 MAX8997_REG_GSMB_CUR,
277 MAX8997_REG_BOOST_CNTL,
278 MAX8997_REG_LEN_CNTL,
279 MAX8997_REG_FLASH_CNTL,
280 MAX8997_REG_WDT_CNTL,
281 MAX8997_REG_MAXFLASH1,
282 MAX8997_REG_MAXFLASH2,
283 MAX8997_REG_FLASHSTATUSMASK,
284
285 MAX8997_REG_GPIOCNTL1,
286 MAX8997_REG_GPIOCNTL2,
287 MAX8997_REG_GPIOCNTL3,
288 MAX8997_REG_GPIOCNTL4,
289 MAX8997_REG_GPIOCNTL5,
290 MAX8997_REG_GPIOCNTL6,
291 MAX8997_REG_GPIOCNTL7,
292 MAX8997_REG_GPIOCNTL8,
293 MAX8997_REG_GPIOCNTL9,
294 MAX8997_REG_GPIOCNTL10,
295 MAX8997_REG_GPIOCNTL11,
296 MAX8997_REG_GPIOCNTL12,
297
298 MAX8997_REG_LDO1CONFIG,
299 MAX8997_REG_LDO2CONFIG,
300 MAX8997_REG_LDO3CONFIG,
301 MAX8997_REG_LDO4CONFIG,
302 MAX8997_REG_LDO5CONFIG,
303 MAX8997_REG_LDO6CONFIG,
304 MAX8997_REG_LDO7CONFIG,
305 MAX8997_REG_LDO8CONFIG,
306 MAX8997_REG_LDO9CONFIG,
307 MAX8997_REG_LDO10CONFIG,
308 MAX8997_REG_LDO11CONFIG,
309 MAX8997_REG_LDO12CONFIG,
310 MAX8997_REG_LDO13CONFIG,
311 MAX8997_REG_LDO14CONFIG,
312 MAX8997_REG_LDO15CONFIG,
313 MAX8997_REG_LDO16CONFIG,
314 MAX8997_REG_LDO17CONFIG,
315 MAX8997_REG_LDO18CONFIG,
316 MAX8997_REG_LDO21CONFIG,
317
318 MAX8997_REG_DVSOKTIMER1,
319 MAX8997_REG_DVSOKTIMER2,
320 MAX8997_REG_DVSOKTIMER4,
321 MAX8997_REG_DVSOKTIMER5,
322};
323
324u8 max8997_dumpaddr_muic[] = {
325 MAX8997_MUIC_REG_INTMASK1,
326 MAX8997_MUIC_REG_INTMASK2,
327 MAX8997_MUIC_REG_INTMASK3,
328 MAX8997_MUIC_REG_CDETCTRL,
329 MAX8997_MUIC_REG_CONTROL1,
330 MAX8997_MUIC_REG_CONTROL2,
331 MAX8997_MUIC_REG_CONTROL3,
332};
333
334u8 max8997_dumpaddr_haptic[] = {
335 MAX8997_HAPTIC_REG_CONF1,
336 MAX8997_HAPTIC_REG_CONF2,
337 MAX8997_HAPTIC_REG_DRVCONF,
338 MAX8997_HAPTIC_REG_CYCLECONF1,
339 MAX8997_HAPTIC_REG_CYCLECONF2,
340 MAX8997_HAPTIC_REG_SIGCONF1,
341 MAX8997_HAPTIC_REG_SIGCONF2,
342 MAX8997_HAPTIC_REG_SIGCONF3,
343 MAX8997_HAPTIC_REG_SIGCONF4,
344 MAX8997_HAPTIC_REG_SIGDC1,
345 MAX8997_HAPTIC_REG_SIGDC2,
346 MAX8997_HAPTIC_REG_SIGPWMDC1,
347 MAX8997_HAPTIC_REG_SIGPWMDC2,
348 MAX8997_HAPTIC_REG_SIGPWMDC3,
349 MAX8997_HAPTIC_REG_SIGPWMDC4,
350};
351
352static int max8997_freeze(struct device *dev)
353{
354 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
355 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
356 int i;
357
358 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++)
359 max8997_read_reg(i2c, max8997_dumpaddr_pmic[i],
360 &max8997->reg_dump[i]);
361
362 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++)
363 max8997_read_reg(i2c, max8997_dumpaddr_muic[i],
364 &max8997->reg_dump[i + MAX8997_REG_PMIC_END]);
365
366 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++)
367 max8997_read_reg(i2c, max8997_dumpaddr_haptic[i],
368 &max8997->reg_dump[i + MAX8997_REG_PMIC_END +
369 MAX8997_MUIC_REG_END]);
370
371 return 0;
372}
373
374static int max8997_restore(struct device *dev)
375{
376 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
377 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
378 int i;
379
380 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++)
381 max8997_write_reg(i2c, max8997_dumpaddr_pmic[i],
382 max8997->reg_dump[i]);
383
384 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++)
385 max8997_write_reg(i2c, max8997_dumpaddr_muic[i],
386 max8997->reg_dump[i + MAX8997_REG_PMIC_END]);
387
388 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++)
389 max8997_write_reg(i2c, max8997_dumpaddr_haptic[i],
390 max8997->reg_dump[i + MAX8997_REG_PMIC_END +
391 MAX8997_MUIC_REG_END]);
392
393 return 0;
394}
395
396const struct dev_pm_ops max8997_pm = {
397 .freeze = max8997_freeze,
398 .restore = max8997_restore,
399};
400
401static struct i2c_driver max8997_i2c_driver = {
402 .driver = {
403 .name = "max8997",
404 .owner = THIS_MODULE,
405 .pm = &max8997_pm,
406 },
407 .probe = max8997_i2c_probe,
408 .remove = max8997_i2c_remove,
409 .id_table = max8997_i2c_id,
410};
411
412static int __init max8997_i2c_init(void)
413{
414 return i2c_add_driver(&max8997_i2c_driver);
415}
416/* init early so consumer devices can complete system boot */
417subsys_initcall(max8997_i2c_init);
418
419static void __exit max8997_i2c_exit(void)
420{
421 i2c_del_driver(&max8997_i2c_driver);
422}
423module_exit(max8997_i2c_exit);
424
425MODULE_DESCRIPTION("MAXIM 8997 multi-function core driver");
426MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
427MODULE_LICENSE("GPL");