linux/drivers/mfd/bd9571mwv.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * ROHM BD9571MWV-M and BD9574MVF-M core driver
   4 *
   5 * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
   6 * Copyright (C) 2020 Renesas Electronics Corporation
   7 *
   8 * Based on the TPS65086 driver
   9 */
  10
  11#include <linux/i2c.h>
  12#include <linux/interrupt.h>
  13#include <linux/mfd/core.h>
  14#include <linux/mfd/rohm-generic.h>
  15#include <linux/module.h>
  16
  17#include <linux/mfd/bd9571mwv.h>
  18
  19static const struct mfd_cell bd9571mwv_cells[] = {
  20        { .name = "bd9571mwv-regulator", },
  21        { .name = "bd9571mwv-gpio", },
  22};
  23
  24static const struct regmap_range bd9571mwv_readable_yes_ranges[] = {
  25        regmap_reg_range(BD9571MWV_VENDOR_CODE, BD9571MWV_PRODUCT_REVISION),
  26        regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT),
  27        regmap_reg_range(BD9571MWV_AVS_SET_MONI, BD9571MWV_AVS_DVFS_VID(3)),
  28        regmap_reg_range(BD9571MWV_VD18_VID, BD9571MWV_VD33_VID),
  29        regmap_reg_range(BD9571MWV_DVFS_VINIT, BD9571MWV_DVFS_VINIT),
  30        regmap_reg_range(BD9571MWV_DVFS_SETVMAX, BD9571MWV_DVFS_MONIVDAC),
  31        regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN),
  32        regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INTMASK),
  33        regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK),
  34};
  35
  36static const struct regmap_access_table bd9571mwv_readable_table = {
  37        .yes_ranges     = bd9571mwv_readable_yes_ranges,
  38        .n_yes_ranges   = ARRAY_SIZE(bd9571mwv_readable_yes_ranges),
  39};
  40
  41static const struct regmap_range bd9571mwv_writable_yes_ranges[] = {
  42        regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT),
  43        regmap_reg_range(BD9571MWV_AVS_VD09_VID(0), BD9571MWV_AVS_VD09_VID(3)),
  44        regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_SETVID),
  45        regmap_reg_range(BD9571MWV_GPIO_DIR, BD9571MWV_GPIO_OUT),
  46        regmap_reg_range(BD9571MWV_GPIO_INT_SET, BD9571MWV_GPIO_INTMASK),
  47        regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK),
  48};
  49
  50static const struct regmap_access_table bd9571mwv_writable_table = {
  51        .yes_ranges     = bd9571mwv_writable_yes_ranges,
  52        .n_yes_ranges   = ARRAY_SIZE(bd9571mwv_writable_yes_ranges),
  53};
  54
  55static const struct regmap_range bd9571mwv_volatile_yes_ranges[] = {
  56        regmap_reg_range(BD9571MWV_DVFS_MONIVDAC, BD9571MWV_DVFS_MONIVDAC),
  57        regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN),
  58        regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INT),
  59        regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTREQ),
  60};
  61
  62static const struct regmap_access_table bd9571mwv_volatile_table = {
  63        .yes_ranges     = bd9571mwv_volatile_yes_ranges,
  64        .n_yes_ranges   = ARRAY_SIZE(bd9571mwv_volatile_yes_ranges),
  65};
  66
  67static const struct regmap_config bd9571mwv_regmap_config = {
  68        .reg_bits       = 8,
  69        .val_bits       = 8,
  70        .cache_type     = REGCACHE_RBTREE,
  71        .rd_table       = &bd9571mwv_readable_table,
  72        .wr_table       = &bd9571mwv_writable_table,
  73        .volatile_table = &bd9571mwv_volatile_table,
  74        .max_register   = 0xff,
  75};
  76
  77static const struct regmap_irq bd9571mwv_irqs[] = {
  78        REGMAP_IRQ_REG(BD9571MWV_IRQ_MD1, 0,
  79                       BD9571MWV_INT_INTREQ_MD1_INT),
  80        REGMAP_IRQ_REG(BD9571MWV_IRQ_MD2_E1, 0,
  81                       BD9571MWV_INT_INTREQ_MD2_E1_INT),
  82        REGMAP_IRQ_REG(BD9571MWV_IRQ_MD2_E2, 0,
  83                       BD9571MWV_INT_INTREQ_MD2_E2_INT),
  84        REGMAP_IRQ_REG(BD9571MWV_IRQ_PROT_ERR, 0,
  85                       BD9571MWV_INT_INTREQ_PROT_ERR_INT),
  86        REGMAP_IRQ_REG(BD9571MWV_IRQ_GP, 0,
  87                       BD9571MWV_INT_INTREQ_GP_INT),
  88        REGMAP_IRQ_REG(BD9571MWV_IRQ_128H_OF, 0,
  89                       BD9571MWV_INT_INTREQ_128H_OF_INT),
  90        REGMAP_IRQ_REG(BD9571MWV_IRQ_WDT_OF, 0,
  91                       BD9571MWV_INT_INTREQ_WDT_OF_INT),
  92        REGMAP_IRQ_REG(BD9571MWV_IRQ_BKUP_TRG, 0,
  93                       BD9571MWV_INT_INTREQ_BKUP_TRG_INT),
  94};
  95
  96static struct regmap_irq_chip bd9571mwv_irq_chip = {
  97        .name           = "bd9571mwv",
  98        .status_base    = BD9571MWV_INT_INTREQ,
  99        .mask_base      = BD9571MWV_INT_INTMASK,
 100        .ack_base       = BD9571MWV_INT_INTREQ,
 101        .init_ack_masked = true,
 102        .num_regs       = 1,
 103        .irqs           = bd9571mwv_irqs,
 104        .num_irqs       = ARRAY_SIZE(bd9571mwv_irqs),
 105};
 106
 107static const struct mfd_cell bd9574mwf_cells[] = {
 108        { .name = "bd9574mwf-regulator", },
 109        { .name = "bd9574mwf-gpio", },
 110};
 111
 112static const struct regmap_range bd9574mwf_readable_yes_ranges[] = {
 113        regmap_reg_range(BD9571MWV_VENDOR_CODE, BD9571MWV_PRODUCT_REVISION),
 114        regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT),
 115        regmap_reg_range(BD9571MWV_DVFS_VINIT, BD9571MWV_DVFS_SETVMAX),
 116        regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_MONIVDAC),
 117        regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN),
 118        regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INTMASK),
 119        regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK),
 120};
 121
 122static const struct regmap_access_table bd9574mwf_readable_table = {
 123        .yes_ranges     = bd9574mwf_readable_yes_ranges,
 124        .n_yes_ranges   = ARRAY_SIZE(bd9574mwf_readable_yes_ranges),
 125};
 126
 127static const struct regmap_range bd9574mwf_writable_yes_ranges[] = {
 128        regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT),
 129        regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_SETVID),
 130        regmap_reg_range(BD9571MWV_GPIO_DIR, BD9571MWV_GPIO_OUT),
 131        regmap_reg_range(BD9571MWV_GPIO_INT_SET, BD9571MWV_GPIO_INTMASK),
 132        regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK),
 133};
 134
 135static const struct regmap_access_table bd9574mwf_writable_table = {
 136        .yes_ranges     = bd9574mwf_writable_yes_ranges,
 137        .n_yes_ranges   = ARRAY_SIZE(bd9574mwf_writable_yes_ranges),
 138};
 139
 140static const struct regmap_range bd9574mwf_volatile_yes_ranges[] = {
 141        regmap_reg_range(BD9571MWV_DVFS_MONIVDAC, BD9571MWV_DVFS_MONIVDAC),
 142        regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN),
 143        regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INT),
 144        regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTREQ),
 145};
 146
 147static const struct regmap_access_table bd9574mwf_volatile_table = {
 148        .yes_ranges     = bd9574mwf_volatile_yes_ranges,
 149        .n_yes_ranges   = ARRAY_SIZE(bd9574mwf_volatile_yes_ranges),
 150};
 151
 152static const struct regmap_config bd9574mwf_regmap_config = {
 153        .reg_bits       = 8,
 154        .val_bits       = 8,
 155        .cache_type     = REGCACHE_RBTREE,
 156        .rd_table       = &bd9574mwf_readable_table,
 157        .wr_table       = &bd9574mwf_writable_table,
 158        .volatile_table = &bd9574mwf_volatile_table,
 159        .max_register   = 0xff,
 160};
 161
 162static struct regmap_irq_chip bd9574mwf_irq_chip = {
 163        .name           = "bd9574mwf",
 164        .status_base    = BD9571MWV_INT_INTREQ,
 165        .mask_base      = BD9571MWV_INT_INTMASK,
 166        .ack_base       = BD9571MWV_INT_INTREQ,
 167        .init_ack_masked = true,
 168        .num_regs       = 1,
 169        .irqs           = bd9571mwv_irqs,
 170        .num_irqs       = ARRAY_SIZE(bd9571mwv_irqs),
 171};
 172
 173static int bd957x_identify(struct device *dev, struct regmap *regmap)
 174{
 175        unsigned int value;
 176        int ret;
 177
 178        ret = regmap_read(regmap, BD9571MWV_VENDOR_CODE, &value);
 179        if (ret) {
 180                dev_err(dev, "Failed to read vendor code register (ret=%i)\n",
 181                        ret);
 182                return ret;
 183        }
 184
 185        if (value != BD9571MWV_VENDOR_CODE_VAL) {
 186                dev_err(dev, "Invalid vendor code ID %02x (expected %02x)\n",
 187                        value, BD9571MWV_VENDOR_CODE_VAL);
 188                return -EINVAL;
 189        }
 190
 191        ret = regmap_read(regmap, BD9571MWV_PRODUCT_CODE, &value);
 192        if (ret) {
 193                dev_err(dev, "Failed to read product code register (ret=%i)\n",
 194                        ret);
 195                return ret;
 196        }
 197        ret = regmap_read(regmap, BD9571MWV_PRODUCT_REVISION, &value);
 198        if (ret) {
 199                dev_err(dev, "Failed to read revision register (ret=%i)\n",
 200                        ret);
 201                return ret;
 202        }
 203
 204        return 0;
 205}
 206
 207static int bd9571mwv_probe(struct i2c_client *client,
 208                           const struct i2c_device_id *ids)
 209{
 210        const struct regmap_config *regmap_config;
 211        const struct regmap_irq_chip *irq_chip;
 212        const struct mfd_cell *cells;
 213        struct device *dev = &client->dev;
 214        struct regmap *regmap;
 215        struct regmap_irq_chip_data *irq_data;
 216        int ret, num_cells, irq = client->irq;
 217
 218        /* Read the PMIC product code */
 219        ret = i2c_smbus_read_byte_data(client, BD9571MWV_PRODUCT_CODE);
 220        if (ret < 0) {
 221                dev_err(dev, "Failed to read product code\n");
 222                return ret;
 223        }
 224
 225        switch (ret) {
 226        case BD9571MWV_PRODUCT_CODE_BD9571MWV:
 227                regmap_config = &bd9571mwv_regmap_config;
 228                irq_chip = &bd9571mwv_irq_chip;
 229                cells = bd9571mwv_cells;
 230                num_cells = ARRAY_SIZE(bd9571mwv_cells);
 231                break;
 232        case BD9571MWV_PRODUCT_CODE_BD9574MWF:
 233                regmap_config = &bd9574mwf_regmap_config;
 234                irq_chip = &bd9574mwf_irq_chip;
 235                cells = bd9574mwf_cells;
 236                num_cells = ARRAY_SIZE(bd9574mwf_cells);
 237                break;
 238        default:
 239                dev_err(dev, "Unsupported device 0x%x\n", ret);
 240                return -ENODEV;
 241        }
 242
 243        regmap = devm_regmap_init_i2c(client, regmap_config);
 244        if (IS_ERR(regmap)) {
 245                dev_err(dev, "Failed to initialize register map\n");
 246                return PTR_ERR(regmap);
 247        }
 248
 249        ret = bd957x_identify(dev, regmap);
 250        if (ret)
 251                return ret;
 252
 253        ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT, 0,
 254                                       irq_chip, &irq_data);
 255        if (ret) {
 256                dev_err(dev, "Failed to register IRQ chip\n");
 257                return ret;
 258        }
 259
 260        return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, num_cells,
 261                                    NULL, 0, regmap_irq_get_domain(irq_data));
 262}
 263
 264static const struct of_device_id bd9571mwv_of_match_table[] = {
 265        { .compatible = "rohm,bd9571mwv", },
 266        { .compatible = "rohm,bd9574mwf", },
 267        { /* sentinel */ }
 268};
 269MODULE_DEVICE_TABLE(of, bd9571mwv_of_match_table);
 270
 271static const struct i2c_device_id bd9571mwv_id_table[] = {
 272        { "bd9571mwv", 0 },
 273        { /* sentinel */ }
 274};
 275MODULE_DEVICE_TABLE(i2c, bd9571mwv_id_table);
 276
 277static struct i2c_driver bd9571mwv_driver = {
 278        .driver         = {
 279                .name   = "bd9571mwv",
 280                .of_match_table = bd9571mwv_of_match_table,
 281        },
 282        .probe          = bd9571mwv_probe,
 283        .id_table       = bd9571mwv_id_table,
 284};
 285module_i2c_driver(bd9571mwv_driver);
 286
 287MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>");
 288MODULE_DESCRIPTION("BD9571MWV PMIC Driver");
 289MODULE_LICENSE("GPL v2");
 290