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_MAPLE,
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(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
389err:
390	mfd_remove_devices(da9055->dev);
391	return ret;
392}
393
394void 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
400MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
401MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
402