mfd: Remove dev_err() usage after platform_get_irq()
[linux-2.6-block.git] / drivers / mfd / mt6397-core.c
CommitLineData
1802d0be 1// SPDX-License-Identifier: GPL-2.0-only
6df8dd5c
FF
2/*
3 * Copyright (c) 2014 MediaTek Inc.
4 * Author: Flora Fu, MediaTek
6df8dd5c
FF
5 */
6
7#include <linux/interrupt.h>
8#include <linux/module.h>
9#include <linux/of_device.h>
10#include <linux/of_irq.h>
11#include <linux/regmap.h>
12#include <linux/mfd/core.h>
13#include <linux/mfd/mt6397/core.h>
44760cf3 14#include <linux/mfd/mt6323/core.h>
6df8dd5c 15#include <linux/mfd/mt6397/registers.h>
44760cf3 16#include <linux/mfd/mt6323/registers.h>
6df8dd5c 17
a5d7ea09
EH
18#define MT6397_RTC_BASE 0xe000
19#define MT6397_RTC_SIZE 0x3e
20
44760cf3 21#define MT6323_CID_CODE 0x23
1d2c25ed
JC
22#define MT6391_CID_CODE 0x91
23#define MT6397_CID_CODE 0x97
24
a5d7ea09
EH
25static const struct resource mt6397_rtc_resources[] = {
26 {
27 .start = MT6397_RTC_BASE,
28 .end = MT6397_RTC_BASE + MT6397_RTC_SIZE,
29 .flags = IORESOURCE_MEM,
30 },
31 {
32 .start = MT6397_IRQ_RTC,
33 .end = MT6397_IRQ_RTC,
34 .flags = IORESOURCE_IRQ,
35 },
36};
37
55d1d154
CZ
38static const struct resource mt6323_keys_resources[] = {
39 DEFINE_RES_IRQ(MT6323_IRQ_STATUS_PWRKEY),
40 DEFINE_RES_IRQ(MT6323_IRQ_STATUS_FCHRKEY),
41};
42
43static const struct resource mt6397_keys_resources[] = {
44 DEFINE_RES_IRQ(MT6397_IRQ_PWRKEY),
45 DEFINE_RES_IRQ(MT6397_IRQ_HOMEKEY),
46};
47
44760cf3
JC
48static const struct mfd_cell mt6323_devs[] = {
49 {
50 .name = "mt6323-regulator",
51 .of_compatible = "mediatek,mt6323-regulator"
040fc9b1 52 }, {
1cb8af8d
SW
53 .name = "mt6323-led",
54 .of_compatible = "mediatek,mt6323-led"
55d1d154
CZ
55 }, {
56 .name = "mtk-pmic-keys",
57 .num_resources = ARRAY_SIZE(mt6323_keys_resources),
58 .resources = mt6323_keys_resources,
59 .of_compatible = "mediatek,mt6323-keys"
1cb8af8d 60 },
44760cf3
JC
61};
62
6df8dd5c
FF
63static const struct mfd_cell mt6397_devs[] = {
64 {
65 .name = "mt6397-rtc",
a5d7ea09
EH
66 .num_resources = ARRAY_SIZE(mt6397_rtc_resources),
67 .resources = mt6397_rtc_resources,
6df8dd5c
FF
68 .of_compatible = "mediatek,mt6397-rtc",
69 }, {
70 .name = "mt6397-regulator",
71 .of_compatible = "mediatek,mt6397-regulator",
72 }, {
73 .name = "mt6397-codec",
74 .of_compatible = "mediatek,mt6397-codec",
75 }, {
76 .name = "mt6397-clk",
77 .of_compatible = "mediatek,mt6397-clk",
cf55078b
HY
78 }, {
79 .name = "mt6397-pinctrl",
80 .of_compatible = "mediatek,mt6397-pinctrl",
55d1d154
CZ
81 }, {
82 .name = "mtk-pmic-keys",
83 .num_resources = ARRAY_SIZE(mt6397_keys_resources),
84 .resources = mt6397_keys_resources,
85 .of_compatible = "mediatek,mt6397-keys"
86 }
6df8dd5c
FF
87};
88
89static void mt6397_irq_lock(struct irq_data *data)
90{
1e84aa44 91 struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
6df8dd5c
FF
92
93 mutex_lock(&mt6397->irqlock);
94}
95
96static void mt6397_irq_sync_unlock(struct irq_data *data)
97{
1e84aa44 98 struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
6df8dd5c 99
feec4799
JC
100 regmap_write(mt6397->regmap, mt6397->int_con[0],
101 mt6397->irq_masks_cur[0]);
102 regmap_write(mt6397->regmap, mt6397->int_con[1],
103 mt6397->irq_masks_cur[1]);
6df8dd5c
FF
104
105 mutex_unlock(&mt6397->irqlock);
106}
107
108static void mt6397_irq_disable(struct irq_data *data)
109{
1e84aa44 110 struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
6df8dd5c
FF
111 int shift = data->hwirq & 0xf;
112 int reg = data->hwirq >> 4;
113
114 mt6397->irq_masks_cur[reg] &= ~BIT(shift);
115}
116
117static void mt6397_irq_enable(struct irq_data *data)
118{
1e84aa44 119 struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
6df8dd5c
FF
120 int shift = data->hwirq & 0xf;
121 int reg = data->hwirq >> 4;
122
123 mt6397->irq_masks_cur[reg] |= BIT(shift);
124}
125
f3151ab4
HC
126#ifdef CONFIG_PM_SLEEP
127static int mt6397_irq_set_wake(struct irq_data *irq_data, unsigned int on)
128{
129 struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(irq_data);
130 int shift = irq_data->hwirq & 0xf;
131 int reg = irq_data->hwirq >> 4;
132
133 if (on)
134 mt6397->wake_mask[reg] |= BIT(shift);
135 else
136 mt6397->wake_mask[reg] &= ~BIT(shift);
137
138 return 0;
139}
140#else
141#define mt6397_irq_set_wake NULL
142#endif
143
6df8dd5c
FF
144static struct irq_chip mt6397_irq_chip = {
145 .name = "mt6397-irq",
146 .irq_bus_lock = mt6397_irq_lock,
147 .irq_bus_sync_unlock = mt6397_irq_sync_unlock,
148 .irq_enable = mt6397_irq_enable,
149 .irq_disable = mt6397_irq_disable,
f3151ab4 150 .irq_set_wake = mt6397_irq_set_wake,
6df8dd5c
FF
151};
152
153static void mt6397_irq_handle_reg(struct mt6397_chip *mt6397, int reg,
154 int irqbase)
155{
156 unsigned int status;
157 int i, irq, ret;
158
159 ret = regmap_read(mt6397->regmap, reg, &status);
160 if (ret) {
161 dev_err(mt6397->dev, "Failed to read irq status: %d\n", ret);
162 return;
163 }
164
165 for (i = 0; i < 16; i++) {
166 if (status & BIT(i)) {
167 irq = irq_find_mapping(mt6397->irq_domain, irqbase + i);
168 if (irq)
169 handle_nested_irq(irq);
170 }
171 }
172
173 regmap_write(mt6397->regmap, reg, status);
174}
175
176static irqreturn_t mt6397_irq_thread(int irq, void *data)
177{
178 struct mt6397_chip *mt6397 = data;
179
feec4799
JC
180 mt6397_irq_handle_reg(mt6397, mt6397->int_status[0], 0);
181 mt6397_irq_handle_reg(mt6397, mt6397->int_status[1], 16);
6df8dd5c
FF
182
183 return IRQ_HANDLED;
184}
185
186static int mt6397_irq_domain_map(struct irq_domain *d, unsigned int irq,
187 irq_hw_number_t hw)
188{
189 struct mt6397_chip *mt6397 = d->host_data;
190
191 irq_set_chip_data(irq, mt6397);
192 irq_set_chip_and_handler(irq, &mt6397_irq_chip, handle_level_irq);
193 irq_set_nested_thread(irq, 1);
6df8dd5c 194 irq_set_noprobe(irq);
6df8dd5c
FF
195
196 return 0;
197}
198
7ce7b26f 199static const struct irq_domain_ops mt6397_irq_domain_ops = {
6df8dd5c
FF
200 .map = mt6397_irq_domain_map,
201};
202
203static int mt6397_irq_init(struct mt6397_chip *mt6397)
204{
205 int ret;
206
207 mutex_init(&mt6397->irqlock);
208
209 /* Mask all interrupt sources */
feec4799
JC
210 regmap_write(mt6397->regmap, mt6397->int_con[0], 0x0);
211 regmap_write(mt6397->regmap, mt6397->int_con[1], 0x0);
6df8dd5c
FF
212
213 mt6397->irq_domain = irq_domain_add_linear(mt6397->dev->of_node,
214 MT6397_IRQ_NR, &mt6397_irq_domain_ops, mt6397);
215 if (!mt6397->irq_domain) {
216 dev_err(mt6397->dev, "could not create irq domain\n");
217 return -ENOMEM;
218 }
219
220 ret = devm_request_threaded_irq(mt6397->dev, mt6397->irq, NULL,
221 mt6397_irq_thread, IRQF_ONESHOT, "mt6397-pmic", mt6397);
222 if (ret) {
223 dev_err(mt6397->dev, "failed to register irq=%d; err: %d\n",
224 mt6397->irq, ret);
225 return ret;
226 }
227
228 return 0;
229}
230
f3151ab4
HC
231#ifdef CONFIG_PM_SLEEP
232static int mt6397_irq_suspend(struct device *dev)
233{
234 struct mt6397_chip *chip = dev_get_drvdata(dev);
235
feec4799
JC
236 regmap_write(chip->regmap, chip->int_con[0], chip->wake_mask[0]);
237 regmap_write(chip->regmap, chip->int_con[1], chip->wake_mask[1]);
f3151ab4
HC
238
239 enable_irq_wake(chip->irq);
240
241 return 0;
242}
243
244static int mt6397_irq_resume(struct device *dev)
245{
246 struct mt6397_chip *chip = dev_get_drvdata(dev);
247
feec4799
JC
248 regmap_write(chip->regmap, chip->int_con[0], chip->irq_masks_cur[0]);
249 regmap_write(chip->regmap, chip->int_con[1], chip->irq_masks_cur[1]);
f3151ab4
HC
250
251 disable_irq_wake(chip->irq);
252
253 return 0;
254}
255#endif
256
257static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_irq_suspend,
258 mt6397_irq_resume);
259
6df8dd5c
FF
260static int mt6397_probe(struct platform_device *pdev)
261{
262 int ret;
1d2c25ed
JC
263 unsigned int id;
264 struct mt6397_chip *pmic;
6df8dd5c 265
1d2c25ed
JC
266 pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
267 if (!pmic)
6df8dd5c
FF
268 return -ENOMEM;
269
1d2c25ed 270 pmic->dev = &pdev->dev;
feec4799 271
6df8dd5c
FF
272 /*
273 * mt6397 MFD is child device of soc pmic wrapper.
274 * Regmap is set from its parent.
275 */
1d2c25ed
JC
276 pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL);
277 if (!pmic->regmap)
6df8dd5c
FF
278 return -ENODEV;
279
1d2c25ed
JC
280 platform_set_drvdata(pdev, pmic);
281
282 ret = regmap_read(pmic->regmap, MT6397_CID, &id);
283 if (ret) {
284 dev_err(pmic->dev, "Failed to read chip id: %d\n", ret);
1387ff53 285 return ret;
1d2c25ed
JC
286 }
287
1387ff53
HC
288 pmic->irq = platform_get_irq(pdev, 0);
289 if (pmic->irq <= 0)
290 return pmic->irq;
291
1d2c25ed 292 switch (id & 0xff) {
44760cf3
JC
293 case MT6323_CID_CODE:
294 pmic->int_con[0] = MT6323_INT_CON0;
295 pmic->int_con[1] = MT6323_INT_CON1;
296 pmic->int_status[0] = MT6323_INT_STATUS0;
297 pmic->int_status[1] = MT6323_INT_STATUS1;
1387ff53
HC
298 ret = mt6397_irq_init(pmic);
299 if (ret)
300 return ret;
301
08e380a5
LD
302 ret = devm_mfd_add_devices(&pdev->dev, -1, mt6323_devs,
303 ARRAY_SIZE(mt6323_devs), NULL,
e695d3a0 304 0, pmic->irq_domain);
44760cf3
JC
305 break;
306
1d2c25ed
JC
307 case MT6397_CID_CODE:
308 case MT6391_CID_CODE:
309 pmic->int_con[0] = MT6397_INT_CON0;
310 pmic->int_con[1] = MT6397_INT_CON1;
311 pmic->int_status[0] = MT6397_INT_STATUS0;
312 pmic->int_status[1] = MT6397_INT_STATUS1;
1387ff53
HC
313 ret = mt6397_irq_init(pmic);
314 if (ret)
315 return ret;
316
08e380a5
LD
317 ret = devm_mfd_add_devices(&pdev->dev, -1, mt6397_devs,
318 ARRAY_SIZE(mt6397_devs), NULL,
e695d3a0 319 0, pmic->irq_domain);
1d2c25ed
JC
320 break;
321
322 default:
323 dev_err(&pdev->dev, "unsupported chip: %d\n", id);
a177276a 324 return -ENODEV;
1d2c25ed 325 }
6df8dd5c 326
1d2c25ed
JC
327 if (ret) {
328 irq_domain_remove(pmic->irq_domain);
6df8dd5c 329 dev_err(&pdev->dev, "failed to add child devices: %d\n", ret);
1d2c25ed 330 }
6df8dd5c
FF
331
332 return ret;
333}
334
6df8dd5c
FF
335static const struct of_device_id mt6397_of_match[] = {
336 { .compatible = "mediatek,mt6397" },
44760cf3 337 { .compatible = "mediatek,mt6323" },
6df8dd5c
FF
338 { }
339};
340MODULE_DEVICE_TABLE(of, mt6397_of_match);
341
e1d9a109
JMC
342static const struct platform_device_id mt6397_id[] = {
343 { "mt6397", 0 },
344 { },
345};
346MODULE_DEVICE_TABLE(platform, mt6397_id);
347
6df8dd5c
FF
348static struct platform_driver mt6397_driver = {
349 .probe = mt6397_probe,
6df8dd5c
FF
350 .driver = {
351 .name = "mt6397",
352 .of_match_table = of_match_ptr(mt6397_of_match),
f3151ab4 353 .pm = &mt6397_pm_ops,
6df8dd5c 354 },
e1d9a109 355 .id_table = mt6397_id,
6df8dd5c
FF
356};
357
358module_platform_driver(mt6397_driver);
359
360MODULE_AUTHOR("Flora Fu, MediaTek");
361MODULE_DESCRIPTION("Driver for MediaTek MT6397 PMIC");
362MODULE_LICENSE("GPL");