1f7cb7fe3SCristian Ciocaltea // SPDX-License-Identifier: GPL-2.0+
2f7cb7fe3SCristian Ciocaltea /*
3f7cb7fe3SCristian Ciocaltea * Core support for ATC260x PMICs
4f7cb7fe3SCristian Ciocaltea *
5f7cb7fe3SCristian Ciocaltea * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
6f7cb7fe3SCristian Ciocaltea * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
7f7cb7fe3SCristian Ciocaltea */
8f7cb7fe3SCristian Ciocaltea
9f7cb7fe3SCristian Ciocaltea #include <linux/interrupt.h>
10f7cb7fe3SCristian Ciocaltea #include <linux/mfd/atc260x/core.h>
11f7cb7fe3SCristian Ciocaltea #include <linux/mfd/core.h>
12f7cb7fe3SCristian Ciocaltea #include <linux/module.h>
13f7cb7fe3SCristian Ciocaltea #include <linux/of.h>
14f7cb7fe3SCristian Ciocaltea #include <linux/regmap.h>
15f7cb7fe3SCristian Ciocaltea
16f7cb7fe3SCristian Ciocaltea #define ATC260X_CHIP_REV_MAX 31
17f7cb7fe3SCristian Ciocaltea
18f7cb7fe3SCristian Ciocaltea struct atc260x_init_regs {
19f7cb7fe3SCristian Ciocaltea unsigned int cmu_devrst;
20f7cb7fe3SCristian Ciocaltea unsigned int cmu_devrst_ints;
21f7cb7fe3SCristian Ciocaltea unsigned int ints_msk;
22f7cb7fe3SCristian Ciocaltea unsigned int pad_en;
23f7cb7fe3SCristian Ciocaltea unsigned int pad_en_extirq;
24f7cb7fe3SCristian Ciocaltea };
25f7cb7fe3SCristian Ciocaltea
regmap_lock_mutex(void * __mutex)26f7cb7fe3SCristian Ciocaltea static void regmap_lock_mutex(void *__mutex)
27f7cb7fe3SCristian Ciocaltea {
28f7cb7fe3SCristian Ciocaltea struct mutex *mutex = __mutex;
29f7cb7fe3SCristian Ciocaltea
30f7cb7fe3SCristian Ciocaltea /*
31f7cb7fe3SCristian Ciocaltea * Using regmap within an atomic context (e.g. accessing a PMIC when
32f7cb7fe3SCristian Ciocaltea * powering system down) is normally allowed only if the regmap type
33f7cb7fe3SCristian Ciocaltea * is MMIO and the regcache type is either REGCACHE_NONE or
34f7cb7fe3SCristian Ciocaltea * REGCACHE_FLAT. For slow buses like I2C and SPI, the regmap is
35f7cb7fe3SCristian Ciocaltea * internally protected by a mutex which is acquired non-atomically.
36f7cb7fe3SCristian Ciocaltea *
37f7cb7fe3SCristian Ciocaltea * Let's improve this by using a customized locking scheme inspired
38f7cb7fe3SCristian Ciocaltea * from I2C atomic transfer. See i2c_in_atomic_xfer_mode() for a
39f7cb7fe3SCristian Ciocaltea * starting point.
40f7cb7fe3SCristian Ciocaltea */
41f7cb7fe3SCristian Ciocaltea if (system_state > SYSTEM_RUNNING && irqs_disabled())
42f7cb7fe3SCristian Ciocaltea mutex_trylock(mutex);
43f7cb7fe3SCristian Ciocaltea else
44f7cb7fe3SCristian Ciocaltea mutex_lock(mutex);
45f7cb7fe3SCristian Ciocaltea }
46f7cb7fe3SCristian Ciocaltea
regmap_unlock_mutex(void * __mutex)47f7cb7fe3SCristian Ciocaltea static void regmap_unlock_mutex(void *__mutex)
48f7cb7fe3SCristian Ciocaltea {
49f7cb7fe3SCristian Ciocaltea struct mutex *mutex = __mutex;
50f7cb7fe3SCristian Ciocaltea
51f7cb7fe3SCristian Ciocaltea mutex_unlock(mutex);
52f7cb7fe3SCristian Ciocaltea }
53f7cb7fe3SCristian Ciocaltea
54f7cb7fe3SCristian Ciocaltea static const struct regmap_config atc2603c_regmap_config = {
55f7cb7fe3SCristian Ciocaltea .reg_bits = 8,
56f7cb7fe3SCristian Ciocaltea .val_bits = 16,
57f7cb7fe3SCristian Ciocaltea .max_register = ATC2603C_SADDR,
58f7cb7fe3SCristian Ciocaltea .cache_type = REGCACHE_NONE,
59f7cb7fe3SCristian Ciocaltea };
60f7cb7fe3SCristian Ciocaltea
61f7cb7fe3SCristian Ciocaltea static const struct regmap_config atc2609a_regmap_config = {
62f7cb7fe3SCristian Ciocaltea .reg_bits = 8,
63f7cb7fe3SCristian Ciocaltea .val_bits = 16,
64f7cb7fe3SCristian Ciocaltea .max_register = ATC2609A_SADDR,
65f7cb7fe3SCristian Ciocaltea .cache_type = REGCACHE_NONE,
66f7cb7fe3SCristian Ciocaltea };
67f7cb7fe3SCristian Ciocaltea
68f7cb7fe3SCristian Ciocaltea static const struct regmap_irq atc2603c_regmap_irqs[] = {
69f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_AUDIO, 0, ATC2603C_INTS_MSK_AUDIO),
70f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_OV, 0, ATC2603C_INTS_MSK_OV),
71f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_OC, 0, ATC2603C_INTS_MSK_OC),
72f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_OT, 0, ATC2603C_INTS_MSK_OT),
73f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_UV, 0, ATC2603C_INTS_MSK_UV),
74f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_ALARM, 0, ATC2603C_INTS_MSK_ALARM),
75f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_ONOFF, 0, ATC2603C_INTS_MSK_ONOFF),
76f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_SGPIO, 0, ATC2603C_INTS_MSK_SGPIO),
77f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_IR, 0, ATC2603C_INTS_MSK_IR),
78f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_REMCON, 0, ATC2603C_INTS_MSK_REMCON),
79f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2603C_IRQ_POWER_IN, 0, ATC2603C_INTS_MSK_POWERIN),
80f7cb7fe3SCristian Ciocaltea };
81f7cb7fe3SCristian Ciocaltea
82f7cb7fe3SCristian Ciocaltea static const struct regmap_irq atc2609a_regmap_irqs[] = {
83f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_AUDIO, 0, ATC2609A_INTS_MSK_AUDIO),
84f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_OV, 0, ATC2609A_INTS_MSK_OV),
85f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_OC, 0, ATC2609A_INTS_MSK_OC),
86f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_OT, 0, ATC2609A_INTS_MSK_OT),
87f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_UV, 0, ATC2609A_INTS_MSK_UV),
88f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_ALARM, 0, ATC2609A_INTS_MSK_ALARM),
89f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_ONOFF, 0, ATC2609A_INTS_MSK_ONOFF),
90f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_WKUP, 0, ATC2609A_INTS_MSK_WKUP),
91f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_IR, 0, ATC2609A_INTS_MSK_IR),
92f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_REMCON, 0, ATC2609A_INTS_MSK_REMCON),
93f7cb7fe3SCristian Ciocaltea REGMAP_IRQ_REG(ATC2609A_IRQ_POWER_IN, 0, ATC2609A_INTS_MSK_POWERIN),
94f7cb7fe3SCristian Ciocaltea };
95f7cb7fe3SCristian Ciocaltea
96f7cb7fe3SCristian Ciocaltea static const struct regmap_irq_chip atc2603c_regmap_irq_chip = {
97f7cb7fe3SCristian Ciocaltea .name = "atc2603c",
98f7cb7fe3SCristian Ciocaltea .irqs = atc2603c_regmap_irqs,
99f7cb7fe3SCristian Ciocaltea .num_irqs = ARRAY_SIZE(atc2603c_regmap_irqs),
100f7cb7fe3SCristian Ciocaltea .num_regs = 1,
101f7cb7fe3SCristian Ciocaltea .status_base = ATC2603C_INTS_PD,
102*3db3b9a5SAidan MacDonald .unmask_base = ATC2603C_INTS_MSK,
103f7cb7fe3SCristian Ciocaltea };
104f7cb7fe3SCristian Ciocaltea
105f7cb7fe3SCristian Ciocaltea static const struct regmap_irq_chip atc2609a_regmap_irq_chip = {
106f7cb7fe3SCristian Ciocaltea .name = "atc2609a",
107f7cb7fe3SCristian Ciocaltea .irqs = atc2609a_regmap_irqs,
108f7cb7fe3SCristian Ciocaltea .num_irqs = ARRAY_SIZE(atc2609a_regmap_irqs),
109f7cb7fe3SCristian Ciocaltea .num_regs = 1,
110f7cb7fe3SCristian Ciocaltea .status_base = ATC2609A_INTS_PD,
111*3db3b9a5SAidan MacDonald .unmask_base = ATC2609A_INTS_MSK,
112f7cb7fe3SCristian Ciocaltea };
113f7cb7fe3SCristian Ciocaltea
114f7cb7fe3SCristian Ciocaltea static const struct resource atc2603c_onkey_resources[] = {
115f7cb7fe3SCristian Ciocaltea DEFINE_RES_IRQ(ATC2603C_IRQ_ONOFF),
116f7cb7fe3SCristian Ciocaltea };
117f7cb7fe3SCristian Ciocaltea
118f7cb7fe3SCristian Ciocaltea static const struct resource atc2609a_onkey_resources[] = {
119f7cb7fe3SCristian Ciocaltea DEFINE_RES_IRQ(ATC2609A_IRQ_ONOFF),
120f7cb7fe3SCristian Ciocaltea };
121f7cb7fe3SCristian Ciocaltea
122f7cb7fe3SCristian Ciocaltea static const struct mfd_cell atc2603c_mfd_cells[] = {
123f7cb7fe3SCristian Ciocaltea { .name = "atc260x-regulator" },
124f7cb7fe3SCristian Ciocaltea { .name = "atc260x-pwrc" },
125f7cb7fe3SCristian Ciocaltea {
126f7cb7fe3SCristian Ciocaltea .name = "atc260x-onkey",
127f7cb7fe3SCristian Ciocaltea .num_resources = ARRAY_SIZE(atc2603c_onkey_resources),
128f7cb7fe3SCristian Ciocaltea .resources = atc2603c_onkey_resources,
129f7cb7fe3SCristian Ciocaltea },
130f7cb7fe3SCristian Ciocaltea };
131f7cb7fe3SCristian Ciocaltea
132f7cb7fe3SCristian Ciocaltea static const struct mfd_cell atc2609a_mfd_cells[] = {
133f7cb7fe3SCristian Ciocaltea { .name = "atc260x-regulator" },
134f7cb7fe3SCristian Ciocaltea { .name = "atc260x-pwrc" },
135f7cb7fe3SCristian Ciocaltea {
136f7cb7fe3SCristian Ciocaltea .name = "atc260x-onkey",
137f7cb7fe3SCristian Ciocaltea .num_resources = ARRAY_SIZE(atc2609a_onkey_resources),
138f7cb7fe3SCristian Ciocaltea .resources = atc2609a_onkey_resources,
139f7cb7fe3SCristian Ciocaltea },
140f7cb7fe3SCristian Ciocaltea };
141f7cb7fe3SCristian Ciocaltea
142f7cb7fe3SCristian Ciocaltea static const struct atc260x_init_regs atc2603c_init_regs = {
143f7cb7fe3SCristian Ciocaltea .cmu_devrst = ATC2603C_CMU_DEVRST,
144f7cb7fe3SCristian Ciocaltea .cmu_devrst_ints = ATC2603C_CMU_DEVRST_INTS,
145f7cb7fe3SCristian Ciocaltea .ints_msk = ATC2603C_INTS_MSK,
146f7cb7fe3SCristian Ciocaltea .pad_en = ATC2603C_PAD_EN,
147f7cb7fe3SCristian Ciocaltea .pad_en_extirq = ATC2603C_PAD_EN_EXTIRQ,
148f7cb7fe3SCristian Ciocaltea };
149f7cb7fe3SCristian Ciocaltea
150f7cb7fe3SCristian Ciocaltea static const struct atc260x_init_regs atc2609a_init_regs = {
151f7cb7fe3SCristian Ciocaltea .cmu_devrst = ATC2609A_CMU_DEVRST,
152f7cb7fe3SCristian Ciocaltea .cmu_devrst_ints = ATC2609A_CMU_DEVRST_INTS,
153f7cb7fe3SCristian Ciocaltea .ints_msk = ATC2609A_INTS_MSK,
154f7cb7fe3SCristian Ciocaltea .pad_en = ATC2609A_PAD_EN,
155f7cb7fe3SCristian Ciocaltea .pad_en_extirq = ATC2609A_PAD_EN_EXTIRQ,
156f7cb7fe3SCristian Ciocaltea };
157f7cb7fe3SCristian Ciocaltea
atc260x_cmu_reset(struct atc260x * atc260x)158f7cb7fe3SCristian Ciocaltea static void atc260x_cmu_reset(struct atc260x *atc260x)
159f7cb7fe3SCristian Ciocaltea {
160f7cb7fe3SCristian Ciocaltea const struct atc260x_init_regs *regs = atc260x->init_regs;
161f7cb7fe3SCristian Ciocaltea
162f7cb7fe3SCristian Ciocaltea /* Assert reset */
163f7cb7fe3SCristian Ciocaltea regmap_update_bits(atc260x->regmap, regs->cmu_devrst,
164f7cb7fe3SCristian Ciocaltea regs->cmu_devrst_ints, ~regs->cmu_devrst_ints);
165f7cb7fe3SCristian Ciocaltea
166f7cb7fe3SCristian Ciocaltea /* De-assert reset */
167f7cb7fe3SCristian Ciocaltea regmap_update_bits(atc260x->regmap, regs->cmu_devrst,
168f7cb7fe3SCristian Ciocaltea regs->cmu_devrst_ints, regs->cmu_devrst_ints);
169f7cb7fe3SCristian Ciocaltea }
170f7cb7fe3SCristian Ciocaltea
atc260x_dev_init(struct atc260x * atc260x)171f7cb7fe3SCristian Ciocaltea static void atc260x_dev_init(struct atc260x *atc260x)
172f7cb7fe3SCristian Ciocaltea {
173f7cb7fe3SCristian Ciocaltea const struct atc260x_init_regs *regs = atc260x->init_regs;
174f7cb7fe3SCristian Ciocaltea
175f7cb7fe3SCristian Ciocaltea /* Initialize interrupt block */
176f7cb7fe3SCristian Ciocaltea atc260x_cmu_reset(atc260x);
177f7cb7fe3SCristian Ciocaltea
178f7cb7fe3SCristian Ciocaltea /* Disable all interrupt sources */
179f7cb7fe3SCristian Ciocaltea regmap_write(atc260x->regmap, regs->ints_msk, 0);
180f7cb7fe3SCristian Ciocaltea
181f7cb7fe3SCristian Ciocaltea /* Enable EXTIRQ pad */
182f7cb7fe3SCristian Ciocaltea regmap_update_bits(atc260x->regmap, regs->pad_en,
183f7cb7fe3SCristian Ciocaltea regs->pad_en_extirq, regs->pad_en_extirq);
184f7cb7fe3SCristian Ciocaltea }
185f7cb7fe3SCristian Ciocaltea
186f7cb7fe3SCristian Ciocaltea /**
187f7cb7fe3SCristian Ciocaltea * atc260x_match_device(): Setup ATC260x variant related fields
188f7cb7fe3SCristian Ciocaltea *
189f7cb7fe3SCristian Ciocaltea * @atc260x: ATC260x device to setup (.dev field must be set)
190f7cb7fe3SCristian Ciocaltea * @regmap_cfg: regmap config associated with this ATC260x device
191f7cb7fe3SCristian Ciocaltea *
192f7cb7fe3SCristian Ciocaltea * This lets the ATC260x core configure the MFD cells and register maps
193f7cb7fe3SCristian Ciocaltea * for later use.
194f7cb7fe3SCristian Ciocaltea */
atc260x_match_device(struct atc260x * atc260x,struct regmap_config * regmap_cfg)195f7cb7fe3SCristian Ciocaltea int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_cfg)
196f7cb7fe3SCristian Ciocaltea {
197f7cb7fe3SCristian Ciocaltea struct device *dev = atc260x->dev;
198f7cb7fe3SCristian Ciocaltea const void *of_data;
199f7cb7fe3SCristian Ciocaltea
200f7cb7fe3SCristian Ciocaltea of_data = of_device_get_match_data(dev);
201f7cb7fe3SCristian Ciocaltea if (!of_data)
202f7cb7fe3SCristian Ciocaltea return -ENODEV;
203f7cb7fe3SCristian Ciocaltea
204f7cb7fe3SCristian Ciocaltea atc260x->ic_type = (unsigned long)of_data;
205f7cb7fe3SCristian Ciocaltea
206f7cb7fe3SCristian Ciocaltea switch (atc260x->ic_type) {
207f7cb7fe3SCristian Ciocaltea case ATC2603C:
208f7cb7fe3SCristian Ciocaltea *regmap_cfg = atc2603c_regmap_config;
209f7cb7fe3SCristian Ciocaltea atc260x->regmap_irq_chip = &atc2603c_regmap_irq_chip;
210f7cb7fe3SCristian Ciocaltea atc260x->cells = atc2603c_mfd_cells;
211f7cb7fe3SCristian Ciocaltea atc260x->nr_cells = ARRAY_SIZE(atc2603c_mfd_cells);
212f7cb7fe3SCristian Ciocaltea atc260x->type_name = "atc2603c";
213f7cb7fe3SCristian Ciocaltea atc260x->rev_reg = ATC2603C_CHIP_VER;
214f7cb7fe3SCristian Ciocaltea atc260x->init_regs = &atc2603c_init_regs;
215f7cb7fe3SCristian Ciocaltea break;
216f7cb7fe3SCristian Ciocaltea case ATC2609A:
217f7cb7fe3SCristian Ciocaltea *regmap_cfg = atc2609a_regmap_config;
218f7cb7fe3SCristian Ciocaltea atc260x->regmap_irq_chip = &atc2609a_regmap_irq_chip;
219f7cb7fe3SCristian Ciocaltea atc260x->cells = atc2609a_mfd_cells;
220f7cb7fe3SCristian Ciocaltea atc260x->nr_cells = ARRAY_SIZE(atc2609a_mfd_cells);
221f7cb7fe3SCristian Ciocaltea atc260x->type_name = "atc2609a";
222f7cb7fe3SCristian Ciocaltea atc260x->rev_reg = ATC2609A_CHIP_VER;
223f7cb7fe3SCristian Ciocaltea atc260x->init_regs = &atc2609a_init_regs;
224f7cb7fe3SCristian Ciocaltea break;
225f7cb7fe3SCristian Ciocaltea default:
226f7cb7fe3SCristian Ciocaltea dev_err(dev, "Unsupported ATC260x device type: %u\n",
227f7cb7fe3SCristian Ciocaltea atc260x->ic_type);
228f7cb7fe3SCristian Ciocaltea return -EINVAL;
229f7cb7fe3SCristian Ciocaltea }
230f7cb7fe3SCristian Ciocaltea
231f7cb7fe3SCristian Ciocaltea atc260x->regmap_mutex = devm_kzalloc(dev, sizeof(*atc260x->regmap_mutex),
232f7cb7fe3SCristian Ciocaltea GFP_KERNEL);
233f7cb7fe3SCristian Ciocaltea if (!atc260x->regmap_mutex)
234f7cb7fe3SCristian Ciocaltea return -ENOMEM;
235f7cb7fe3SCristian Ciocaltea
236f7cb7fe3SCristian Ciocaltea mutex_init(atc260x->regmap_mutex);
237f7cb7fe3SCristian Ciocaltea
238f7cb7fe3SCristian Ciocaltea regmap_cfg->lock = regmap_lock_mutex,
239f7cb7fe3SCristian Ciocaltea regmap_cfg->unlock = regmap_unlock_mutex,
240f7cb7fe3SCristian Ciocaltea regmap_cfg->lock_arg = atc260x->regmap_mutex;
241f7cb7fe3SCristian Ciocaltea
242f7cb7fe3SCristian Ciocaltea return 0;
243f7cb7fe3SCristian Ciocaltea }
244f7cb7fe3SCristian Ciocaltea EXPORT_SYMBOL_GPL(atc260x_match_device);
245f7cb7fe3SCristian Ciocaltea
246f7cb7fe3SCristian Ciocaltea /**
247f7cb7fe3SCristian Ciocaltea * atc260x_device_probe(): Probe a configured ATC260x device
248f7cb7fe3SCristian Ciocaltea *
249f7cb7fe3SCristian Ciocaltea * @atc260x: ATC260x device to probe (must be configured)
250f7cb7fe3SCristian Ciocaltea *
251f7cb7fe3SCristian Ciocaltea * This function lets the ATC260x core register the ATC260x MFD devices
252f7cb7fe3SCristian Ciocaltea * and IRQCHIP. The ATC260x device passed in must be fully configured
253f7cb7fe3SCristian Ciocaltea * with atc260x_match_device, its IRQ set, and regmap created.
254f7cb7fe3SCristian Ciocaltea */
atc260x_device_probe(struct atc260x * atc260x)255f7cb7fe3SCristian Ciocaltea int atc260x_device_probe(struct atc260x *atc260x)
256f7cb7fe3SCristian Ciocaltea {
257f7cb7fe3SCristian Ciocaltea struct device *dev = atc260x->dev;
258f7cb7fe3SCristian Ciocaltea unsigned int chip_rev;
259f7cb7fe3SCristian Ciocaltea int ret;
260f7cb7fe3SCristian Ciocaltea
261f7cb7fe3SCristian Ciocaltea if (!atc260x->irq) {
262f7cb7fe3SCristian Ciocaltea dev_err(dev, "No interrupt support\n");
263f7cb7fe3SCristian Ciocaltea return -EINVAL;
264f7cb7fe3SCristian Ciocaltea }
265f7cb7fe3SCristian Ciocaltea
266f7cb7fe3SCristian Ciocaltea /* Initialize the hardware */
267f7cb7fe3SCristian Ciocaltea atc260x_dev_init(atc260x);
268f7cb7fe3SCristian Ciocaltea
269f7cb7fe3SCristian Ciocaltea ret = regmap_read(atc260x->regmap, atc260x->rev_reg, &chip_rev);
270f7cb7fe3SCristian Ciocaltea if (ret) {
271f7cb7fe3SCristian Ciocaltea dev_err(dev, "Failed to get chip revision\n");
272f7cb7fe3SCristian Ciocaltea return ret;
273f7cb7fe3SCristian Ciocaltea }
274f7cb7fe3SCristian Ciocaltea
275f7cb7fe3SCristian Ciocaltea if (chip_rev > ATC260X_CHIP_REV_MAX) {
276f7cb7fe3SCristian Ciocaltea dev_err(dev, "Unknown chip revision: %u\n", chip_rev);
277f7cb7fe3SCristian Ciocaltea return -EINVAL;
278f7cb7fe3SCristian Ciocaltea }
279f7cb7fe3SCristian Ciocaltea
280f7cb7fe3SCristian Ciocaltea atc260x->ic_ver = __ffs(chip_rev + 1U);
281f7cb7fe3SCristian Ciocaltea
282f7cb7fe3SCristian Ciocaltea dev_info(dev, "Detected chip type %s rev.%c\n",
283f7cb7fe3SCristian Ciocaltea atc260x->type_name, 'A' + atc260x->ic_ver);
284f7cb7fe3SCristian Ciocaltea
285f7cb7fe3SCristian Ciocaltea ret = devm_regmap_add_irq_chip(dev, atc260x->regmap, atc260x->irq, IRQF_ONESHOT,
286f7cb7fe3SCristian Ciocaltea -1, atc260x->regmap_irq_chip, &atc260x->irq_data);
287f7cb7fe3SCristian Ciocaltea if (ret) {
288f7cb7fe3SCristian Ciocaltea dev_err(dev, "Failed to add IRQ chip: %d\n", ret);
289f7cb7fe3SCristian Ciocaltea return ret;
290f7cb7fe3SCristian Ciocaltea }
291f7cb7fe3SCristian Ciocaltea
292f7cb7fe3SCristian Ciocaltea ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
293f7cb7fe3SCristian Ciocaltea atc260x->cells, atc260x->nr_cells, NULL, 0,
294f7cb7fe3SCristian Ciocaltea regmap_irq_get_domain(atc260x->irq_data));
295f7cb7fe3SCristian Ciocaltea if (ret) {
296f7cb7fe3SCristian Ciocaltea dev_err(dev, "Failed to add child devices: %d\n", ret);
297f7cb7fe3SCristian Ciocaltea regmap_del_irq_chip(atc260x->irq, atc260x->irq_data);
298f7cb7fe3SCristian Ciocaltea }
299f7cb7fe3SCristian Ciocaltea
300f7cb7fe3SCristian Ciocaltea return ret;
301f7cb7fe3SCristian Ciocaltea }
302f7cb7fe3SCristian Ciocaltea EXPORT_SYMBOL_GPL(atc260x_device_probe);
303f7cb7fe3SCristian Ciocaltea
304f7cb7fe3SCristian Ciocaltea MODULE_DESCRIPTION("ATC260x PMICs Core support");
305f7cb7fe3SCristian Ciocaltea MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
306f7cb7fe3SCristian Ciocaltea MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
307f7cb7fe3SCristian Ciocaltea MODULE_LICENSE("GPL");
308