blob: 6d0af8486269a0e2b9f44c7b3ca60632477a970a [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Ashish Jangam28964342012-09-14 18:54:50 +05302/*
3 * Device access for Dialog DA9055 PMICs.
4 *
5 * Copyright(c) 2012 Dialog Semiconductor Ltd.
6 *
7 * Author: David Dajun Chen <dchen@diasemi.com>
Ashish Jangam28964342012-09-14 18:54:50 +05308 */
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
Krzysztof Kozlowski7ce7b262015-04-27 21:54:13 +0900221static const struct regmap_irq da9055_irqs[] = {
Ashish Jangam28964342012-09-14 18:54:50 +0530222 [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
Krzysztof Kozlowski7ce7b262015-04-27 21:54:13 +0900244const struct regmap_config da9055_regmap_config = {
Ashish Jangam28964342012-09-14 18:54:50 +0530245 .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 struct resource da9055_onkey_resource = {
258 .name = "ONKEY",
259 .start = DA9055_IRQ_NONKEY,
260 .end = DA9055_IRQ_NONKEY,
261 .flags = IORESOURCE_IRQ,
262};
263
264static 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
279static struct resource da9055_hwmon_resource = {
280 .name = "HWMON",
281 .start = DA9055_IRQ_HWMON,
282 .end = DA9055_IRQ_HWMON,
283 .flags = IORESOURCE_IRQ,
284};
285
286static 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
Geert Uytterhoevenc8f675f2013-11-18 14:32:57 +0100293static const struct mfd_cell da9055_devs[] = {
Ashish Jangam28964342012-09-14 18:54:50 +0530294 {
Steve Twissbd597f42014-08-22 15:26:55 +0100295 .of_compatible = "dlg,da9055-gpio",
Ashish Jangam28964342012-09-14 18:54:50 +0530296 .name = "da9055-gpio",
297 },
298 {
Steve Twissbd597f42014-08-22 15:26:55 +0100299 .of_compatible = "dlg,da9055-regulator",
Ashish Jangam28964342012-09-14 18:54:50 +0530300 .name = "da9055-regulator",
301 .id = 1,
302 },
303 {
Steve Twissbd597f42014-08-22 15:26:55 +0100304 .of_compatible = "dlg,da9055-regulator",
Ashish Jangam28964342012-09-14 18:54:50 +0530305 .name = "da9055-regulator",
306 .id = 2,
307 },
308 {
Steve Twissbd597f42014-08-22 15:26:55 +0100309 .of_compatible = "dlg,da9055-regulator",
Ashish Jangam28964342012-09-14 18:54:50 +0530310 .name = "da9055-regulator",
311 .id = 3,
312 },
313 {
Steve Twissbd597f42014-08-22 15:26:55 +0100314 .of_compatible = "dlg,da9055-regulator",
Ashish Jangam28964342012-09-14 18:54:50 +0530315 .name = "da9055-regulator",
316 .id = 4,
317 },
318 {
Steve Twissbd597f42014-08-22 15:26:55 +0100319 .of_compatible = "dlg,da9055-regulator",
Ashish Jangam28964342012-09-14 18:54:50 +0530320 .name = "da9055-regulator",
321 .id = 5,
322 },
323 {
Steve Twissbd597f42014-08-22 15:26:55 +0100324 .of_compatible = "dlg,da9055-regulator",
Ashish Jangam28964342012-09-14 18:54:50 +0530325 .name = "da9055-regulator",
326 .id = 6,
327 },
328 {
Steve Twissbd597f42014-08-22 15:26:55 +0100329 .of_compatible = "dlg,da9055-regulator",
Ashish Jangam28964342012-09-14 18:54:50 +0530330 .name = "da9055-regulator",
331 .id = 7,
332 .resources = &da9055_ld05_6_resource,
333 .num_resources = 1,
334 },
335 {
Steve Twissbd597f42014-08-22 15:26:55 +0100336 .of_compatible = "dlg,da9055-regulator",
Ashish Jangam28964342012-09-14 18:54:50 +0530337 .name = "da9055-regulator",
338 .resources = &da9055_ld05_6_resource,
339 .num_resources = 1,
340 .id = 8,
341 },
342 {
Steve Twissbd597f42014-08-22 15:26:55 +0100343 .of_compatible = "dlg,da9055-onkey",
Ashish Jangam28964342012-09-14 18:54:50 +0530344 .name = "da9055-onkey",
345 .resources = &da9055_onkey_resource,
346 .num_resources = 1,
347 },
348 {
Steve Twissbd597f42014-08-22 15:26:55 +0100349 .of_compatible = "dlg,da9055-rtc",
Ashish Jangam28964342012-09-14 18:54:50 +0530350 .name = "da9055-rtc",
351 .resources = da9055_rtc_resource,
352 .num_resources = ARRAY_SIZE(da9055_rtc_resource),
353 },
354 {
Steve Twissbd597f42014-08-22 15:26:55 +0100355 .of_compatible = "dlg,da9055-hwmon",
Ashish Jangam28964342012-09-14 18:54:50 +0530356 .name = "da9055-hwmon",
357 .resources = &da9055_hwmon_resource,
358 .num_resources = 1,
359 },
360 {
Steve Twissbd597f42014-08-22 15:26:55 +0100361 .of_compatible = "dlg,da9055-watchdog",
Ashish Jangam28964342012-09-14 18:54:50 +0530362 .name = "da9055-watchdog",
363 },
364};
365
Krzysztof Kozlowski7ce7b262015-04-27 21:54:13 +0900366static const struct regmap_irq_chip da9055_regmap_irq_chip = {
Ashish Jangam28964342012-09-14 18:54:50 +0530367 .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
Bill Pembertonf791be42012-11-19 13:23:04 -0500376int da9055_device_init(struct da9055 *da9055)
Ashish Jangam28964342012-09-14 18:54:50 +0530377{
Jingoo Han334a41c2013-07-30 17:10:05 +0900378 struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
Ashish Jangam28964342012-09-14 18:54:50 +0530379 int ret;
Ankur Raina4b3b4a52013-07-05 18:48:30 +0530380 uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF};
Ashish Jangam28964342012-09-14 18:54:50 +0530381
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
Ankur Raina4b3b4a52013-07-05 18:48:30 +0530390 ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events);
391 if (ret < 0)
392 return ret;
393
Ashish Jangam28964342012-09-14 18:54:50 +0530394 ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
Ashish Jangam3cec5f42013-03-18 14:42:38 +0530395 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
Ashish Jangam28964342012-09-14 18:54:50 +0530396 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
411err:
412 mfd_remove_devices(da9055->dev);
413 return ret;
414}
415
Bill Pemberton4740f732012-11-19 13:26:01 -0500416void da9055_device_exit(struct da9055 *da9055)
Ashish Jangam28964342012-09-14 18:54:50 +0530417{
418 regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);
419 mfd_remove_devices(da9055->dev);
420}
421
422MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
423MODULE_LICENSE("GPL");
424MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");