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_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_RTC, 105 .num_resources = ARRAY_SIZE(da9063_rtc_resources), 106 .resources = da9063_rtc_resources, 107 .of_compatible = "dlg,da9063-rtc", 108 }, 109 { 110 .name = DA9063_DRVNAME_VIBRATION, 111 }, 112 }; 113 114 static int da9063_clear_fault_log(struct da9063 *da9063) 115 { 116 int ret = 0; 117 int fault_log = 0; 118 119 ret = regmap_read(da9063->regmap, DA9063_REG_FAULT_LOG, &fault_log); 120 if (ret < 0) { 121 dev_err(da9063->dev, "Cannot read FAULT_LOG.\n"); 122 return -EIO; 123 } 124 125 if (fault_log) { 126 if (fault_log & DA9063_TWD_ERROR) 127 dev_dbg(da9063->dev, 128 "Fault log entry detected: DA9063_TWD_ERROR\n"); 129 if (fault_log & DA9063_POR) 130 dev_dbg(da9063->dev, 131 "Fault log entry detected: DA9063_POR\n"); 132 if (fault_log & DA9063_VDD_FAULT) 133 dev_dbg(da9063->dev, 134 "Fault log entry detected: DA9063_VDD_FAULT\n"); 135 if (fault_log & DA9063_VDD_START) 136 dev_dbg(da9063->dev, 137 "Fault log entry detected: DA9063_VDD_START\n"); 138 if (fault_log & DA9063_TEMP_CRIT) 139 dev_dbg(da9063->dev, 140 "Fault log entry detected: DA9063_TEMP_CRIT\n"); 141 if (fault_log & DA9063_KEY_RESET) 142 dev_dbg(da9063->dev, 143 "Fault log entry detected: DA9063_KEY_RESET\n"); 144 if (fault_log & DA9063_NSHUTDOWN) 145 dev_dbg(da9063->dev, 146 "Fault log entry detected: DA9063_NSHUTDOWN\n"); 147 if (fault_log & DA9063_WAIT_SHUT) 148 dev_dbg(da9063->dev, 149 "Fault log entry detected: DA9063_WAIT_SHUT\n"); 150 } 151 152 ret = regmap_write(da9063->regmap, 153 DA9063_REG_FAULT_LOG, 154 fault_log); 155 if (ret < 0) 156 dev_err(da9063->dev, 157 "Cannot reset FAULT_LOG values %d\n", ret); 158 159 return ret; 160 } 161 162 int da9063_device_init(struct da9063 *da9063, unsigned int irq) 163 { 164 struct da9063_pdata *pdata = da9063->dev->platform_data; 165 int model, variant_id, variant_code; 166 int ret; 167 168 ret = da9063_clear_fault_log(da9063); 169 if (ret < 0) 170 dev_err(da9063->dev, "Cannot clear fault log\n"); 171 172 if (pdata) { 173 da9063->flags = pdata->flags; 174 da9063->irq_base = pdata->irq_base; 175 } else { 176 da9063->flags = 0; 177 da9063->irq_base = -1; 178 } 179 da9063->chip_irq = irq; 180 181 if (pdata && pdata->init != NULL) { 182 ret = pdata->init(da9063); 183 if (ret != 0) { 184 dev_err(da9063->dev, 185 "Platform initialization failed.\n"); 186 return ret; 187 } 188 } 189 190 ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model); 191 if (ret < 0) { 192 dev_err(da9063->dev, "Cannot read chip model id.\n"); 193 return -EIO; 194 } 195 if (model != PMIC_DA9063) { 196 dev_err(da9063->dev, "Invalid chip model id: 0x%02x\n", model); 197 return -ENODEV; 198 } 199 200 ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &variant_id); 201 if (ret < 0) { 202 dev_err(da9063->dev, "Cannot read chip variant id.\n"); 203 return -EIO; 204 } 205 206 variant_code = variant_id >> DA9063_CHIP_VARIANT_SHIFT; 207 208 dev_info(da9063->dev, 209 "Device detected (chip-ID: 0x%02X, var-ID: 0x%02X)\n", 210 model, variant_id); 211 212 if (variant_code < PMIC_DA9063_BB && variant_code != PMIC_DA9063_AD) { 213 dev_err(da9063->dev, 214 "Cannot support variant code: 0x%02X\n", variant_code); 215 return -ENODEV; 216 } 217 218 da9063->model = model; 219 da9063->variant_code = variant_code; 220 221 ret = da9063_irq_init(da9063); 222 if (ret) { 223 dev_err(da9063->dev, "Cannot initialize interrupts.\n"); 224 return ret; 225 } 226 227 da9063->irq_base = regmap_irq_chip_get_base(da9063->regmap_irq); 228 229 ret = mfd_add_devices(da9063->dev, -1, da9063_devs, 230 ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base, 231 NULL); 232 if (ret) 233 dev_err(da9063->dev, "Cannot add MFD cells\n"); 234 235 return ret; 236 } 237 238 void da9063_device_exit(struct da9063 *da9063) 239 { 240 mfd_remove_devices(da9063->dev); 241 da9063_irq_exit(da9063); 242 } 243 244 MODULE_DESCRIPTION("PMIC driver for Dialog DA9063"); 245 MODULE_AUTHOR("Krystian Garbaciak"); 246 MODULE_AUTHOR("Michal Hajduk"); 247 MODULE_LICENSE("GPL"); 248