1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Device access for Dialog DA9055 PMICs.
4 *
5 * Copyright(c) 2012 Dialog Semiconductor Ltd.
6 *
7 * Author: David Dajun Chen <dchen@diasemi.com>
8 */
9
10 #include <linux/module.h>
11 #include <linux/device.h>
12 #include <linux/input.h>
13 #include <linux/irq.h>
14 #include <linux/mutex.h>
15
16 #include <linux/mfd/core.h>
17 #include <linux/mfd/da9055/core.h>
18 #include <linux/mfd/da9055/pdata.h>
19 #include <linux/mfd/da9055/reg.h>
20
21 #define DA9055_IRQ_NONKEY_MASK 0x01
22 #define DA9055_IRQ_ALM_MASK 0x02
23 #define DA9055_IRQ_TICK_MASK 0x04
24 #define DA9055_IRQ_ADC_MASK 0x08
25 #define DA9055_IRQ_BUCK_ILIM_MASK 0x08
26
da9055_register_readable(struct device * dev,unsigned int reg)27 static bool da9055_register_readable(struct device *dev, unsigned int reg)
28 {
29 switch (reg) {
30 case DA9055_REG_STATUS_A:
31 case DA9055_REG_STATUS_B:
32 case DA9055_REG_EVENT_A:
33 case DA9055_REG_EVENT_B:
34 case DA9055_REG_EVENT_C:
35 case DA9055_REG_IRQ_MASK_A:
36 case DA9055_REG_IRQ_MASK_B:
37 case DA9055_REG_IRQ_MASK_C:
38
39 case DA9055_REG_CONTROL_A:
40 case DA9055_REG_CONTROL_B:
41 case DA9055_REG_CONTROL_C:
42 case DA9055_REG_CONTROL_D:
43 case DA9055_REG_CONTROL_E:
44
45 case DA9055_REG_ADC_MAN:
46 case DA9055_REG_ADC_CONT:
47 case DA9055_REG_VSYS_MON:
48 case DA9055_REG_ADC_RES_L:
49 case DA9055_REG_ADC_RES_H:
50 case DA9055_REG_VSYS_RES:
51 case DA9055_REG_ADCIN1_RES:
52 case DA9055_REG_ADCIN2_RES:
53 case DA9055_REG_ADCIN3_RES:
54
55 case DA9055_REG_COUNT_S:
56 case DA9055_REG_COUNT_MI:
57 case DA9055_REG_COUNT_H:
58 case DA9055_REG_COUNT_D:
59 case DA9055_REG_COUNT_MO:
60 case DA9055_REG_COUNT_Y:
61 case DA9055_REG_ALARM_H:
62 case DA9055_REG_ALARM_D:
63 case DA9055_REG_ALARM_MI:
64 case DA9055_REG_ALARM_MO:
65 case DA9055_REG_ALARM_Y:
66
67 case DA9055_REG_GPIO0_1:
68 case DA9055_REG_GPIO2:
69 case DA9055_REG_GPIO_MODE0_2:
70
71 case DA9055_REG_BCORE_CONT:
72 case DA9055_REG_BMEM_CONT:
73 case DA9055_REG_LDO1_CONT:
74 case DA9055_REG_LDO2_CONT:
75 case DA9055_REG_LDO3_CONT:
76 case DA9055_REG_LDO4_CONT:
77 case DA9055_REG_LDO5_CONT:
78 case DA9055_REG_LDO6_CONT:
79 case DA9055_REG_BUCK_LIM:
80 case DA9055_REG_BCORE_MODE:
81 case DA9055_REG_VBCORE_A:
82 case DA9055_REG_VBMEM_A:
83 case DA9055_REG_VLDO1_A:
84 case DA9055_REG_VLDO2_A:
85 case DA9055_REG_VLDO3_A:
86 case DA9055_REG_VLDO4_A:
87 case DA9055_REG_VLDO5_A:
88 case DA9055_REG_VLDO6_A:
89 case DA9055_REG_VBCORE_B:
90 case DA9055_REG_VBMEM_B:
91 case DA9055_REG_VLDO1_B:
92 case DA9055_REG_VLDO2_B:
93 case DA9055_REG_VLDO3_B:
94 case DA9055_REG_VLDO4_B:
95 case DA9055_REG_VLDO5_B:
96 case DA9055_REG_VLDO6_B:
97 return true;
98 default:
99 return false;
100 }
101 }
102
da9055_register_writeable(struct device * dev,unsigned int reg)103 static bool da9055_register_writeable(struct device *dev, unsigned int reg)
104 {
105 switch (reg) {
106 case DA9055_REG_STATUS_A:
107 case DA9055_REG_STATUS_B:
108 case DA9055_REG_EVENT_A:
109 case DA9055_REG_EVENT_B:
110 case DA9055_REG_EVENT_C:
111 case DA9055_REG_IRQ_MASK_A:
112 case DA9055_REG_IRQ_MASK_B:
113 case DA9055_REG_IRQ_MASK_C:
114
115 case DA9055_REG_CONTROL_A:
116 case DA9055_REG_CONTROL_B:
117 case DA9055_REG_CONTROL_C:
118 case DA9055_REG_CONTROL_D:
119 case DA9055_REG_CONTROL_E:
120
121 case DA9055_REG_ADC_MAN:
122 case DA9055_REG_ADC_CONT:
123 case DA9055_REG_VSYS_MON:
124 case DA9055_REG_ADC_RES_L:
125 case DA9055_REG_ADC_RES_H:
126 case DA9055_REG_VSYS_RES:
127 case DA9055_REG_ADCIN1_RES:
128 case DA9055_REG_ADCIN2_RES:
129 case DA9055_REG_ADCIN3_RES:
130
131 case DA9055_REG_COUNT_S:
132 case DA9055_REG_COUNT_MI:
133 case DA9055_REG_COUNT_H:
134 case DA9055_REG_COUNT_D:
135 case DA9055_REG_COUNT_MO:
136 case DA9055_REG_COUNT_Y:
137 case DA9055_REG_ALARM_H:
138 case DA9055_REG_ALARM_D:
139 case DA9055_REG_ALARM_MI:
140 case DA9055_REG_ALARM_MO:
141 case DA9055_REG_ALARM_Y:
142
143 case DA9055_REG_GPIO0_1:
144 case DA9055_REG_GPIO2:
145 case DA9055_REG_GPIO_MODE0_2:
146
147 case DA9055_REG_BCORE_CONT:
148 case DA9055_REG_BMEM_CONT:
149 case DA9055_REG_LDO1_CONT:
150 case DA9055_REG_LDO2_CONT:
151 case DA9055_REG_LDO3_CONT:
152 case DA9055_REG_LDO4_CONT:
153 case DA9055_REG_LDO5_CONT:
154 case DA9055_REG_LDO6_CONT:
155 case DA9055_REG_BUCK_LIM:
156 case DA9055_REG_BCORE_MODE:
157 case DA9055_REG_VBCORE_A:
158 case DA9055_REG_VBMEM_A:
159 case DA9055_REG_VLDO1_A:
160 case DA9055_REG_VLDO2_A:
161 case DA9055_REG_VLDO3_A:
162 case DA9055_REG_VLDO4_A:
163 case DA9055_REG_VLDO5_A:
164 case DA9055_REG_VLDO6_A:
165 case DA9055_REG_VBCORE_B:
166 case DA9055_REG_VBMEM_B:
167 case DA9055_REG_VLDO1_B:
168 case DA9055_REG_VLDO2_B:
169 case DA9055_REG_VLDO3_B:
170 case DA9055_REG_VLDO4_B:
171 case DA9055_REG_VLDO5_B:
172 case DA9055_REG_VLDO6_B:
173 return true;
174 default:
175 return false;
176 }
177 }
178
da9055_register_volatile(struct device * dev,unsigned int reg)179 static bool da9055_register_volatile(struct device *dev, unsigned int reg)
180 {
181 switch (reg) {
182 case DA9055_REG_STATUS_A:
183 case DA9055_REG_STATUS_B:
184 case DA9055_REG_EVENT_A:
185 case DA9055_REG_EVENT_B:
186 case DA9055_REG_EVENT_C:
187
188 case DA9055_REG_CONTROL_A:
189 case DA9055_REG_CONTROL_E:
190
191 case DA9055_REG_ADC_MAN:
192 case DA9055_REG_ADC_RES_L:
193 case DA9055_REG_ADC_RES_H:
194 case DA9055_REG_VSYS_RES:
195 case DA9055_REG_ADCIN1_RES:
196 case DA9055_REG_ADCIN2_RES:
197 case DA9055_REG_ADCIN3_RES:
198
199 case DA9055_REG_COUNT_S:
200 case DA9055_REG_COUNT_MI:
201 case DA9055_REG_COUNT_H:
202 case DA9055_REG_COUNT_D:
203 case DA9055_REG_COUNT_MO:
204 case DA9055_REG_COUNT_Y:
205 case DA9055_REG_ALARM_MI:
206
207 case DA9055_REG_BCORE_CONT:
208 case DA9055_REG_BMEM_CONT:
209 case DA9055_REG_LDO1_CONT:
210 case DA9055_REG_LDO2_CONT:
211 case DA9055_REG_LDO3_CONT:
212 case DA9055_REG_LDO4_CONT:
213 case DA9055_REG_LDO5_CONT:
214 case DA9055_REG_LDO6_CONT:
215 return true;
216 default:
217 return false;
218 }
219 }
220
221 static const struct regmap_irq da9055_irqs[] = {
222 [DA9055_IRQ_NONKEY] = {
223 .reg_offset = 0,
224 .mask = DA9055_IRQ_NONKEY_MASK,
225 },
226 [DA9055_IRQ_ALARM] = {
227 .reg_offset = 0,
228 .mask = DA9055_IRQ_ALM_MASK,
229 },
230 [DA9055_IRQ_TICK] = {
231 .reg_offset = 0,
232 .mask = DA9055_IRQ_TICK_MASK,
233 },
234 [DA9055_IRQ_HWMON] = {
235 .reg_offset = 0,
236 .mask = DA9055_IRQ_ADC_MASK,
237 },
238 [DA9055_IRQ_REGULATOR] = {
239 .reg_offset = 1,
240 .mask = DA9055_IRQ_BUCK_ILIM_MASK,
241 },
242 };
243
244 const struct regmap_config da9055_regmap_config = {
245 .reg_bits = 8,
246 .val_bits = 8,
247
248 .cache_type = REGCACHE_RBTREE,
249
250 .max_register = DA9055_MAX_REGISTER_CNT,
251 .readable_reg = da9055_register_readable,
252 .writeable_reg = da9055_register_writeable,
253 .volatile_reg = da9055_register_volatile,
254 };
255 EXPORT_SYMBOL_GPL(da9055_regmap_config);
256
257 static struct resource da9055_onkey_resource = {
258 .name = "ONKEY",
259 .start = DA9055_IRQ_NONKEY,
260 .end = DA9055_IRQ_NONKEY,
261 .flags = IORESOURCE_IRQ,
262 };
263
264 static struct resource da9055_rtc_resource[] = {
265 {
266 .name = "ALM",
267 .start = DA9055_IRQ_ALARM,
268 .end = DA9055_IRQ_ALARM,
269 .flags = IORESOURCE_IRQ,
270 },
271 {
272 .name = "TICK",
273 .start = DA9055_IRQ_TICK,
274 .end = DA9055_IRQ_TICK,
275 .flags = IORESOURCE_IRQ,
276 },
277 };
278
279 static struct resource da9055_hwmon_resource = {
280 .name = "HWMON",
281 .start = DA9055_IRQ_HWMON,
282 .end = DA9055_IRQ_HWMON,
283 .flags = IORESOURCE_IRQ,
284 };
285
286 static struct resource da9055_ld05_6_resource = {
287 .name = "REGULATOR",
288 .start = DA9055_IRQ_REGULATOR,
289 .end = DA9055_IRQ_REGULATOR,
290 .flags = IORESOURCE_IRQ,
291 };
292
293 static const struct mfd_cell da9055_devs[] = {
294 {
295 .of_compatible = "dlg,da9055-gpio",
296 .name = "da9055-gpio",
297 },
298 {
299 .of_compatible = "dlg,da9055-regulator",
300 .name = "da9055-regulator",
301 .id = 1,
302 },
303 {
304 .of_compatible = "dlg,da9055-regulator",
305 .name = "da9055-regulator",
306 .id = 2,
307 },
308 {
309 .of_compatible = "dlg,da9055-regulator",
310 .name = "da9055-regulator",
311 .id = 3,
312 },
313 {
314 .of_compatible = "dlg,da9055-regulator",
315 .name = "da9055-regulator",
316 .id = 4,
317 },
318 {
319 .of_compatible = "dlg,da9055-regulator",
320 .name = "da9055-regulator",
321 .id = 5,
322 },
323 {
324 .of_compatible = "dlg,da9055-regulator",
325 .name = "da9055-regulator",
326 .id = 6,
327 },
328 {
329 .of_compatible = "dlg,da9055-regulator",
330 .name = "da9055-regulator",
331 .id = 7,
332 .resources = &da9055_ld05_6_resource,
333 .num_resources = 1,
334 },
335 {
336 .of_compatible = "dlg,da9055-regulator",
337 .name = "da9055-regulator",
338 .resources = &da9055_ld05_6_resource,
339 .num_resources = 1,
340 .id = 8,
341 },
342 {
343 .of_compatible = "dlg,da9055-onkey",
344 .name = "da9055-onkey",
345 .resources = &da9055_onkey_resource,
346 .num_resources = 1,
347 },
348 {
349 .of_compatible = "dlg,da9055-rtc",
350 .name = "da9055-rtc",
351 .resources = da9055_rtc_resource,
352 .num_resources = ARRAY_SIZE(da9055_rtc_resource),
353 },
354 {
355 .of_compatible = "dlg,da9055-hwmon",
356 .name = "da9055-hwmon",
357 .resources = &da9055_hwmon_resource,
358 .num_resources = 1,
359 },
360 {
361 .of_compatible = "dlg,da9055-watchdog",
362 .name = "da9055-watchdog",
363 },
364 };
365
366 static const struct regmap_irq_chip da9055_regmap_irq_chip = {
367 .name = "da9055_irq",
368 .status_base = DA9055_REG_EVENT_A,
369 .mask_base = DA9055_REG_IRQ_MASK_A,
370 .ack_base = DA9055_REG_EVENT_A,
371 .num_regs = 3,
372 .irqs = da9055_irqs,
373 .num_irqs = ARRAY_SIZE(da9055_irqs),
374 };
375
da9055_device_init(struct da9055 * da9055)376 int da9055_device_init(struct da9055 *da9055)
377 {
378 struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
379 int ret;
380 uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF};
381
382 if (pdata && pdata->init != NULL)
383 pdata->init(da9055);
384
385 if (!pdata || !pdata->irq_base)
386 da9055->irq_base = -1;
387 else
388 da9055->irq_base = pdata->irq_base;
389
390 ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events);
391 if (ret < 0)
392 return ret;
393
394 ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
395 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
396 da9055->irq_base, &da9055_regmap_irq_chip,
397 &da9055->irq_data);
398 if (ret < 0)
399 return ret;
400
401 da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data);
402
403 ret = mfd_add_devices(da9055->dev, -1,
404 da9055_devs, ARRAY_SIZE(da9055_devs),
405 NULL, da9055->irq_base, NULL);
406 if (ret)
407 goto err;
408
409 return 0;
410
411 err:
412 mfd_remove_devices(da9055->dev);
413 return ret;
414 }
415
da9055_device_exit(struct da9055 * da9055)416 void da9055_device_exit(struct da9055 *da9055)
417 {
418 regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);
419 mfd_remove_devices(da9055->dev);
420 }
421
422 MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
423 MODULE_LICENSE("GPL");
424 MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
425