1/*
2 * Device access for Dialog DA9055 PMICs.
3 *
4 * Copyright(c) 2012 Dialog Semiconductor Ltd.
5 *
6 * Author: David Dajun Chen <dchen@diasemi.com>
7 *
8 *  This program is free software; you can redistribute  it and/or modify it
9 *  under  the terms of  the GNU General  Public License as published by the
10 *  Free Software Foundation;  either version 2 of the  License, or (at your
11 *  option) any later version.
12 */
13
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/input.h>
17#include <linux/irq.h>
18#include <linux/mutex.h>
19
20#include <linux/mfd/core.h>
21#include <linux/mfd/da9055/core.h>
22#include <linux/mfd/da9055/pdata.h>
23#include <linux/mfd/da9055/reg.h>
24
25#define DA9055_IRQ_NONKEY_MASK		0x01
26#define DA9055_IRQ_ALM_MASK		0x02
27#define DA9055_IRQ_TICK_MASK		0x04
28#define DA9055_IRQ_ADC_MASK		0x08
29#define DA9055_IRQ_BUCK_ILIM_MASK	0x08
30
31static bool da9055_register_readable(struct device *dev, unsigned int reg)
32{
33	switch (reg) {
34	case DA9055_REG_STATUS_A:
35	case DA9055_REG_STATUS_B:
36	case DA9055_REG_EVENT_A:
37	case DA9055_REG_EVENT_B:
38	case DA9055_REG_EVENT_C:
39	case DA9055_REG_IRQ_MASK_A:
40	case DA9055_REG_IRQ_MASK_B:
41	case DA9055_REG_IRQ_MASK_C:
42
43	case DA9055_REG_CONTROL_A:
44	case DA9055_REG_CONTROL_B:
45	case DA9055_REG_CONTROL_C:
46	case DA9055_REG_CONTROL_D:
47	case DA9055_REG_CONTROL_E:
48
49	case DA9055_REG_ADC_MAN:
50	case DA9055_REG_ADC_CONT:
51	case DA9055_REG_VSYS_MON:
52	case DA9055_REG_ADC_RES_L:
53	case DA9055_REG_ADC_RES_H:
54	case DA9055_REG_VSYS_RES:
55	case DA9055_REG_ADCIN1_RES:
56	case DA9055_REG_ADCIN2_RES:
57	case DA9055_REG_ADCIN3_RES:
58
59	case DA9055_REG_COUNT_S:
60	case DA9055_REG_COUNT_MI:
61	case DA9055_REG_COUNT_H:
62	case DA9055_REG_COUNT_D:
63	case DA9055_REG_COUNT_MO:
64	case DA9055_REG_COUNT_Y:
65	case DA9055_REG_ALARM_H:
66	case DA9055_REG_ALARM_D:
67	case DA9055_REG_ALARM_MI:
68	case DA9055_REG_ALARM_MO:
69	case DA9055_REG_ALARM_Y:
70
71	case DA9055_REG_GPIO0_1:
72	case DA9055_REG_GPIO2:
73	case DA9055_REG_GPIO_MODE0_2:
74
75	case DA9055_REG_BCORE_CONT:
76	case DA9055_REG_BMEM_CONT:
77	case DA9055_REG_LDO1_CONT:
78	case DA9055_REG_LDO2_CONT:
79	case DA9055_REG_LDO3_CONT:
80	case DA9055_REG_LDO4_CONT:
81	case DA9055_REG_LDO5_CONT:
82	case DA9055_REG_LDO6_CONT:
83	case DA9055_REG_BUCK_LIM:
84	case DA9055_REG_BCORE_MODE:
85	case DA9055_REG_VBCORE_A:
86	case DA9055_REG_VBMEM_A:
87	case DA9055_REG_VLDO1_A:
88	case DA9055_REG_VLDO2_A:
89	case DA9055_REG_VLDO3_A:
90	case DA9055_REG_VLDO4_A:
91	case DA9055_REG_VLDO5_A:
92	case DA9055_REG_VLDO6_A:
93	case DA9055_REG_VBCORE_B:
94	case DA9055_REG_VBMEM_B:
95	case DA9055_REG_VLDO1_B:
96	case DA9055_REG_VLDO2_B:
97	case DA9055_REG_VLDO3_B:
98	case DA9055_REG_VLDO4_B:
99	case DA9055_REG_VLDO5_B:
100	case DA9055_REG_VLDO6_B:
101		return true;
102	default:
103		return false;
104	}
105}
106
107static bool da9055_register_writeable(struct device *dev, unsigned int reg)
108{
109	switch (reg) {
110	case DA9055_REG_STATUS_A:
111	case DA9055_REG_STATUS_B:
112	case DA9055_REG_EVENT_A:
113	case DA9055_REG_EVENT_B:
114	case DA9055_REG_EVENT_C:
115	case DA9055_REG_IRQ_MASK_A:
116	case DA9055_REG_IRQ_MASK_B:
117	case DA9055_REG_IRQ_MASK_C:
118
119	case DA9055_REG_CONTROL_A:
120	case DA9055_REG_CONTROL_B:
121	case DA9055_REG_CONTROL_C:
122	case DA9055_REG_CONTROL_D:
123	case DA9055_REG_CONTROL_E:
124
125	case DA9055_REG_ADC_MAN:
126	case DA9055_REG_ADC_CONT:
127	case DA9055_REG_VSYS_MON:
128	case DA9055_REG_ADC_RES_L:
129	case DA9055_REG_ADC_RES_H:
130	case DA9055_REG_VSYS_RES:
131	case DA9055_REG_ADCIN1_RES:
132	case DA9055_REG_ADCIN2_RES:
133	case DA9055_REG_ADCIN3_RES:
134
135	case DA9055_REG_COUNT_S:
136	case DA9055_REG_COUNT_MI:
137	case DA9055_REG_COUNT_H:
138	case DA9055_REG_COUNT_D:
139	case DA9055_REG_COUNT_MO:
140	case DA9055_REG_COUNT_Y:
141	case DA9055_REG_ALARM_H:
142	case DA9055_REG_ALARM_D:
143	case DA9055_REG_ALARM_MI:
144	case DA9055_REG_ALARM_MO:
145	case DA9055_REG_ALARM_Y:
146
147	case DA9055_REG_GPIO0_1:
148	case DA9055_REG_GPIO2:
149	case DA9055_REG_GPIO_MODE0_2:
150
151	case DA9055_REG_BCORE_CONT:
152	case DA9055_REG_BMEM_CONT:
153	case DA9055_REG_LDO1_CONT:
154	case DA9055_REG_LDO2_CONT:
155	case DA9055_REG_LDO3_CONT:
156	case DA9055_REG_LDO4_CONT:
157	case DA9055_REG_LDO5_CONT:
158	case DA9055_REG_LDO6_CONT:
159	case DA9055_REG_BUCK_LIM:
160	case DA9055_REG_BCORE_MODE:
161	case DA9055_REG_VBCORE_A:
162	case DA9055_REG_VBMEM_A:
163	case DA9055_REG_VLDO1_A:
164	case DA9055_REG_VLDO2_A:
165	case DA9055_REG_VLDO3_A:
166	case DA9055_REG_VLDO4_A:
167	case DA9055_REG_VLDO5_A:
168	case DA9055_REG_VLDO6_A:
169	case DA9055_REG_VBCORE_B:
170	case DA9055_REG_VBMEM_B:
171	case DA9055_REG_VLDO1_B:
172	case DA9055_REG_VLDO2_B:
173	case DA9055_REG_VLDO3_B:
174	case DA9055_REG_VLDO4_B:
175	case DA9055_REG_VLDO5_B:
176	case DA9055_REG_VLDO6_B:
177		return true;
178	default:
179		return false;
180	}
181}
182
183static bool da9055_register_volatile(struct device *dev, unsigned int reg)
184{
185	switch (reg) {
186	case DA9055_REG_STATUS_A:
187	case DA9055_REG_STATUS_B:
188	case DA9055_REG_EVENT_A:
189	case DA9055_REG_EVENT_B:
190	case DA9055_REG_EVENT_C:
191
192	case DA9055_REG_CONTROL_A:
193	case DA9055_REG_CONTROL_E:
194
195	case DA9055_REG_ADC_MAN:
196	case DA9055_REG_ADC_RES_L:
197	case DA9055_REG_ADC_RES_H:
198	case DA9055_REG_VSYS_RES:
199	case DA9055_REG_ADCIN1_RES:
200	case DA9055_REG_ADCIN2_RES:
201	case DA9055_REG_ADCIN3_RES:
202
203	case DA9055_REG_COUNT_S:
204	case DA9055_REG_COUNT_MI:
205	case DA9055_REG_COUNT_H:
206	case DA9055_REG_COUNT_D:
207	case DA9055_REG_COUNT_MO:
208	case DA9055_REG_COUNT_Y:
209	case DA9055_REG_ALARM_MI:
210
211	case DA9055_REG_BCORE_CONT:
212	case DA9055_REG_BMEM_CONT:
213	case DA9055_REG_LDO1_CONT:
214	case DA9055_REG_LDO2_CONT:
215	case DA9055_REG_LDO3_CONT:
216	case DA9055_REG_LDO4_CONT:
217	case DA9055_REG_LDO5_CONT:
218	case DA9055_REG_LDO6_CONT:
219		return true;
220	default:
221		return false;
222	}
223}
224
225static struct regmap_irq da9055_irqs[] = {
226	[DA9055_IRQ_NONKEY] = {
227		.reg_offset = 0,
228		.mask = DA9055_IRQ_NONKEY_MASK,
229	},
230	[DA9055_IRQ_ALARM] = {
231		.reg_offset = 0,
232		.mask = DA9055_IRQ_ALM_MASK,
233	},
234	[DA9055_IRQ_TICK] = {
235		.reg_offset = 0,
236		.mask = DA9055_IRQ_TICK_MASK,
237	},
238	[DA9055_IRQ_HWMON] = {
239		.reg_offset = 0,
240		.mask = DA9055_IRQ_ADC_MASK,
241	},
242	[DA9055_IRQ_REGULATOR] = {
243		.reg_offset = 1,
244		.mask = DA9055_IRQ_BUCK_ILIM_MASK,
245	},
246};
247
248struct regmap_config da9055_regmap_config = {
249	.reg_bits = 8,
250	.val_bits = 8,
251
252	.cache_type = REGCACHE_RBTREE,
253
254	.max_register = DA9055_MAX_REGISTER_CNT,
255	.readable_reg = da9055_register_readable,
256	.writeable_reg = da9055_register_writeable,
257	.volatile_reg = da9055_register_volatile,
258};
259EXPORT_SYMBOL_GPL(da9055_regmap_config);
260
261static struct resource da9055_onkey_resource = {
262	.name = "ONKEY",
263	.start = DA9055_IRQ_NONKEY,
264	.end   = DA9055_IRQ_NONKEY,
265	.flags = IORESOURCE_IRQ,
266};
267
268static struct resource da9055_rtc_resource[] = {
269	{
270		.name = "ALM",
271		.start = DA9055_IRQ_ALARM,
272		.end   = DA9055_IRQ_ALARM,
273		.flags = IORESOURCE_IRQ,
274	},
275	{
276		.name = "TICK",
277		.start = DA9055_IRQ_TICK,
278		.end   = DA9055_IRQ_TICK,
279		.flags = IORESOURCE_IRQ,
280	},
281};
282
283static struct resource da9055_hwmon_resource = {
284	.name = "HWMON",
285	.start = DA9055_IRQ_HWMON,
286	.end   = DA9055_IRQ_HWMON,
287	.flags = IORESOURCE_IRQ,
288};
289
290static struct resource da9055_ld05_6_resource = {
291	.name = "REGULATOR",
292	.start = DA9055_IRQ_REGULATOR,
293	.end   = DA9055_IRQ_REGULATOR,
294	.flags = IORESOURCE_IRQ,
295};
296
297static const struct mfd_cell da9055_devs[] = {
298	{
299		.of_compatible = "dlg,da9055-gpio",
300		.name = "da9055-gpio",
301	},
302	{
303		.of_compatible = "dlg,da9055-regulator",
304		.name = "da9055-regulator",
305		.id = 1,
306	},
307	{
308		.of_compatible = "dlg,da9055-regulator",
309		.name = "da9055-regulator",
310		.id = 2,
311	},
312	{
313		.of_compatible = "dlg,da9055-regulator",
314		.name = "da9055-regulator",
315		.id = 3,
316	},
317	{
318		.of_compatible = "dlg,da9055-regulator",
319		.name = "da9055-regulator",
320		.id = 4,
321	},
322	{
323		.of_compatible = "dlg,da9055-regulator",
324		.name = "da9055-regulator",
325		.id = 5,
326	},
327	{
328		.of_compatible = "dlg,da9055-regulator",
329		.name = "da9055-regulator",
330		.id = 6,
331	},
332	{
333		.of_compatible = "dlg,da9055-regulator",
334		.name = "da9055-regulator",
335		.id = 7,
336		.resources = &da9055_ld05_6_resource,
337		.num_resources = 1,
338	},
339	{
340		.of_compatible = "dlg,da9055-regulator",
341		.name = "da9055-regulator",
342		.resources = &da9055_ld05_6_resource,
343		.num_resources = 1,
344		.id = 8,
345	},
346	{
347		.of_compatible = "dlg,da9055-onkey",
348		.name = "da9055-onkey",
349		.resources = &da9055_onkey_resource,
350		.num_resources = 1,
351	},
352	{
353		.of_compatible = "dlg,da9055-rtc",
354		.name = "da9055-rtc",
355		.resources = da9055_rtc_resource,
356		.num_resources = ARRAY_SIZE(da9055_rtc_resource),
357	},
358	{
359		.of_compatible = "dlg,da9055-hwmon",
360		.name = "da9055-hwmon",
361		.resources = &da9055_hwmon_resource,
362		.num_resources = 1,
363	},
364	{
365		.of_compatible = "dlg,da9055-watchdog",
366		.name = "da9055-watchdog",
367	},
368};
369
370static struct regmap_irq_chip da9055_regmap_irq_chip = {
371	.name = "da9055_irq",
372	.status_base = DA9055_REG_EVENT_A,
373	.mask_base = DA9055_REG_IRQ_MASK_A,
374	.ack_base = DA9055_REG_EVENT_A,
375	.num_regs = 3,
376	.irqs = da9055_irqs,
377	.num_irqs = ARRAY_SIZE(da9055_irqs),
378};
379
380int da9055_device_init(struct da9055 *da9055)
381{
382	struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
383	int ret;
384	uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF};
385
386	if (pdata && pdata->init != NULL)
387		pdata->init(da9055);
388
389	if (!pdata || !pdata->irq_base)
390		da9055->irq_base = -1;
391	else
392		da9055->irq_base = pdata->irq_base;
393
394	ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events);
395	if (ret < 0)
396		return ret;
397
398	ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
399				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
400				  da9055->irq_base, &da9055_regmap_irq_chip,
401				  &da9055->irq_data);
402	if (ret < 0)
403		return ret;
404
405	da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data);
406
407	ret = mfd_add_devices(da9055->dev, -1,
408			      da9055_devs, ARRAY_SIZE(da9055_devs),
409			      NULL, da9055->irq_base, NULL);
410	if (ret)
411		goto err;
412
413	return 0;
414
415err:
416	mfd_remove_devices(da9055->dev);
417	return ret;
418}
419
420void da9055_device_exit(struct da9055 *da9055)
421{
422	regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);
423	mfd_remove_devices(da9055->dev);
424}
425
426MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
427MODULE_LICENSE("GPL");
428MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
429