aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig12
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/max8907.c331
3 files changed, 344 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d1facef28a60..856ec00ab787 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -476,6 +476,18 @@ config MFD_MAX77693
476 additional drivers must be enabled in order to use the functionality 476 additional drivers must be enabled in order to use the functionality
477 of the device. 477 of the device.
478 478
479config MFD_MAX8907
480 tristate "Maxim Semiconductor MAX8907 PMIC Support"
481 select MFD_CORE
482 depends on I2C=y && GENERIC_HARDIRQS
483 select REGMAP_I2C
484 select REGMAP_IRQ
485 help
486 Say yes here to support for Maxim Semiconductor MAX8907. This is
487 a Power Management IC. This driver provides common support for
488 accessing the device; additional drivers must be enabled in order
489 to use the functionality of the device.
490
479config MFD_MAX8925 491config MFD_MAX8925
480 bool "Maxim Semiconductor MAX8925 PMIC Support" 492 bool "Maxim Semiconductor MAX8925 PMIC Support"
481 depends on I2C=y && GENERIC_HARDIRQS 493 depends on I2C=y && GENERIC_HARDIRQS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 79dd22d1dc3d..2a4108d98442 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -92,6 +92,7 @@ obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
92 92
93obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o 93obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o
94obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o 94obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o
95obj-$(CONFIG_MFD_MAX8907) += max8907.o
95max8925-objs := max8925-core.o max8925-i2c.o 96max8925-objs := max8925-core.o max8925-i2c.o
96obj-$(CONFIG_MFD_MAX8925) += max8925.o 97obj-$(CONFIG_MFD_MAX8925) += max8925.o
97obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o 98obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o
diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c
new file mode 100644
index 000000000000..6497c98e030d
--- /dev/null
+++ b/drivers/mfd/max8907.c
@@ -0,0 +1,331 @@
1/*
2 * max8907.c - mfd driver for MAX8907
3 *
4 * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
5 * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
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 version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/err.h>
13#include <linux/i2c.h>
14#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/irq.h>
17#include <linux/mfd/core.h>
18#include <linux/mfd/max8907.h>
19#include <linux/module.h>
20#include <linux/of_device.h>
21#include <linux/regmap.h>
22#include <linux/slab.h>
23
24static struct mfd_cell max8907_cells[] = {
25 { .name = "max8907-regulator", },
26 { .name = "max8907-rtc", },
27};
28
29static bool max8907_gen_is_volatile_reg(struct device *dev, unsigned int reg)
30{
31 switch (reg) {
32 case MAX8907_REG_ON_OFF_IRQ1:
33 case MAX8907_REG_ON_OFF_STAT:
34 case MAX8907_REG_ON_OFF_IRQ2:
35 case MAX8907_REG_CHG_IRQ1:
36 case MAX8907_REG_CHG_IRQ2:
37 case MAX8907_REG_CHG_STAT:
38 return true;
39 default:
40 return false;
41 }
42}
43
44static bool max8907_gen_is_precious_reg(struct device *dev, unsigned int reg)
45{
46 switch (reg) {
47 case MAX8907_REG_ON_OFF_IRQ1:
48 case MAX8907_REG_ON_OFF_IRQ2:
49 case MAX8907_REG_CHG_IRQ1:
50 case MAX8907_REG_CHG_IRQ2:
51 return true;
52 default:
53 return false;
54 }
55}
56
57static bool max8907_gen_is_writeable_reg(struct device *dev, unsigned int reg)
58{
59 return !max8907_gen_is_volatile_reg(dev, reg);
60}
61
62static const struct regmap_config max8907_regmap_gen_config = {
63 .reg_bits = 8,
64 .val_bits = 8,
65 .volatile_reg = max8907_gen_is_volatile_reg,
66 .precious_reg = max8907_gen_is_precious_reg,
67 .writeable_reg = max8907_gen_is_writeable_reg,
68 .max_register = MAX8907_REG_LDO20VOUT,
69 .cache_type = REGCACHE_RBTREE,
70};
71
72static bool max8907_rtc_is_volatile_reg(struct device *dev, unsigned int reg)
73{
74 if (reg <= MAX8907_REG_RTC_YEAR2)
75 return true;
76
77 switch (reg) {
78 case MAX8907_REG_RTC_STATUS:
79 case MAX8907_REG_RTC_IRQ:
80 return true;
81 default:
82 return false;
83 }
84}
85
86static bool max8907_rtc_is_precious_reg(struct device *dev, unsigned int reg)
87{
88 switch (reg) {
89 case MAX8907_REG_RTC_IRQ:
90 return true;
91 default:
92 return false;
93 }
94}
95
96static bool max8907_rtc_is_writeable_reg(struct device *dev, unsigned int reg)
97{
98 switch (reg) {
99 case MAX8907_REG_RTC_STATUS:
100 case MAX8907_REG_RTC_IRQ:
101 return false;
102 default:
103 return true;
104 }
105}
106
107static const struct regmap_config max8907_regmap_rtc_config = {
108 .reg_bits = 8,
109 .val_bits = 8,
110 .volatile_reg = max8907_rtc_is_volatile_reg,
111 .precious_reg = max8907_rtc_is_precious_reg,
112 .writeable_reg = max8907_rtc_is_writeable_reg,
113 .max_register = MAX8907_REG_MPL_CNTL,
114 .cache_type = REGCACHE_RBTREE,
115};
116
117static const struct regmap_irq max8907_chg_irqs[] = {
118 { .reg_offset = 0, .mask = 1 << 0, },
119 { .reg_offset = 0, .mask = 1 << 1, },
120 { .reg_offset = 0, .mask = 1 << 2, },
121 { .reg_offset = 1, .mask = 1 << 0, },
122 { .reg_offset = 1, .mask = 1 << 1, },
123 { .reg_offset = 1, .mask = 1 << 2, },
124 { .reg_offset = 1, .mask = 1 << 3, },
125 { .reg_offset = 1, .mask = 1 << 4, },
126 { .reg_offset = 1, .mask = 1 << 5, },
127 { .reg_offset = 1, .mask = 1 << 6, },
128 { .reg_offset = 1, .mask = 1 << 7, },
129};
130
131static const struct regmap_irq_chip max8907_chg_irq_chip = {
132 .name = "max8907 chg",
133 .status_base = MAX8907_REG_CHG_IRQ1,
134 .mask_base = MAX8907_REG_CHG_IRQ1_MASK,
135 .wake_base = MAX8907_REG_CHG_IRQ1_MASK,
136 .irq_reg_stride = MAX8907_REG_CHG_IRQ2 - MAX8907_REG_CHG_IRQ1,
137 .num_regs = 2,
138 .irqs = max8907_chg_irqs,
139 .num_irqs = ARRAY_SIZE(max8907_chg_irqs),
140};
141
142static const struct regmap_irq max8907_on_off_irqs[] = {
143 { .reg_offset = 0, .mask = 1 << 0, },
144 { .reg_offset = 0, .mask = 1 << 1, },
145 { .reg_offset = 0, .mask = 1 << 2, },
146 { .reg_offset = 0, .mask = 1 << 3, },
147 { .reg_offset = 0, .mask = 1 << 4, },
148 { .reg_offset = 0, .mask = 1 << 5, },
149 { .reg_offset = 0, .mask = 1 << 6, },
150 { .reg_offset = 0, .mask = 1 << 7, },
151 { .reg_offset = 1, .mask = 1 << 0, },
152 { .reg_offset = 1, .mask = 1 << 1, },
153};
154
155static const struct regmap_irq_chip max8907_on_off_irq_chip = {
156 .name = "max8907 on_off",
157 .status_base = MAX8907_REG_ON_OFF_IRQ1,
158 .mask_base = MAX8907_REG_ON_OFF_IRQ1_MASK,
159 .irq_reg_stride = MAX8907_REG_ON_OFF_IRQ2 - MAX8907_REG_ON_OFF_IRQ1,
160 .num_regs = 2,
161 .irqs = max8907_on_off_irqs,
162 .num_irqs = ARRAY_SIZE(max8907_on_off_irqs),
163};
164
165static const struct regmap_irq max8907_rtc_irqs[] = {
166 { .reg_offset = 0, .mask = 1 << 2, },
167 { .reg_offset = 0, .mask = 1 << 3, },
168};
169
170static const struct regmap_irq_chip max8907_rtc_irq_chip = {
171 .name = "max8907 rtc",
172 .status_base = MAX8907_REG_RTC_IRQ,
173 .mask_base = MAX8907_REG_RTC_IRQ_MASK,
174 .num_regs = 1,
175 .irqs = max8907_rtc_irqs,
176 .num_irqs = ARRAY_SIZE(max8907_rtc_irqs),
177};
178
179static __devinit int max8907_i2c_probe(struct i2c_client *i2c,
180 const struct i2c_device_id *id)
181{
182 struct max8907 *max8907;
183 int ret;
184
185 max8907 = devm_kzalloc(&i2c->dev, sizeof(struct max8907), GFP_KERNEL);
186 if (!max8907) {
187 ret = -ENOMEM;
188 goto err_alloc_drvdata;
189 }
190
191 max8907->dev = &i2c->dev;
192 dev_set_drvdata(max8907->dev, max8907);
193
194 max8907->i2c_gen = i2c;
195 i2c_set_clientdata(i2c, max8907);
196 max8907->regmap_gen = devm_regmap_init_i2c(i2c,
197 &max8907_regmap_gen_config);
198 if (IS_ERR(max8907->regmap_gen)) {
199 ret = PTR_ERR(max8907->regmap_gen);
200 dev_err(&i2c->dev, "gen regmap init failed: %d\n", ret);
201 goto err_regmap_gen;
202 }
203
204 max8907->i2c_rtc = i2c_new_dummy(i2c->adapter, MAX8907_RTC_I2C_ADDR);
205 if (!max8907->i2c_rtc) {
206 ret = -ENOMEM;
207 goto err_dummy_rtc;
208 }
209 i2c_set_clientdata(max8907->i2c_rtc, max8907);
210 max8907->regmap_rtc = devm_regmap_init_i2c(max8907->i2c_rtc,
211 &max8907_regmap_rtc_config);
212 if (IS_ERR(max8907->regmap_rtc)) {
213 ret = PTR_ERR(max8907->regmap_rtc);
214 dev_err(&i2c->dev, "rtc regmap init failed: %d\n", ret);
215 goto err_regmap_rtc;
216 }
217
218 irq_set_status_flags(max8907->i2c_gen->irq, IRQ_NOAUTOEN);
219
220 ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq,
221 IRQF_ONESHOT | IRQF_SHARED, -1,
222 &max8907_chg_irq_chip,
223 &max8907->irqc_chg);
224 if (ret != 0) {
225 dev_err(&i2c->dev, "failed to add chg irq chip: %d\n", ret);
226 goto err_irqc_chg;
227 }
228 ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq,
229 IRQF_ONESHOT | IRQF_SHARED, -1,
230 &max8907_on_off_irq_chip,
231 &max8907->irqc_on_off);
232 if (ret != 0) {
233 dev_err(&i2c->dev, "failed to add on off irq chip: %d\n", ret);
234 goto err_irqc_on_off;
235 }
236 ret = regmap_add_irq_chip(max8907->regmap_rtc, max8907->i2c_gen->irq,
237 IRQF_ONESHOT | IRQF_SHARED, -1,
238 &max8907_rtc_irq_chip,
239 &max8907->irqc_rtc);
240 if (ret != 0) {
241 dev_err(&i2c->dev, "failed to add rtc irq chip: %d\n", ret);
242 goto err_irqc_rtc;
243 }
244
245 enable_irq(max8907->i2c_gen->irq);
246
247 ret = mfd_add_devices(max8907->dev, -1, max8907_cells,
248 ARRAY_SIZE(max8907_cells), NULL, 0, NULL);
249 if (ret != 0) {
250 dev_err(&i2c->dev, "failed to add MFD devices %d\n", ret);
251 goto err_add_devices;
252 }
253
254 return 0;
255
256err_add_devices:
257 regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc);
258err_irqc_rtc:
259 regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off);
260err_irqc_on_off:
261 regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg);
262err_irqc_chg:
263err_regmap_rtc:
264 i2c_unregister_device(max8907->i2c_rtc);
265err_dummy_rtc:
266err_regmap_gen:
267err_alloc_drvdata:
268 return ret;
269}
270
271static __devexit int max8907_i2c_remove(struct i2c_client *i2c)
272{
273 struct max8907 *max8907 = i2c_get_clientdata(i2c);
274
275 mfd_remove_devices(max8907->dev);
276
277 regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc);
278 regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off);
279 regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg);
280
281 i2c_unregister_device(max8907->i2c_rtc);
282
283 return 0;
284}
285
286#ifdef CONFIG_OF
287static struct of_device_id max8907_of_match[] = {
288 { .compatible = "maxim,max8907" },
289 { },
290};
291MODULE_DEVICE_TABLE(of, max8907_of_match);
292#endif
293
294static const struct i2c_device_id max8907_i2c_id[] = {
295 {"max8907", 0},
296 {}
297};
298MODULE_DEVICE_TABLE(i2c, max8907_i2c_id);
299
300static struct i2c_driver max8907_i2c_driver = {
301 .driver = {
302 .name = "max8907",
303 .owner = THIS_MODULE,
304 .of_match_table = of_match_ptr(max8907_of_match),
305 },
306 .probe = max8907_i2c_probe,
307 .remove = max8907_i2c_remove,
308 .id_table = max8907_i2c_id,
309};
310
311static int __init max8907_i2c_init(void)
312{
313 int ret = -ENODEV;
314
315 ret = i2c_add_driver(&max8907_i2c_driver);
316 if (ret != 0)
317 pr_err("Failed to register I2C driver: %d\n", ret);
318
319 return ret;
320}
321subsys_initcall(max8907_i2c_init);
322
323static void __exit max8907_i2c_exit(void)
324{
325 i2c_del_driver(&max8907_i2c_driver);
326}
327module_exit(max8907_i2c_exit);
328
329MODULE_DESCRIPTION("MAX8907 multi-function core driver");
330MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
331MODULE_LICENSE("GPL v2");