1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2014 MediaTek Inc.
4 * Author: Flora Fu, MediaTek
5 */
6
7 #include <linux/interrupt.h>
8 #include <linux/ioport.h>
9 #include <linux/irqdomain.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/platform_device.h>
13 #include <linux/regmap.h>
14 #include <linux/mfd/core.h>
15 #include <linux/mfd/mt6323/core.h>
16 #include <linux/mfd/mt6328/core.h>
17 #include <linux/mfd/mt6331/core.h>
18 #include <linux/mfd/mt6357/core.h>
19 #include <linux/mfd/mt6358/core.h>
20 #include <linux/mfd/mt6359/core.h>
21 #include <linux/mfd/mt6397/core.h>
22 #include <linux/mfd/mt6323/registers.h>
23 #include <linux/mfd/mt6328/registers.h>
24 #include <linux/mfd/mt6331/registers.h>
25 #include <linux/mfd/mt6357/registers.h>
26 #include <linux/mfd/mt6358/registers.h>
27 #include <linux/mfd/mt6359/registers.h>
28 #include <linux/mfd/mt6397/registers.h>
29
30 #define MT6323_RTC_BASE 0x8000
31 #define MT6323_RTC_SIZE 0x40
32
33 #define MT6357_RTC_BASE 0x0588
34 #define MT6357_RTC_SIZE 0x3c
35
36 #define MT6331_RTC_BASE 0x4000
37 #define MT6331_RTC_SIZE 0x40
38
39 #define MT6358_RTC_BASE 0x0588
40 #define MT6358_RTC_SIZE 0x3c
41
42 #define MT6397_RTC_BASE 0xe000
43 #define MT6397_RTC_SIZE 0x3e
44
45 #define MT6323_PWRC_BASE 0x8000
46 #define MT6323_PWRC_SIZE 0x40
47
48 static const struct resource mt6323_rtc_resources[] = {
49 DEFINE_RES_MEM(MT6323_RTC_BASE, MT6323_RTC_SIZE),
50 DEFINE_RES_IRQ(MT6323_IRQ_STATUS_RTC),
51 };
52
53 static const struct resource mt6357_rtc_resources[] = {
54 DEFINE_RES_MEM(MT6357_RTC_BASE, MT6357_RTC_SIZE),
55 DEFINE_RES_IRQ(MT6357_IRQ_RTC),
56 };
57
58 static const struct resource mt6331_rtc_resources[] = {
59 DEFINE_RES_MEM(MT6331_RTC_BASE, MT6331_RTC_SIZE),
60 DEFINE_RES_IRQ(MT6331_IRQ_STATUS_RTC),
61 };
62
63 static const struct resource mt6358_rtc_resources[] = {
64 DEFINE_RES_MEM(MT6358_RTC_BASE, MT6358_RTC_SIZE),
65 DEFINE_RES_IRQ(MT6358_IRQ_RTC),
66 };
67
68 static const struct resource mt6397_rtc_resources[] = {
69 DEFINE_RES_MEM(MT6397_RTC_BASE, MT6397_RTC_SIZE),
70 DEFINE_RES_IRQ(MT6397_IRQ_RTC),
71 };
72
73 static const struct resource mt6358_keys_resources[] = {
74 DEFINE_RES_IRQ_NAMED(MT6358_IRQ_PWRKEY, "powerkey"),
75 DEFINE_RES_IRQ_NAMED(MT6358_IRQ_HOMEKEY, "homekey"),
76 DEFINE_RES_IRQ_NAMED(MT6358_IRQ_PWRKEY_R, "powerkey_r"),
77 DEFINE_RES_IRQ_NAMED(MT6358_IRQ_HOMEKEY_R, "homekey_r"),
78 };
79
80 static const struct resource mt6359_keys_resources[] = {
81 DEFINE_RES_IRQ_NAMED(MT6359_IRQ_PWRKEY, "powerkey"),
82 DEFINE_RES_IRQ_NAMED(MT6359_IRQ_HOMEKEY, "homekey"),
83 DEFINE_RES_IRQ_NAMED(MT6359_IRQ_PWRKEY_R, "powerkey_r"),
84 DEFINE_RES_IRQ_NAMED(MT6359_IRQ_HOMEKEY_R, "homekey_r"),
85 };
86
87 static const struct resource mt6359_accdet_resources[] = {
88 DEFINE_RES_IRQ_NAMED(MT6359_IRQ_ACCDET, "accdet_irq"),
89 DEFINE_RES_IRQ_NAMED(MT6359_IRQ_ACCDET_EINT0, "accdet_eint0"),
90 DEFINE_RES_IRQ_NAMED(MT6359_IRQ_ACCDET_EINT1, "accdet_eint1"),
91 };
92
93 static const struct resource mt6323_keys_resources[] = {
94 DEFINE_RES_IRQ_NAMED(MT6323_IRQ_STATUS_PWRKEY, "powerkey"),
95 DEFINE_RES_IRQ_NAMED(MT6323_IRQ_STATUS_FCHRKEY, "homekey"),
96 };
97
98 static const struct resource mt6328_keys_resources[] = {
99 DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_PWRKEY, "powerkey"),
100 DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_HOMEKEY, "homekey"),
101 DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_PWRKEY_R, "powerkey_r"),
102 DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_HOMEKEY_R, "homekey_r"),
103 };
104
105 static const struct resource mt6357_keys_resources[] = {
106 DEFINE_RES_IRQ_NAMED(MT6357_IRQ_PWRKEY, "powerkey"),
107 DEFINE_RES_IRQ_NAMED(MT6357_IRQ_HOMEKEY, "homekey"),
108 DEFINE_RES_IRQ_NAMED(MT6357_IRQ_PWRKEY_R, "powerkey_r"),
109 DEFINE_RES_IRQ_NAMED(MT6357_IRQ_HOMEKEY_R, "homekey_r"),
110 };
111
112 static const struct resource mt6331_keys_resources[] = {
113 DEFINE_RES_IRQ_NAMED(MT6331_IRQ_STATUS_PWRKEY, "powerkey"),
114 DEFINE_RES_IRQ_NAMED(MT6331_IRQ_STATUS_HOMEKEY, "homekey"),
115 };
116
117 static const struct resource mt6397_keys_resources[] = {
118 DEFINE_RES_IRQ_NAMED(MT6397_IRQ_PWRKEY, "powerkey"),
119 DEFINE_RES_IRQ_NAMED(MT6397_IRQ_HOMEKEY, "homekey"),
120 };
121
122 static const struct resource mt6323_pwrc_resources[] = {
123 DEFINE_RES_MEM(MT6323_PWRC_BASE, MT6323_PWRC_SIZE),
124 };
125
126 static const struct mfd_cell mt6323_devs[] = {
127 {
128 .name = "mt6323-auxadc",
129 .of_compatible = "mediatek,mt6323-auxadc",
130 }, {
131 .name = "mt6323-efuse",
132 .of_compatible = "mediatek,mt6323-efuse",
133 }, {
134 .name = "mt6323-rtc",
135 .num_resources = ARRAY_SIZE(mt6323_rtc_resources),
136 .resources = mt6323_rtc_resources,
137 .of_compatible = "mediatek,mt6323-rtc",
138 }, {
139 .name = "mt6323-regulator",
140 .of_compatible = "mediatek,mt6323-regulator"
141 }, {
142 .name = "mt6323-led",
143 .of_compatible = "mediatek,mt6323-led"
144 }, {
145 .name = "mt6323-keys",
146 .num_resources = ARRAY_SIZE(mt6323_keys_resources),
147 .resources = mt6323_keys_resources,
148 .of_compatible = "mediatek,mt6323-keys"
149 }, {
150 .name = "mt6323-pwrc",
151 .num_resources = ARRAY_SIZE(mt6323_pwrc_resources),
152 .resources = mt6323_pwrc_resources,
153 .of_compatible = "mediatek,mt6323-pwrc"
154 },
155 };
156
157 static const struct mfd_cell mt6328_devs[] = {
158 {
159 .name = "mt6328-regulator",
160 .of_compatible = "mediatek,mt6328-regulator"
161 }, {
162 .name = "mt6328-keys",
163 .num_resources = ARRAY_SIZE(mt6328_keys_resources),
164 .resources = mt6328_keys_resources,
165 .of_compatible = "mediatek,mt6328-keys"
166 },
167 };
168
169 static const struct mfd_cell mt6357_devs[] = {
170 {
171 .name = "mt6359-auxadc",
172 .of_compatible = "mediatek,mt6357-auxadc"
173 }, {
174 .name = "mt6357-regulator",
175 }, {
176 .name = "mt6357-rtc",
177 .num_resources = ARRAY_SIZE(mt6357_rtc_resources),
178 .resources = mt6357_rtc_resources,
179 .of_compatible = "mediatek,mt6357-rtc",
180 }, {
181 .name = "mt6357-sound",
182 .of_compatible = "mediatek,mt6357-sound"
183 }, {
184 .name = "mt6357-keys",
185 .num_resources = ARRAY_SIZE(mt6357_keys_resources),
186 .resources = mt6357_keys_resources,
187 .of_compatible = "mediatek,mt6357-keys"
188 },
189 };
190
191 /* MT6331 is always used in combination with MT6332 */
192 static const struct mfd_cell mt6331_mt6332_devs[] = {
193 {
194 .name = "mt6331-rtc",
195 .num_resources = ARRAY_SIZE(mt6331_rtc_resources),
196 .resources = mt6331_rtc_resources,
197 .of_compatible = "mediatek,mt6331-rtc",
198 }, {
199 .name = "mt6331-regulator",
200 .of_compatible = "mediatek,mt6331-regulator"
201 }, {
202 .name = "mt6332-regulator",
203 .of_compatible = "mediatek,mt6332-regulator"
204 }, {
205 .name = "mt6331-keys",
206 .num_resources = ARRAY_SIZE(mt6331_keys_resources),
207 .resources = mt6331_keys_resources,
208 .of_compatible = "mediatek,mt6331-keys"
209 },
210 };
211
212 static const struct mfd_cell mt6358_devs[] = {
213 {
214 .name = "mt6359-auxadc",
215 .of_compatible = "mediatek,mt6358-auxadc"
216 }, {
217 .name = "mt6358-regulator",
218 .of_compatible = "mediatek,mt6358-regulator"
219 }, {
220 .name = "mt6358-rtc",
221 .num_resources = ARRAY_SIZE(mt6358_rtc_resources),
222 .resources = mt6358_rtc_resources,
223 .of_compatible = "mediatek,mt6358-rtc",
224 }, {
225 .name = "mt6358-sound",
226 .of_compatible = "mediatek,mt6358-sound"
227 }, {
228 .name = "mt6358-keys",
229 .num_resources = ARRAY_SIZE(mt6358_keys_resources),
230 .resources = mt6358_keys_resources,
231 .of_compatible = "mediatek,mt6358-keys"
232 },
233 };
234
235 static const struct mfd_cell mt6359_devs[] = {
236 {
237 .name = "mt6359-auxadc",
238 .of_compatible = "mediatek,mt6359-auxadc"
239 },
240 { .name = "mt6359-regulator", },
241 {
242 .name = "mt6359-rtc",
243 .num_resources = ARRAY_SIZE(mt6358_rtc_resources),
244 .resources = mt6358_rtc_resources,
245 .of_compatible = "mediatek,mt6358-rtc",
246 },
247 { .name = "mt6359-sound", },
248 {
249 .name = "mt6359-keys",
250 .num_resources = ARRAY_SIZE(mt6359_keys_resources),
251 .resources = mt6359_keys_resources,
252 .of_compatible = "mediatek,mt6359-keys"
253 },
254 {
255 .name = "mt6359-accdet",
256 .of_compatible = "mediatek,mt6359-accdet",
257 .num_resources = ARRAY_SIZE(mt6359_accdet_resources),
258 .resources = mt6359_accdet_resources,
259 },
260 };
261
262 static const struct mfd_cell mt6397_devs[] = {
263 {
264 .name = "mt6397-rtc",
265 .num_resources = ARRAY_SIZE(mt6397_rtc_resources),
266 .resources = mt6397_rtc_resources,
267 .of_compatible = "mediatek,mt6397-rtc",
268 }, {
269 .name = "mt6397-regulator",
270 .of_compatible = "mediatek,mt6397-regulator",
271 }, {
272 .name = "mt6397-codec",
273 .of_compatible = "mediatek,mt6397-codec",
274 }, {
275 .name = "mt6397-clk",
276 .of_compatible = "mediatek,mt6397-clk",
277 }, {
278 .name = "mt6397-pinctrl",
279 .of_compatible = "mediatek,mt6397-pinctrl",
280 }, {
281 .name = "mt6397-keys",
282 .num_resources = ARRAY_SIZE(mt6397_keys_resources),
283 .resources = mt6397_keys_resources,
284 .of_compatible = "mediatek,mt6397-keys"
285 }
286 };
287
288 struct chip_data {
289 u32 cid_addr;
290 u32 cid_shift;
291 const struct mfd_cell *cells;
292 int cell_size;
293 int (*irq_init)(struct mt6397_chip *chip);
294 };
295
296 static const struct chip_data mt6323_core = {
297 .cid_addr = MT6323_CID,
298 .cid_shift = 0,
299 .cells = mt6323_devs,
300 .cell_size = ARRAY_SIZE(mt6323_devs),
301 .irq_init = mt6397_irq_init,
302 };
303
304 static const struct chip_data mt6328_core = {
305 .cid_addr = MT6328_HWCID,
306 .cid_shift = 8,
307 .cells = mt6328_devs,
308 .cell_size = ARRAY_SIZE(mt6328_devs),
309 .irq_init = mt6397_irq_init,
310 };
311
312 static const struct chip_data mt6357_core = {
313 .cid_addr = MT6357_SWCID,
314 .cid_shift = 8,
315 .cells = mt6357_devs,
316 .cell_size = ARRAY_SIZE(mt6357_devs),
317 .irq_init = mt6358_irq_init,
318 };
319
320 static const struct chip_data mt6331_mt6332_core = {
321 .cid_addr = MT6331_HWCID,
322 .cid_shift = 8,
323 .cells = mt6331_mt6332_devs,
324 .cell_size = ARRAY_SIZE(mt6331_mt6332_devs),
325 .irq_init = mt6397_irq_init,
326 };
327
328 static const struct chip_data mt6358_core = {
329 .cid_addr = MT6358_SWCID,
330 .cid_shift = 8,
331 .cells = mt6358_devs,
332 .cell_size = ARRAY_SIZE(mt6358_devs),
333 .irq_init = mt6358_irq_init,
334 };
335
336 static const struct chip_data mt6359_core = {
337 .cid_addr = MT6359_SWCID,
338 .cid_shift = 8,
339 .cells = mt6359_devs,
340 .cell_size = ARRAY_SIZE(mt6359_devs),
341 .irq_init = mt6358_irq_init,
342 };
343
344 static const struct chip_data mt6397_core = {
345 .cid_addr = MT6397_CID,
346 .cid_shift = 0,
347 .cells = mt6397_devs,
348 .cell_size = ARRAY_SIZE(mt6397_devs),
349 .irq_init = mt6397_irq_init,
350 };
351
mt6397_probe(struct platform_device * pdev)352 static int mt6397_probe(struct platform_device *pdev)
353 {
354 int ret;
355 unsigned int id = 0;
356 struct mt6397_chip *pmic;
357 const struct chip_data *pmic_core;
358
359 pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
360 if (!pmic)
361 return -ENOMEM;
362
363 pmic->dev = &pdev->dev;
364
365 /*
366 * mt6397 MFD is child device of soc pmic wrapper.
367 * Regmap is set from its parent.
368 */
369 pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL);
370 if (!pmic->regmap)
371 return -ENODEV;
372
373 pmic_core = of_device_get_match_data(&pdev->dev);
374 if (!pmic_core)
375 return -ENODEV;
376
377 ret = regmap_read(pmic->regmap, pmic_core->cid_addr, &id);
378 if (ret) {
379 dev_err(&pdev->dev, "Failed to read chip id: %d\n", ret);
380 return ret;
381 }
382
383 pmic->chip_id = (id >> pmic_core->cid_shift) & 0xff;
384
385 platform_set_drvdata(pdev, pmic);
386
387 pmic->irq = platform_get_irq(pdev, 0);
388 if (pmic->irq <= 0)
389 return pmic->irq;
390
391 ret = pmic_core->irq_init(pmic);
392 if (ret)
393 return ret;
394
395 ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
396 pmic_core->cells, pmic_core->cell_size,
397 NULL, 0, pmic->irq_domain);
398 if (ret) {
399 irq_domain_remove(pmic->irq_domain);
400 dev_err(&pdev->dev, "failed to add child devices: %d\n", ret);
401 }
402
403 return ret;
404 }
405
406 static const struct of_device_id mt6397_of_match[] = {
407 {
408 .compatible = "mediatek,mt6323",
409 .data = &mt6323_core,
410 }, {
411 .compatible = "mediatek,mt6328",
412 .data = &mt6328_core,
413 }, {
414 .compatible = "mediatek,mt6331",
415 .data = &mt6331_mt6332_core,
416 }, {
417 .compatible = "mediatek,mt6357",
418 .data = &mt6357_core,
419 }, {
420 .compatible = "mediatek,mt6358",
421 .data = &mt6358_core,
422 }, {
423 .compatible = "mediatek,mt6359",
424 .data = &mt6359_core,
425 }, {
426 .compatible = "mediatek,mt6397",
427 .data = &mt6397_core,
428 }, {
429 /* sentinel */
430 }
431 };
432 MODULE_DEVICE_TABLE(of, mt6397_of_match);
433
434 static const struct platform_device_id mt6397_id[] = {
435 { "mt6397", 0 },
436 { },
437 };
438 MODULE_DEVICE_TABLE(platform, mt6397_id);
439
440 static struct platform_driver mt6397_driver = {
441 .probe = mt6397_probe,
442 .driver = {
443 .name = "mt6397",
444 .of_match_table = mt6397_of_match,
445 },
446 .id_table = mt6397_id,
447 };
448
449 module_platform_driver(mt6397_driver);
450
451 MODULE_AUTHOR("Flora Fu, MediaTek");
452 MODULE_DESCRIPTION("Driver for MediaTek MT6397 PMIC");
453 MODULE_LICENSE("GPL");
454