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