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