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, Dialog Semiconductor 8 * Author: Michal Hajduk, Dialog Semiconductor 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 37 static 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 46 static 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 61 static struct resource da9063_onkey_resources[] = { 62 { 63 .name = "ONKEY", 64 .start = DA9063_IRQ_ONKEY, 65 .end = DA9063_IRQ_ONKEY, 66 .flags = IORESOURCE_IRQ, 67 }, 68 }; 69 70 static struct resource da9063_hwmon_resources[] = { 71 { 72 .start = DA9063_IRQ_ADC_RDY, 73 .end = DA9063_IRQ_ADC_RDY, 74 .flags = IORESOURCE_IRQ, 75 }, 76 }; 77 78 79 static const struct mfd_cell da9063_common_devs[] = { 80 { 81 .name = DA9063_DRVNAME_REGULATORS, 82 .num_resources = ARRAY_SIZE(da9063_regulators_resources), 83 .resources = da9063_regulators_resources, 84 }, 85 { 86 .name = DA9063_DRVNAME_LEDS, 87 }, 88 { 89 .name = DA9063_DRVNAME_WATCHDOG, 90 .of_compatible = "dlg,da9063-watchdog", 91 }, 92 { 93 .name = DA9063_DRVNAME_HWMON, 94 .num_resources = ARRAY_SIZE(da9063_hwmon_resources), 95 .resources = da9063_hwmon_resources, 96 }, 97 { 98 .name = DA9063_DRVNAME_ONKEY, 99 .num_resources = ARRAY_SIZE(da9063_onkey_resources), 100 .resources = da9063_onkey_resources, 101 .of_compatible = "dlg,da9063-onkey", 102 }, 103 { 104 .name = DA9063_DRVNAME_VIBRATION, 105 }, 106 }; 107 108 /* Only present on DA9063 , not on DA9063L */ 109 static const struct mfd_cell da9063_devs[] = { 110 { 111 .name = DA9063_DRVNAME_RTC, 112 .num_resources = ARRAY_SIZE(da9063_rtc_resources), 113 .resources = da9063_rtc_resources, 114 .of_compatible = "dlg,da9063-rtc", 115 }, 116 }; 117 118 static int da9063_clear_fault_log(struct da9063 *da9063) 119 { 120 int ret = 0; 121 int fault_log = 0; 122 123 ret = regmap_read(da9063->regmap, DA9063_REG_FAULT_LOG, &fault_log); 124 if (ret < 0) { 125 dev_err(da9063->dev, "Cannot read FAULT_LOG.\n"); 126 return -EIO; 127 } 128 129 if (fault_log) { 130 if (fault_log & DA9063_TWD_ERROR) 131 dev_dbg(da9063->dev, 132 "Fault log entry detected: DA9063_TWD_ERROR\n"); 133 if (fault_log & DA9063_POR) 134 dev_dbg(da9063->dev, 135 "Fault log entry detected: DA9063_POR\n"); 136 if (fault_log & DA9063_VDD_FAULT) 137 dev_dbg(da9063->dev, 138 "Fault log entry detected: DA9063_VDD_FAULT\n"); 139 if (fault_log & DA9063_VDD_START) 140 dev_dbg(da9063->dev, 141 "Fault log entry detected: DA9063_VDD_START\n"); 142 if (fault_log & DA9063_TEMP_CRIT) 143 dev_dbg(da9063->dev, 144 "Fault log entry detected: DA9063_TEMP_CRIT\n"); 145 if (fault_log & DA9063_KEY_RESET) 146 dev_dbg(da9063->dev, 147 "Fault log entry detected: DA9063_KEY_RESET\n"); 148 if (fault_log & DA9063_NSHUTDOWN) 149 dev_dbg(da9063->dev, 150 "Fault log entry detected: DA9063_NSHUTDOWN\n"); 151 if (fault_log & DA9063_WAIT_SHUT) 152 dev_dbg(da9063->dev, 153 "Fault log entry detected: DA9063_WAIT_SHUT\n"); 154 } 155 156 ret = regmap_write(da9063->regmap, 157 DA9063_REG_FAULT_LOG, 158 fault_log); 159 if (ret < 0) 160 dev_err(da9063->dev, 161 "Cannot reset FAULT_LOG values %d\n", ret); 162 163 return ret; 164 } 165 166 int da9063_device_init(struct da9063 *da9063, unsigned int irq) 167 { 168 struct da9063_pdata *pdata = da9063->dev->platform_data; 169 int model, variant_id, variant_code; 170 int ret; 171 172 ret = da9063_clear_fault_log(da9063); 173 if (ret < 0) 174 dev_err(da9063->dev, "Cannot clear fault log\n"); 175 176 if (pdata) { 177 da9063->flags = pdata->flags; 178 da9063->irq_base = pdata->irq_base; 179 } else { 180 da9063->flags = 0; 181 da9063->irq_base = -1; 182 } 183 da9063->chip_irq = irq; 184 185 if (pdata && pdata->init != NULL) { 186 ret = pdata->init(da9063); 187 if (ret != 0) { 188 dev_err(da9063->dev, 189 "Platform initialization failed.\n"); 190 return ret; 191 } 192 } 193 194 ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model); 195 if (ret < 0) { 196 dev_err(da9063->dev, "Cannot read chip model id.\n"); 197 return -EIO; 198 } 199 if (model != PMIC_CHIP_ID_DA9063) { 200 dev_err(da9063->dev, "Invalid chip model id: 0x%02x\n", model); 201 return -ENODEV; 202 } 203 204 ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &variant_id); 205 if (ret < 0) { 206 dev_err(da9063->dev, "Cannot read chip variant id.\n"); 207 return -EIO; 208 } 209 210 variant_code = variant_id >> DA9063_CHIP_VARIANT_SHIFT; 211 212 dev_info(da9063->dev, 213 "Device detected (chip-ID: 0x%02X, var-ID: 0x%02X)\n", 214 model, variant_id); 215 216 if (variant_code < PMIC_DA9063_BB && variant_code != PMIC_DA9063_AD) { 217 dev_err(da9063->dev, 218 "Cannot support variant code: 0x%02X\n", variant_code); 219 return -ENODEV; 220 } 221 222 da9063->variant_code = variant_code; 223 224 ret = da9063_irq_init(da9063); 225 if (ret) { 226 dev_err(da9063->dev, "Cannot initialize interrupts.\n"); 227 return ret; 228 } 229 230 da9063->irq_base = regmap_irq_chip_get_base(da9063->regmap_irq); 231 232 ret = devm_mfd_add_devices(da9063->dev, PLATFORM_DEVID_NONE, 233 da9063_common_devs, 234 ARRAY_SIZE(da9063_common_devs), 235 NULL, da9063->irq_base, NULL); 236 if (ret) { 237 dev_err(da9063->dev, "Failed to add child devices\n"); 238 return ret; 239 } 240 241 if (da9063->type == PMIC_TYPE_DA9063) { 242 ret = devm_mfd_add_devices(da9063->dev, PLATFORM_DEVID_NONE, 243 da9063_devs, ARRAY_SIZE(da9063_devs), 244 NULL, da9063->irq_base, NULL); 245 if (ret) { 246 dev_err(da9063->dev, "Failed to add child devices\n"); 247 return ret; 248 } 249 } 250 251 return ret; 252 } 253 254 MODULE_DESCRIPTION("PMIC driver for Dialog DA9063"); 255 MODULE_AUTHOR("Krystian Garbaciak"); 256 MODULE_AUTHOR("Michal Hajduk"); 257 MODULE_LICENSE("GPL"); 258