xref: /openbmc/linux/drivers/mfd/da9055-core.c (revision 2a598d0b)
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 	DEFINE_RES_IRQ_NAMED(DA9055_IRQ_NONKEY, "ONKEY");
259 
260 static 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 
265 static const struct resource da9055_hwmon_resource =
266 	DEFINE_RES_IRQ_NAMED(DA9055_IRQ_HWMON, "HWMON");
267 
268 static const struct resource da9055_ld05_6_resource =
269 	DEFINE_RES_IRQ_NAMED(DA9055_IRQ_REGULATOR, "REGULATOR");
270 
271 static 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 
344 static 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 
354 int da9055_device_init(struct da9055 *da9055)
355 {
356 	struct da9055_pdata *pdata = dev_get_platdata(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, 3, clear_events);
369 	if (ret < 0)
370 		return ret;
371 
372 	ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
373 				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
374 				  da9055->irq_base, &da9055_regmap_irq_chip,
375 				  &da9055->irq_data);
376 	if (ret < 0)
377 		return ret;
378 
379 	da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data);
380 
381 	ret = mfd_add_devices(da9055->dev, -1,
382 			      da9055_devs, ARRAY_SIZE(da9055_devs),
383 			      NULL, da9055->irq_base, NULL);
384 	if (ret)
385 		goto err;
386 
387 	return 0;
388 
389 err:
390 	mfd_remove_devices(da9055->dev);
391 	return ret;
392 }
393 
394 void da9055_device_exit(struct da9055 *da9055)
395 {
396 	regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);
397 	mfd_remove_devices(da9055->dev);
398 }
399 
400 MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
401 MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
402