Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * da9063-core.c: Device access for Dialog DA9063 modules
  3 *
  4 * Copyright 2012 Dialog Semiconductors Ltd.
  5 * Copyright 2013 Philipp Zabel, Pengutronix
  6 *
  7 * Author: Krystian Garbaciak, Dialog Semiconductor
  8 * Author: Michal Hajduk, Dialog Semiconductor
  9 *
 10 *  This program is free software; you can redistribute  it and/or modify it
 11 *  under  the terms of  the GNU General  Public License as published by the
 12 *  Free Software Foundation;  either version 2 of the  License, or (at your
 13 *  option) any later version.
 14 *
 15 */
 16
 17#include <linux/kernel.h>
 18#include <linux/module.h>
 19#include <linux/init.h>
 20#include <linux/slab.h>
 21#include <linux/device.h>
 22#include <linux/delay.h>
 23#include <linux/interrupt.h>
 24#include <linux/mutex.h>
 25#include <linux/mfd/core.h>
 26#include <linux/regmap.h>
 27
 28#include <linux/mfd/da9063/core.h>
 29#include <linux/mfd/da9063/pdata.h>
 30#include <linux/mfd/da9063/registers.h>
 31
 32#include <linux/proc_fs.h>
 33#include <linux/kthread.h>
 34#include <linux/uaccess.h>
 35
 36
 37static struct resource da9063_regulators_resources[] = {
 38	{
 39		.name	= "LDO_LIM",
 40		.start	= DA9063_IRQ_LDO_LIM,
 41		.end	= DA9063_IRQ_LDO_LIM,
 42		.flags	= IORESOURCE_IRQ,
 43	},
 44};
 45
 46static struct resource da9063_rtc_resources[] = {
 47	{
 48		.name	= "ALARM",
 49		.start	= DA9063_IRQ_ALARM,
 50		.end	= DA9063_IRQ_ALARM,
 51		.flags	= IORESOURCE_IRQ,
 52	},
 53	{
 54		.name	= "TICK",
 55		.start	= DA9063_IRQ_TICK,
 56		.end	= DA9063_IRQ_TICK,
 57		.flags	= IORESOURCE_IRQ,
 58	}
 59};
 60
 61static struct resource da9063_onkey_resources[] = {
 62	{
 63		.name	= "ONKEY",
 64		.start	= DA9063_IRQ_ONKEY,
 65		.end	= DA9063_IRQ_ONKEY,
 66		.flags	= IORESOURCE_IRQ,
 67	},
 68};
 69
 70static struct resource da9063_hwmon_resources[] = {
 71	{
 72		.start	= DA9063_IRQ_ADC_RDY,
 73		.end	= DA9063_IRQ_ADC_RDY,
 74		.flags	= IORESOURCE_IRQ,
 75	},
 76};
 77
 78
 79static const struct mfd_cell da9063_devs[] = {
 80	{
 81		.name		= DA9063_DRVNAME_REGULATORS,
 82		.num_resources	= ARRAY_SIZE(da9063_regulators_resources),
 83		.resources	= da9063_regulators_resources,
 84	},
 85	{
 86		.name		= DA9063_DRVNAME_LEDS,
 87	},
 88	{
 89		.name		= DA9063_DRVNAME_WATCHDOG,
 90		.of_compatible	= "dlg,da9063-watchdog",
 91	},
 92	{
 93		.name		= DA9063_DRVNAME_HWMON,
 94		.num_resources	= ARRAY_SIZE(da9063_hwmon_resources),
 95		.resources	= da9063_hwmon_resources,
 96	},
 97	{
 98		.name		= DA9063_DRVNAME_ONKEY,
 99		.num_resources	= ARRAY_SIZE(da9063_onkey_resources),
100		.resources	= da9063_onkey_resources,
101		.of_compatible = "dlg,da9063-onkey",
102	},
103	{
104		.name		= DA9063_DRVNAME_RTC,
105		.num_resources	= ARRAY_SIZE(da9063_rtc_resources),
106		.resources	= da9063_rtc_resources,
107		.of_compatible	= "dlg,da9063-rtc",
108	},
109	{
110		.name		= DA9063_DRVNAME_VIBRATION,
111	},
112};
113
114static int da9063_clear_fault_log(struct da9063 *da9063)
115{
116	int ret = 0;
117	int fault_log = 0;
118
119	ret = regmap_read(da9063->regmap, DA9063_REG_FAULT_LOG, &fault_log);
120	if (ret < 0) {
121		dev_err(da9063->dev, "Cannot read FAULT_LOG.\n");
122		return -EIO;
123	}
124
125	if (fault_log) {
126		if (fault_log & DA9063_TWD_ERROR)
127			dev_dbg(da9063->dev,
128				"Fault log entry detected: DA9063_TWD_ERROR\n");
129		if (fault_log & DA9063_POR)
130			dev_dbg(da9063->dev,
131				"Fault log entry detected: DA9063_POR\n");
132		if (fault_log & DA9063_VDD_FAULT)
133			dev_dbg(da9063->dev,
134				"Fault log entry detected: DA9063_VDD_FAULT\n");
135		if (fault_log & DA9063_VDD_START)
136			dev_dbg(da9063->dev,
137				"Fault log entry detected: DA9063_VDD_START\n");
138		if (fault_log & DA9063_TEMP_CRIT)
139			dev_dbg(da9063->dev,
140				"Fault log entry detected: DA9063_TEMP_CRIT\n");
141		if (fault_log & DA9063_KEY_RESET)
142			dev_dbg(da9063->dev,
143				"Fault log entry detected: DA9063_KEY_RESET\n");
144		if (fault_log & DA9063_NSHUTDOWN)
145			dev_dbg(da9063->dev,
146				"Fault log entry detected: DA9063_NSHUTDOWN\n");
147		if (fault_log & DA9063_WAIT_SHUT)
148			dev_dbg(da9063->dev,
149				"Fault log entry detected: DA9063_WAIT_SHUT\n");
150	}
151
152	ret = regmap_write(da9063->regmap,
153			   DA9063_REG_FAULT_LOG,
154			   fault_log);
155	if (ret < 0)
156		dev_err(da9063->dev,
157			"Cannot reset FAULT_LOG values %d\n", ret);
158
159	return ret;
160}
161
162int da9063_device_init(struct da9063 *da9063, unsigned int irq)
163{
164	struct da9063_pdata *pdata = da9063->dev->platform_data;
165	int model, variant_id, variant_code;
166	int ret;
167
168	ret = da9063_clear_fault_log(da9063);
169	if (ret < 0)
170		dev_err(da9063->dev, "Cannot clear fault log\n");
171
172	if (pdata) {
173		da9063->flags = pdata->flags;
174		da9063->irq_base = pdata->irq_base;
175	} else {
176		da9063->flags = 0;
177		da9063->irq_base = -1;
178	}
179	da9063->chip_irq = irq;
180
181	if (pdata && pdata->init != NULL) {
182		ret = pdata->init(da9063);
183		if (ret != 0) {
184			dev_err(da9063->dev,
185				"Platform initialization failed.\n");
186			return ret;
187		}
188	}
189
190	ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model);
191	if (ret < 0) {
192		dev_err(da9063->dev, "Cannot read chip model id.\n");
193		return -EIO;
194	}
195	if (model != PMIC_DA9063) {
196		dev_err(da9063->dev, "Invalid chip model id: 0x%02x\n", model);
197		return -ENODEV;
198	}
199
200	ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &variant_id);
201	if (ret < 0) {
202		dev_err(da9063->dev, "Cannot read chip variant id.\n");
203		return -EIO;
204	}
205
206	variant_code = variant_id >> DA9063_CHIP_VARIANT_SHIFT;
207
208	dev_info(da9063->dev,
209		 "Device detected (chip-ID: 0x%02X, var-ID: 0x%02X)\n",
210		 model, variant_id);
211
212	if (variant_code < PMIC_DA9063_BB && variant_code != PMIC_DA9063_AD) {
213		dev_err(da9063->dev,
214			"Cannot support variant code: 0x%02X\n", variant_code);
215		return -ENODEV;
216	}
217
218	da9063->model = model;
219	da9063->variant_code = variant_code;
220
221	ret = da9063_irq_init(da9063);
222	if (ret) {
223		dev_err(da9063->dev, "Cannot initialize interrupts.\n");
224		return ret;
225	}
226
227	da9063->irq_base = regmap_irq_chip_get_base(da9063->regmap_irq);
228
229	ret = mfd_add_devices(da9063->dev, -1, da9063_devs,
230			      ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base,
231			      NULL);
232	if (ret)
233		dev_err(da9063->dev, "Cannot add MFD cells\n");
234
235	return ret;
236}
237
238void da9063_device_exit(struct da9063 *da9063)
239{
240	mfd_remove_devices(da9063->dev);
241	da9063_irq_exit(da9063);
242}
243
244MODULE_DESCRIPTION("PMIC driver for Dialog DA9063");
245MODULE_AUTHOR("Krystian Garbaciak");
246MODULE_AUTHOR("Michal Hajduk");
247MODULE_LICENSE("GPL");