da9055-core.c (9432B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Device access for Dialog DA9055 PMICs. 4 * 5 * Copyright(c) 2012 Dialog Semiconductor Ltd. 6 * 7 * Author: David Dajun Chen <dchen@diasemi.com> 8 */ 9 10#include <linux/module.h> 11#include <linux/device.h> 12#include <linux/input.h> 13#include <linux/irq.h> 14#include <linux/mutex.h> 15 16#include <linux/mfd/core.h> 17#include <linux/mfd/da9055/core.h> 18#include <linux/mfd/da9055/pdata.h> 19#include <linux/mfd/da9055/reg.h> 20 21#define DA9055_IRQ_NONKEY_MASK 0x01 22#define DA9055_IRQ_ALM_MASK 0x02 23#define DA9055_IRQ_TICK_MASK 0x04 24#define DA9055_IRQ_ADC_MASK 0x08 25#define DA9055_IRQ_BUCK_ILIM_MASK 0x08 26 27static bool da9055_register_readable(struct device *dev, unsigned int reg) 28{ 29 switch (reg) { 30 case DA9055_REG_STATUS_A: 31 case DA9055_REG_STATUS_B: 32 case DA9055_REG_EVENT_A: 33 case DA9055_REG_EVENT_B: 34 case DA9055_REG_EVENT_C: 35 case DA9055_REG_IRQ_MASK_A: 36 case DA9055_REG_IRQ_MASK_B: 37 case DA9055_REG_IRQ_MASK_C: 38 39 case DA9055_REG_CONTROL_A: 40 case DA9055_REG_CONTROL_B: 41 case DA9055_REG_CONTROL_C: 42 case DA9055_REG_CONTROL_D: 43 case DA9055_REG_CONTROL_E: 44 45 case DA9055_REG_ADC_MAN: 46 case DA9055_REG_ADC_CONT: 47 case DA9055_REG_VSYS_MON: 48 case DA9055_REG_ADC_RES_L: 49 case DA9055_REG_ADC_RES_H: 50 case DA9055_REG_VSYS_RES: 51 case DA9055_REG_ADCIN1_RES: 52 case DA9055_REG_ADCIN2_RES: 53 case DA9055_REG_ADCIN3_RES: 54 55 case DA9055_REG_COUNT_S: 56 case DA9055_REG_COUNT_MI: 57 case DA9055_REG_COUNT_H: 58 case DA9055_REG_COUNT_D: 59 case DA9055_REG_COUNT_MO: 60 case DA9055_REG_COUNT_Y: 61 case DA9055_REG_ALARM_H: 62 case DA9055_REG_ALARM_D: 63 case DA9055_REG_ALARM_MI: 64 case DA9055_REG_ALARM_MO: 65 case DA9055_REG_ALARM_Y: 66 67 case DA9055_REG_GPIO0_1: 68 case DA9055_REG_GPIO2: 69 case DA9055_REG_GPIO_MODE0_2: 70 71 case DA9055_REG_BCORE_CONT: 72 case DA9055_REG_BMEM_CONT: 73 case DA9055_REG_LDO1_CONT: 74 case DA9055_REG_LDO2_CONT: 75 case DA9055_REG_LDO3_CONT: 76 case DA9055_REG_LDO4_CONT: 77 case DA9055_REG_LDO5_CONT: 78 case DA9055_REG_LDO6_CONT: 79 case DA9055_REG_BUCK_LIM: 80 case DA9055_REG_BCORE_MODE: 81 case DA9055_REG_VBCORE_A: 82 case DA9055_REG_VBMEM_A: 83 case DA9055_REG_VLDO1_A: 84 case DA9055_REG_VLDO2_A: 85 case DA9055_REG_VLDO3_A: 86 case DA9055_REG_VLDO4_A: 87 case DA9055_REG_VLDO5_A: 88 case DA9055_REG_VLDO6_A: 89 case DA9055_REG_VBCORE_B: 90 case DA9055_REG_VBMEM_B: 91 case DA9055_REG_VLDO1_B: 92 case DA9055_REG_VLDO2_B: 93 case DA9055_REG_VLDO3_B: 94 case DA9055_REG_VLDO4_B: 95 case DA9055_REG_VLDO5_B: 96 case DA9055_REG_VLDO6_B: 97 return true; 98 default: 99 return false; 100 } 101} 102 103static bool da9055_register_writeable(struct device *dev, unsigned int reg) 104{ 105 switch (reg) { 106 case DA9055_REG_STATUS_A: 107 case DA9055_REG_STATUS_B: 108 case DA9055_REG_EVENT_A: 109 case DA9055_REG_EVENT_B: 110 case DA9055_REG_EVENT_C: 111 case DA9055_REG_IRQ_MASK_A: 112 case DA9055_REG_IRQ_MASK_B: 113 case DA9055_REG_IRQ_MASK_C: 114 115 case DA9055_REG_CONTROL_A: 116 case DA9055_REG_CONTROL_B: 117 case DA9055_REG_CONTROL_C: 118 case DA9055_REG_CONTROL_D: 119 case DA9055_REG_CONTROL_E: 120 121 case DA9055_REG_ADC_MAN: 122 case DA9055_REG_ADC_CONT: 123 case DA9055_REG_VSYS_MON: 124 case DA9055_REG_ADC_RES_L: 125 case DA9055_REG_ADC_RES_H: 126 case DA9055_REG_VSYS_RES: 127 case DA9055_REG_ADCIN1_RES: 128 case DA9055_REG_ADCIN2_RES: 129 case DA9055_REG_ADCIN3_RES: 130 131 case DA9055_REG_COUNT_S: 132 case DA9055_REG_COUNT_MI: 133 case DA9055_REG_COUNT_H: 134 case DA9055_REG_COUNT_D: 135 case DA9055_REG_COUNT_MO: 136 case DA9055_REG_COUNT_Y: 137 case DA9055_REG_ALARM_H: 138 case DA9055_REG_ALARM_D: 139 case DA9055_REG_ALARM_MI: 140 case DA9055_REG_ALARM_MO: 141 case DA9055_REG_ALARM_Y: 142 143 case DA9055_REG_GPIO0_1: 144 case DA9055_REG_GPIO2: 145 case DA9055_REG_GPIO_MODE0_2: 146 147 case DA9055_REG_BCORE_CONT: 148 case DA9055_REG_BMEM_CONT: 149 case DA9055_REG_LDO1_CONT: 150 case DA9055_REG_LDO2_CONT: 151 case DA9055_REG_LDO3_CONT: 152 case DA9055_REG_LDO4_CONT: 153 case DA9055_REG_LDO5_CONT: 154 case DA9055_REG_LDO6_CONT: 155 case DA9055_REG_BUCK_LIM: 156 case DA9055_REG_BCORE_MODE: 157 case DA9055_REG_VBCORE_A: 158 case DA9055_REG_VBMEM_A: 159 case DA9055_REG_VLDO1_A: 160 case DA9055_REG_VLDO2_A: 161 case DA9055_REG_VLDO3_A: 162 case DA9055_REG_VLDO4_A: 163 case DA9055_REG_VLDO5_A: 164 case DA9055_REG_VLDO6_A: 165 case DA9055_REG_VBCORE_B: 166 case DA9055_REG_VBMEM_B: 167 case DA9055_REG_VLDO1_B: 168 case DA9055_REG_VLDO2_B: 169 case DA9055_REG_VLDO3_B: 170 case DA9055_REG_VLDO4_B: 171 case DA9055_REG_VLDO5_B: 172 case DA9055_REG_VLDO6_B: 173 return true; 174 default: 175 return false; 176 } 177} 178 179static bool da9055_register_volatile(struct device *dev, unsigned int reg) 180{ 181 switch (reg) { 182 case DA9055_REG_STATUS_A: 183 case DA9055_REG_STATUS_B: 184 case DA9055_REG_EVENT_A: 185 case DA9055_REG_EVENT_B: 186 case DA9055_REG_EVENT_C: 187 188 case DA9055_REG_CONTROL_A: 189 case DA9055_REG_CONTROL_E: 190 191 case DA9055_REG_ADC_MAN: 192 case DA9055_REG_ADC_RES_L: 193 case DA9055_REG_ADC_RES_H: 194 case DA9055_REG_VSYS_RES: 195 case DA9055_REG_ADCIN1_RES: 196 case DA9055_REG_ADCIN2_RES: 197 case DA9055_REG_ADCIN3_RES: 198 199 case DA9055_REG_COUNT_S: 200 case DA9055_REG_COUNT_MI: 201 case DA9055_REG_COUNT_H: 202 case DA9055_REG_COUNT_D: 203 case DA9055_REG_COUNT_MO: 204 case DA9055_REG_COUNT_Y: 205 case DA9055_REG_ALARM_MI: 206 207 case DA9055_REG_BCORE_CONT: 208 case DA9055_REG_BMEM_CONT: 209 case DA9055_REG_LDO1_CONT: 210 case DA9055_REG_LDO2_CONT: 211 case DA9055_REG_LDO3_CONT: 212 case DA9055_REG_LDO4_CONT: 213 case DA9055_REG_LDO5_CONT: 214 case DA9055_REG_LDO6_CONT: 215 return true; 216 default: 217 return false; 218 } 219} 220 221static const struct regmap_irq da9055_irqs[] = { 222 [DA9055_IRQ_NONKEY] = { 223 .reg_offset = 0, 224 .mask = DA9055_IRQ_NONKEY_MASK, 225 }, 226 [DA9055_IRQ_ALARM] = { 227 .reg_offset = 0, 228 .mask = DA9055_IRQ_ALM_MASK, 229 }, 230 [DA9055_IRQ_TICK] = { 231 .reg_offset = 0, 232 .mask = DA9055_IRQ_TICK_MASK, 233 }, 234 [DA9055_IRQ_HWMON] = { 235 .reg_offset = 0, 236 .mask = DA9055_IRQ_ADC_MASK, 237 }, 238 [DA9055_IRQ_REGULATOR] = { 239 .reg_offset = 1, 240 .mask = DA9055_IRQ_BUCK_ILIM_MASK, 241 }, 242}; 243 244const struct regmap_config da9055_regmap_config = { 245 .reg_bits = 8, 246 .val_bits = 8, 247 248 .cache_type = REGCACHE_RBTREE, 249 250 .max_register = DA9055_MAX_REGISTER_CNT, 251 .readable_reg = da9055_register_readable, 252 .writeable_reg = da9055_register_writeable, 253 .volatile_reg = da9055_register_volatile, 254}; 255EXPORT_SYMBOL_GPL(da9055_regmap_config); 256 257static const struct resource da9055_onkey_resource = 258 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_NONKEY, "ONKEY"); 259 260static const struct resource da9055_rtc_resource[] = { 261 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_ALARM, "ALM"), 262 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_TICK, "TICK"), 263}; 264 265static const struct resource da9055_hwmon_resource = 266 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_HWMON, "HWMON"); 267 268static const struct resource da9055_ld05_6_resource = 269 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_REGULATOR, "REGULATOR"); 270 271static const struct mfd_cell da9055_devs[] = { 272 { 273 .of_compatible = "dlg,da9055-gpio", 274 .name = "da9055-gpio", 275 }, 276 { 277 .of_compatible = "dlg,da9055-regulator", 278 .name = "da9055-regulator", 279 .id = 1, 280 }, 281 { 282 .of_compatible = "dlg,da9055-regulator", 283 .name = "da9055-regulator", 284 .id = 2, 285 }, 286 { 287 .of_compatible = "dlg,da9055-regulator", 288 .name = "da9055-regulator", 289 .id = 3, 290 }, 291 { 292 .of_compatible = "dlg,da9055-regulator", 293 .name = "da9055-regulator", 294 .id = 4, 295 }, 296 { 297 .of_compatible = "dlg,da9055-regulator", 298 .name = "da9055-regulator", 299 .id = 5, 300 }, 301 { 302 .of_compatible = "dlg,da9055-regulator", 303 .name = "da9055-regulator", 304 .id = 6, 305 }, 306 { 307 .of_compatible = "dlg,da9055-regulator", 308 .name = "da9055-regulator", 309 .id = 7, 310 .resources = &da9055_ld05_6_resource, 311 .num_resources = 1, 312 }, 313 { 314 .of_compatible = "dlg,da9055-regulator", 315 .name = "da9055-regulator", 316 .resources = &da9055_ld05_6_resource, 317 .num_resources = 1, 318 .id = 8, 319 }, 320 { 321 .of_compatible = "dlg,da9055-onkey", 322 .name = "da9055-onkey", 323 .resources = &da9055_onkey_resource, 324 .num_resources = 1, 325 }, 326 { 327 .of_compatible = "dlg,da9055-rtc", 328 .name = "da9055-rtc", 329 .resources = da9055_rtc_resource, 330 .num_resources = ARRAY_SIZE(da9055_rtc_resource), 331 }, 332 { 333 .of_compatible = "dlg,da9055-hwmon", 334 .name = "da9055-hwmon", 335 .resources = &da9055_hwmon_resource, 336 .num_resources = 1, 337 }, 338 { 339 .of_compatible = "dlg,da9055-watchdog", 340 .name = "da9055-watchdog", 341 }, 342}; 343 344static const struct regmap_irq_chip da9055_regmap_irq_chip = { 345 .name = "da9055_irq", 346 .status_base = DA9055_REG_EVENT_A, 347 .mask_base = DA9055_REG_IRQ_MASK_A, 348 .ack_base = DA9055_REG_EVENT_A, 349 .num_regs = 3, 350 .irqs = da9055_irqs, 351 .num_irqs = ARRAY_SIZE(da9055_irqs), 352}; 353 354int da9055_device_init(struct da9055 *da9055) 355{ 356 struct da9055_pdata *pdata = dev_get_platdata(da9055->dev); 357 int ret; 358 uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF}; 359 360 if (pdata && pdata->init != NULL) 361 pdata->init(da9055); 362 363 if (!pdata || !pdata->irq_base) 364 da9055->irq_base = -1; 365 else 366 da9055->irq_base = pdata->irq_base; 367 368 ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events); 369 if (ret < 0) 370 return ret; 371 372 ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, 373 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 374 da9055->irq_base, &da9055_regmap_irq_chip, 375 &da9055->irq_data); 376 if (ret < 0) 377 return ret; 378 379 da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data); 380 381 ret = mfd_add_devices(da9055->dev, -1, 382 da9055_devs, ARRAY_SIZE(da9055_devs), 383 NULL, da9055->irq_base, NULL); 384 if (ret) 385 goto err; 386 387 return 0; 388 389err: 390 mfd_remove_devices(da9055->dev); 391 return ret; 392} 393 394void da9055_device_exit(struct da9055 *da9055) 395{ 396 regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data); 397 mfd_remove_devices(da9055->dev); 398} 399 400MODULE_DESCRIPTION("Core support for the DA9055 PMIC"); 401MODULE_LICENSE("GPL"); 402MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");