summaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorMarek Vasut <marek.vasut@gmail.com>2017-07-17 16:45:12 -0400
committerLee Jones <lee.jones@linaro.org>2017-09-05 03:46:00 -0400
commitd3ea212720948acff862b4c842d5b464ad338841 (patch)
tree1cc0b6df8618c6f74995dea3073e540288813b33 /drivers/mfd
parentec58871fb9c50429d6b5570066a7166da8faf086 (diff)
mfd: Add ROHM BD9571MWV-M MFD PMIC driver
Add the MFD part of the ROHM BD9571MWV-M PMIC driver and MAINTAINERS entry. The MFD part only specifies the regmap bits for the PMIC and binds the subdevs together. Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig14
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/bd9571mwv.c230
3 files changed, 245 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 42fb90ae3345..79e4ec6f19a8 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -133,6 +133,20 @@ config MFD_BCM590XX
133 help 133 help
134 Support for the BCM590xx PMUs from Broadcom 134 Support for the BCM590xx PMUs from Broadcom
135 135
136config MFD_BD9571MWV
137 tristate "ROHM BD9571MWV PMIC"
138 select MFD_CORE
139 select REGMAP_I2C
140 select REGMAP_IRQ
141 depends on I2C
142 help
143 Support for the ROHM BD9571MWV PMIC, which contains single
144 voltage regulator, voltage sampling units, GPIO block and
145 watchdog block.
146
147 This driver can also be built as a module. If so, the module
148 will be called bd9571mwv.
149
136config MFD_AC100 150config MFD_AC100
137 tristate "X-Powers AC100" 151 tristate "X-Powers AC100"
138 select MFD_CORE 152 select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b80b1a314ca5..21e19a5f3f3c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_ACT8945A) += act8945a.o
10obj-$(CONFIG_MFD_SM501) += sm501.o 10obj-$(CONFIG_MFD_SM501) += sm501.o
11obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o 11obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
12obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o 12obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
13obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o
13cros_ec_core-objs := cros_ec.o 14cros_ec_core-objs := cros_ec.o
14cros_ec_core-$(CONFIG_ACPI) += cros_ec_acpi_gpe.o 15cros_ec_core-$(CONFIG_ACPI) += cros_ec_acpi_gpe.o
15obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o 16obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o
diff --git a/drivers/mfd/bd9571mwv.c b/drivers/mfd/bd9571mwv.c
new file mode 100644
index 000000000000..64e088dfe7b0
--- /dev/null
+++ b/drivers/mfd/bd9571mwv.c
@@ -0,0 +1,230 @@
1/*
2 * ROHM BD9571MWV-M MFD driver
3 *
4 * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether expressed or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License version 2 for more details.
14 *
15 * Based on the TPS65086 driver
16 */
17
18#include <linux/i2c.h>
19#include <linux/interrupt.h>
20#include <linux/mfd/core.h>
21#include <linux/module.h>
22
23#include <linux/mfd/bd9571mwv.h>
24
25static const struct mfd_cell bd9571mwv_cells[] = {
26 { .name = "bd9571mwv-regulator", },
27 { .name = "bd9571mwv-gpio", },
28};
29
30static const struct regmap_range bd9571mwv_readable_yes_ranges[] = {
31 regmap_reg_range(BD9571MWV_VENDOR_CODE, BD9571MWV_PRODUCT_REVISION),
32 regmap_reg_range(BD9571MWV_AVS_SET_MONI, BD9571MWV_AVS_DVFS_VID(3)),
33 regmap_reg_range(BD9571MWV_VD18_VID, BD9571MWV_VD33_VID),
34 regmap_reg_range(BD9571MWV_DVFS_VINIT, BD9571MWV_DVFS_VINIT),
35 regmap_reg_range(BD9571MWV_DVFS_SETVMAX, BD9571MWV_DVFS_MONIVDAC),
36 regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN),
37 regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INTMASK),
38 regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK),
39};
40
41static const struct regmap_access_table bd9571mwv_readable_table = {
42 .yes_ranges = bd9571mwv_readable_yes_ranges,
43 .n_yes_ranges = ARRAY_SIZE(bd9571mwv_readable_yes_ranges),
44};
45
46static const struct regmap_range bd9571mwv_writable_yes_ranges[] = {
47 regmap_reg_range(BD9571MWV_AVS_VD09_VID(0), BD9571MWV_AVS_VD09_VID(3)),
48 regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_SETVID),
49 regmap_reg_range(BD9571MWV_GPIO_DIR, BD9571MWV_GPIO_OUT),
50 regmap_reg_range(BD9571MWV_GPIO_INT_SET, BD9571MWV_GPIO_INTMASK),
51 regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK),
52};
53
54static const struct regmap_access_table bd9571mwv_writable_table = {
55 .yes_ranges = bd9571mwv_writable_yes_ranges,
56 .n_yes_ranges = ARRAY_SIZE(bd9571mwv_writable_yes_ranges),
57};
58
59static const struct regmap_range bd9571mwv_volatile_yes_ranges[] = {
60 regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN),
61 regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INT),
62 regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTREQ),
63};
64
65static const struct regmap_access_table bd9571mwv_volatile_table = {
66 .yes_ranges = bd9571mwv_volatile_yes_ranges,
67 .n_yes_ranges = ARRAY_SIZE(bd9571mwv_volatile_yes_ranges),
68};
69
70static const struct regmap_config bd9571mwv_regmap_config = {
71 .reg_bits = 8,
72 .val_bits = 8,
73 .cache_type = REGCACHE_RBTREE,
74 .rd_table = &bd9571mwv_readable_table,
75 .wr_table = &bd9571mwv_writable_table,
76 .volatile_table = &bd9571mwv_volatile_table,
77 .max_register = 0xff,
78};
79
80static const struct regmap_irq bd9571mwv_irqs[] = {
81 REGMAP_IRQ_REG(BD9571MWV_IRQ_MD1, 0,
82 BD9571MWV_INT_INTREQ_MD1_INT),
83 REGMAP_IRQ_REG(BD9571MWV_IRQ_MD2_E1, 0,
84 BD9571MWV_INT_INTREQ_MD2_E1_INT),
85 REGMAP_IRQ_REG(BD9571MWV_IRQ_MD2_E2, 0,
86 BD9571MWV_INT_INTREQ_MD2_E2_INT),
87 REGMAP_IRQ_REG(BD9571MWV_IRQ_PROT_ERR, 0,
88 BD9571MWV_INT_INTREQ_PROT_ERR_INT),
89 REGMAP_IRQ_REG(BD9571MWV_IRQ_GP, 0,
90 BD9571MWV_INT_INTREQ_GP_INT),
91 REGMAP_IRQ_REG(BD9571MWV_IRQ_128H_OF, 0,
92 BD9571MWV_INT_INTREQ_128H_OF_INT),
93 REGMAP_IRQ_REG(BD9571MWV_IRQ_WDT_OF, 0,
94 BD9571MWV_INT_INTREQ_WDT_OF_INT),
95 REGMAP_IRQ_REG(BD9571MWV_IRQ_BKUP_TRG, 0,
96 BD9571MWV_INT_INTREQ_BKUP_TRG_INT),
97};
98
99static struct regmap_irq_chip bd9571mwv_irq_chip = {
100 .name = "bd9571mwv",
101 .status_base = BD9571MWV_INT_INTREQ,
102 .mask_base = BD9571MWV_INT_INTMASK,
103 .ack_base = BD9571MWV_INT_INTREQ,
104 .init_ack_masked = true,
105 .num_regs = 1,
106 .irqs = bd9571mwv_irqs,
107 .num_irqs = ARRAY_SIZE(bd9571mwv_irqs),
108};
109
110static int bd9571mwv_identify(struct bd9571mwv *bd)
111{
112 struct device *dev = bd->dev;
113 unsigned int value;
114 int ret;
115
116 ret = regmap_read(bd->regmap, BD9571MWV_VENDOR_CODE, &value);
117 if (ret) {
118 dev_err(dev, "Failed to read vendor code register (ret=%i)\n",
119 ret);
120 return ret;
121 }
122
123 if (value != BD9571MWV_VENDOR_CODE_VAL) {
124 dev_err(dev, "Invalid vendor code ID %02x (expected %02x)\n",
125 value, BD9571MWV_VENDOR_CODE_VAL);
126 return -EINVAL;
127 }
128
129 ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_CODE, &value);
130 if (ret) {
131 dev_err(dev, "Failed to read product code register (ret=%i)\n",
132 ret);
133 return ret;
134 }
135
136 if (value != BD9571MWV_PRODUCT_CODE_VAL) {
137 dev_err(dev, "Invalid product code ID %02x (expected %02x)\n",
138 value, BD9571MWV_PRODUCT_CODE_VAL);
139 return -EINVAL;
140 }
141
142 ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_REVISION, &value);
143 if (ret) {
144 dev_err(dev, "Failed to read revision register (ret=%i)\n",
145 ret);
146 return ret;
147 }
148
149 dev_info(dev, "Device: BD9571MWV rev. %d\n", value & 0xff);
150
151 return 0;
152}
153
154static int bd9571mwv_probe(struct i2c_client *client,
155 const struct i2c_device_id *ids)
156{
157 struct bd9571mwv *bd;
158 int ret;
159
160 bd = devm_kzalloc(&client->dev, sizeof(*bd), GFP_KERNEL);
161 if (!bd)
162 return -ENOMEM;
163
164 i2c_set_clientdata(client, bd);
165 bd->dev = &client->dev;
166 bd->irq = client->irq;
167
168 bd->regmap = devm_regmap_init_i2c(client, &bd9571mwv_regmap_config);
169 if (IS_ERR(bd->regmap)) {
170 dev_err(bd->dev, "Failed to initialize register map\n");
171 return PTR_ERR(bd->regmap);
172 }
173
174 ret = bd9571mwv_identify(bd);
175 if (ret)
176 return ret;
177
178 ret = regmap_add_irq_chip(bd->regmap, bd->irq, IRQF_ONESHOT, 0,
179 &bd9571mwv_irq_chip, &bd->irq_data);
180 if (ret) {
181 dev_err(bd->dev, "Failed to register IRQ chip\n");
182 return ret;
183 }
184
185 ret = mfd_add_devices(bd->dev, PLATFORM_DEVID_AUTO, bd9571mwv_cells,
186 ARRAY_SIZE(bd9571mwv_cells), NULL, 0,
187 regmap_irq_get_domain(bd->irq_data));
188 if (ret) {
189 regmap_del_irq_chip(bd->irq, bd->irq_data);
190 return ret;
191 }
192
193 return 0;
194}
195
196static int bd9571mwv_remove(struct i2c_client *client)
197{
198 struct bd9571mwv *bd = i2c_get_clientdata(client);
199
200 regmap_del_irq_chip(bd->irq, bd->irq_data);
201
202 return 0;
203}
204
205static const struct of_device_id bd9571mwv_of_match_table[] = {
206 { .compatible = "rohm,bd9571mwv", },
207 { /* sentinel */ }
208};
209MODULE_DEVICE_TABLE(of, bd9571mwv_of_match_table);
210
211static const struct i2c_device_id bd9571mwv_id_table[] = {
212 { "bd9571mwv", 0 },
213 { /* sentinel */ }
214};
215MODULE_DEVICE_TABLE(i2c, bd9571mwv_id_table);
216
217static struct i2c_driver bd9571mwv_driver = {
218 .driver = {
219 .name = "bd9571mwv",
220 .of_match_table = bd9571mwv_of_match_table,
221 },
222 .probe = bd9571mwv_probe,
223 .remove = bd9571mwv_remove,
224 .id_table = bd9571mwv_id_table,
225};
226module_i2c_driver(bd9571mwv_driver);
227
228MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>");
229MODULE_DESCRIPTION("BD9571MWV PMIC Driver");
230MODULE_LICENSE("GPL v2");