brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · df407c3 Raw
207 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Device access for Dialog DA9063 modules4 *5 * Copyright 2012 Dialog Semiconductors Ltd.6 * Copyright 2013 Philipp Zabel, Pengutronix7 *8 * Author: Krystian Garbaciak, Dialog Semiconductor9 * Author: Michal Hajduk, Dialog Semiconductor10 *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");207