1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright 2012 Samsung Electronics Co., Ltd
4 * http://www.samsung.com
5 * Copyright 2025 Linaro Ltd.
6 *
7 * Samsung SxM core driver
8 */
9
10 #include <linux/device.h>
11 #include <linux/err.h>
12 #include <linux/export.h>
13 #include <linux/interrupt.h>
14 #include <linux/mfd/core.h>
15 #include <linux/mfd/samsung/core.h>
16 #include <linux/mfd/samsung/irq.h>
17 #include <linux/mfd/samsung/s2mps11.h>
18 #include <linux/mfd/samsung/s2mps13.h>
19 #include <linux/module.h>
20 #include <linux/of.h>
21 #include <linux/pm.h>
22 #include <linux/pm_runtime.h>
23 #include <linux/regmap.h>
24 #include "sec-core.h"
25
26 static const struct resource s5m8767_rtc_resources[] = {
27 DEFINE_RES_IRQ_NAMED(S5M8767_IRQ_RTCA1, "alarm"),
28 };
29
30 static const struct mfd_cell s5m8767_devs[] = {
31 MFD_CELL_NAME("s5m8767-pmic"),
32 MFD_CELL_RES("s5m-rtc", s5m8767_rtc_resources),
33 MFD_CELL_OF("s5m8767-clk", NULL, NULL, 0, 0, "samsung,s5m8767-clk"),
34 };
35
36 static const struct mfd_cell s2dos05_devs[] = {
37 MFD_CELL_NAME("s2dos05-regulator"),
38 };
39
40 static const struct resource s2mpg10_rtc_resources[] = {
41 DEFINE_RES_IRQ_NAMED(S2MPG10_IRQ_RTCA0, "alarm"),
42 };
43
44 static const struct mfd_cell s2mpg10_devs[] = {
45 MFD_CELL_NAME("s2mpg10-meter"),
46 MFD_CELL_NAME("s2mpg10-regulator"),
47 MFD_CELL_RES("s2mpg10-rtc", s2mpg10_rtc_resources),
48 MFD_CELL_OF("s2mpg10-clk", NULL, NULL, 0, 0, "samsung,s2mpg10-clk"),
49 MFD_CELL_OF("s2mpg10-gpio", NULL, NULL, 0, 0, "samsung,s2mpg10-gpio"),
50 };
51
52 static const struct mfd_cell s2mpg11_devs[] = {
53 MFD_CELL_NAME("s2mpg11-meter"),
54 MFD_CELL_NAME("s2mpg11-regulator"),
55 MFD_CELL_OF("s2mpg11-gpio", NULL, NULL, 0, 0, "samsung,s2mpg11-gpio"),
56 };
57
58 static const struct resource s2mps11_rtc_resources[] = {
59 DEFINE_RES_IRQ_NAMED(S2MPS11_IRQ_RTCA0, "alarm"),
60 };
61
62 static const struct mfd_cell s2mps11_devs[] = {
63 MFD_CELL_NAME("s2mps11-regulator"),
64 MFD_CELL_RES("s2mps14-rtc", s2mps11_rtc_resources),
65 MFD_CELL_OF("s2mps11-clk", NULL, NULL, 0, 0, "samsung,s2mps11-clk"),
66 };
67
68 static const struct resource s2mps14_rtc_resources[] = {
69 DEFINE_RES_IRQ_NAMED(S2MPS14_IRQ_RTCA0, "alarm"),
70 };
71
72 static const struct mfd_cell s2mps13_devs[] = {
73 MFD_CELL_NAME("s2mps13-regulator"),
74 MFD_CELL_RES("s2mps13-rtc", s2mps14_rtc_resources),
75 MFD_CELL_OF("s2mps13-clk", NULL, NULL, 0, 0, "samsung,s2mps13-clk"),
76 };
77
78 static const struct mfd_cell s2mps14_devs[] = {
79 MFD_CELL_NAME("s2mps14-regulator"),
80 MFD_CELL_RES("s2mps14-rtc", s2mps14_rtc_resources),
81 MFD_CELL_OF("s2mps14-clk", NULL, NULL, 0, 0, "samsung,s2mps14-clk"),
82 };
83
84 static const struct mfd_cell s2mps15_devs[] = {
85 MFD_CELL_NAME("s2mps15-regulator"),
86 MFD_CELL_RES("s2mps15-rtc", s2mps14_rtc_resources),
87 MFD_CELL_OF("s2mps13-clk", NULL, NULL, 0, 0, "samsung,s2mps13-clk"),
88 };
89
90 static const struct mfd_cell s2mpa01_devs[] = {
91 MFD_CELL_NAME("s2mpa01-pmic"),
92 MFD_CELL_RES("s2mps14-rtc", s2mps14_rtc_resources),
93 };
94
95 static const struct mfd_cell s2mpu02_devs[] = {
96 MFD_CELL_NAME("s2mpu02-regulator"),
97 };
98
99 static const struct resource s2mpu05_rtc_resources[] = {
100 DEFINE_RES_IRQ_NAMED(S2MPU05_IRQ_RTCA0, "alarm"),
101 };
102
103 static const struct mfd_cell s2mpu05_devs[] = {
104 MFD_CELL_NAME("s2mpu05-regulator"),
105 MFD_CELL_RES("s2mps15-rtc", s2mpu05_rtc_resources),
106 };
107
sec_pmic_dump_rev(struct sec_pmic_dev * sec_pmic)108 static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic)
109 {
110 unsigned int val;
111
112 /* For s2mpg1x, the revision is in a different regmap */
113 switch (sec_pmic->device_type) {
114 case S2MPG10:
115 case S2MPG11:
116 return;
117 default:
118 break;
119 }
120
121 /* For each device type, the REG_ID is always the first register */
122 if (!regmap_read(sec_pmic->regmap_pmic, S2MPS11_REG_ID, &val))
123 dev_dbg(sec_pmic->dev, "Revision: 0x%x\n", val);
124 }
125
sec_pmic_configure(struct sec_pmic_dev * sec_pmic)126 static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic)
127 {
128 int err;
129
130 if (sec_pmic->device_type != S2MPS13X)
131 return;
132
133 if (sec_pmic->pdata->disable_wrstbi) {
134 /*
135 * If WRSTBI pin is pulled down this feature must be disabled
136 * because each Suspend to RAM will trigger buck voltage reset
137 * to default values.
138 */
139 err = regmap_update_bits(sec_pmic->regmap_pmic,
140 S2MPS13_REG_WRSTBI,
141 S2MPS13_REG_WRSTBI_MASK, 0x0);
142 if (err)
143 dev_warn(sec_pmic->dev,
144 "Cannot initialize WRSTBI config: %d\n",
145 err);
146 }
147 }
148
149 /*
150 * Only the common platform data elements for s5m8767 are parsed here from the
151 * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and
152 * others have to parse their own platform data elements from device tree.
153 *
154 * The s5m8767 platform data structure is instantiated here and the drivers for
155 * the sub-modules need not instantiate another instance while parsing their
156 * platform data.
157 */
158 static struct sec_platform_data *
sec_pmic_parse_dt_pdata(struct device * dev)159 sec_pmic_parse_dt_pdata(struct device *dev)
160 {
161 struct sec_platform_data *pd;
162
163 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
164 if (!pd)
165 return ERR_PTR(-ENOMEM);
166
167 pd->manual_poweroff = of_property_read_bool(dev->of_node,
168 "samsung,s2mps11-acokb-ground");
169 pd->disable_wrstbi = of_property_read_bool(dev->of_node,
170 "samsung,s2mps11-wrstbi-ground");
171 return pd;
172 }
173
sec_pmic_probe(struct device * dev,int device_type,unsigned int irq,struct regmap * regmap,struct i2c_client * client)174 int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq,
175 struct regmap *regmap, struct i2c_client *client)
176 {
177 struct regmap_irq_chip_data *irq_data;
178 struct sec_platform_data *pdata;
179 const struct mfd_cell *sec_devs;
180 struct sec_pmic_dev *sec_pmic;
181 int ret, num_sec_devs;
182
183 sec_pmic = devm_kzalloc(dev, sizeof(*sec_pmic), GFP_KERNEL);
184 if (!sec_pmic)
185 return -ENOMEM;
186
187 dev_set_drvdata(dev, sec_pmic);
188 sec_pmic->dev = dev;
189 sec_pmic->device_type = device_type;
190 sec_pmic->i2c = client;
191 sec_pmic->irq = irq;
192 sec_pmic->regmap_pmic = regmap;
193
194 pdata = sec_pmic_parse_dt_pdata(sec_pmic->dev);
195 if (IS_ERR(pdata)) {
196 ret = PTR_ERR(pdata);
197 return ret;
198 }
199
200 sec_pmic->pdata = pdata;
201
202 irq_data = sec_irq_init(sec_pmic);
203 if (IS_ERR(irq_data))
204 return PTR_ERR(irq_data);
205
206 pm_runtime_set_active(sec_pmic->dev);
207
208 switch (sec_pmic->device_type) {
209 case S5M8767X:
210 sec_devs = s5m8767_devs;
211 num_sec_devs = ARRAY_SIZE(s5m8767_devs);
212 break;
213 case S2DOS05:
214 sec_devs = s2dos05_devs;
215 num_sec_devs = ARRAY_SIZE(s2dos05_devs);
216 break;
217 case S2MPA01:
218 sec_devs = s2mpa01_devs;
219 num_sec_devs = ARRAY_SIZE(s2mpa01_devs);
220 break;
221 case S2MPG10:
222 sec_devs = s2mpg10_devs;
223 num_sec_devs = ARRAY_SIZE(s2mpg10_devs);
224 break;
225 case S2MPG11:
226 sec_devs = s2mpg11_devs;
227 num_sec_devs = ARRAY_SIZE(s2mpg11_devs);
228 break;
229 case S2MPS11X:
230 sec_devs = s2mps11_devs;
231 num_sec_devs = ARRAY_SIZE(s2mps11_devs);
232 break;
233 case S2MPS13X:
234 sec_devs = s2mps13_devs;
235 num_sec_devs = ARRAY_SIZE(s2mps13_devs);
236 break;
237 case S2MPS14X:
238 sec_devs = s2mps14_devs;
239 num_sec_devs = ARRAY_SIZE(s2mps14_devs);
240 break;
241 case S2MPS15X:
242 sec_devs = s2mps15_devs;
243 num_sec_devs = ARRAY_SIZE(s2mps15_devs);
244 break;
245 case S2MPU02:
246 sec_devs = s2mpu02_devs;
247 num_sec_devs = ARRAY_SIZE(s2mpu02_devs);
248 break;
249 case S2MPU05:
250 sec_devs = s2mpu05_devs;
251 num_sec_devs = ARRAY_SIZE(s2mpu05_devs);
252 break;
253 default:
254 return dev_err_probe(sec_pmic->dev, -EINVAL,
255 "Unsupported device type %d\n",
256 sec_pmic->device_type);
257 }
258 ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs,
259 NULL, 0, regmap_irq_get_domain(irq_data));
260 if (ret)
261 return ret;
262
263 sec_pmic_configure(sec_pmic);
264 sec_pmic_dump_rev(sec_pmic);
265
266 return ret;
267 }
268 EXPORT_SYMBOL_GPL(sec_pmic_probe);
269
sec_pmic_shutdown(struct device * dev)270 void sec_pmic_shutdown(struct device *dev)
271 {
272 struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev);
273 unsigned int reg, mask;
274
275 if (!sec_pmic->pdata->manual_poweroff)
276 return;
277
278 switch (sec_pmic->device_type) {
279 case S2MPS11X:
280 reg = S2MPS11_REG_CTRL1;
281 mask = S2MPS11_CTRL1_PWRHOLD_MASK;
282 break;
283 default:
284 /*
285 * Currently only one board with S2MPS11 needs this, so just
286 * ignore the rest.
287 */
288 dev_warn(sec_pmic->dev,
289 "Unsupported device %d for manual power off\n",
290 sec_pmic->device_type);
291 return;
292 }
293
294 regmap_update_bits(sec_pmic->regmap_pmic, reg, mask, 0);
295 }
296 EXPORT_SYMBOL_GPL(sec_pmic_shutdown);
297
sec_pmic_suspend(struct device * dev)298 static int sec_pmic_suspend(struct device *dev)
299 {
300 struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev);
301
302 if (device_may_wakeup(dev))
303 enable_irq_wake(sec_pmic->irq);
304 /*
305 * PMIC IRQ must be disabled during suspend for RTC alarm
306 * to work properly.
307 * When device is woken up from suspend, an
308 * interrupt occurs before resuming I2C bus controller.
309 * The interrupt is handled by regmap_irq_thread which tries
310 * to read RTC registers. This read fails (I2C is still
311 * suspended) and RTC Alarm interrupt is disabled.
312 */
313 disable_irq(sec_pmic->irq);
314
315 return 0;
316 }
317
sec_pmic_resume(struct device * dev)318 static int sec_pmic_resume(struct device *dev)
319 {
320 struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev);
321
322 if (device_may_wakeup(dev))
323 disable_irq_wake(sec_pmic->irq);
324 enable_irq(sec_pmic->irq);
325
326 return 0;
327 }
328
329 DEFINE_SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);
330 EXPORT_SYMBOL_GPL(sec_pmic_pm_ops);
331
332 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
333 MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
334 MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
335 MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>");
336 MODULE_DESCRIPTION("Core driver for the Samsung S5M");
337 MODULE_LICENSE("GPL");
338