1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * ROHM BD9571MWV-M MFD driver 4 * 5 * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com> 6 * 7 * Based on the TPS65086 driver 8 */ 9 10 #include <linux/i2c.h> 11 #include <linux/interrupt.h> 12 #include <linux/mfd/core.h> 13 #include <linux/module.h> 14 15 #include <linux/mfd/bd9571mwv.h> 16 17 static const struct mfd_cell bd9571mwv_cells[] = { 18 { .name = "bd9571mwv-regulator", }, 19 { .name = "bd9571mwv-gpio", }, 20 }; 21 22 static const struct regmap_range bd9571mwv_readable_yes_ranges[] = { 23 regmap_reg_range(BD9571MWV_VENDOR_CODE, BD9571MWV_PRODUCT_REVISION), 24 regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT), 25 regmap_reg_range(BD9571MWV_AVS_SET_MONI, BD9571MWV_AVS_DVFS_VID(3)), 26 regmap_reg_range(BD9571MWV_VD18_VID, BD9571MWV_VD33_VID), 27 regmap_reg_range(BD9571MWV_DVFS_VINIT, BD9571MWV_DVFS_VINIT), 28 regmap_reg_range(BD9571MWV_DVFS_SETVMAX, BD9571MWV_DVFS_MONIVDAC), 29 regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN), 30 regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INTMASK), 31 regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK), 32 }; 33 34 static const struct regmap_access_table bd9571mwv_readable_table = { 35 .yes_ranges = bd9571mwv_readable_yes_ranges, 36 .n_yes_ranges = ARRAY_SIZE(bd9571mwv_readable_yes_ranges), 37 }; 38 39 static const struct regmap_range bd9571mwv_writable_yes_ranges[] = { 40 regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT), 41 regmap_reg_range(BD9571MWV_AVS_VD09_VID(0), BD9571MWV_AVS_VD09_VID(3)), 42 regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_SETVID), 43 regmap_reg_range(BD9571MWV_GPIO_DIR, BD9571MWV_GPIO_OUT), 44 regmap_reg_range(BD9571MWV_GPIO_INT_SET, BD9571MWV_GPIO_INTMASK), 45 regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK), 46 }; 47 48 static const struct regmap_access_table bd9571mwv_writable_table = { 49 .yes_ranges = bd9571mwv_writable_yes_ranges, 50 .n_yes_ranges = ARRAY_SIZE(bd9571mwv_writable_yes_ranges), 51 }; 52 53 static const struct regmap_range bd9571mwv_volatile_yes_ranges[] = { 54 regmap_reg_range(BD9571MWV_DVFS_MONIVDAC, BD9571MWV_DVFS_MONIVDAC), 55 regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN), 56 regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INT), 57 regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTREQ), 58 }; 59 60 static const struct regmap_access_table bd9571mwv_volatile_table = { 61 .yes_ranges = bd9571mwv_volatile_yes_ranges, 62 .n_yes_ranges = ARRAY_SIZE(bd9571mwv_volatile_yes_ranges), 63 }; 64 65 static const struct regmap_config bd9571mwv_regmap_config = { 66 .reg_bits = 8, 67 .val_bits = 8, 68 .cache_type = REGCACHE_RBTREE, 69 .rd_table = &bd9571mwv_readable_table, 70 .wr_table = &bd9571mwv_writable_table, 71 .volatile_table = &bd9571mwv_volatile_table, 72 .max_register = 0xff, 73 }; 74 75 static const struct regmap_irq bd9571mwv_irqs[] = { 76 REGMAP_IRQ_REG(BD9571MWV_IRQ_MD1, 0, 77 BD9571MWV_INT_INTREQ_MD1_INT), 78 REGMAP_IRQ_REG(BD9571MWV_IRQ_MD2_E1, 0, 79 BD9571MWV_INT_INTREQ_MD2_E1_INT), 80 REGMAP_IRQ_REG(BD9571MWV_IRQ_MD2_E2, 0, 81 BD9571MWV_INT_INTREQ_MD2_E2_INT), 82 REGMAP_IRQ_REG(BD9571MWV_IRQ_PROT_ERR, 0, 83 BD9571MWV_INT_INTREQ_PROT_ERR_INT), 84 REGMAP_IRQ_REG(BD9571MWV_IRQ_GP, 0, 85 BD9571MWV_INT_INTREQ_GP_INT), 86 REGMAP_IRQ_REG(BD9571MWV_IRQ_128H_OF, 0, 87 BD9571MWV_INT_INTREQ_128H_OF_INT), 88 REGMAP_IRQ_REG(BD9571MWV_IRQ_WDT_OF, 0, 89 BD9571MWV_INT_INTREQ_WDT_OF_INT), 90 REGMAP_IRQ_REG(BD9571MWV_IRQ_BKUP_TRG, 0, 91 BD9571MWV_INT_INTREQ_BKUP_TRG_INT), 92 }; 93 94 static struct regmap_irq_chip bd9571mwv_irq_chip = { 95 .name = "bd9571mwv", 96 .status_base = BD9571MWV_INT_INTREQ, 97 .mask_base = BD9571MWV_INT_INTMASK, 98 .ack_base = BD9571MWV_INT_INTREQ, 99 .init_ack_masked = true, 100 .num_regs = 1, 101 .irqs = bd9571mwv_irqs, 102 .num_irqs = ARRAY_SIZE(bd9571mwv_irqs), 103 }; 104 105 static int bd9571mwv_identify(struct bd9571mwv *bd) 106 { 107 struct device *dev = bd->dev; 108 unsigned int value; 109 int ret; 110 111 ret = regmap_read(bd->regmap, BD9571MWV_VENDOR_CODE, &value); 112 if (ret) { 113 dev_err(dev, "Failed to read vendor code register (ret=%i)\n", 114 ret); 115 return ret; 116 } 117 118 if (value != BD9571MWV_VENDOR_CODE_VAL) { 119 dev_err(dev, "Invalid vendor code ID %02x (expected %02x)\n", 120 value, BD9571MWV_VENDOR_CODE_VAL); 121 return -EINVAL; 122 } 123 124 ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_CODE, &value); 125 if (ret) { 126 dev_err(dev, "Failed to read product code register (ret=%i)\n", 127 ret); 128 return ret; 129 } 130 131 if (value != BD9571MWV_PRODUCT_CODE_VAL) { 132 dev_err(dev, "Invalid product code ID %02x (expected %02x)\n", 133 value, BD9571MWV_PRODUCT_CODE_VAL); 134 return -EINVAL; 135 } 136 137 ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_REVISION, &value); 138 if (ret) { 139 dev_err(dev, "Failed to read revision register (ret=%i)\n", 140 ret); 141 return ret; 142 } 143 144 dev_info(dev, "Device: BD9571MWV rev. %d\n", value & 0xff); 145 146 return 0; 147 } 148 149 static int bd9571mwv_probe(struct i2c_client *client, 150 const struct i2c_device_id *ids) 151 { 152 struct bd9571mwv *bd; 153 int ret; 154 155 bd = devm_kzalloc(&client->dev, sizeof(*bd), GFP_KERNEL); 156 if (!bd) 157 return -ENOMEM; 158 159 i2c_set_clientdata(client, bd); 160 bd->dev = &client->dev; 161 bd->irq = client->irq; 162 163 bd->regmap = devm_regmap_init_i2c(client, &bd9571mwv_regmap_config); 164 if (IS_ERR(bd->regmap)) { 165 dev_err(bd->dev, "Failed to initialize register map\n"); 166 return PTR_ERR(bd->regmap); 167 } 168 169 ret = bd9571mwv_identify(bd); 170 if (ret) 171 return ret; 172 173 ret = devm_regmap_add_irq_chip(bd->dev, bd->regmap, bd->irq, 174 IRQF_ONESHOT, 0, &bd9571mwv_irq_chip, 175 &bd->irq_data); 176 if (ret) { 177 dev_err(bd->dev, "Failed to register IRQ chip\n"); 178 return ret; 179 } 180 181 return devm_mfd_add_devices(bd->dev, PLATFORM_DEVID_AUTO, 182 bd9571mwv_cells, ARRAY_SIZE(bd9571mwv_cells), 183 NULL, 0, regmap_irq_get_domain(bd->irq_data)); 184 } 185 186 static const struct of_device_id bd9571mwv_of_match_table[] = { 187 { .compatible = "rohm,bd9571mwv", }, 188 { /* sentinel */ } 189 }; 190 MODULE_DEVICE_TABLE(of, bd9571mwv_of_match_table); 191 192 static const struct i2c_device_id bd9571mwv_id_table[] = { 193 { "bd9571mwv", 0 }, 194 { /* sentinel */ } 195 }; 196 MODULE_DEVICE_TABLE(i2c, bd9571mwv_id_table); 197 198 static struct i2c_driver bd9571mwv_driver = { 199 .driver = { 200 .name = "bd9571mwv", 201 .of_match_table = bd9571mwv_of_match_table, 202 }, 203 .probe = bd9571mwv_probe, 204 .id_table = bd9571mwv_id_table, 205 }; 206 module_i2c_driver(bd9571mwv_driver); 207 208 MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>"); 209 MODULE_DESCRIPTION("BD9571MWV PMIC Driver"); 210 MODULE_LICENSE("GPL v2"); 211