GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / mfd / mt6397-core.c
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/module.h>
10 #include <linux/of_device.h>
11 #include <linux/of_irq.h>
12 #include <linux/regmap.h>
13 #include <linux/mfd/core.h>
14 #include <linux/mfd/mt6323/core.h>
15 #include <linux/mfd/mt6358/core.h>
16 #include <linux/mfd/mt6359/core.h>
17 #include <linux/mfd/mt6397/core.h>
18 #include <linux/mfd/mt6323/registers.h>
19 #include <linux/mfd/mt6358/registers.h>
20 #include <linux/mfd/mt6359/registers.h>
21 #include <linux/mfd/mt6397/registers.h>
22
23 #define MT6323_RTC_BASE         0x8000
24 #define MT6323_RTC_SIZE         0x40
25
26 #define MT6358_RTC_BASE         0x0588
27 #define MT6358_RTC_SIZE         0x3c
28
29 #define MT6397_RTC_BASE         0xe000
30 #define MT6397_RTC_SIZE         0x3e
31
32 #define MT6323_PWRC_BASE        0x8000
33 #define MT6323_PWRC_SIZE        0x40
34
35 static const struct resource mt6323_rtc_resources[] = {
36         DEFINE_RES_MEM(MT6323_RTC_BASE, MT6323_RTC_SIZE),
37         DEFINE_RES_IRQ(MT6323_IRQ_STATUS_RTC),
38 };
39
40 static const struct resource mt6358_rtc_resources[] = {
41         DEFINE_RES_MEM(MT6358_RTC_BASE, MT6358_RTC_SIZE),
42         DEFINE_RES_IRQ(MT6358_IRQ_RTC),
43 };
44
45 static const struct resource mt6397_rtc_resources[] = {
46         DEFINE_RES_MEM(MT6397_RTC_BASE, MT6397_RTC_SIZE),
47         DEFINE_RES_IRQ(MT6397_IRQ_RTC),
48 };
49
50 static const struct resource mt6358_keys_resources[] = {
51         DEFINE_RES_IRQ_NAMED(MT6358_IRQ_PWRKEY, "powerkey"),
52         DEFINE_RES_IRQ_NAMED(MT6358_IRQ_HOMEKEY, "homekey"),
53         DEFINE_RES_IRQ_NAMED(MT6358_IRQ_PWRKEY_R, "powerkey_r"),
54         DEFINE_RES_IRQ_NAMED(MT6358_IRQ_HOMEKEY_R, "homekey_r"),
55 };
56
57 static const struct resource mt6359_keys_resources[] = {
58         DEFINE_RES_IRQ_NAMED(MT6359_IRQ_PWRKEY, "powerkey"),
59         DEFINE_RES_IRQ_NAMED(MT6359_IRQ_HOMEKEY, "homekey"),
60         DEFINE_RES_IRQ_NAMED(MT6359_IRQ_PWRKEY_R, "powerkey_r"),
61         DEFINE_RES_IRQ_NAMED(MT6359_IRQ_HOMEKEY_R, "homekey_r"),
62 };
63
64 static const struct resource mt6323_keys_resources[] = {
65         DEFINE_RES_IRQ_NAMED(MT6323_IRQ_STATUS_PWRKEY, "powerkey"),
66         DEFINE_RES_IRQ_NAMED(MT6323_IRQ_STATUS_FCHRKEY, "homekey"),
67 };
68
69 static const struct resource mt6397_keys_resources[] = {
70         DEFINE_RES_IRQ_NAMED(MT6397_IRQ_PWRKEY, "powerkey"),
71         DEFINE_RES_IRQ_NAMED(MT6397_IRQ_HOMEKEY, "homekey"),
72 };
73
74 static const struct resource mt6323_pwrc_resources[] = {
75         DEFINE_RES_MEM(MT6323_PWRC_BASE, MT6323_PWRC_SIZE),
76 };
77
78 static const struct mfd_cell mt6323_devs[] = {
79         {
80                 .name = "mt6323-rtc",
81                 .num_resources = ARRAY_SIZE(mt6323_rtc_resources),
82                 .resources = mt6323_rtc_resources,
83                 .of_compatible = "mediatek,mt6323-rtc",
84         }, {
85                 .name = "mt6323-regulator",
86                 .of_compatible = "mediatek,mt6323-regulator"
87         }, {
88                 .name = "mt6323-led",
89                 .of_compatible = "mediatek,mt6323-led"
90         }, {
91                 .name = "mtk-pmic-keys",
92                 .num_resources = ARRAY_SIZE(mt6323_keys_resources),
93                 .resources = mt6323_keys_resources,
94                 .of_compatible = "mediatek,mt6323-keys"
95         }, {
96                 .name = "mt6323-pwrc",
97                 .num_resources = ARRAY_SIZE(mt6323_pwrc_resources),
98                 .resources = mt6323_pwrc_resources,
99                 .of_compatible = "mediatek,mt6323-pwrc"
100         },
101 };
102
103 static const struct mfd_cell mt6358_devs[] = {
104         {
105                 .name = "mt6358-regulator",
106                 .of_compatible = "mediatek,mt6358-regulator"
107         }, {
108                 .name = "mt6358-rtc",
109                 .num_resources = ARRAY_SIZE(mt6358_rtc_resources),
110                 .resources = mt6358_rtc_resources,
111                 .of_compatible = "mediatek,mt6358-rtc",
112         }, {
113                 .name = "mt6358-sound",
114                 .of_compatible = "mediatek,mt6358-sound"
115         }, {
116                 .name = "mt6358-keys",
117                 .num_resources = ARRAY_SIZE(mt6358_keys_resources),
118                 .resources = mt6358_keys_resources,
119                 .of_compatible = "mediatek,mt6358-keys"
120         },
121 };
122
123 static const struct mfd_cell mt6359_devs[] = {
124         { .name = "mt6359-regulator", },
125         {
126                 .name = "mt6359-rtc",
127                 .num_resources = ARRAY_SIZE(mt6358_rtc_resources),
128                 .resources = mt6358_rtc_resources,
129                 .of_compatible = "mediatek,mt6358-rtc",
130         },
131         { .name = "mt6359-sound", },
132         {
133                 .name = "mtk-pmic-keys",
134                 .num_resources = ARRAY_SIZE(mt6359_keys_resources),
135                 .resources = mt6359_keys_resources,
136                 .of_compatible = "mediatek,mt6359-keys"
137         },
138 };
139
140 static const struct mfd_cell mt6397_devs[] = {
141         {
142                 .name = "mt6397-rtc",
143                 .num_resources = ARRAY_SIZE(mt6397_rtc_resources),
144                 .resources = mt6397_rtc_resources,
145                 .of_compatible = "mediatek,mt6397-rtc",
146         }, {
147                 .name = "mt6397-regulator",
148                 .of_compatible = "mediatek,mt6397-regulator",
149         }, {
150                 .name = "mt6397-codec",
151                 .of_compatible = "mediatek,mt6397-codec",
152         }, {
153                 .name = "mt6397-clk",
154                 .of_compatible = "mediatek,mt6397-clk",
155         }, {
156                 .name = "mt6397-pinctrl",
157                 .of_compatible = "mediatek,mt6397-pinctrl",
158         }, {
159                 .name = "mtk-pmic-keys",
160                 .num_resources = ARRAY_SIZE(mt6397_keys_resources),
161                 .resources = mt6397_keys_resources,
162                 .of_compatible = "mediatek,mt6397-keys"
163         }
164 };
165
166 struct chip_data {
167         u32 cid_addr;
168         u32 cid_shift;
169         const struct mfd_cell *cells;
170         int cell_size;
171         int (*irq_init)(struct mt6397_chip *chip);
172 };
173
174 static const struct chip_data mt6323_core = {
175         .cid_addr = MT6323_CID,
176         .cid_shift = 0,
177         .cells = mt6323_devs,
178         .cell_size = ARRAY_SIZE(mt6323_devs),
179         .irq_init = mt6397_irq_init,
180 };
181
182 static const struct chip_data mt6358_core = {
183         .cid_addr = MT6358_SWCID,
184         .cid_shift = 8,
185         .cells = mt6358_devs,
186         .cell_size = ARRAY_SIZE(mt6358_devs),
187         .irq_init = mt6358_irq_init,
188 };
189
190 static const struct chip_data mt6359_core = {
191         .cid_addr = MT6359_SWCID,
192         .cid_shift = 8,
193         .cells = mt6359_devs,
194         .cell_size = ARRAY_SIZE(mt6359_devs),
195         .irq_init = mt6358_irq_init,
196 };
197
198 static const struct chip_data mt6397_core = {
199         .cid_addr = MT6397_CID,
200         .cid_shift = 0,
201         .cells = mt6397_devs,
202         .cell_size = ARRAY_SIZE(mt6397_devs),
203         .irq_init = mt6397_irq_init,
204 };
205
206 static int mt6397_probe(struct platform_device *pdev)
207 {
208         int ret;
209         unsigned int id = 0;
210         struct mt6397_chip *pmic;
211         const struct chip_data *pmic_core;
212
213         pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
214         if (!pmic)
215                 return -ENOMEM;
216
217         pmic->dev = &pdev->dev;
218
219         /*
220          * mt6397 MFD is child device of soc pmic wrapper.
221          * Regmap is set from its parent.
222          */
223         pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL);
224         if (!pmic->regmap)
225                 return -ENODEV;
226
227         pmic_core = of_device_get_match_data(&pdev->dev);
228         if (!pmic_core)
229                 return -ENODEV;
230
231         ret = regmap_read(pmic->regmap, pmic_core->cid_addr, &id);
232         if (ret) {
233                 dev_err(&pdev->dev, "Failed to read chip id: %d\n", ret);
234                 return ret;
235         }
236
237         pmic->chip_id = (id >> pmic_core->cid_shift) & 0xff;
238
239         platform_set_drvdata(pdev, pmic);
240
241         pmic->irq = platform_get_irq(pdev, 0);
242         if (pmic->irq <= 0)
243                 return pmic->irq;
244
245         ret = pmic_core->irq_init(pmic);
246         if (ret)
247                 return ret;
248
249         ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
250                                    pmic_core->cells, pmic_core->cell_size,
251                                    NULL, 0, pmic->irq_domain);
252         if (ret) {
253                 irq_domain_remove(pmic->irq_domain);
254                 dev_err(&pdev->dev, "failed to add child devices: %d\n", ret);
255         }
256
257         return ret;
258 }
259
260 static const struct of_device_id mt6397_of_match[] = {
261         {
262                 .compatible = "mediatek,mt6323",
263                 .data = &mt6323_core,
264         }, {
265                 .compatible = "mediatek,mt6358",
266                 .data = &mt6358_core,
267         }, {
268                 .compatible = "mediatek,mt6359",
269                 .data = &mt6359_core,
270         }, {
271                 .compatible = "mediatek,mt6397",
272                 .data = &mt6397_core,
273         }, {
274                 /* sentinel */
275         }
276 };
277 MODULE_DEVICE_TABLE(of, mt6397_of_match);
278
279 static const struct platform_device_id mt6397_id[] = {
280         { "mt6397", 0 },
281         { },
282 };
283 MODULE_DEVICE_TABLE(platform, mt6397_id);
284
285 static struct platform_driver mt6397_driver = {
286         .probe = mt6397_probe,
287         .driver = {
288                 .name = "mt6397",
289                 .of_match_table = mt6397_of_match,
290         },
291         .id_table = mt6397_id,
292 };
293
294 module_platform_driver(mt6397_driver);
295
296 MODULE_AUTHOR("Flora Fu, MediaTek");
297 MODULE_DESCRIPTION("Driver for MediaTek MT6397 PMIC");
298 MODULE_LICENSE("GPL");