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
27static 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
103static 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
179static 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
221static 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
244const 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};
255EXPORT_SYMBOL_GPL(da9055_regmap_config);
256
257static const struct resource da9055_onkey_resource =
258 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_NONKEY, "ONKEY");
259
260static const struct resource da9055_rtc_resource[] = {
261 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_ALARM, "ALM"),
262 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_TICK, "TICK"),
263};
264
265static const struct resource da9055_hwmon_resource =
266 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_HWMON, "HWMON");
267
268static const struct resource da9055_ld05_6_resource =
269 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_REGULATOR, "REGULATOR");
270
271static const struct mfd_cell da9055_devs[] = {
272 {
273 .of_compatible = "dlg,da9055-gpio",
274 .name = "da9055-gpio",
275 },
276 {
277 .of_compatible = "dlg,da9055-regulator",
278 .name = "da9055-regulator",
279 .id = 1,
280 },
281 {
282 .of_compatible = "dlg,da9055-regulator",
283 .name = "da9055-regulator",
284 .id = 2,
285 },
286 {
287 .of_compatible = "dlg,da9055-regulator",
288 .name = "da9055-regulator",
289 .id = 3,
290 },
291 {
292 .of_compatible = "dlg,da9055-regulator",
293 .name = "da9055-regulator",
294 .id = 4,
295 },
296 {
297 .of_compatible = "dlg,da9055-regulator",
298 .name = "da9055-regulator",
299 .id = 5,
300 },
301 {
302 .of_compatible = "dlg,da9055-regulator",
303 .name = "da9055-regulator",
304 .id = 6,
305 },
306 {
307 .of_compatible = "dlg,da9055-regulator",
308 .name = "da9055-regulator",
309 .id = 7,
310 .resources = &da9055_ld05_6_resource,
311 .num_resources = 1,
312 },
313 {
314 .of_compatible = "dlg,da9055-regulator",
315 .name = "da9055-regulator",
316 .resources = &da9055_ld05_6_resource,
317 .num_resources = 1,
318 .id = 8,
319 },
320 {
321 .of_compatible = "dlg,da9055-onkey",
322 .name = "da9055-onkey",
323 .resources = &da9055_onkey_resource,
324 .num_resources = 1,
325 },
326 {
327 .of_compatible = "dlg,da9055-rtc",
328 .name = "da9055-rtc",
329 .resources = da9055_rtc_resource,
330 .num_resources = ARRAY_SIZE(da9055_rtc_resource),
331 },
332 {
333 .of_compatible = "dlg,da9055-hwmon",
334 .name = "da9055-hwmon",
335 .resources = &da9055_hwmon_resource,
336 .num_resources = 1,
337 },
338 {
339 .of_compatible = "dlg,da9055-watchdog",
340 .name = "da9055-watchdog",
341 },
342};
343
344static const struct regmap_irq_chip da9055_regmap_irq_chip = {
345 .name = "da9055_irq",
346 .status_base = DA9055_REG_EVENT_A,
347 .mask_base = DA9055_REG_IRQ_MASK_A,
348 .ack_base = DA9055_REG_EVENT_A,
349 .num_regs = 3,
350 .irqs = da9055_irqs,
351 .num_irqs = ARRAY_SIZE(da9055_irqs),
352};
353
354int da9055_device_init(struct da9055 *da9055)
355{
356 struct da9055_pdata *pdata = dev_get_platdata(dev: da9055->dev);
357 int ret;
358 uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF};
359
360 if (pdata && pdata->init != NULL)
361 pdata->init(da9055);
362
363 if (!pdata || !pdata->irq_base)
364 da9055->irq_base = -1;
365 else
366 da9055->irq_base = pdata->irq_base;
367
368 ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, reg_cnt: 3, val: clear_events);
369 if (ret < 0)
370 return ret;
371
372 ret = regmap_add_irq_chip(map: da9055->regmap, irq: da9055->chip_irq,
373 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
374 irq_base: da9055->irq_base, chip: &da9055_regmap_irq_chip,
375 data: &da9055->irq_data);
376 if (ret < 0)
377 return ret;
378
379 da9055->irq_base = regmap_irq_chip_get_base(data: da9055->irq_data);
380
381 ret = mfd_add_devices(parent: da9055->dev, id: -1,
382 cells: da9055_devs, ARRAY_SIZE(da9055_devs),
383 NULL, irq_base: da9055->irq_base, NULL);
384 if (ret)
385 goto err;
386
387 return 0;
388
389err:
390 mfd_remove_devices(parent: da9055->dev);
391 return ret;
392}
393
394void da9055_device_exit(struct da9055 *da9055)
395{
396 regmap_del_irq_chip(irq: da9055->chip_irq, data: da9055->irq_data);
397 mfd_remove_devices(parent: da9055->dev);
398}
399
400MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
401MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
402

source code of linux/drivers/mfd/da9055-core.c