]>
Commit | Line | Data |
---|---|---|
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> | |
7c3f7cd5 | 8 | #include <linux/ioport.h> |
6df8dd5c FF |
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> | |
44760cf3 | 14 | #include <linux/mfd/mt6323/core.h> |
708cb5cc | 15 | #include <linux/mfd/mt6397/core.h> |
44760cf3 | 16 | #include <linux/mfd/mt6323/registers.h> |
708cb5cc | 17 | #include <linux/mfd/mt6397/registers.h> |
6df8dd5c | 18 | |
8391c6cb JF |
19 | #define MT6323_RTC_BASE 0x8000 |
20 | #define MT6323_RTC_SIZE 0x40 | |
21 | ||
a5d7ea09 EH |
22 | #define MT6397_RTC_BASE 0xe000 |
23 | #define MT6397_RTC_SIZE 0x3e | |
24 | ||
8391c6cb JF |
25 | #define MT6323_PWRC_BASE 0x8000 |
26 | #define MT6323_PWRC_SIZE 0x40 | |
27 | ||
28 | static const struct resource mt6323_rtc_resources[] = { | |
29 | DEFINE_RES_MEM(MT6323_RTC_BASE, MT6323_RTC_SIZE), | |
30 | DEFINE_RES_IRQ(MT6323_IRQ_STATUS_RTC), | |
31 | }; | |
32 | ||
a5d7ea09 | 33 | static const struct resource mt6397_rtc_resources[] = { |
7c3f7cd5 JF |
34 | DEFINE_RES_MEM(MT6397_RTC_BASE, MT6397_RTC_SIZE), |
35 | DEFINE_RES_IRQ(MT6397_IRQ_RTC), | |
a5d7ea09 EH |
36 | }; |
37 | ||
55d1d154 CZ |
38 | static const struct resource mt6323_keys_resources[] = { |
39 | DEFINE_RES_IRQ(MT6323_IRQ_STATUS_PWRKEY), | |
40 | DEFINE_RES_IRQ(MT6323_IRQ_STATUS_FCHRKEY), | |
41 | }; | |
42 | ||
43 | static const struct resource mt6397_keys_resources[] = { | |
44 | DEFINE_RES_IRQ(MT6397_IRQ_PWRKEY), | |
45 | DEFINE_RES_IRQ(MT6397_IRQ_HOMEKEY), | |
46 | }; | |
47 | ||
8391c6cb JF |
48 | static const struct resource mt6323_pwrc_resources[] = { |
49 | DEFINE_RES_MEM(MT6323_PWRC_BASE, MT6323_PWRC_SIZE), | |
50 | }; | |
51 | ||
44760cf3 JC |
52 | static const struct mfd_cell mt6323_devs[] = { |
53 | { | |
8391c6cb JF |
54 | .name = "mt6323-rtc", |
55 | .num_resources = ARRAY_SIZE(mt6323_rtc_resources), | |
56 | .resources = mt6323_rtc_resources, | |
57 | .of_compatible = "mediatek,mt6323-rtc", | |
58 | }, { | |
44760cf3 JC |
59 | .name = "mt6323-regulator", |
60 | .of_compatible = "mediatek,mt6323-regulator" | |
040fc9b1 | 61 | }, { |
1cb8af8d SW |
62 | .name = "mt6323-led", |
63 | .of_compatible = "mediatek,mt6323-led" | |
55d1d154 CZ |
64 | }, { |
65 | .name = "mtk-pmic-keys", | |
66 | .num_resources = ARRAY_SIZE(mt6323_keys_resources), | |
67 | .resources = mt6323_keys_resources, | |
68 | .of_compatible = "mediatek,mt6323-keys" | |
8391c6cb JF |
69 | }, { |
70 | .name = "mt6323-pwrc", | |
71 | .num_resources = ARRAY_SIZE(mt6323_pwrc_resources), | |
72 | .resources = mt6323_pwrc_resources, | |
73 | .of_compatible = "mediatek,mt6323-pwrc" | |
1cb8af8d | 74 | }, |
44760cf3 JC |
75 | }; |
76 | ||
6df8dd5c FF |
77 | static const struct mfd_cell mt6397_devs[] = { |
78 | { | |
79 | .name = "mt6397-rtc", | |
a5d7ea09 EH |
80 | .num_resources = ARRAY_SIZE(mt6397_rtc_resources), |
81 | .resources = mt6397_rtc_resources, | |
6df8dd5c FF |
82 | .of_compatible = "mediatek,mt6397-rtc", |
83 | }, { | |
84 | .name = "mt6397-regulator", | |
85 | .of_compatible = "mediatek,mt6397-regulator", | |
86 | }, { | |
87 | .name = "mt6397-codec", | |
88 | .of_compatible = "mediatek,mt6397-codec", | |
89 | }, { | |
90 | .name = "mt6397-clk", | |
91 | .of_compatible = "mediatek,mt6397-clk", | |
cf55078b HY |
92 | }, { |
93 | .name = "mt6397-pinctrl", | |
94 | .of_compatible = "mediatek,mt6397-pinctrl", | |
55d1d154 CZ |
95 | }, { |
96 | .name = "mtk-pmic-keys", | |
97 | .num_resources = ARRAY_SIZE(mt6397_keys_resources), | |
98 | .resources = mt6397_keys_resources, | |
99 | .of_compatible = "mediatek,mt6397-keys" | |
100 | } | |
6df8dd5c FF |
101 | }; |
102 | ||
f3151ab4 HC |
103 | #ifdef CONFIG_PM_SLEEP |
104 | static int mt6397_irq_suspend(struct device *dev) | |
105 | { | |
106 | struct mt6397_chip *chip = dev_get_drvdata(dev); | |
107 | ||
feec4799 JC |
108 | regmap_write(chip->regmap, chip->int_con[0], chip->wake_mask[0]); |
109 | regmap_write(chip->regmap, chip->int_con[1], chip->wake_mask[1]); | |
f3151ab4 HC |
110 | |
111 | enable_irq_wake(chip->irq); | |
112 | ||
113 | return 0; | |
114 | } | |
115 | ||
116 | static int mt6397_irq_resume(struct device *dev) | |
117 | { | |
118 | struct mt6397_chip *chip = dev_get_drvdata(dev); | |
119 | ||
feec4799 JC |
120 | regmap_write(chip->regmap, chip->int_con[0], chip->irq_masks_cur[0]); |
121 | regmap_write(chip->regmap, chip->int_con[1], chip->irq_masks_cur[1]); | |
f3151ab4 HC |
122 | |
123 | disable_irq_wake(chip->irq); | |
124 | ||
125 | return 0; | |
126 | } | |
127 | #endif | |
128 | ||
129 | static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_irq_suspend, | |
130 | mt6397_irq_resume); | |
131 | ||
603d9299 FW |
132 | struct chip_data { |
133 | u32 cid_addr; | |
134 | u32 cid_shift; | |
135 | }; | |
136 | ||
137 | static const struct chip_data mt6323_core = { | |
138 | .cid_addr = MT6323_CID, | |
139 | .cid_shift = 0, | |
140 | }; | |
141 | ||
142 | static const struct chip_data mt6397_core = { | |
143 | .cid_addr = MT6397_CID, | |
144 | .cid_shift = 0, | |
145 | }; | |
146 | ||
6df8dd5c FF |
147 | static int mt6397_probe(struct platform_device *pdev) |
148 | { | |
149 | int ret; | |
1d2c25ed JC |
150 | unsigned int id; |
151 | struct mt6397_chip *pmic; | |
603d9299 | 152 | const struct chip_data *pmic_core; |
6df8dd5c | 153 | |
1d2c25ed JC |
154 | pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); |
155 | if (!pmic) | |
6df8dd5c FF |
156 | return -ENOMEM; |
157 | ||
1d2c25ed | 158 | pmic->dev = &pdev->dev; |
feec4799 | 159 | |
6df8dd5c FF |
160 | /* |
161 | * mt6397 MFD is child device of soc pmic wrapper. | |
162 | * Regmap is set from its parent. | |
163 | */ | |
1d2c25ed JC |
164 | pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL); |
165 | if (!pmic->regmap) | |
6df8dd5c FF |
166 | return -ENODEV; |
167 | ||
603d9299 FW |
168 | pmic_core = of_device_get_match_data(&pdev->dev); |
169 | if (!pmic_core) | |
170 | return -ENODEV; | |
1d2c25ed | 171 | |
603d9299 | 172 | ret = regmap_read(pmic->regmap, pmic_core->cid_addr, &id); |
1d2c25ed | 173 | if (ret) { |
603d9299 | 174 | dev_err(&pdev->dev, "Failed to read chip id: %d\n", ret); |
1387ff53 | 175 | return ret; |
1d2c25ed JC |
176 | } |
177 | ||
603d9299 FW |
178 | pmic->chip_id = (id >> pmic_core->cid_shift) & 0xff; |
179 | ||
180 | platform_set_drvdata(pdev, pmic); | |
181 | ||
1387ff53 HC |
182 | pmic->irq = platform_get_irq(pdev, 0); |
183 | if (pmic->irq <= 0) | |
184 | return pmic->irq; | |
185 | ||
603d9299 FW |
186 | ret = mt6397_irq_init(pmic); |
187 | if (ret) | |
188 | return ret; | |
1387ff53 | 189 | |
603d9299 FW |
190 | switch (pmic->chip_id) { |
191 | case MT6323_CHIP_ID: | |
08e380a5 LD |
192 | ret = devm_mfd_add_devices(&pdev->dev, -1, mt6323_devs, |
193 | ARRAY_SIZE(mt6323_devs), NULL, | |
e695d3a0 | 194 | 0, pmic->irq_domain); |
44760cf3 JC |
195 | break; |
196 | ||
708cb5cc HHW |
197 | case MT6391_CHIP_ID: |
198 | case MT6397_CHIP_ID: | |
08e380a5 LD |
199 | ret = devm_mfd_add_devices(&pdev->dev, -1, mt6397_devs, |
200 | ARRAY_SIZE(mt6397_devs), NULL, | |
e695d3a0 | 201 | 0, pmic->irq_domain); |
1d2c25ed JC |
202 | break; |
203 | ||
204 | default: | |
603d9299 | 205 | dev_err(&pdev->dev, "unsupported chip: %d\n", pmic->chip_id); |
a177276a | 206 | return -ENODEV; |
1d2c25ed | 207 | } |
6df8dd5c | 208 | |
1d2c25ed JC |
209 | if (ret) { |
210 | irq_domain_remove(pmic->irq_domain); | |
6df8dd5c | 211 | dev_err(&pdev->dev, "failed to add child devices: %d\n", ret); |
1d2c25ed | 212 | } |
6df8dd5c FF |
213 | |
214 | return ret; | |
215 | } | |
216 | ||
6df8dd5c | 217 | static const struct of_device_id mt6397_of_match[] = { |
603d9299 FW |
218 | { |
219 | .compatible = "mediatek,mt6323", | |
220 | .data = &mt6323_core, | |
221 | }, { | |
222 | .compatible = "mediatek,mt6397", | |
223 | .data = &mt6397_core, | |
224 | }, { | |
225 | /* sentinel */ | |
226 | } | |
6df8dd5c FF |
227 | }; |
228 | MODULE_DEVICE_TABLE(of, mt6397_of_match); | |
229 | ||
e1d9a109 JMC |
230 | static const struct platform_device_id mt6397_id[] = { |
231 | { "mt6397", 0 }, | |
232 | { }, | |
233 | }; | |
234 | MODULE_DEVICE_TABLE(platform, mt6397_id); | |
235 | ||
6df8dd5c FF |
236 | static struct platform_driver mt6397_driver = { |
237 | .probe = mt6397_probe, | |
6df8dd5c FF |
238 | .driver = { |
239 | .name = "mt6397", | |
240 | .of_match_table = of_match_ptr(mt6397_of_match), | |
f3151ab4 | 241 | .pm = &mt6397_pm_ops, |
6df8dd5c | 242 | }, |
e1d9a109 | 243 | .id_table = mt6397_id, |
6df8dd5c FF |
244 | }; |
245 | ||
246 | module_platform_driver(mt6397_driver); | |
247 | ||
248 | MODULE_AUTHOR("Flora Fu, MediaTek"); | |
249 | MODULE_DESCRIPTION("Driver for MediaTek MT6397 PMIC"); | |
250 | MODULE_LICENSE("GPL"); |