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 const 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
248const struct 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 const struct mfd_cell da9055_devs[] = {
298 {
299 .of_compatible = "dlg,da9055-gpio",
300 .name = "da9055-gpio",
301 },
302 {
303 .of_compatible = "dlg,da9055-regulator",
304 .name = "da9055-regulator",
305 .id = 1,
306 },
307 {
308 .of_compatible = "dlg,da9055-regulator",
309 .name = "da9055-regulator",
310 .id = 2,
311 },
312 {
313 .of_compatible = "dlg,da9055-regulator",
314 .name = "da9055-regulator",
315 .id = 3,
316 },
317 {
318 .of_compatible = "dlg,da9055-regulator",
319 .name = "da9055-regulator",
320 .id = 4,
321 },
322 {
323 .of_compatible = "dlg,da9055-regulator",
324 .name = "da9055-regulator",
325 .id = 5,
326 },
327 {
328 .of_compatible = "dlg,da9055-regulator",
329 .name = "da9055-regulator",
330 .id = 6,
331 },
332 {
333 .of_compatible = "dlg,da9055-regulator",
334 .name = "da9055-regulator",
335 .id = 7,
336 .resources = &da9055_ld05_6_resource,
337 .num_resources = 1,
338 },
339 {
340 .of_compatible = "dlg,da9055-regulator",
341 .name = "da9055-regulator",
342 .resources = &da9055_ld05_6_resource,
343 .num_resources = 1,
344 .id = 8,
345 },
346 {
347 .of_compatible = "dlg,da9055-onkey",
348 .name = "da9055-onkey",
349 .resources = &da9055_onkey_resource,
350 .num_resources = 1,
351 },
352 {
353 .of_compatible = "dlg,da9055-rtc",
354 .name = "da9055-rtc",
355 .resources = da9055_rtc_resource,
356 .num_resources = ARRAY_SIZE(da9055_rtc_resource),
357 },
358 {
359 .of_compatible = "dlg,da9055-hwmon",
360 .name = "da9055-hwmon",
361 .resources = &da9055_hwmon_resource,
362 .num_resources = 1,
363 },
364 {
365 .of_compatible = "dlg,da9055-watchdog",
366 .name = "da9055-watchdog",
367 },
368};
369
370static const 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 da9055_device_init(struct da9055 *da9055)
381{
382 struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
383 int ret;
384 uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF};
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
394 ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events);
395 if (ret < 0)
396 return ret;
397
398 ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
399 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
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
415err:
416 mfd_remove_devices(da9055->dev);
417 return ret;
418}
419
420void da9055_device_exit(struct da9055 *da9055)
421{
422 regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);
423 mfd_remove_devices(da9055->dev);
424}
425
426MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
427MODULE_LICENSE("GPL");
428MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
429