Linux Audio

Check our new training course

Loading...
v6.8
  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");
v4.6
 
  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 <krystian.garbaciak@diasemi.com>,
  8 *         Michal Hajduk <michal.hajduk@diasemi.com>
  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 <krystian.garbaciak@diasemi.com>, Michal Hajduk <michal.hajduk@diasemi.com>");
 
246MODULE_LICENSE("GPL");