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