xref: /openbmc/linux/drivers/mfd/da9055-core.c (revision 36fe4655)
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 
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 
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 
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 const 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 const 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 const 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 const 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 
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 
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