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