xref: /openbmc/linux/drivers/mfd/da9063-core.c (revision a0fa0abe)
19efbc6f1SWolfram Sang // SPDX-License-Identifier: GPL-2.0+
28e685483SKrystian Garbaciak /*
39efbc6f1SWolfram Sang  * Device access for Dialog DA9063 modules
48e685483SKrystian Garbaciak  *
58e685483SKrystian Garbaciak  * Copyright 2012 Dialog Semiconductors Ltd.
68e685483SKrystian Garbaciak  * Copyright 2013 Philipp Zabel, Pengutronix
78e685483SKrystian Garbaciak  *
837778d83SSteve Twiss  * Author: Krystian Garbaciak, Dialog Semiconductor
937778d83SSteve Twiss  * Author: Michal Hajduk, Dialog Semiconductor
108e685483SKrystian Garbaciak  *
118e685483SKrystian Garbaciak  */
128e685483SKrystian Garbaciak 
138e685483SKrystian Garbaciak #include <linux/kernel.h>
148e685483SKrystian Garbaciak #include <linux/module.h>
158e685483SKrystian Garbaciak #include <linux/init.h>
168e685483SKrystian Garbaciak #include <linux/slab.h>
178e685483SKrystian Garbaciak #include <linux/device.h>
188e685483SKrystian Garbaciak #include <linux/delay.h>
198e685483SKrystian Garbaciak #include <linux/interrupt.h>
208e685483SKrystian Garbaciak #include <linux/mutex.h>
218e685483SKrystian Garbaciak #include <linux/mfd/core.h>
228e685483SKrystian Garbaciak #include <linux/regmap.h>
238e685483SKrystian Garbaciak 
248e685483SKrystian Garbaciak #include <linux/mfd/da9063/core.h>
258e685483SKrystian Garbaciak #include <linux/mfd/da9063/registers.h>
268e685483SKrystian Garbaciak 
278e685483SKrystian Garbaciak #include <linux/proc_fs.h>
288e685483SKrystian Garbaciak #include <linux/kthread.h>
298e685483SKrystian Garbaciak #include <linux/uaccess.h>
308e685483SKrystian Garbaciak 
318e685483SKrystian Garbaciak 
32*a0fa0abeSRikard Falkeborn static const struct resource da9063_regulators_resources[] = {
33a0e08b86SKrystian Garbaciak 	{
34a0e08b86SKrystian Garbaciak 		.name	= "LDO_LIM",
35a0e08b86SKrystian Garbaciak 		.start	= DA9063_IRQ_LDO_LIM,
36a0e08b86SKrystian Garbaciak 		.end	= DA9063_IRQ_LDO_LIM,
37a0e08b86SKrystian Garbaciak 		.flags	= IORESOURCE_IRQ,
38a0e08b86SKrystian Garbaciak 	},
39a0e08b86SKrystian Garbaciak };
40a0e08b86SKrystian Garbaciak 
41*a0fa0abeSRikard Falkeborn static const struct resource da9063_rtc_resources[] = {
42a0e08b86SKrystian Garbaciak 	{
43a0e08b86SKrystian Garbaciak 		.name	= "ALARM",
44a0e08b86SKrystian Garbaciak 		.start	= DA9063_IRQ_ALARM,
45a0e08b86SKrystian Garbaciak 		.end	= DA9063_IRQ_ALARM,
46a0e08b86SKrystian Garbaciak 		.flags	= IORESOURCE_IRQ,
47a0e08b86SKrystian Garbaciak 	},
48a0e08b86SKrystian Garbaciak 	{
49a0e08b86SKrystian Garbaciak 		.name	= "TICK",
50a0e08b86SKrystian Garbaciak 		.start	= DA9063_IRQ_TICK,
51a0e08b86SKrystian Garbaciak 		.end	= DA9063_IRQ_TICK,
52a0e08b86SKrystian Garbaciak 		.flags	= IORESOURCE_IRQ,
53a0e08b86SKrystian Garbaciak 	}
54a0e08b86SKrystian Garbaciak };
55a0e08b86SKrystian Garbaciak 
56*a0fa0abeSRikard Falkeborn static const struct resource da9063_onkey_resources[] = {
57a0e08b86SKrystian Garbaciak 	{
589011e4a8SSteve Twiss 		.name	= "ONKEY",
59a0e08b86SKrystian Garbaciak 		.start	= DA9063_IRQ_ONKEY,
60a0e08b86SKrystian Garbaciak 		.end	= DA9063_IRQ_ONKEY,
61a0e08b86SKrystian Garbaciak 		.flags	= IORESOURCE_IRQ,
62a0e08b86SKrystian Garbaciak 	},
63a0e08b86SKrystian Garbaciak };
64a0e08b86SKrystian Garbaciak 
65*a0fa0abeSRikard Falkeborn static const struct resource da9063_hwmon_resources[] = {
66a0e08b86SKrystian Garbaciak 	{
67a0e08b86SKrystian Garbaciak 		.start	= DA9063_IRQ_ADC_RDY,
68a0e08b86SKrystian Garbaciak 		.end	= DA9063_IRQ_ADC_RDY,
69a0e08b86SKrystian Garbaciak 		.flags	= IORESOURCE_IRQ,
70a0e08b86SKrystian Garbaciak 	},
71a0e08b86SKrystian Garbaciak };
72a0e08b86SKrystian Garbaciak 
73a0e08b86SKrystian Garbaciak 
74c2ffec5eSMarek Vasut static const struct mfd_cell da9063_common_devs[] = {
758e685483SKrystian Garbaciak 	{
768e685483SKrystian Garbaciak 		.name		= DA9063_DRVNAME_REGULATORS,
77a0e08b86SKrystian Garbaciak 		.num_resources	= ARRAY_SIZE(da9063_regulators_resources),
78a0e08b86SKrystian Garbaciak 		.resources	= da9063_regulators_resources,
798e685483SKrystian Garbaciak 	},
808e685483SKrystian Garbaciak 	{
818e685483SKrystian Garbaciak 		.name		= DA9063_DRVNAME_LEDS,
828e685483SKrystian Garbaciak 	},
838e685483SKrystian Garbaciak 	{
848e685483SKrystian Garbaciak 		.name		= DA9063_DRVNAME_WATCHDOG,
8571e03de4SSteve Twiss 		.of_compatible	= "dlg,da9063-watchdog",
868e685483SKrystian Garbaciak 	},
878e685483SKrystian Garbaciak 	{
888e685483SKrystian Garbaciak 		.name		= DA9063_DRVNAME_HWMON,
89a0e08b86SKrystian Garbaciak 		.num_resources	= ARRAY_SIZE(da9063_hwmon_resources),
90a0e08b86SKrystian Garbaciak 		.resources	= da9063_hwmon_resources,
918e685483SKrystian Garbaciak 	},
928e685483SKrystian Garbaciak 	{
938e685483SKrystian Garbaciak 		.name		= DA9063_DRVNAME_ONKEY,
94a0e08b86SKrystian Garbaciak 		.num_resources	= ARRAY_SIZE(da9063_onkey_resources),
95a0e08b86SKrystian Garbaciak 		.resources	= da9063_onkey_resources,
969011e4a8SSteve Twiss 		.of_compatible = "dlg,da9063-onkey",
978e685483SKrystian Garbaciak 	},
988e685483SKrystian Garbaciak 	{
99c2ffec5eSMarek Vasut 		.name		= DA9063_DRVNAME_VIBRATION,
100c2ffec5eSMarek Vasut 	},
101c2ffec5eSMarek Vasut };
102c2ffec5eSMarek Vasut 
103c2ffec5eSMarek Vasut /* Only present on DA9063 , not on DA9063L */
104c2ffec5eSMarek Vasut static const struct mfd_cell da9063_devs[] = {
105c2ffec5eSMarek Vasut 	{
1068e685483SKrystian Garbaciak 		.name		= DA9063_DRVNAME_RTC,
107a0e08b86SKrystian Garbaciak 		.num_resources	= ARRAY_SIZE(da9063_rtc_resources),
108a0e08b86SKrystian Garbaciak 		.resources	= da9063_rtc_resources,
10971e03de4SSteve Twiss 		.of_compatible	= "dlg,da9063-rtc",
1108e685483SKrystian Garbaciak 	},
1118e685483SKrystian Garbaciak };
1128e685483SKrystian Garbaciak 
da9063_clear_fault_log(struct da9063 * da9063)1139011e4a8SSteve Twiss static int da9063_clear_fault_log(struct da9063 *da9063)
1149011e4a8SSteve Twiss {
1159011e4a8SSteve Twiss 	int ret = 0;
1169011e4a8SSteve Twiss 	int fault_log = 0;
1179011e4a8SSteve Twiss 
1189011e4a8SSteve Twiss 	ret = regmap_read(da9063->regmap, DA9063_REG_FAULT_LOG, &fault_log);
1199011e4a8SSteve Twiss 	if (ret < 0) {
1209011e4a8SSteve Twiss 		dev_err(da9063->dev, "Cannot read FAULT_LOG.\n");
1219011e4a8SSteve Twiss 		return -EIO;
1229011e4a8SSteve Twiss 	}
1239011e4a8SSteve Twiss 
1249011e4a8SSteve Twiss 	if (fault_log) {
1259011e4a8SSteve Twiss 		if (fault_log & DA9063_TWD_ERROR)
1269011e4a8SSteve Twiss 			dev_dbg(da9063->dev,
1279011e4a8SSteve Twiss 				"Fault log entry detected: DA9063_TWD_ERROR\n");
1289011e4a8SSteve Twiss 		if (fault_log & DA9063_POR)
1299011e4a8SSteve Twiss 			dev_dbg(da9063->dev,
1309011e4a8SSteve Twiss 				"Fault log entry detected: DA9063_POR\n");
1319011e4a8SSteve Twiss 		if (fault_log & DA9063_VDD_FAULT)
1329011e4a8SSteve Twiss 			dev_dbg(da9063->dev,
1339011e4a8SSteve Twiss 				"Fault log entry detected: DA9063_VDD_FAULT\n");
1349011e4a8SSteve Twiss 		if (fault_log & DA9063_VDD_START)
1359011e4a8SSteve Twiss 			dev_dbg(da9063->dev,
1369011e4a8SSteve Twiss 				"Fault log entry detected: DA9063_VDD_START\n");
1379011e4a8SSteve Twiss 		if (fault_log & DA9063_TEMP_CRIT)
1389011e4a8SSteve Twiss 			dev_dbg(da9063->dev,
1399011e4a8SSteve Twiss 				"Fault log entry detected: DA9063_TEMP_CRIT\n");
1409011e4a8SSteve Twiss 		if (fault_log & DA9063_KEY_RESET)
1419011e4a8SSteve Twiss 			dev_dbg(da9063->dev,
1429011e4a8SSteve Twiss 				"Fault log entry detected: DA9063_KEY_RESET\n");
1439011e4a8SSteve Twiss 		if (fault_log & DA9063_NSHUTDOWN)
1449011e4a8SSteve Twiss 			dev_dbg(da9063->dev,
1459011e4a8SSteve Twiss 				"Fault log entry detected: DA9063_NSHUTDOWN\n");
1469011e4a8SSteve Twiss 		if (fault_log & DA9063_WAIT_SHUT)
1479011e4a8SSteve Twiss 			dev_dbg(da9063->dev,
1489011e4a8SSteve Twiss 				"Fault log entry detected: DA9063_WAIT_SHUT\n");
1499011e4a8SSteve Twiss 	}
1509011e4a8SSteve Twiss 
1519011e4a8SSteve Twiss 	ret = regmap_write(da9063->regmap,
1529011e4a8SSteve Twiss 			   DA9063_REG_FAULT_LOG,
1539011e4a8SSteve Twiss 			   fault_log);
1549011e4a8SSteve Twiss 	if (ret < 0)
1559011e4a8SSteve Twiss 		dev_err(da9063->dev,
1569011e4a8SSteve Twiss 			"Cannot reset FAULT_LOG values %d\n", ret);
1579011e4a8SSteve Twiss 
1589011e4a8SSteve Twiss 	return ret;
1599011e4a8SSteve Twiss }
1609011e4a8SSteve Twiss 
da9063_device_init(struct da9063 * da9063,unsigned int irq)1618e685483SKrystian Garbaciak int da9063_device_init(struct da9063 *da9063, unsigned int irq)
1628e685483SKrystian Garbaciak {
1638e685483SKrystian Garbaciak 	int ret;
1648e685483SKrystian Garbaciak 
1659011e4a8SSteve Twiss 	ret = da9063_clear_fault_log(da9063);
1669011e4a8SSteve Twiss 	if (ret < 0)
1679011e4a8SSteve Twiss 		dev_err(da9063->dev, "Cannot clear fault log\n");
1689011e4a8SSteve Twiss 
1698e685483SKrystian Garbaciak 	da9063->flags = 0;
170439b8bddSDmitry Lavnikevich 	da9063->irq_base = -1;
1718e685483SKrystian Garbaciak 	da9063->chip_irq = irq;
1728e685483SKrystian Garbaciak 
173a0e08b86SKrystian Garbaciak 	ret = da9063_irq_init(da9063);
174a0e08b86SKrystian Garbaciak 	if (ret) {
175a0e08b86SKrystian Garbaciak 		dev_err(da9063->dev, "Cannot initialize interrupts.\n");
176a0e08b86SKrystian Garbaciak 		return ret;
177a0e08b86SKrystian Garbaciak 	}
178a0e08b86SKrystian Garbaciak 
179439b8bddSDmitry Lavnikevich 	da9063->irq_base = regmap_irq_chip_get_base(da9063->regmap_irq);
180439b8bddSDmitry Lavnikevich 
181152bed76SMarek Vasut 	ret = devm_mfd_add_devices(da9063->dev, PLATFORM_DEVID_NONE,
182c2ffec5eSMarek Vasut 				   da9063_common_devs,
183c2ffec5eSMarek Vasut 				   ARRAY_SIZE(da9063_common_devs),
184c2ffec5eSMarek Vasut 				   NULL, da9063->irq_base, NULL);
185c2ffec5eSMarek Vasut 	if (ret) {
186c2ffec5eSMarek Vasut 		dev_err(da9063->dev, "Failed to add child devices\n");
187c2ffec5eSMarek Vasut 		return ret;
188c2ffec5eSMarek Vasut 	}
189c2ffec5eSMarek Vasut 
190c2ffec5eSMarek Vasut 	if (da9063->type == PMIC_TYPE_DA9063) {
191c2ffec5eSMarek Vasut 		ret = devm_mfd_add_devices(da9063->dev, PLATFORM_DEVID_NONE,
192152bed76SMarek Vasut 					   da9063_devs, ARRAY_SIZE(da9063_devs),
193152bed76SMarek Vasut 					   NULL, da9063->irq_base, NULL);
194c2ffec5eSMarek Vasut 		if (ret) {
195c2ffec5eSMarek Vasut 			dev_err(da9063->dev, "Failed to add child devices\n");
196c2ffec5eSMarek Vasut 			return ret;
197c2ffec5eSMarek Vasut 		}
198c2ffec5eSMarek Vasut 	}
1998e685483SKrystian Garbaciak 
2008e685483SKrystian Garbaciak 	return ret;
2018e685483SKrystian Garbaciak }
2028e685483SKrystian Garbaciak 
2038e685483SKrystian Garbaciak MODULE_DESCRIPTION("PMIC driver for Dialog DA9063");
20437778d83SSteve Twiss MODULE_AUTHOR("Krystian Garbaciak");
20537778d83SSteve Twiss MODULE_AUTHOR("Michal Hajduk");
2068e685483SKrystian Garbaciak MODULE_LICENSE("GPL");
207