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 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>");
 403