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");
v3.15
 
  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		.start	= DA9063_IRQ_ONKEY,
 64		.end	= DA9063_IRQ_ONKEY,
 65		.flags	= IORESOURCE_IRQ,
 66	},
 67};
 68
 69static struct resource da9063_hwmon_resources[] = {
 70	{
 71		.start	= DA9063_IRQ_ADC_RDY,
 72		.end	= DA9063_IRQ_ADC_RDY,
 73		.flags	= IORESOURCE_IRQ,
 74	},
 75};
 76
 77
 78static const struct mfd_cell da9063_devs[] = {
 79	{
 80		.name		= DA9063_DRVNAME_REGULATORS,
 81		.num_resources	= ARRAY_SIZE(da9063_regulators_resources),
 82		.resources	= da9063_regulators_resources,
 83	},
 84	{
 85		.name		= DA9063_DRVNAME_LEDS,
 86	},
 87	{
 88		.name		= DA9063_DRVNAME_WATCHDOG,
 
 89	},
 90	{
 91		.name		= DA9063_DRVNAME_HWMON,
 92		.num_resources	= ARRAY_SIZE(da9063_hwmon_resources),
 93		.resources	= da9063_hwmon_resources,
 94	},
 95	{
 96		.name		= DA9063_DRVNAME_ONKEY,
 97		.num_resources	= ARRAY_SIZE(da9063_onkey_resources),
 98		.resources	= da9063_onkey_resources,
 
 99	},
100	{
 
 
 
 
 
 
 
101		.name		= DA9063_DRVNAME_RTC,
102		.num_resources	= ARRAY_SIZE(da9063_rtc_resources),
103		.resources	= da9063_rtc_resources,
104	},
105	{
106		.name		= DA9063_DRVNAME_VIBRATION,
107	},
108};
109
110int da9063_device_init(struct da9063 *da9063, unsigned int irq)
111{
112	struct da9063_pdata *pdata = da9063->dev->platform_data;
113	int model, variant_id, variant_code;
114	int ret;
115
116	if (pdata) {
117		da9063->flags = pdata->flags;
118		da9063->irq_base = pdata->irq_base;
119	} else {
120		da9063->flags = 0;
121		da9063->irq_base = 0;
122	}
123	da9063->chip_irq = irq;
124
125	if (pdata && pdata->init != NULL) {
126		ret = pdata->init(da9063);
127		if (ret != 0) {
128			dev_err(da9063->dev,
129				"Platform initialization failed.\n");
130			return ret;
131		}
132	}
133
134	ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model);
135	if (ret < 0) {
136		dev_err(da9063->dev, "Cannot read chip model id.\n");
137		return -EIO;
138	}
139	if (model != PMIC_DA9063) {
140		dev_err(da9063->dev, "Invalid chip model id: 0x%02x\n", model);
141		return -ENODEV;
142	}
143
144	ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &variant_id);
145	if (ret < 0) {
146		dev_err(da9063->dev, "Cannot read chip variant id.\n");
147		return -EIO;
148	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
150	variant_code = variant_id >> DA9063_CHIP_VARIANT_SHIFT;
 
151
152	dev_info(da9063->dev,
153		 "Device detected (chip-ID: 0x%02X, var-ID: 0x%02X)\n",
154		 model, variant_id);
155
156	if (variant_code != PMIC_DA9063_BB) {
157		dev_err(da9063->dev, "Unknown chip variant code: 0x%02X\n",
158				variant_code);
159		return -ENODEV;
160	}
161
162	da9063->model = model;
163	da9063->variant_code = variant_code;
 
164
165	ret = da9063_irq_init(da9063);
166	if (ret) {
167		dev_err(da9063->dev, "Cannot initialize interrupts.\n");
168		return ret;
169	}
170
171	ret = mfd_add_devices(da9063->dev, -1, da9063_devs,
172			      ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base,
173			      NULL);
174	if (ret)
175		dev_err(da9063->dev, "Cannot add MFD cells\n");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
177	return ret;
178}
179
180void da9063_device_exit(struct da9063 *da9063)
181{
182	mfd_remove_devices(da9063->dev);
183	da9063_irq_exit(da9063);
184}
185
186MODULE_DESCRIPTION("PMIC driver for Dialog DA9063");
187MODULE_AUTHOR("Krystian Garbaciak <krystian.garbaciak@diasemi.com>, Michal Hajduk <michal.hajduk@diasemi.com>");
 
188MODULE_LICENSE("GPL");