aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorAshish Jangam <ashish.jangam@kpitcummins.com>2012-09-14 09:24:50 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-09-28 19:25:28 -0400
commit2896434cf272acace1b7093d5e4ba8022ed11ac8 (patch)
treee81902cfebd1fa1cc7096206b88e4a7bacffa3e0 /drivers/mfd
parent5863eabb2a317ef499d340aa7201233a4fc9211e (diff)
mfd: DA9055 core driver
This is the DA9055 MFD core driver that instantiate all the dependent component drivers and provides them the device access via I2C. This patch is functionally tested on Samsung SMDK6410. Signed-off-by: David Dajun Chen <dchen@diasemi.com> Signed-off-by: Ashish Jangam <ashish.jangam@kpitcummins.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig17
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/da9055-core.c423
-rw-r--r--drivers/mfd/da9055-i2c.c93
4 files changed, 536 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 84d6ea2d74f4..6bfa2a1ec9df 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -430,6 +430,23 @@ config MFD_DA9052_I2C
430 for accessing the device, additional drivers must be enabled in 430 for accessing the device, additional drivers must be enabled in
431 order to use the functionality of the device. 431 order to use the functionality of the device.
432 432
433config MFD_DA9055
434 bool "Dialog Semiconductor DA9055 PMIC Support"
435 select REGMAP_I2C
436 select REGMAP_IRQ
437 select PMIC_DA9055
438 select MFD_CORE
439 depends on I2C=y
440 help
441 Say yes here for support of Dialog Semiconductor DA9055. This is
442 a Power Management IC. This driver provides common support for
443 accessing the device as well as the I2C interface to the chip itself.
444 Additional drivers must be enabled in order to use the functionality
445 of the device.
446
447 This driver can be built as a module. If built as a module it will be
448 called "da9055"
449
433config PMIC_ADP5520 450config PMIC_ADP5520
434 bool "Analog Devices ADP5520/01 MFD PMIC Core Support" 451 bool "Analog Devices ADP5520/01 MFD PMIC Core Support"
435 depends on I2C=y 452 depends on I2C=y
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 083acf97af26..33c0e49f7e60 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -91,6 +91,9 @@ obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
91 91
92obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o 92obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o
93 93
94da9055-objs := da9055-core.o da9055-i2c.o
95obj-$(CONFIG_MFD_DA9055) += da9055.o
96
94obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o 97obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o
95obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o 98obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o
96obj-$(CONFIG_MFD_MAX8907) += max8907.o 99obj-$(CONFIG_MFD_MAX8907) += max8907.o
diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c
new file mode 100644
index 000000000000..ff6c77f392bd
--- /dev/null
+++ b/drivers/mfd/da9055-core.c
@@ -0,0 +1,423 @@
1/*
2 * Device access for Dialog DA9055 PMICs.
3 *
4 * Copyright(c) 2012 Dialog Semiconductor Ltd.
5 *
6 * Author: David Dajun Chen <dchen@diasemi.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/input.h>
17#include <linux/irq.h>
18#include <linux/mutex.h>
19
20#include <linux/mfd/core.h>
21#include <linux/mfd/da9055/core.h>
22#include <linux/mfd/da9055/pdata.h>
23#include <linux/mfd/da9055/reg.h>
24
25#define DA9055_IRQ_NONKEY_MASK 0x01
26#define DA9055_IRQ_ALM_MASK 0x02
27#define DA9055_IRQ_TICK_MASK 0x04
28#define DA9055_IRQ_ADC_MASK 0x08
29#define DA9055_IRQ_BUCK_ILIM_MASK 0x08
30
31static bool da9055_register_readable(struct device *dev, unsigned int reg)
32{
33 switch (reg) {
34 case DA9055_REG_STATUS_A:
35 case DA9055_REG_STATUS_B:
36 case DA9055_REG_EVENT_A:
37 case DA9055_REG_EVENT_B:
38 case DA9055_REG_EVENT_C:
39 case DA9055_REG_IRQ_MASK_A:
40 case DA9055_REG_IRQ_MASK_B:
41 case DA9055_REG_IRQ_MASK_C:
42
43 case DA9055_REG_CONTROL_A:
44 case DA9055_REG_CONTROL_B:
45 case DA9055_REG_CONTROL_C:
46 case DA9055_REG_CONTROL_D:
47 case DA9055_REG_CONTROL_E:
48
49 case DA9055_REG_ADC_MAN:
50 case DA9055_REG_ADC_CONT:
51 case DA9055_REG_VSYS_MON:
52 case DA9055_REG_ADC_RES_L:
53 case DA9055_REG_ADC_RES_H:
54 case DA9055_REG_VSYS_RES:
55 case DA9055_REG_ADCIN1_RES:
56 case DA9055_REG_ADCIN2_RES:
57 case DA9055_REG_ADCIN3_RES:
58
59 case DA9055_REG_COUNT_S:
60 case DA9055_REG_COUNT_MI:
61 case DA9055_REG_COUNT_H:
62 case DA9055_REG_COUNT_D:
63 case DA9055_REG_COUNT_MO:
64 case DA9055_REG_COUNT_Y:
65 case DA9055_REG_ALARM_H:
66 case DA9055_REG_ALARM_D:
67 case DA9055_REG_ALARM_MI:
68 case DA9055_REG_ALARM_MO:
69 case DA9055_REG_ALARM_Y:
70
71 case DA9055_REG_GPIO0_1:
72 case DA9055_REG_GPIO2:
73 case DA9055_REG_GPIO_MODE0_2:
74
75 case DA9055_REG_BCORE_CONT:
76 case DA9055_REG_BMEM_CONT:
77 case DA9055_REG_LDO1_CONT:
78 case DA9055_REG_LDO2_CONT:
79 case DA9055_REG_LDO3_CONT:
80 case DA9055_REG_LDO4_CONT:
81 case DA9055_REG_LDO5_CONT:
82 case DA9055_REG_LDO6_CONT:
83 case DA9055_REG_BUCK_LIM:
84 case DA9055_REG_BCORE_MODE:
85 case DA9055_REG_VBCORE_A:
86 case DA9055_REG_VBMEM_A:
87 case DA9055_REG_VLDO1_A:
88 case DA9055_REG_VLDO2_A:
89 case DA9055_REG_VLDO3_A:
90 case DA9055_REG_VLDO4_A:
91 case DA9055_REG_VLDO5_A:
92 case DA9055_REG_VLDO6_A:
93 case DA9055_REG_VBCORE_B:
94 case DA9055_REG_VBMEM_B:
95 case DA9055_REG_VLDO1_B:
96 case DA9055_REG_VLDO2_B:
97 case DA9055_REG_VLDO3_B:
98 case DA9055_REG_VLDO4_B:
99 case DA9055_REG_VLDO5_B:
100 case DA9055_REG_VLDO6_B:
101 return true;
102 default:
103 return false;
104 }
105}
106
107static bool da9055_register_writeable(struct device *dev, unsigned int reg)
108{
109 switch (reg) {
110 case DA9055_REG_STATUS_A:
111 case DA9055_REG_STATUS_B:
112 case DA9055_REG_EVENT_A:
113 case DA9055_REG_EVENT_B:
114 case DA9055_REG_EVENT_C:
115 case DA9055_REG_IRQ_MASK_A:
116 case DA9055_REG_IRQ_MASK_B:
117 case DA9055_REG_IRQ_MASK_C:
118
119 case DA9055_REG_CONTROL_A:
120 case DA9055_REG_CONTROL_B:
121 case DA9055_REG_CONTROL_C:
122 case DA9055_REG_CONTROL_D:
123 case DA9055_REG_CONTROL_E:
124
125 case DA9055_REG_ADC_MAN:
126 case DA9055_REG_ADC_CONT:
127 case DA9055_REG_VSYS_MON:
128 case DA9055_REG_ADC_RES_L:
129 case DA9055_REG_ADC_RES_H:
130 case DA9055_REG_VSYS_RES:
131 case DA9055_REG_ADCIN1_RES:
132 case DA9055_REG_ADCIN2_RES:
133 case DA9055_REG_ADCIN3_RES:
134
135 case DA9055_REG_COUNT_S:
136 case DA9055_REG_COUNT_MI:
137 case DA9055_REG_COUNT_H:
138 case DA9055_REG_COUNT_D:
139 case DA9055_REG_COUNT_MO:
140 case DA9055_REG_COUNT_Y:
141 case DA9055_REG_ALARM_H:
142 case DA9055_REG_ALARM_D:
143 case DA9055_REG_ALARM_MI:
144 case DA9055_REG_ALARM_MO:
145 case DA9055_REG_ALARM_Y:
146
147 case DA9055_REG_GPIO0_1:
148 case DA9055_REG_GPIO2:
149 case DA9055_REG_GPIO_MODE0_2:
150
151 case DA9055_REG_BCORE_CONT:
152 case DA9055_REG_BMEM_CONT:
153 case DA9055_REG_LDO1_CONT:
154 case DA9055_REG_LDO2_CONT:
155 case DA9055_REG_LDO3_CONT:
156 case DA9055_REG_LDO4_CONT:
157 case DA9055_REG_LDO5_CONT:
158 case DA9055_REG_LDO6_CONT:
159 case DA9055_REG_BUCK_LIM:
160 case DA9055_REG_BCORE_MODE:
161 case DA9055_REG_VBCORE_A:
162 case DA9055_REG_VBMEM_A:
163 case DA9055_REG_VLDO1_A:
164 case DA9055_REG_VLDO2_A:
165 case DA9055_REG_VLDO3_A:
166 case DA9055_REG_VLDO4_A:
167 case DA9055_REG_VLDO5_A:
168 case DA9055_REG_VLDO6_A:
169 case DA9055_REG_VBCORE_B:
170 case DA9055_REG_VBMEM_B:
171 case DA9055_REG_VLDO1_B:
172 case DA9055_REG_VLDO2_B:
173 case DA9055_REG_VLDO3_B:
174 case DA9055_REG_VLDO4_B:
175 case DA9055_REG_VLDO5_B:
176 case DA9055_REG_VLDO6_B:
177 return true;
178 default:
179 return false;
180 }
181}
182
183static bool da9055_register_volatile(struct device *dev, unsigned int reg)
184{
185 switch (reg) {
186 case DA9055_REG_STATUS_A:
187 case DA9055_REG_STATUS_B:
188 case DA9055_REG_EVENT_A:
189 case DA9055_REG_EVENT_B:
190 case DA9055_REG_EVENT_C:
191
192 case DA9055_REG_CONTROL_A:
193 case DA9055_REG_CONTROL_E:
194
195 case DA9055_REG_ADC_MAN:
196 case DA9055_REG_ADC_RES_L:
197 case DA9055_REG_ADC_RES_H:
198 case DA9055_REG_VSYS_RES:
199 case DA9055_REG_ADCIN1_RES:
200 case DA9055_REG_ADCIN2_RES:
201 case DA9055_REG_ADCIN3_RES:
202
203 case DA9055_REG_COUNT_S:
204 case DA9055_REG_COUNT_MI:
205 case DA9055_REG_COUNT_H:
206 case DA9055_REG_COUNT_D:
207 case DA9055_REG_COUNT_MO:
208 case DA9055_REG_COUNT_Y:
209 case DA9055_REG_ALARM_MI:
210
211 case DA9055_REG_BCORE_CONT:
212 case DA9055_REG_BMEM_CONT:
213 case DA9055_REG_LDO1_CONT:
214 case DA9055_REG_LDO2_CONT:
215 case DA9055_REG_LDO3_CONT:
216 case DA9055_REG_LDO4_CONT:
217 case DA9055_REG_LDO5_CONT:
218 case DA9055_REG_LDO6_CONT:
219 return true;
220 default:
221 return false;
222 }
223}
224
225static struct regmap_irq da9055_irqs[] = {
226 [DA9055_IRQ_NONKEY] = {
227 .reg_offset = 0,
228 .mask = DA9055_IRQ_NONKEY_MASK,
229 },
230 [DA9055_IRQ_ALARM] = {
231 .reg_offset = 0,
232 .mask = DA9055_IRQ_ALM_MASK,
233 },
234 [DA9055_IRQ_TICK] = {
235 .reg_offset = 0,
236 .mask = DA9055_IRQ_TICK_MASK,
237 },
238 [DA9055_IRQ_HWMON] = {
239 .reg_offset = 0,
240 .mask = DA9055_IRQ_ADC_MASK,
241 },
242 [DA9055_IRQ_REGULATOR] = {
243 .reg_offset = 1,
244 .mask = DA9055_IRQ_BUCK_ILIM_MASK,
245 },
246};
247
248struct regmap_config da9055_regmap_config = {
249 .reg_bits = 8,
250 .val_bits = 8,
251
252 .cache_type = REGCACHE_RBTREE,
253
254 .max_register = DA9055_MAX_REGISTER_CNT,
255 .readable_reg = da9055_register_readable,
256 .writeable_reg = da9055_register_writeable,
257 .volatile_reg = da9055_register_volatile,
258};
259EXPORT_SYMBOL_GPL(da9055_regmap_config);
260
261static struct resource da9055_onkey_resource = {
262 .name = "ONKEY",
263 .start = DA9055_IRQ_NONKEY,
264 .end = DA9055_IRQ_NONKEY,
265 .flags = IORESOURCE_IRQ,
266};
267
268static struct resource da9055_rtc_resource[] = {
269 {
270 .name = "ALM",
271 .start = DA9055_IRQ_ALARM,
272 .end = DA9055_IRQ_ALARM,
273 .flags = IORESOURCE_IRQ,
274 },
275 {
276 .name = "TICK",
277 .start = DA9055_IRQ_TICK,
278 .end = DA9055_IRQ_TICK,
279 .flags = IORESOURCE_IRQ,
280 },
281};
282
283static struct resource da9055_hwmon_resource = {
284 .name = "HWMON",
285 .start = DA9055_IRQ_HWMON,
286 .end = DA9055_IRQ_HWMON,
287 .flags = IORESOURCE_IRQ,
288};
289
290static struct resource da9055_ld05_6_resource = {
291 .name = "REGULATOR",
292 .start = DA9055_IRQ_REGULATOR,
293 .end = DA9055_IRQ_REGULATOR,
294 .flags = IORESOURCE_IRQ,
295};
296
297static struct mfd_cell da9055_devs[] = {
298 {
299 .of_compatible = "dialog,da9055-gpio",
300 .name = "da9055-gpio",
301 },
302 {
303 .of_compatible = "dialog,da9055-regulator",
304 .name = "da9055-regulator",
305 .id = 1,
306 },
307 {
308 .of_compatible = "dialog,da9055-regulator",
309 .name = "da9055-regulator",
310 .id = 2,
311 },
312 {
313 .of_compatible = "dialog,da9055-regulator",
314 .name = "da9055-regulator",
315 .id = 3,
316 },
317 {
318 .of_compatible = "dialog,da9055-regulator",
319 .name = "da9055-regulator",
320 .id = 4,
321 },
322 {
323 .of_compatible = "dialog,da9055-regulator",
324 .name = "da9055-regulator",
325 .id = 5,
326 },
327 {
328 .of_compatible = "dialog,da9055-regulator",
329 .name = "da9055-regulator",
330 .id = 6,
331 },
332 {
333 .of_compatible = "dialog,da9055-regulator",
334 .name = "da9055-regulator",
335 .id = 7,
336 .resources = &da9055_ld05_6_resource,
337 .num_resources = 1,
338 },
339 {
340 .of_compatible = "dialog,da9055-regulator",
341 .name = "da9055-regulator",
342 .resources = &da9055_ld05_6_resource,
343 .num_resources = 1,
344 .id = 8,
345 },
346 {
347 .of_compatible = "dialog,da9055-onkey",
348 .name = "da9055-onkey",
349 .resources = &da9055_onkey_resource,
350 .num_resources = 1,
351 },
352 {
353 .of_compatible = "dialog,da9055-rtc",
354 .name = "da9055-rtc",
355 .resources = da9055_rtc_resource,
356 .num_resources = ARRAY_SIZE(da9055_rtc_resource),
357 },
358 {
359 .of_compatible = "dialog,da9055-hwmon",
360 .name = "da9055-hwmon",
361 .resources = &da9055_hwmon_resource,
362 .num_resources = 1,
363 },
364 {
365 .of_compatible = "dialog,da9055-watchdog",
366 .name = "da9055-watchdog",
367 },
368};
369
370static struct regmap_irq_chip da9055_regmap_irq_chip = {
371 .name = "da9055_irq",
372 .status_base = DA9055_REG_EVENT_A,
373 .mask_base = DA9055_REG_IRQ_MASK_A,
374 .ack_base = DA9055_REG_EVENT_A,
375 .num_regs = 3,
376 .irqs = da9055_irqs,
377 .num_irqs = ARRAY_SIZE(da9055_irqs),
378};
379
380int __devinit da9055_device_init(struct da9055 *da9055)
381{
382 struct da9055_pdata *pdata = da9055->dev->platform_data;
383 int ret;
384
385 if (pdata && pdata->init != NULL)
386 pdata->init(da9055);
387
388 if (!pdata || !pdata->irq_base)
389 da9055->irq_base = -1;
390 else
391 da9055->irq_base = pdata->irq_base;
392
393 ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
394 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
395 da9055->irq_base, &da9055_regmap_irq_chip,
396 &da9055->irq_data);
397 if (ret < 0)
398 return ret;
399
400 da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data);
401
402 ret = mfd_add_devices(da9055->dev, -1,
403 da9055_devs, ARRAY_SIZE(da9055_devs),
404 NULL, da9055->irq_base, NULL);
405 if (ret)
406 goto err;
407
408 return 0;
409
410err:
411 mfd_remove_devices(da9055->dev);
412 return ret;
413}
414
415void __devexit da9055_device_exit(struct da9055 *da9055)
416{
417 regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);
418 mfd_remove_devices(da9055->dev);
419}
420
421MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
422MODULE_LICENSE("GPL");
423MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c
new file mode 100644
index 000000000000..88f6dca53bac
--- /dev/null
+++ b/drivers/mfd/da9055-i2c.c
@@ -0,0 +1,93 @@
1 /* I2C access for DA9055 PMICs.
2 *
3 * Copyright(c) 2012 Dialog Semiconductor Ltd.
4 *
5 * Author: David Dajun Chen <dchen@diasemi.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 */
13
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/i2c.h>
17#include <linux/err.h>
18
19#include <linux/mfd/da9055/core.h>
20
21static int __devinit da9055_i2c_probe(struct i2c_client *i2c,
22 const struct i2c_device_id *id)
23{
24 struct da9055 *da9055;
25 int ret;
26
27 da9055 = devm_kzalloc(&i2c->dev, sizeof(struct da9055), GFP_KERNEL);
28 if (!da9055)
29 return -ENOMEM;
30
31 da9055->regmap = devm_regmap_init_i2c(i2c, &da9055_regmap_config);
32 if (IS_ERR(da9055->regmap)) {
33 ret = PTR_ERR(da9055->regmap);
34 dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
35 ret);
36 return ret;
37 }
38
39 da9055->dev = &i2c->dev;
40 da9055->chip_irq = i2c->irq;
41
42 i2c_set_clientdata(i2c, da9055);
43
44 return da9055_device_init(da9055);
45}
46
47static int __devexit da9055_i2c_remove(struct i2c_client *i2c)
48{
49 struct da9055 *da9055 = i2c_get_clientdata(i2c);
50
51 da9055_device_exit(da9055);
52
53 return 0;
54}
55
56static struct i2c_device_id da9055_i2c_id[] = {
57 {"da9055-pmic", 0},
58 { }
59};
60
61static struct i2c_driver da9055_i2c_driver = {
62 .probe = da9055_i2c_probe,
63 .remove = __devexit_p(da9055_i2c_remove),
64 .id_table = da9055_i2c_id,
65 .driver = {
66 .name = "da9055",
67 .owner = THIS_MODULE,
68 },
69};
70
71static int __init da9055_i2c_init(void)
72{
73 int ret;
74
75 ret = i2c_add_driver(&da9055_i2c_driver);
76 if (ret != 0) {
77 pr_err("DA9055 I2C registration failed %d\n", ret);
78 return ret;
79 }
80
81 return 0;
82}
83subsys_initcall(da9055_i2c_init);
84
85static void __exit da9055_i2c_exit(void)
86{
87 i2c_del_driver(&da9055_i2c_driver);
88}
89module_exit(da9055_i2c_exit);
90
91MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
92MODULE_DESCRIPTION("I2C driver for Dialog DA9055 PMIC");
93MODULE_LICENSE("GPL");