linux/drivers/mfd/da9055-core.c
<<
>>
Prefs
   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 struct resource da9055_onkey_resource = {
 258        .name = "ONKEY",
 259        .start = DA9055_IRQ_NONKEY,
 260        .end   = DA9055_IRQ_NONKEY,
 261        .flags = IORESOURCE_IRQ,
 262};
 263
 264static struct resource da9055_rtc_resource[] = {
 265        {
 266                .name = "ALM",
 267                .start = DA9055_IRQ_ALARM,
 268                .end   = DA9055_IRQ_ALARM,
 269                .flags = IORESOURCE_IRQ,
 270        },
 271        {
 272                .name = "TICK",
 273                .start = DA9055_IRQ_TICK,
 274                .end   = DA9055_IRQ_TICK,
 275                .flags = IORESOURCE_IRQ,
 276        },
 277};
 278
 279static struct resource da9055_hwmon_resource = {
 280        .name = "HWMON",
 281        .start = DA9055_IRQ_HWMON,
 282        .end   = DA9055_IRQ_HWMON,
 283        .flags = IORESOURCE_IRQ,
 284};
 285
 286static struct resource da9055_ld05_6_resource = {
 287        .name = "REGULATOR",
 288        .start = DA9055_IRQ_REGULATOR,
 289        .end   = DA9055_IRQ_REGULATOR,
 290        .flags = IORESOURCE_IRQ,
 291};
 292
 293static const struct mfd_cell da9055_devs[] = {
 294        {
 295                .of_compatible = "dlg,da9055-gpio",
 296                .name = "da9055-gpio",
 297        },
 298        {
 299                .of_compatible = "dlg,da9055-regulator",
 300                .name = "da9055-regulator",
 301                .id = 1,
 302        },
 303        {
 304                .of_compatible = "dlg,da9055-regulator",
 305                .name = "da9055-regulator",
 306                .id = 2,
 307        },
 308        {
 309                .of_compatible = "dlg,da9055-regulator",
 310                .name = "da9055-regulator",
 311                .id = 3,
 312        },
 313        {
 314                .of_compatible = "dlg,da9055-regulator",
 315                .name = "da9055-regulator",
 316                .id = 4,
 317        },
 318        {
 319                .of_compatible = "dlg,da9055-regulator",
 320                .name = "da9055-regulator",
 321                .id = 5,
 322        },
 323        {
 324                .of_compatible = "dlg,da9055-regulator",
 325                .name = "da9055-regulator",
 326                .id = 6,
 327        },
 328        {
 329                .of_compatible = "dlg,da9055-regulator",
 330                .name = "da9055-regulator",
 331                .id = 7,
 332                .resources = &da9055_ld05_6_resource,
 333                .num_resources = 1,
 334        },
 335        {
 336                .of_compatible = "dlg,da9055-regulator",
 337                .name = "da9055-regulator",
 338                .resources = &da9055_ld05_6_resource,
 339                .num_resources = 1,
 340                .id = 8,
 341        },
 342        {
 343                .of_compatible = "dlg,da9055-onkey",
 344                .name = "da9055-onkey",
 345                .resources = &da9055_onkey_resource,
 346                .num_resources = 1,
 347        },
 348        {
 349                .of_compatible = "dlg,da9055-rtc",
 350                .name = "da9055-rtc",
 351                .resources = da9055_rtc_resource,
 352                .num_resources = ARRAY_SIZE(da9055_rtc_resource),
 353        },
 354        {
 355                .of_compatible = "dlg,da9055-hwmon",
 356                .name = "da9055-hwmon",
 357                .resources = &da9055_hwmon_resource,
 358                .num_resources = 1,
 359        },
 360        {
 361                .of_compatible = "dlg,da9055-watchdog",
 362                .name = "da9055-watchdog",
 363        },
 364};
 365
 366static const struct regmap_irq_chip da9055_regmap_irq_chip = {
 367        .name = "da9055_irq",
 368        .status_base = DA9055_REG_EVENT_A,
 369        .mask_base = DA9055_REG_IRQ_MASK_A,
 370        .ack_base = DA9055_REG_EVENT_A,
 371        .num_regs = 3,
 372        .irqs = da9055_irqs,
 373        .num_irqs = ARRAY_SIZE(da9055_irqs),
 374};
 375
 376int da9055_device_init(struct da9055 *da9055)
 377{
 378        struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
 379        int ret;
 380        uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF};
 381
 382        if (pdata && pdata->init != NULL)
 383                pdata->init(da9055);
 384
 385        if (!pdata || !pdata->irq_base)
 386                da9055->irq_base = -1;
 387        else
 388                da9055->irq_base = pdata->irq_base;
 389
 390        ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events);
 391        if (ret < 0)
 392                return ret;
 393
 394        ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
 395                                  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 396                                  da9055->irq_base, &da9055_regmap_irq_chip,
 397                                  &da9055->irq_data);
 398        if (ret < 0)
 399                return ret;
 400
 401        da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data);
 402
 403        ret = mfd_add_devices(da9055->dev, -1,
 404                              da9055_devs, ARRAY_SIZE(da9055_devs),
 405                              NULL, da9055->irq_base, NULL);
 406        if (ret)
 407                goto err;
 408
 409        return 0;
 410
 411err:
 412        mfd_remove_devices(da9055->dev);
 413        return ret;
 414}
 415
 416void da9055_device_exit(struct da9055 *da9055)
 417{
 418        regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);
 419        mfd_remove_devices(da9055->dev);
 420}
 421
 422MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
 423MODULE_LICENSE("GPL");
 424MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
 425