]>
Commit | Line | Data |
---|---|---|
2896434c AJ |
1 | /* |
2 | * Device access for Dialog DA9055 PMICs. | |
3 | * | |
4 | * Copyright(c) 2012 Dialog Semiconductor Ltd. | |
5 | * | |
6 | * Author: David Dajun Chen <[email protected]> | |
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 | ||
31 | static 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 | ||
107 | static 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 | ||
183 | static 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 | ||
7ce7b26f | 225 | static const struct regmap_irq da9055_irqs[] = { |
2896434c AJ |
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 | ||
7ce7b26f | 248 | const struct regmap_config da9055_regmap_config = { |
2896434c AJ |
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 | }; | |
259 | EXPORT_SYMBOL_GPL(da9055_regmap_config); | |
260 | ||
261 | static struct resource da9055_onkey_resource = { | |
262 | .name = "ONKEY", | |
263 | .start = DA9055_IRQ_NONKEY, | |
264 | .end = DA9055_IRQ_NONKEY, | |
265 | .flags = IORESOURCE_IRQ, | |
266 | }; | |
267 | ||
268 | static 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 | ||
283 | static struct resource da9055_hwmon_resource = { | |
284 | .name = "HWMON", | |
285 | .start = DA9055_IRQ_HWMON, | |
286 | .end = DA9055_IRQ_HWMON, | |
287 | .flags = IORESOURCE_IRQ, | |
288 | }; | |
289 | ||
290 | static 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 | ||
c8f675ff | 297 | static const struct mfd_cell da9055_devs[] = { |
2896434c | 298 | { |
bd597f47 | 299 | .of_compatible = "dlg,da9055-gpio", |
2896434c AJ |
300 | .name = "da9055-gpio", |
301 | }, | |
302 | { | |
bd597f47 | 303 | .of_compatible = "dlg,da9055-regulator", |
2896434c AJ |
304 | .name = "da9055-regulator", |
305 | .id = 1, | |
306 | }, | |
307 | { | |
bd597f47 | 308 | .of_compatible = "dlg,da9055-regulator", |
2896434c AJ |
309 | .name = "da9055-regulator", |
310 | .id = 2, | |
311 | }, | |
312 | { | |
bd597f47 | 313 | .of_compatible = "dlg,da9055-regulator", |
2896434c AJ |
314 | .name = "da9055-regulator", |
315 | .id = 3, | |
316 | }, | |
317 | { | |
bd597f47 | 318 | .of_compatible = "dlg,da9055-regulator", |
2896434c AJ |
319 | .name = "da9055-regulator", |
320 | .id = 4, | |
321 | }, | |
322 | { | |
bd597f47 | 323 | .of_compatible = "dlg,da9055-regulator", |
2896434c AJ |
324 | .name = "da9055-regulator", |
325 | .id = 5, | |
326 | }, | |
327 | { | |
bd597f47 | 328 | .of_compatible = "dlg,da9055-regulator", |
2896434c AJ |
329 | .name = "da9055-regulator", |
330 | .id = 6, | |
331 | }, | |
332 | { | |
bd597f47 | 333 | .of_compatible = "dlg,da9055-regulator", |
2896434c AJ |
334 | .name = "da9055-regulator", |
335 | .id = 7, | |
336 | .resources = &da9055_ld05_6_resource, | |
337 | .num_resources = 1, | |
338 | }, | |
339 | { | |
bd597f47 | 340 | .of_compatible = "dlg,da9055-regulator", |
2896434c AJ |
341 | .name = "da9055-regulator", |
342 | .resources = &da9055_ld05_6_resource, | |
343 | .num_resources = 1, | |
344 | .id = 8, | |
345 | }, | |
346 | { | |
bd597f47 | 347 | .of_compatible = "dlg,da9055-onkey", |
2896434c AJ |
348 | .name = "da9055-onkey", |
349 | .resources = &da9055_onkey_resource, | |
350 | .num_resources = 1, | |
351 | }, | |
352 | { | |
bd597f47 | 353 | .of_compatible = "dlg,da9055-rtc", |
2896434c AJ |
354 | .name = "da9055-rtc", |
355 | .resources = da9055_rtc_resource, | |
356 | .num_resources = ARRAY_SIZE(da9055_rtc_resource), | |
357 | }, | |
358 | { | |
bd597f47 | 359 | .of_compatible = "dlg,da9055-hwmon", |
2896434c AJ |
360 | .name = "da9055-hwmon", |
361 | .resources = &da9055_hwmon_resource, | |
362 | .num_resources = 1, | |
363 | }, | |
364 | { | |
bd597f47 | 365 | .of_compatible = "dlg,da9055-watchdog", |
2896434c AJ |
366 | .name = "da9055-watchdog", |
367 | }, | |
368 | }; | |
369 | ||
7ce7b26f | 370 | static const struct regmap_irq_chip da9055_regmap_irq_chip = { |
2896434c AJ |
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 | ||
f791be49 | 380 | int da9055_device_init(struct da9055 *da9055) |
2896434c | 381 | { |
334a41ce | 382 | struct da9055_pdata *pdata = dev_get_platdata(da9055->dev); |
2896434c | 383 | int ret; |
4b3b4a50 | 384 | uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF}; |
2896434c AJ |
385 | |
386 | if (pdata && pdata->init != NULL) | |
387 | pdata->init(da9055); | |
388 | ||
389 | if (!pdata || !pdata->irq_base) | |
390 | da9055->irq_base = -1; | |
391 | else | |
392 | da9055->irq_base = pdata->irq_base; | |
393 | ||
4b3b4a50 AR |
394 | ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events); |
395 | if (ret < 0) | |
396 | return ret; | |
397 | ||
2896434c | 398 | ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, |
3cec5f4e | 399 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
2896434c AJ |
400 | da9055->irq_base, &da9055_regmap_irq_chip, |
401 | &da9055->irq_data); | |
402 | if (ret < 0) | |
403 | return ret; | |
404 | ||
405 | da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data); | |
406 | ||
407 | ret = mfd_add_devices(da9055->dev, -1, | |
408 | da9055_devs, ARRAY_SIZE(da9055_devs), | |
409 | NULL, da9055->irq_base, NULL); | |
410 | if (ret) | |
411 | goto err; | |
412 | ||
413 | return 0; | |
414 | ||
415 | err: | |
416 | mfd_remove_devices(da9055->dev); | |
417 | return ret; | |
418 | } | |
419 | ||
4740f73f | 420 | void da9055_device_exit(struct da9055 *da9055) |
2896434c AJ |
421 | { |
422 | regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data); | |
423 | mfd_remove_devices(da9055->dev); | |
424 | } | |
425 | ||
426 | MODULE_DESCRIPTION("Core support for the DA9055 PMIC"); | |
427 | MODULE_LICENSE("GPL"); | |
428 | MODULE_AUTHOR("David Dajun Chen <[email protected]>"); |