Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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 const 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
248const struct 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 const 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>");