linux/drivers/mfd/da9055-core.c
<<
>>
Prefs
   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