Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Device access for Dialog DA9063 modules
  4 *
  5 * Copyright 2012 Dialog Semiconductors Ltd.
  6 * Copyright 2013 Philipp Zabel, Pengutronix
  7 *
  8 * Author: Krystian Garbaciak, Dialog Semiconductor
  9 * Author: Michal Hajduk, Dialog Semiconductor
 10 *
 11 */
 12
 13#include <linux/kernel.h>
 14#include <linux/module.h>
 15#include <linux/init.h>
 16#include <linux/slab.h>
 17#include <linux/device.h>
 18#include <linux/delay.h>
 19#include <linux/interrupt.h>
 20#include <linux/mutex.h>
 21#include <linux/mfd/core.h>
 22#include <linux/regmap.h>
 23
 24#include <linux/mfd/da9063/core.h>
 25#include <linux/mfd/da9063/registers.h>
 26
 27#include <linux/proc_fs.h>
 28#include <linux/kthread.h>
 29#include <linux/uaccess.h>
 30
 31
 32static const struct resource da9063_regulators_resources[] = {
 33	{
 34		.name	= "LDO_LIM",
 35		.start	= DA9063_IRQ_LDO_LIM,
 36		.end	= DA9063_IRQ_LDO_LIM,
 37		.flags	= IORESOURCE_IRQ,
 38	},
 39};
 40
 41static const struct resource da9063_rtc_resources[] = {
 42	{
 43		.name	= "ALARM",
 44		.start	= DA9063_IRQ_ALARM,
 45		.end	= DA9063_IRQ_ALARM,
 46		.flags	= IORESOURCE_IRQ,
 47	},
 48	{
 49		.name	= "TICK",
 50		.start	= DA9063_IRQ_TICK,
 51		.end	= DA9063_IRQ_TICK,
 52		.flags	= IORESOURCE_IRQ,
 53	}
 54};
 55
 56static const struct resource da9063_onkey_resources[] = {
 57	{
 58		.name	= "ONKEY",
 59		.start	= DA9063_IRQ_ONKEY,
 60		.end	= DA9063_IRQ_ONKEY,
 61		.flags	= IORESOURCE_IRQ,
 62	},
 63};
 64
 65static const struct resource da9063_hwmon_resources[] = {
 66	{
 67		.start	= DA9063_IRQ_ADC_RDY,
 68		.end	= DA9063_IRQ_ADC_RDY,
 69		.flags	= IORESOURCE_IRQ,
 70	},
 71};
 72
 73
 74static const struct mfd_cell da9063_common_devs[] = {
 75	{
 76		.name		= DA9063_DRVNAME_REGULATORS,
 77		.num_resources	= ARRAY_SIZE(da9063_regulators_resources),
 78		.resources	= da9063_regulators_resources,
 79	},
 80	{
 81		.name		= DA9063_DRVNAME_LEDS,
 82	},
 83	{
 84		.name		= DA9063_DRVNAME_WATCHDOG,
 85		.of_compatible	= "dlg,da9063-watchdog",
 86	},
 87	{
 88		.name		= DA9063_DRVNAME_HWMON,
 89		.num_resources	= ARRAY_SIZE(da9063_hwmon_resources),
 90		.resources	= da9063_hwmon_resources,
 91	},
 92	{
 93		.name		= DA9063_DRVNAME_ONKEY,
 94		.num_resources	= ARRAY_SIZE(da9063_onkey_resources),
 95		.resources	= da9063_onkey_resources,
 96		.of_compatible = "dlg,da9063-onkey",
 97	},
 98	{
 99		.name		= DA9063_DRVNAME_VIBRATION,
100	},
101};
102
103/* Only present on DA9063 , not on DA9063L */
104static const struct mfd_cell da9063_devs[] = {
105	{
106		.name		= DA9063_DRVNAME_RTC,
107		.num_resources	= ARRAY_SIZE(da9063_rtc_resources),
108		.resources	= da9063_rtc_resources,
109		.of_compatible	= "dlg,da9063-rtc",
110	},
111};
112
113static int da9063_clear_fault_log(struct da9063 *da9063)
114{
115	int ret = 0;
116	int fault_log = 0;
117
118	ret = regmap_read(da9063->regmap, DA9063_REG_FAULT_LOG, &fault_log);
119	if (ret < 0) {
120		dev_err(da9063->dev, "Cannot read FAULT_LOG.\n");
121		return -EIO;
122	}
123
124	if (fault_log) {
125		if (fault_log & DA9063_TWD_ERROR)
126			dev_dbg(da9063->dev,
127				"Fault log entry detected: DA9063_TWD_ERROR\n");
128		if (fault_log & DA9063_POR)
129			dev_dbg(da9063->dev,
130				"Fault log entry detected: DA9063_POR\n");
131		if (fault_log & DA9063_VDD_FAULT)
132			dev_dbg(da9063->dev,
133				"Fault log entry detected: DA9063_VDD_FAULT\n");
134		if (fault_log & DA9063_VDD_START)
135			dev_dbg(da9063->dev,
136				"Fault log entry detected: DA9063_VDD_START\n");
137		if (fault_log & DA9063_TEMP_CRIT)
138			dev_dbg(da9063->dev,
139				"Fault log entry detected: DA9063_TEMP_CRIT\n");
140		if (fault_log & DA9063_KEY_RESET)
141			dev_dbg(da9063->dev,
142				"Fault log entry detected: DA9063_KEY_RESET\n");
143		if (fault_log & DA9063_NSHUTDOWN)
144			dev_dbg(da9063->dev,
145				"Fault log entry detected: DA9063_NSHUTDOWN\n");
146		if (fault_log & DA9063_WAIT_SHUT)
147			dev_dbg(da9063->dev,
148				"Fault log entry detected: DA9063_WAIT_SHUT\n");
149	}
150
151	ret = regmap_write(da9063->regmap,
152			   DA9063_REG_FAULT_LOG,
153			   fault_log);
154	if (ret < 0)
155		dev_err(da9063->dev,
156			"Cannot reset FAULT_LOG values %d\n", ret);
157
158	return ret;
159}
160
161int da9063_device_init(struct da9063 *da9063, unsigned int irq)
162{
163	int ret;
164
165	ret = da9063_clear_fault_log(da9063);
166	if (ret < 0)
167		dev_err(da9063->dev, "Cannot clear fault log\n");
168
169	da9063->flags = 0;
170	da9063->irq_base = -1;
171	da9063->chip_irq = irq;
172
173	ret = da9063_irq_init(da9063);
174	if (ret) {
175		dev_err(da9063->dev, "Cannot initialize interrupts.\n");
176		return ret;
177	}
178
179	da9063->irq_base = regmap_irq_chip_get_base(da9063->regmap_irq);
180
181	ret = devm_mfd_add_devices(da9063->dev, PLATFORM_DEVID_NONE,
182				   da9063_common_devs,
183				   ARRAY_SIZE(da9063_common_devs),
184				   NULL, da9063->irq_base, NULL);
185	if (ret) {
186		dev_err(da9063->dev, "Failed to add child devices\n");
187		return ret;
188	}
189
190	if (da9063->type == PMIC_TYPE_DA9063) {
191		ret = devm_mfd_add_devices(da9063->dev, PLATFORM_DEVID_NONE,
192					   da9063_devs, ARRAY_SIZE(da9063_devs),
193					   NULL, da9063->irq_base, NULL);
194		if (ret) {
195			dev_err(da9063->dev, "Failed to add child devices\n");
196			return ret;
197		}
198	}
199
200	return ret;
201}
202
203MODULE_DESCRIPTION("PMIC driver for Dialog DA9063");
204MODULE_AUTHOR("Krystian Garbaciak");
205MODULE_AUTHOR("Michal Hajduk");
206MODULE_LICENSE("GPL");