blob: 5f2a182bf355751b749c6a2b86477c0dd61b4c18 [file] [log] [blame]
Thomas Gleixner2025cf92019-05-29 07:18:02 -07001// SPDX-License-Identifier: GPL-2.0-only
Chris Zhongf69a7cf2014-09-03 21:51:44 +08002/*
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02003 * MFD core driver for Rockchip RK808/RK818
Chris Zhongf69a7cf2014-09-03 21:51:44 +08004 *
Tony Xiea921d232018-04-17 15:27:32 +08005 * Copyright (c) 2014-2018, Fuzhou Rockchip Electronics Co., Ltd
Chris Zhongf69a7cf2014-09-03 21:51:44 +08006 *
7 * Author: Chris Zhong <zyw@rock-chips.com>
8 * Author: Zhang Qing <zhangqing@rock-chips.com>
9 *
Wadim Egorov2eedcbf2016-08-29 13:07:58 +020010 * Copyright (C) 2016 PHYTEC Messtechnik GmbH
11 *
12 * Author: Wadim Egorov <w.egorov@phytec.de>
Chris Zhongf69a7cf2014-09-03 21:51:44 +080013 */
14
15#include <linux/i2c.h>
16#include <linux/interrupt.h>
17#include <linux/mfd/rk808.h>
18#include <linux/mfd/core.h>
19#include <linux/module.h>
Wadim Egorov2eedcbf2016-08-29 13:07:58 +020020#include <linux/of_device.h>
Tony Xiea921d232018-04-17 15:27:32 +080021#include <linux/reboot.h>
Chris Zhongf69a7cf2014-09-03 21:51:44 +080022#include <linux/regmap.h>
Tony Xie2dc862f2018-02-07 15:05:03 +080023#include <linux/pinctrl/consumer.h>
24#include <linux/pinctrl/devinfo.h>
Chris Zhongf69a7cf2014-09-03 21:51:44 +080025
26struct rk808_reg_data {
27 int addr;
28 int mask;
29 int value;
30};
31
Doug Anderson2adb3b82014-09-09 16:06:04 -070032static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
33{
34 /*
35 * Notes:
36 * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
37 * we don't use that feature. It's better to cache.
38 * - It's unlikely we care that RK808_DEVCTRL_REG is volatile since
39 * bits are cleared in case when we shutoff anyway, but better safe.
40 */
41
42 switch (reg) {
43 case RK808_SECONDS_REG ... RK808_WEEKS_REG:
44 case RK808_RTC_STATUS_REG:
45 case RK808_VB_MON_REG:
46 case RK808_THERMAL_REG:
47 case RK808_DCDC_UV_STS_REG:
48 case RK808_LDO_UV_STS_REG:
49 case RK808_DCDC_PG_REG:
50 case RK808_LDO_PG_REG:
51 case RK808_DEVCTRL_REG:
52 case RK808_INT_STS_REG1:
53 case RK808_INT_STS_REG2:
54 return true;
55 }
56
57 return false;
58}
59
Tony Xie586c1b42019-06-21 06:32:54 -040060static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
61{
62 /*
63 * Notes:
64 * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
65 * we don't use that feature. It's better to cache.
66 */
67
68 switch (reg) {
69 case RK817_SECONDS_REG ... RK817_WEEKS_REG:
70 case RK817_RTC_STATUS_REG:
71 case RK817_INT_STS_REG0:
72 case RK817_INT_STS_REG1:
73 case RK817_INT_STS_REG2:
74 case RK817_SYS_STS:
75 return true;
76 }
77
shengfei Xub2df0702020-04-27 16:23:59 +080078 return false;
Tony Xie586c1b42019-06-21 06:32:54 -040079}
80
Joseph Chen3bb76af2019-11-01 17:52:18 +080081static bool rk818_is_volatile_reg(struct device *dev, unsigned int reg)
82{
83 /*
84 * Notes:
85 * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
86 * we don't use that feature. It's better to cache.
87 * - It's unlikely we care that RK808_DEVCTRL_REG is volatile since
88 * bits are cleared in case when we shutoff anyway, but better safe.
89 */
90
91 switch (reg) {
92 case RK808_SECONDS_REG ... RK808_WEEKS_REG:
93 case RK808_RTC_STATUS_REG:
94 case RK808_VB_MON_REG:
95 case RK808_THERMAL_REG:
96 case RK808_DCDC_EN_REG:
97 case RK808_LDO_EN_REG:
98 case RK808_DCDC_UV_STS_REG:
99 case RK808_LDO_UV_STS_REG:
100 case RK808_DCDC_PG_REG:
101 case RK808_LDO_PG_REG:
102 case RK808_DEVCTRL_REG:
103 case RK808_INT_STS_REG1:
104 case RK808_INT_STS_REG2:
105 case RK808_INT_STS_MSK_REG1:
106 case RK808_INT_STS_MSK_REG2:
Joseph Chen5a363f32019-11-09 17:17:45 +0800107 case RK816_INT_STS_REG1:
108 case RK816_INT_STS_MSK_REG1:
Joseph Chen3bb76af2019-11-01 17:52:18 +0800109 case RK818_SUP_STS_REG ... RK818_SAVE_DATA19:
110 return true;
111 }
112
113 return false;
114}
115
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200116static const struct regmap_config rk818_regmap_config = {
117 .reg_bits = 8,
118 .val_bits = 8,
Joseph Chen3bb76af2019-11-01 17:52:18 +0800119 .max_register = RK818_SAVE_DATA19,
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200120 .cache_type = REGCACHE_RBTREE,
Joseph Chen3bb76af2019-11-01 17:52:18 +0800121 .volatile_reg = rk818_is_volatile_reg,
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200122};
123
Elaine Zhang990f05f2017-08-21 03:28:38 +0200124static const struct regmap_config rk805_regmap_config = {
125 .reg_bits = 8,
126 .val_bits = 8,
127 .max_register = RK805_OFF_SOURCE_REG,
128 .cache_type = REGCACHE_RBTREE,
129 .volatile_reg = rk808_is_volatile_reg,
130};
131
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800132static const struct regmap_config rk808_regmap_config = {
133 .reg_bits = 8,
134 .val_bits = 8,
135 .max_register = RK808_IO_POL_REG,
Doug Anderson2adb3b82014-09-09 16:06:04 -0700136 .cache_type = REGCACHE_RBTREE,
137 .volatile_reg = rk808_is_volatile_reg,
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800138};
139
Joseph Chen5a363f32019-11-09 17:17:45 +0800140static const struct regmap_config rk816_regmap_config = {
141 .reg_bits = 8,
142 .val_bits = 8,
143 .max_register = RK816_DATA18_REG,
144 .cache_type = REGCACHE_RBTREE,
145 .volatile_reg = rk818_is_volatile_reg,
146};
147
Tony Xie586c1b42019-06-21 06:32:54 -0400148static const struct regmap_config rk817_regmap_config = {
149 .reg_bits = 8,
150 .val_bits = 8,
151 .max_register = RK817_GPIO_INT_CFG,
shengfei Xub2df0702020-04-27 16:23:59 +0800152 .num_reg_defaults_raw = RK817_GPIO_INT_CFG + 1,
153 .cache_type = REGCACHE_RBTREE,
Tony Xie586c1b42019-06-21 06:32:54 -0400154 .volatile_reg = rk817_is_volatile_reg,
155};
156
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800157static struct resource rtc_resources[] = {
Heiko Stuebnereeb86ed2019-09-17 10:12:56 +0200158 DEFINE_RES_IRQ(RK808_IRQ_RTC_ALARM),
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800159};
160
Joseph Chen5a363f32019-11-09 17:17:45 +0800161static struct resource rk816_rtc_resources[] = {
162 DEFINE_RES_IRQ(RK816_IRQ_RTC_ALARM),
163};
164
Tony Xie586c1b42019-06-21 06:32:54 -0400165static struct resource rk817_rtc_resources[] = {
166 DEFINE_RES_IRQ(RK817_IRQ_RTC_ALARM),
167};
168
Joseph Chenf7c22392017-08-21 03:28:42 +0200169static struct resource rk805_key_resources[] = {
Heiko Stuebnerbc85e4a2019-09-17 10:12:54 +0200170 DEFINE_RES_IRQ(RK805_IRQ_PWRON_FALL),
Shengfei Xud061e5e2019-09-25 19:20:05 +0800171 DEFINE_RES_IRQ(RK805_IRQ_PWRON_RISE),
Joseph Chenf7c22392017-08-21 03:28:42 +0200172};
173
Joseph Chen5a363f32019-11-09 17:17:45 +0800174static struct resource rk816_pwrkey_resources[] = {
175 DEFINE_RES_IRQ(RK816_IRQ_PWRON_FALL),
176 DEFINE_RES_IRQ(RK816_IRQ_PWRON_RISE),
177};
178
Tony Xie586c1b42019-06-21 06:32:54 -0400179static struct resource rk817_pwrkey_resources[] = {
Tony Xie586c1b42019-06-21 06:32:54 -0400180 DEFINE_RES_IRQ(RK817_IRQ_PWRON_FALL),
Shengfei Xud061e5e2019-09-25 19:20:05 +0800181 DEFINE_RES_IRQ(RK817_IRQ_PWRON_RISE),
Tony Xie586c1b42019-06-21 06:32:54 -0400182};
183
Elaine Zhang990f05f2017-08-21 03:28:38 +0200184static const struct mfd_cell rk805s[] = {
185 { .name = "rk808-clkout", },
186 { .name = "rk808-regulator", },
Joseph Chen8d249b62017-08-21 03:28:41 +0200187 { .name = "rk805-pinctrl", },
Elaine Zhang990f05f2017-08-21 03:28:38 +0200188 {
189 .name = "rk808-rtc",
190 .num_resources = ARRAY_SIZE(rtc_resources),
191 .resources = &rtc_resources[0],
192 },
Joseph Chenf7c22392017-08-21 03:28:42 +0200193 { .name = "rk805-pwrkey",
194 .num_resources = ARRAY_SIZE(rk805_key_resources),
195 .resources = &rk805_key_resources[0],
196 },
Elaine Zhang990f05f2017-08-21 03:28:38 +0200197};
198
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800199static const struct mfd_cell rk808s[] = {
200 { .name = "rk808-clkout", },
201 { .name = "rk808-regulator", },
202 {
203 .name = "rk808-rtc",
204 .num_resources = ARRAY_SIZE(rtc_resources),
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200205 .resources = rtc_resources,
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800206 },
207};
208
Joseph Chen5a363f32019-11-09 17:17:45 +0800209static const struct mfd_cell rk816s[] = {
210 { .name = "rk808-clkout", },
211 { .name = "rk808-regulator", },
212 { .name = "rk805-pinctrl", },
213 { .name = "rk816-battery", .of_compatible = "rk816-battery", },
214 {
215 .name = "rk805-pwrkey",
216 .num_resources = ARRAY_SIZE(rk816_pwrkey_resources),
217 .resources = &rk816_pwrkey_resources[0],
218 },
219 {
220 .name = "rk808-rtc",
221 .num_resources = ARRAY_SIZE(rk816_rtc_resources),
222 .resources = &rk816_rtc_resources[0],
223 },
224};
225
Tony Xie586c1b42019-06-21 06:32:54 -0400226static const struct mfd_cell rk817s[] = {
227 { .name = "rk808-clkout",},
228 { .name = "rk808-regulator",},
229 {
Heiko Stuebnerbc85e4a2019-09-17 10:12:54 +0200230 .name = "rk805-pwrkey",
Tony Xie586c1b42019-06-21 06:32:54 -0400231 .num_resources = ARRAY_SIZE(rk817_pwrkey_resources),
232 .resources = &rk817_pwrkey_resources[0],
233 },
234 {
235 .name = "rk808-rtc",
236 .num_resources = ARRAY_SIZE(rk817_rtc_resources),
237 .resources = &rk817_rtc_resources[0],
238 },
Shunhua Land66acca2019-09-12 16:07:40 +0800239 {
240 .name = "rk817-codec",
241 .of_compatible = "rockchip,rk817-codec",
242 },
Tony Xie586c1b42019-06-21 06:32:54 -0400243};
244
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200245static const struct mfd_cell rk818s[] = {
246 { .name = "rk808-clkout", },
247 { .name = "rk808-regulator", },
248 {
249 .name = "rk808-rtc",
250 .num_resources = ARRAY_SIZE(rtc_resources),
251 .resources = rtc_resources,
252 },
253};
254
Elaine Zhang990f05f2017-08-21 03:28:38 +0200255static const struct rk808_reg_data rk805_pre_init_reg[] = {
Elaine Zhang990f05f2017-08-21 03:28:38 +0200256 {RK805_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_400MA},
Elaine Zhang990f05f2017-08-21 03:28:38 +0200257 {RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C},
258};
259
Joseph Chenf7bff6c2017-11-21 10:27:59 +0800260static struct rk808_reg_data rk805_suspend_reg[] = {
261 {RK805_BUCK3_CONFIG_REG, PWM_MODE_MSK, AUTO_PWM_MODE},
262};
263
264static struct rk808_reg_data rk805_resume_reg[] = {
265 {RK805_BUCK3_CONFIG_REG, PWM_MODE_MSK, FPWM_MODE},
266};
267
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200268static const struct rk808_reg_data rk808_pre_init_reg[] = {
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800269 { RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_150MA },
270 { RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_200MA },
271 { RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
272 { RK808_BUCK1_CONFIG_REG, BUCK1_RATE_MASK, BUCK_ILMIN_200MA },
273 { RK808_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_200MA },
Chris Zhonge19f7422015-02-28 18:09:06 +0800274 { RK808_DCDC_UV_ACT_REG, BUCK_UV_ACT_MASK, BUCK_UV_ACT_DISABLE},
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800275 { RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT |
276 VB_LO_SEL_3500MV },
277};
278
Joseph Chen5a363f32019-11-09 17:17:45 +0800279static const struct rk808_reg_data rk816_pre_init_reg[] = {
280 /* buck4 Max ILMIT*/
281 { RK816_BUCK4_CONFIG_REG, REG_WRITE_MSK, BUCK4_MAX_ILIMIT },
282 /* hotdie temperature: 105c*/
283 { RK816_THERMAL_REG, REG_WRITE_MSK, TEMP105C },
284 /* set buck 12.5mv/us */
285 { RK816_BUCK1_CONFIG_REG, BUCK_RATE_MSK, BUCK_RATE_12_5MV_US },
286 { RK816_BUCK2_CONFIG_REG, BUCK_RATE_MSK, BUCK_RATE_12_5MV_US },
287 /* enable RTC_PERIOD & RTC_ALARM int */
288 { RK816_INT_STS_MSK_REG2, REG_WRITE_MSK, RTC_PERIOD_ALARM_INT_EN },
289 /* set bat 3.0 low and act shutdown */
290 { RK816_VB_MON_REG, VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK,
291 RK816_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN },
292 /* enable PWRON rising/faling int */
293 { RK816_INT_STS_MSK_REG1, REG_WRITE_MSK, RK816_PWRON_FALL_RISE_INT_EN },
294 /* enable PLUG IN/OUT int */
295 { RK816_INT_STS_MSK_REG3, REG_WRITE_MSK, PLUGIN_OUT_INT_EN },
296 /* clear int flags */
297 { RK816_INT_STS_REG1, REG_WRITE_MSK, ALL_INT_FLAGS_ST },
298 { RK816_INT_STS_REG2, REG_WRITE_MSK, ALL_INT_FLAGS_ST },
299 { RK816_INT_STS_REG3, REG_WRITE_MSK, ALL_INT_FLAGS_ST },
300 { RK816_DCDC_EN_REG2, BOOST_EN_MASK, BOOST_DISABLE },
301 /* set write mask bit 1, otherwise 'is_enabled()' get wrong status */
302 { RK816_LDO_EN_REG1, REGS_WMSK, REGS_WMSK },
303 { RK816_LDO_EN_REG2, REGS_WMSK, REGS_WMSK },
304};
305
Tony Xie586c1b42019-06-21 06:32:54 -0400306static const struct rk808_reg_data rk817_pre_init_reg[] = {
shengfei Xub2df0702020-04-27 16:23:59 +0800307 {RK817_SYS_CFG(3), RK817_SLPPOL_MSK, RK817_SLPPOL_L},
Tony Xie586c1b42019-06-21 06:32:54 -0400308 {RK817_RTC_CTRL_REG, RTC_STOP, RTC_STOP},
Heiko Stuebnerdbd16ef2019-09-17 10:12:55 +0200309 {RK817_GPIO_INT_CFG, RK817_INT_POL_MSK, RK817_INT_POL_L},
Tony Xie586c1b42019-06-21 06:32:54 -0400310 {RK817_SYS_CFG(1), RK817_HOTDIE_TEMP_MSK | RK817_TSD_TEMP_MSK,
311 RK817_HOTDIE_105 | RK817_TSD_140},
312};
313
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200314static const struct rk808_reg_data rk818_pre_init_reg[] = {
315 /* improve efficiency */
316 { RK818_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_250MA },
317 { RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_250MA },
318 { RK818_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
319 { RK818_USB_CTRL_REG, RK818_USB_ILIM_SEL_MASK,
320 RK818_USB_ILMIN_2000MA },
321 /* close charger when usb lower then 3.4V */
322 { RK818_USB_CTRL_REG, RK818_USB_CHG_SD_VSEL_MASK,
323 (0x7 << 4) },
324 /* no action when vref */
325 { RK818_H5V_EN_REG, BIT(1), RK818_REF_RDY_CTRL },
326 /* enable HDMI 5V */
327 { RK818_H5V_EN_REG, BIT(0), RK818_H5V_EN },
328 { RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT |
329 VB_LO_SEL_3500MV },
330};
331
Elaine Zhang990f05f2017-08-21 03:28:38 +0200332static const struct regmap_irq rk805_irqs[] = {
333 [RK805_IRQ_PWRON_RISE] = {
334 .mask = RK805_IRQ_PWRON_RISE_MSK,
335 .reg_offset = 0,
336 },
337 [RK805_IRQ_VB_LOW] = {
338 .mask = RK805_IRQ_VB_LOW_MSK,
339 .reg_offset = 0,
340 },
341 [RK805_IRQ_PWRON] = {
342 .mask = RK805_IRQ_PWRON_MSK,
343 .reg_offset = 0,
344 },
345 [RK805_IRQ_PWRON_LP] = {
346 .mask = RK805_IRQ_PWRON_LP_MSK,
347 .reg_offset = 0,
348 },
349 [RK805_IRQ_HOTDIE] = {
350 .mask = RK805_IRQ_HOTDIE_MSK,
351 .reg_offset = 0,
352 },
353 [RK805_IRQ_RTC_ALARM] = {
354 .mask = RK805_IRQ_RTC_ALARM_MSK,
355 .reg_offset = 0,
356 },
357 [RK805_IRQ_RTC_PERIOD] = {
358 .mask = RK805_IRQ_RTC_PERIOD_MSK,
359 .reg_offset = 0,
360 },
361 [RK805_IRQ_PWRON_FALL] = {
362 .mask = RK805_IRQ_PWRON_FALL_MSK,
363 .reg_offset = 0,
364 },
365};
366
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800367static const struct regmap_irq rk808_irqs[] = {
368 /* INT_STS */
369 [RK808_IRQ_VOUT_LO] = {
370 .mask = RK808_IRQ_VOUT_LO_MSK,
371 .reg_offset = 0,
372 },
373 [RK808_IRQ_VB_LO] = {
374 .mask = RK808_IRQ_VB_LO_MSK,
375 .reg_offset = 0,
376 },
377 [RK808_IRQ_PWRON] = {
378 .mask = RK808_IRQ_PWRON_MSK,
379 .reg_offset = 0,
380 },
381 [RK808_IRQ_PWRON_LP] = {
382 .mask = RK808_IRQ_PWRON_LP_MSK,
383 .reg_offset = 0,
384 },
385 [RK808_IRQ_HOTDIE] = {
386 .mask = RK808_IRQ_HOTDIE_MSK,
387 .reg_offset = 0,
388 },
389 [RK808_IRQ_RTC_ALARM] = {
390 .mask = RK808_IRQ_RTC_ALARM_MSK,
391 .reg_offset = 0,
392 },
393 [RK808_IRQ_RTC_PERIOD] = {
394 .mask = RK808_IRQ_RTC_PERIOD_MSK,
395 .reg_offset = 0,
396 },
397
398 /* INT_STS2 */
399 [RK808_IRQ_PLUG_IN_INT] = {
400 .mask = RK808_IRQ_PLUG_IN_INT_MSK,
401 .reg_offset = 1,
402 },
403 [RK808_IRQ_PLUG_OUT_INT] = {
404 .mask = RK808_IRQ_PLUG_OUT_INT_MSK,
405 .reg_offset = 1,
406 },
407};
408
Joseph Chenf7bff6c2017-11-21 10:27:59 +0800409static struct rk808_reg_data rk816_suspend_reg[] = {
410 /* set bat 3.4v low and act irq */
411 { RK816_VB_MON_REG, VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK,
412 RK816_VBAT_LOW_3V4 | EN_VBAT_LOW_IRQ },
413};
414
415static struct rk808_reg_data rk816_resume_reg[] = {
416 /* set bat 3.0v low and act shutdown */
417 { RK816_VB_MON_REG, VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK,
418 RK816_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN },
419};
420
Joseph Chen5a363f32019-11-09 17:17:45 +0800421static const struct regmap_irq rk816_irqs[] = {
422 /* INT_STS */
423 [RK816_IRQ_PWRON_FALL] = {
424 .mask = RK816_IRQ_PWRON_FALL_MSK,
425 .reg_offset = 0,
426 },
427 [RK816_IRQ_PWRON_RISE] = {
428 .mask = RK816_IRQ_PWRON_RISE_MSK,
429 .reg_offset = 0,
430 },
431 [RK816_IRQ_VB_LOW] = {
432 .mask = RK816_IRQ_VB_LOW_MSK,
433 .reg_offset = 1,
434 },
435 [RK816_IRQ_PWRON] = {
436 .mask = RK816_IRQ_PWRON_MSK,
437 .reg_offset = 1,
438 },
439 [RK816_IRQ_PWRON_LP] = {
440 .mask = RK816_IRQ_PWRON_LP_MSK,
441 .reg_offset = 1,
442 },
443 [RK816_IRQ_HOTDIE] = {
444 .mask = RK816_IRQ_HOTDIE_MSK,
445 .reg_offset = 1,
446 },
447 [RK816_IRQ_RTC_ALARM] = {
448 .mask = RK816_IRQ_RTC_ALARM_MSK,
449 .reg_offset = 1,
450 },
451 [RK816_IRQ_RTC_PERIOD] = {
452 .mask = RK816_IRQ_RTC_PERIOD_MSK,
453 .reg_offset = 1,
454 },
455 [RK816_IRQ_USB_OV] = {
456 .mask = RK816_IRQ_USB_OV_MSK,
457 .reg_offset = 1,
458 },
459};
460
Joseph Chenf7bff6c2017-11-21 10:27:59 +0800461static struct rk808_reg_data rk818_suspend_reg[] = {
462 /* set bat 3.4v low and act irq */
463 { RK808_VB_MON_REG, VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK,
464 RK808_VBAT_LOW_3V4 | EN_VBAT_LOW_IRQ },
465};
466
467static struct rk808_reg_data rk818_resume_reg[] = {
468 /* set bat 3.0v low and act shutdown */
469 { RK808_VB_MON_REG, VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK,
470 RK808_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN },
471};
472
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200473static const struct regmap_irq rk818_irqs[] = {
474 /* INT_STS */
475 [RK818_IRQ_VOUT_LO] = {
476 .mask = RK818_IRQ_VOUT_LO_MSK,
477 .reg_offset = 0,
478 },
479 [RK818_IRQ_VB_LO] = {
480 .mask = RK818_IRQ_VB_LO_MSK,
481 .reg_offset = 0,
482 },
483 [RK818_IRQ_PWRON] = {
484 .mask = RK818_IRQ_PWRON_MSK,
485 .reg_offset = 0,
486 },
487 [RK818_IRQ_PWRON_LP] = {
488 .mask = RK818_IRQ_PWRON_LP_MSK,
489 .reg_offset = 0,
490 },
491 [RK818_IRQ_HOTDIE] = {
492 .mask = RK818_IRQ_HOTDIE_MSK,
493 .reg_offset = 0,
494 },
495 [RK818_IRQ_RTC_ALARM] = {
496 .mask = RK818_IRQ_RTC_ALARM_MSK,
497 .reg_offset = 0,
498 },
499 [RK818_IRQ_RTC_PERIOD] = {
500 .mask = RK818_IRQ_RTC_PERIOD_MSK,
501 .reg_offset = 0,
502 },
503 [RK818_IRQ_USB_OV] = {
504 .mask = RK818_IRQ_USB_OV_MSK,
505 .reg_offset = 0,
506 },
507
508 /* INT_STS2 */
509 [RK818_IRQ_PLUG_IN] = {
510 .mask = RK818_IRQ_PLUG_IN_MSK,
511 .reg_offset = 1,
512 },
513 [RK818_IRQ_PLUG_OUT] = {
514 .mask = RK818_IRQ_PLUG_OUT_MSK,
515 .reg_offset = 1,
516 },
517 [RK818_IRQ_CHG_OK] = {
518 .mask = RK818_IRQ_CHG_OK_MSK,
519 .reg_offset = 1,
520 },
521 [RK818_IRQ_CHG_TE] = {
522 .mask = RK818_IRQ_CHG_TE_MSK,
523 .reg_offset = 1,
524 },
525 [RK818_IRQ_CHG_TS1] = {
526 .mask = RK818_IRQ_CHG_TS1_MSK,
527 .reg_offset = 1,
528 },
529 [RK818_IRQ_TS2] = {
530 .mask = RK818_IRQ_TS2_MSK,
531 .reg_offset = 1,
532 },
533 [RK818_IRQ_CHG_CVTLIM] = {
534 .mask = RK818_IRQ_CHG_CVTLIM_MSK,
535 .reg_offset = 1,
536 },
537 [RK818_IRQ_DISCHG_ILIM] = {
538 .mask = RK818_IRQ_DISCHG_ILIM_MSK,
539 .reg_offset = 1,
540 },
541};
542
Tony Xie586c1b42019-06-21 06:32:54 -0400543static const struct regmap_irq rk817_irqs[RK817_IRQ_END] = {
544 REGMAP_IRQ_REG_LINE(0, 8),
545 REGMAP_IRQ_REG_LINE(1, 8),
546 REGMAP_IRQ_REG_LINE(2, 8),
547 REGMAP_IRQ_REG_LINE(3, 8),
548 REGMAP_IRQ_REG_LINE(4, 8),
549 REGMAP_IRQ_REG_LINE(5, 8),
550 REGMAP_IRQ_REG_LINE(6, 8),
551 REGMAP_IRQ_REG_LINE(7, 8),
552 REGMAP_IRQ_REG_LINE(8, 8),
553 REGMAP_IRQ_REG_LINE(9, 8),
554 REGMAP_IRQ_REG_LINE(10, 8),
555 REGMAP_IRQ_REG_LINE(11, 8),
556 REGMAP_IRQ_REG_LINE(12, 8),
557 REGMAP_IRQ_REG_LINE(13, 8),
558 REGMAP_IRQ_REG_LINE(14, 8),
559 REGMAP_IRQ_REG_LINE(15, 8),
560 REGMAP_IRQ_REG_LINE(16, 8),
561 REGMAP_IRQ_REG_LINE(17, 8),
562 REGMAP_IRQ_REG_LINE(18, 8),
563 REGMAP_IRQ_REG_LINE(19, 8),
564 REGMAP_IRQ_REG_LINE(20, 8),
565 REGMAP_IRQ_REG_LINE(21, 8),
566 REGMAP_IRQ_REG_LINE(22, 8),
567 REGMAP_IRQ_REG_LINE(23, 8)
568};
569
Elaine Zhang990f05f2017-08-21 03:28:38 +0200570static struct regmap_irq_chip rk805_irq_chip = {
571 .name = "rk805",
572 .irqs = rk805_irqs,
573 .num_irqs = ARRAY_SIZE(rk805_irqs),
574 .num_regs = 1,
575 .status_base = RK805_INT_STS_REG,
576 .mask_base = RK805_INT_STS_MSK_REG,
577 .ack_base = RK805_INT_STS_REG,
578 .init_ack_masked = true,
579};
580
Bhumika Goyal24e34b92017-01-25 00:55:24 +0530581static const struct regmap_irq_chip rk808_irq_chip = {
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800582 .name = "rk808",
583 .irqs = rk808_irqs,
584 .num_irqs = ARRAY_SIZE(rk808_irqs),
585 .num_regs = 2,
586 .irq_reg_stride = 2,
587 .status_base = RK808_INT_STS_REG1,
588 .mask_base = RK808_INT_STS_MSK_REG1,
589 .ack_base = RK808_INT_STS_REG1,
590 .init_ack_masked = true,
591};
592
Joseph Chen5a363f32019-11-09 17:17:45 +0800593static const struct regmap_irq rk816_battery_irqs[] = {
594 /* INT_STS */
595 [RK816_IRQ_PLUG_IN] = {
596 .mask = RK816_IRQ_PLUG_IN_MSK,
597 .reg_offset = 0,
598 },
599 [RK816_IRQ_PLUG_OUT] = {
600 .mask = RK816_IRQ_PLUG_OUT_MSK,
601 .reg_offset = 0,
602 },
603 [RK816_IRQ_CHG_OK] = {
604 .mask = RK816_IRQ_CHG_OK_MSK,
605 .reg_offset = 0,
606 },
607 [RK816_IRQ_CHG_TE] = {
608 .mask = RK816_IRQ_CHG_TE_MSK,
609 .reg_offset = 0,
610 },
611 [RK816_IRQ_CHG_TS] = {
612 .mask = RK816_IRQ_CHG_TS_MSK,
613 .reg_offset = 0,
614 },
615 [RK816_IRQ_CHG_CVTLIM] = {
616 .mask = RK816_IRQ_CHG_CVTLIM_MSK,
617 .reg_offset = 0,
618 },
619 [RK816_IRQ_DISCHG_ILIM] = {
620 .mask = RK816_IRQ_DISCHG_ILIM_MSK,
621 .reg_offset = 0,
622 },
623};
624
625static struct regmap_irq_chip rk816_irq_chip = {
626 .name = "rk816",
627 .irqs = rk816_irqs,
628 .num_irqs = ARRAY_SIZE(rk816_irqs),
629 .num_regs = 2,
630 .irq_reg_stride = 3,
631 .status_base = RK816_INT_STS_REG1,
632 .mask_base = RK816_INT_STS_MSK_REG1,
633 .ack_base = RK816_INT_STS_REG1,
634 .init_ack_masked = true,
635};
636
637static struct regmap_irq_chip rk816_battery_irq_chip = {
638 .name = "rk816_battery",
639 .irqs = rk816_battery_irqs,
640 .num_irqs = ARRAY_SIZE(rk816_battery_irqs),
641 .num_regs = 1,
642 .status_base = RK816_INT_STS_REG3,
643 .mask_base = RK816_INT_STS_MSK_REG3,
644 .ack_base = RK816_INT_STS_REG3,
645 .init_ack_masked = true,
646};
647
Tony Xie586c1b42019-06-21 06:32:54 -0400648static struct regmap_irq_chip rk817_irq_chip = {
649 .name = "rk817",
650 .irqs = rk817_irqs,
651 .num_irqs = ARRAY_SIZE(rk817_irqs),
652 .num_regs = 3,
653 .irq_reg_stride = 2,
654 .status_base = RK817_INT_STS_REG0,
655 .mask_base = RK817_INT_STS_MSK_REG0,
656 .ack_base = RK817_INT_STS_REG0,
657 .init_ack_masked = true,
658};
659
Bhumika Goyal24e34b92017-01-25 00:55:24 +0530660static const struct regmap_irq_chip rk818_irq_chip = {
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200661 .name = "rk818",
662 .irqs = rk818_irqs,
663 .num_irqs = ARRAY_SIZE(rk818_irqs),
664 .num_regs = 2,
665 .irq_reg_stride = 2,
666 .status_base = RK818_INT_STS_REG1,
667 .mask_base = RK818_INT_STS_MSK_REG1,
668 .ack_base = RK818_INT_STS_REG1,
669 .init_ack_masked = true,
670};
671
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800672static struct i2c_client *rk808_i2c_client;
Joseph Chenf7bff6c2017-11-21 10:27:59 +0800673static struct rk808_reg_data *suspend_reg, *resume_reg;
674static int suspend_reg_num, resume_reg_num;
Elaine Zhang990f05f2017-08-21 03:28:38 +0200675
Robin Murphy7a52cbc2020-01-12 01:55:03 +0000676static void rk808_pm_power_off(void)
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800677{
678 int ret;
Robin Murphy7a52cbc2020-01-12 01:55:03 +0000679 unsigned int reg, bit;
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800680 struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
681
Robin Murphy7a52cbc2020-01-12 01:55:03 +0000682 switch (rk808->variant) {
683 case RK805_ID:
684 reg = RK805_DEV_CTRL_REG;
685 bit = DEV_OFF;
686 break;
687 case RK808_ID:
688 reg = RK808_DEVCTRL_REG,
689 bit = DEV_OFF_RST;
690 break;
Joseph Chen5a363f32019-11-09 17:17:45 +0800691 case RK816_ID:
692 reg = RK816_DEV_CTRL_REG,
693 bit = DEV_OFF;
694 break;
Robin Murphy7a52cbc2020-01-12 01:55:03 +0000695 case RK818_ID:
696 reg = RK818_DEVCTRL_REG;
697 bit = DEV_OFF;
698 break;
699 default:
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800700 return;
Robin Murphy7a52cbc2020-01-12 01:55:03 +0000701 }
702 ret = regmap_update_bits(rk808->regmap, reg, bit, bit);
Jianhong Chenb2e2c852016-10-17 17:03:10 +0800703 if (ret)
Stefan Mavrodievac195d92019-06-07 15:42:26 +0300704 dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
Jianhong Chenb2e2c852016-10-17 17:03:10 +0800705}
706
Tony Xie2dc862f2018-02-07 15:05:03 +0800707static void rk817_shutdown_prepare(void)
708{
709 int ret;
710 struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
711
712 /* close rtc int when power off */
713 regmap_update_bits(rk808->regmap,
714 RK817_INT_STS_MSK_REG0,
715 (0x3 << 5), (0x3 << 5));
716 regmap_update_bits(rk808->regmap,
717 RK817_RTC_INT_REG,
718 (0x3 << 2), (0x0 << 2));
719
720 if (rk808->pins && rk808->pins->p && rk808->pins->power_off) {
721 ret = regmap_update_bits(rk808->regmap,
722 RK817_SYS_CFG(3),
723 RK817_SLPPIN_FUNC_MSK,
724 SLPPIN_NULL_FUN);
725 if (ret)
726 pr_err("shutdown: config SLPPIN_NULL_FUN error!\n");
727
728 ret = regmap_update_bits(rk808->regmap,
729 RK817_SYS_CFG(3),
730 RK817_SLPPOL_MSK,
731 RK817_SLPPOL_H);
732 if (ret)
733 pr_err("shutdown: config RK817_SLPPOL_H error!\n");
734
735 ret = pinctrl_select_state(rk808->pins->p,
736 rk808->pins->power_off);
737 if (ret)
738 pr_info("%s:failed to activate pwroff state\n",
739 __func__);
740 }
741
742 /* pmic sleep shutdown function */
743 ret = regmap_update_bits(rk808->regmap,
744 RK817_SYS_CFG(3),
745 RK817_SLPPIN_FUNC_MSK, SLPPIN_DN_FUN);
746 if (ret)
747 dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
748 /* pmic need the SCL clock to synchronize register */
749 mdelay(2);
750}
751
Robin Murphy90df3a82020-01-12 01:55:02 +0000752static void rk8xx_shutdown(struct i2c_client *client)
Tony Xie586c1b42019-06-21 06:32:54 -0400753{
Robin Murphy90df3a82020-01-12 01:55:02 +0000754 struct rk808 *rk808 = i2c_get_clientdata(client);
Tony Xie2dc862f2018-02-07 15:05:03 +0800755 int ret = 0;
Tony Xie586c1b42019-06-21 06:32:54 -0400756
Robin Murphy90df3a82020-01-12 01:55:02 +0000757 switch (rk808->variant) {
Robin Murphy42679762020-01-12 01:55:04 +0000758 case RK805_ID:
759 ret = regmap_update_bits(rk808->regmap,
760 RK805_GPIO_IO_POL_REG,
761 SLP_SD_MSK,
762 SHUTDOWN_FUN);
763 break;
Robin Murphy90df3a82020-01-12 01:55:02 +0000764 case RK809_ID:
765 case RK817_ID:
Tony Xie2dc862f2018-02-07 15:05:03 +0800766 rk817_shutdown_prepare();
Robin Murphy90df3a82020-01-12 01:55:02 +0000767 break;
768 default:
769 return;
Tony Xie586c1b42019-06-21 06:32:54 -0400770 }
Robin Murphy90df3a82020-01-12 01:55:02 +0000771 if (ret)
772 dev_warn(&client->dev,
773 "Cannot switch to power down function\n");
Tony Xie586c1b42019-06-21 06:32:54 -0400774}
775
Tony Xie2dc862f2018-02-07 15:05:03 +0800776static int rk817_pinctrl_init(struct device *dev, struct rk808 *rk808)
777{
778 int ret;
779 struct platform_device *pinctrl_dev;
780 struct pinctrl_state *default_st;
781
782 pinctrl_dev = platform_device_alloc("rk805-pinctrl", -1);
783 if (!pinctrl_dev) {
784 dev_err(dev, "Alloc pinctrl dev failed!\n");
785 return -ENOMEM;
786 }
787
788 pinctrl_dev->dev.parent = dev;
789
790 ret = platform_device_add(pinctrl_dev);
791
792 if (ret) {
793 platform_device_put(pinctrl_dev);
794 dev_err(dev, "Add rk805-pinctrl dev failed!\n");
795 return ret;
796 }
797 if (dev->pins && !IS_ERR(dev->pins->p)) {
798 dev_info(dev, "had get a pinctrl!\n");
799 return 0;
800 }
801
802 rk808->pins = devm_kzalloc(dev, sizeof(struct rk808_pin_info),
803 GFP_KERNEL);
804 if (!rk808->pins)
805 return -ENOMEM;
806
807 rk808->pins->p = devm_pinctrl_get(dev);
808 if (IS_ERR(rk808->pins->p)) {
809 rk808->pins->p = NULL;
810 dev_err(dev, "no pinctrl handle\n");
811 return 0;
812 }
813
814 default_st = pinctrl_lookup_state(rk808->pins->p,
815 PINCTRL_STATE_DEFAULT);
816
817 if (IS_ERR(default_st)) {
818 dev_dbg(dev, "no default pinctrl state\n");
819 return -EINVAL;
820 }
821
822 ret = pinctrl_select_state(rk808->pins->p, default_st);
823 if (ret) {
824 dev_dbg(dev, "failed to activate default pinctrl state\n");
825 return -EINVAL;
826 }
827
828 rk808->pins->power_off = pinctrl_lookup_state(rk808->pins->p,
829 "pmic-power-off");
830 if (IS_ERR(rk808->pins->power_off)) {
831 rk808->pins->power_off = NULL;
832 dev_dbg(dev, "no power-off pinctrl state\n");
833 }
834
835 rk808->pins->sleep = pinctrl_lookup_state(rk808->pins->p,
836 "pmic-sleep");
837 if (IS_ERR(rk808->pins->sleep)) {
838 rk808->pins->sleep = NULL;
839 dev_dbg(dev, "no sleep-setting state\n");
840 }
841
842 rk808->pins->reset = pinctrl_lookup_state(rk808->pins->p,
843 "pmic-reset");
844 if (IS_ERR(rk808->pins->reset)) {
845 rk808->pins->reset = NULL;
846 dev_dbg(dev, "no reset-setting pinctrl state\n");
847 return 0;
848 }
849
Tony Xie2dc862f2018-02-07 15:05:03 +0800850 ret = pinctrl_select_state(rk808->pins->p, rk808->pins->reset);
851
852 if (ret)
853 dev_dbg(dev, "failed to activate reset-setting pinctrl state\n");
854
855 return 0;
856}
857
Tony Xiea921d232018-04-17 15:27:32 +0800858struct rk817_reboot_data_t {
859 struct rk808 *rk808;
860 struct notifier_block reboot_notifier;
861};
862
863static struct rk817_reboot_data_t rk817_reboot_data;
864
865static int rk817_reboot_notifier_handler(struct notifier_block *nb,
866 unsigned long action, void *cmd)
867{
868 struct rk817_reboot_data_t *data;
869 struct device *dev;
870 int value, power_en_active0, power_en_active1;
871 int ret, i;
872 static const char * const pmic_rst_reg_only_cmd[] = {
873 "loader", "bootloader", "fastboot", "recovery",
874 "ums", "panic", "watchdog", "charge",
875 };
876
877 data = container_of(nb, struct rk817_reboot_data_t, reboot_notifier);
878 dev = &data->rk808->i2c->dev;
879
880 regmap_read(data->rk808->regmap, RK817_POWER_EN_SAVE0,
881 &power_en_active0);
882 if (power_en_active0 != 0) {
883 regmap_read(data->rk808->regmap, RK817_POWER_EN_SAVE1,
884 &power_en_active1);
885 value = power_en_active0 & 0x0f;
886 regmap_write(data->rk808->regmap,
887 RK817_POWER_EN_REG(0),
888 value | 0xf0);
889 value = (power_en_active0 & 0xf0) >> 4;
890 regmap_write(data->rk808->regmap,
891 RK817_POWER_EN_REG(1),
892 value | 0xf0);
893 value = power_en_active1 & 0x0f;
894 regmap_write(data->rk808->regmap,
895 RK817_POWER_EN_REG(2),
896 value | 0xf0);
897 value = (power_en_active1 & 0xf0) >> 4;
898 regmap_write(data->rk808->regmap,
899 RK817_POWER_EN_REG(3),
900 value | 0xf0);
901 } else {
902 dev_info(dev, "reboot: not restore POWER_EN\n");
903 }
904
905 if (action != SYS_RESTART || !cmd)
906 return NOTIFY_OK;
907
908 /*
909 * When system restart, there are two rst actions of PMIC sleep if
910 * board hardware support:
911 *
912 * 0b'00: reset the PMIC itself completely.
913 * 0b'01: reset the 'RST' related register only.
914 *
915 * In the case of 0b'00, PMIC reset itself which triggers SoC NPOR-reset
916 * at the same time, so the command: reboot load/bootload/recovery, etc
917 * is not effect any more.
918 *
919 * Here we check if this reboot cmd is what we expect for 0b'01.
920 */
921 for (i = 0; i < ARRAY_SIZE(pmic_rst_reg_only_cmd); i++) {
922 if (!strcmp(cmd, pmic_rst_reg_only_cmd[i])) {
923 ret = regmap_update_bits(data->rk808->regmap,
924 RK817_SYS_CFG(3),
925 RK817_RST_FUNC_MSK,
926 RK817_RST_FUNC_REG);
927 if (ret)
928 dev_err(dev, "reboot: force RK817_RST_FUNC_REG error!\n");
929 else
930 dev_info(dev, "reboot: force RK817_RST_FUNC_REG ok!\n");
931 break;
932 }
933 }
934
935 return NOTIFY_OK;
936}
937
Tony Xie2dc862f2018-02-07 15:05:03 +0800938static void rk817_of_property_prepare(struct rk808 *rk808, struct device *dev)
939{
940 u32 inner;
941 int ret, func, msk, val;
942 struct device_node *np = dev->of_node;
943
944 ret = of_property_read_u32_index(np, "fb-inner-reg-idxs", 0, &inner);
945 if (!ret && inner == RK817_ID_DCDC3)
946 regmap_update_bits(rk808->regmap, RK817_POWER_CONFIG,
947 RK817_BUCK3_FB_RES_MSK,
948 RK817_BUCK3_FB_RES_INTER);
949 else
950 regmap_update_bits(rk808->regmap, RK817_POWER_CONFIG,
951 RK817_BUCK3_FB_RES_MSK,
952 RK817_BUCK3_FB_RES_EXT);
953 dev_info(dev, "support dcdc3 fb mode:%d, %d\n", ret, inner);
954
955 ret = of_property_read_u32(np, "pmic-reset-func", &func);
956
957 msk = RK817_SLPPIN_FUNC_MSK | RK817_RST_FUNC_MSK;
958 val = SLPPIN_NULL_FUN;
959
960 if (!ret && func < RK817_RST_FUNC_CNT) {
961 val |= RK817_RST_FUNC_MSK &
962 (func << RK817_RST_FUNC_SFT);
963 } else {
964 val |= RK817_RST_FUNC_REG;
965 }
966
967 regmap_update_bits(rk808->regmap, RK817_SYS_CFG(3), msk, val);
968
969 dev_info(dev, "support pmic reset mode:%d,%d\n", ret, func);
Tony Xiea921d232018-04-17 15:27:32 +0800970
971 rk817_reboot_data.rk808 = rk808;
972 rk817_reboot_data.reboot_notifier.notifier_call =
973 rk817_reboot_notifier_handler;
974 ret = register_reboot_notifier(&rk817_reboot_data.reboot_notifier);
975 if (ret)
976 dev_err(dev, "failed to register reboot nb\n");
Tony Xie2dc862f2018-02-07 15:05:03 +0800977}
978
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200979static const struct of_device_id rk808_of_match[] = {
Elaine Zhang990f05f2017-08-21 03:28:38 +0200980 { .compatible = "rockchip,rk805" },
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200981 { .compatible = "rockchip,rk808" },
Tony Xie586c1b42019-06-21 06:32:54 -0400982 { .compatible = "rockchip,rk809" },
Joseph Chen5a363f32019-11-09 17:17:45 +0800983 { .compatible = "rockchip,rk816" },
Tony Xie586c1b42019-06-21 06:32:54 -0400984 { .compatible = "rockchip,rk817" },
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200985 { .compatible = "rockchip,rk818" },
986 { },
987};
988MODULE_DEVICE_TABLE(of, rk808_of_match);
989
Chris Zhongf69a7cf2014-09-03 21:51:44 +0800990static int rk808_probe(struct i2c_client *client,
991 const struct i2c_device_id *id)
992{
993 struct device_node *np = client->dev.of_node;
994 struct rk808 *rk808;
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200995 const struct rk808_reg_data *pre_init_reg;
Joseph Chen5a363f32019-11-09 17:17:45 +0800996 const struct regmap_irq_chip *battery_irq_chip = NULL;
Wadim Egorov2eedcbf2016-08-29 13:07:58 +0200997 const struct mfd_cell *cells;
Joseph Chen501f6ea2019-11-01 17:54:38 +0800998 unsigned char pmic_id_msb, pmic_id_lsb;
999 u8 on_source = 0, off_source = 0;
1000 unsigned int on, off;
1001 int msb, lsb;
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001002 int nr_pre_init_regs;
1003 int nr_cells;
Joseph Chen501f6ea2019-11-01 17:54:38 +08001004
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001005 int ret;
1006 int i;
Tony Xie2dc862f2018-02-07 15:05:03 +08001007 void (*of_property_prepare_fn)(struct rk808 *rk808,
1008 struct device *dev) = NULL;
1009 int (*pinctrl_init)(struct device *dev, struct rk808 *rk808) = NULL;
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001010
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001011 rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL);
1012 if (!rk808)
1013 return -ENOMEM;
1014
Tony Xie586c1b42019-06-21 06:32:54 -04001015 if (of_device_is_compatible(np, "rockchip,rk817") ||
1016 of_device_is_compatible(np, "rockchip,rk809")) {
1017 pmic_id_msb = RK817_ID_MSB;
1018 pmic_id_lsb = RK817_ID_LSB;
1019 } else {
1020 pmic_id_msb = RK808_ID_MSB;
1021 pmic_id_lsb = RK808_ID_LSB;
1022 }
1023
Elaine Zhang9d6105e2017-08-21 03:28:34 +02001024 /* Read chip variant */
Tony Xie586c1b42019-06-21 06:32:54 -04001025 msb = i2c_smbus_read_byte_data(client, pmic_id_msb);
Elaine Zhang9d6105e2017-08-21 03:28:34 +02001026 if (msb < 0) {
1027 dev_err(&client->dev, "failed to read the chip id at 0x%x\n",
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001028 RK808_ID_MSB);
Elaine Zhang9d6105e2017-08-21 03:28:34 +02001029 return msb;
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001030 }
1031
Tony Xie586c1b42019-06-21 06:32:54 -04001032 lsb = i2c_smbus_read_byte_data(client, pmic_id_lsb);
Elaine Zhang9d6105e2017-08-21 03:28:34 +02001033 if (lsb < 0) {
1034 dev_err(&client->dev, "failed to read the chip id at 0x%x\n",
1035 RK808_ID_LSB);
1036 return lsb;
1037 }
1038
1039 rk808->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
1040 dev_info(&client->dev, "chip id: 0x%x\n", (unsigned int)rk808->variant);
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001041
1042 switch (rk808->variant) {
Elaine Zhang990f05f2017-08-21 03:28:38 +02001043 case RK805_ID:
1044 rk808->regmap_cfg = &rk805_regmap_config;
1045 rk808->regmap_irq_chip = &rk805_irq_chip;
1046 pre_init_reg = rk805_pre_init_reg;
1047 nr_pre_init_regs = ARRAY_SIZE(rk805_pre_init_reg);
1048 cells = rk805s;
1049 nr_cells = ARRAY_SIZE(rk805s);
Joseph Chen501f6ea2019-11-01 17:54:38 +08001050 on_source = RK805_ON_SOURCE_REG;
1051 off_source = RK805_OFF_SOURCE_REG;
Joseph Chenf7bff6c2017-11-21 10:27:59 +08001052 suspend_reg = rk805_suspend_reg;
1053 suspend_reg_num = ARRAY_SIZE(rk805_suspend_reg);
1054 resume_reg = rk805_resume_reg;
1055 resume_reg_num = ARRAY_SIZE(rk805_resume_reg);
Elaine Zhang990f05f2017-08-21 03:28:38 +02001056 break;
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001057 case RK808_ID:
1058 rk808->regmap_cfg = &rk808_regmap_config;
1059 rk808->regmap_irq_chip = &rk808_irq_chip;
1060 pre_init_reg = rk808_pre_init_reg;
1061 nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
1062 cells = rk808s;
1063 nr_cells = ARRAY_SIZE(rk808s);
1064 break;
Joseph Chen5a363f32019-11-09 17:17:45 +08001065 case RK816_ID:
1066 rk808->regmap_cfg = &rk816_regmap_config;
1067 rk808->regmap_irq_chip = &rk816_irq_chip;
1068 battery_irq_chip = &rk816_battery_irq_chip;
1069 pre_init_reg = rk816_pre_init_reg;
1070 nr_pre_init_regs = ARRAY_SIZE(rk816_pre_init_reg);
1071 cells = rk816s;
1072 nr_cells = ARRAY_SIZE(rk816s);
1073 on_source = RK816_ON_SOURCE_REG;
1074 off_source = RK816_OFF_SOURCE_REG;
Joseph Chenf7bff6c2017-11-21 10:27:59 +08001075 suspend_reg = rk816_suspend_reg;
1076 suspend_reg_num = ARRAY_SIZE(rk816_suspend_reg);
1077 resume_reg = rk816_resume_reg;
1078 resume_reg_num = ARRAY_SIZE(rk816_resume_reg);
Joseph Chen5a363f32019-11-09 17:17:45 +08001079 break;
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001080 case RK818_ID:
1081 rk808->regmap_cfg = &rk818_regmap_config;
1082 rk808->regmap_irq_chip = &rk818_irq_chip;
1083 pre_init_reg = rk818_pre_init_reg;
1084 nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
1085 cells = rk818s;
1086 nr_cells = ARRAY_SIZE(rk818s);
Joseph Chen501f6ea2019-11-01 17:54:38 +08001087 on_source = RK818_ON_SOURCE_REG;
1088 off_source = RK818_OFF_SOURCE_REG;
Joseph Chenf7bff6c2017-11-21 10:27:59 +08001089 suspend_reg = rk818_suspend_reg;
1090 suspend_reg_num = ARRAY_SIZE(rk818_suspend_reg);
1091 resume_reg = rk818_resume_reg;
1092 resume_reg_num = ARRAY_SIZE(rk818_resume_reg);
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001093 break;
Tony Xie586c1b42019-06-21 06:32:54 -04001094 case RK809_ID:
1095 case RK817_ID:
1096 rk808->regmap_cfg = &rk817_regmap_config;
1097 rk808->regmap_irq_chip = &rk817_irq_chip;
1098 pre_init_reg = rk817_pre_init_reg;
1099 nr_pre_init_regs = ARRAY_SIZE(rk817_pre_init_reg);
1100 cells = rk817s;
1101 nr_cells = ARRAY_SIZE(rk817s);
Joseph Chen501f6ea2019-11-01 17:54:38 +08001102 on_source = RK817_ON_SOURCE_REG;
1103 off_source = RK817_OFF_SOURCE_REG;
Tony Xie2dc862f2018-02-07 15:05:03 +08001104 of_property_prepare_fn = rk817_of_property_prepare;
1105 pinctrl_init = rk817_pinctrl_init;
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001106 break;
1107 default:
1108 dev_err(&client->dev, "Unsupported RK8XX ID %lu\n",
1109 rk808->variant);
1110 return -EINVAL;
1111 }
1112
1113 rk808->i2c = client;
1114 i2c_set_clientdata(client, rk808);
1115
1116 rk808->regmap = devm_regmap_init_i2c(client, rk808->regmap_cfg);
1117 if (IS_ERR(rk808->regmap)) {
1118 dev_err(&client->dev, "regmap initialization failed\n");
1119 return PTR_ERR(rk808->regmap);
1120 }
1121
Joseph Chen501f6ea2019-11-01 17:54:38 +08001122 if (on_source && off_source) {
1123 ret = regmap_read(rk808->regmap, on_source, &on);
1124 if (ret) {
1125 dev_err(&client->dev, "read 0x%x failed\n", on_source);
1126 return ret;
1127 }
1128
1129 ret = regmap_read(rk808->regmap, off_source, &off);
1130 if (ret) {
1131 dev_err(&client->dev, "read 0x%x failed\n", off_source);
1132 return ret;
1133 }
1134
1135 dev_info(&client->dev, "source: on=0x%02x, off=0x%02x\n",
1136 on, off);
1137 }
1138
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001139 if (!client->irq) {
1140 dev_err(&client->dev, "No interrupt support, no core IRQ\n");
1141 return -EINVAL;
1142 }
1143
Tony Xie2dc862f2018-02-07 15:05:03 +08001144 if (of_property_prepare_fn)
1145 of_property_prepare_fn(rk808, &client->dev);
1146
1147 i2c_set_clientdata(client, rk808);
1148 rk808->i2c = client;
1149 rk808_i2c_client = client;
1150
1151 if (pinctrl_init) {
1152 ret = pinctrl_init(&client->dev, rk808);
1153 if (ret)
1154 return ret;
1155 }
1156
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001157 ret = regmap_add_irq_chip(rk808->regmap, client->irq,
1158 IRQF_ONESHOT, -1,
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001159 rk808->regmap_irq_chip, &rk808->irq_data);
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001160 if (ret) {
1161 dev_err(&client->dev, "Failed to add irq_chip %d\n", ret);
1162 return ret;
1163 }
1164
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001165 for (i = 0; i < nr_pre_init_regs; i++) {
1166 ret = regmap_update_bits(rk808->regmap,
1167 pre_init_reg[i].addr,
1168 pre_init_reg[i].mask,
1169 pre_init_reg[i].value);
1170 if (ret) {
1171 dev_err(&client->dev,
1172 "0x%x write err\n",
1173 pre_init_reg[i].addr);
1174 return ret;
1175 }
1176 }
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001177
Joseph Chen5a363f32019-11-09 17:17:45 +08001178 if (battery_irq_chip) {
1179 ret = regmap_add_irq_chip(rk808->regmap, client->irq,
1180 IRQF_ONESHOT | IRQF_SHARED, -1,
1181 battery_irq_chip,
1182 &rk808->battery_irq_data);
1183 if (ret) {
1184 dev_err(&client->dev,
1185 "Failed to add batterry irq_chip %d\n", ret);
1186 regmap_del_irq_chip(client->irq, rk808->irq_data);
1187 return ret;
1188 }
1189 }
1190
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001191 ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
1192 cells, nr_cells, NULL, 0,
1193 regmap_irq_get_domain(rk808->irq_data));
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001194 if (ret) {
1195 dev_err(&client->dev, "failed to add MFD devices %d\n", ret);
1196 goto err_irq;
1197 }
1198
Soeren Mochd8f083a2020-01-12 01:55:00 +00001199 if (of_property_read_bool(np, "rockchip,system-power-controller")) {
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001200 rk808_i2c_client = client;
Robin Murphy7a52cbc2020-01-12 01:55:03 +00001201 pm_power_off = rk808_pm_power_off;
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001202 }
1203
1204 return 0;
1205
1206err_irq:
1207 regmap_del_irq_chip(client->irq, rk808->irq_data);
Joseph Chen5a363f32019-11-09 17:17:45 +08001208 if (battery_irq_chip)
1209 regmap_del_irq_chip(client->irq, rk808->battery_irq_data);
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001210 return ret;
1211}
1212
1213static int rk808_remove(struct i2c_client *client)
1214{
1215 struct rk808 *rk808 = i2c_get_clientdata(client);
1216
1217 regmap_del_irq_chip(client->irq, rk808->irq_data);
Stefan Mavrodiev76304992019-06-07 15:42:25 +03001218
1219 /**
1220 * pm_power_off may points to a function from another module.
1221 * Check if the pointer is set by us and only then overwrite it.
1222 */
Robin Murphy7a52cbc2020-01-12 01:55:03 +00001223 if (pm_power_off == rk808_pm_power_off)
Stefan Mavrodiev76304992019-06-07 15:42:25 +03001224 pm_power_off = NULL;
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001225
1226 return 0;
1227}
1228
Arnd Bergmann5752bc42019-07-08 14:53:02 +02001229static int __maybe_unused rk8xx_suspend(struct device *dev)
Tony Xie586c1b42019-06-21 06:32:54 -04001230{
Robin Murphy08e8c0d2020-01-12 01:55:01 +00001231 struct rk808 *rk808 = i2c_get_clientdata(to_i2c_client(dev));
Joseph Chenf7bff6c2017-11-21 10:27:59 +08001232 int i, ret = 0;
Tony Xie2dc862f2018-02-07 15:05:03 +08001233 int value;
Tony Xie586c1b42019-06-21 06:32:54 -04001234
Joseph Chenf7bff6c2017-11-21 10:27:59 +08001235 for (i = 0; i < suspend_reg_num; i++) {
1236 ret = regmap_update_bits(rk808->regmap,
1237 suspend_reg[i].addr,
1238 suspend_reg[i].mask,
1239 suspend_reg[i].value);
1240 if (ret) {
1241 dev_err(dev, "0x%x write err\n",
1242 suspend_reg[i].addr);
1243 return ret;
1244 }
1245 }
1246
Tony Xie586c1b42019-06-21 06:32:54 -04001247 switch (rk808->variant) {
Robin Murphy42679762020-01-12 01:55:04 +00001248 case RK805_ID:
1249 ret = regmap_update_bits(rk808->regmap,
1250 RK805_GPIO_IO_POL_REG,
1251 SLP_SD_MSK,
1252 SLEEP_FUN);
1253 break;
Tony Xie586c1b42019-06-21 06:32:54 -04001254 case RK809_ID:
1255 case RK817_ID:
Tony Xie2dc862f2018-02-07 15:05:03 +08001256 if (rk808->pins && rk808->pins->p && rk808->pins->sleep) {
1257 ret = regmap_update_bits(rk808->regmap,
1258 RK817_SYS_CFG(3),
1259 RK817_SLPPIN_FUNC_MSK,
1260 SLPPIN_NULL_FUN);
1261 if (ret) {
1262 dev_err(dev, "suspend: config SLPPIN_NULL_FUN error!\n");
1263 return ret;
1264 }
1265
1266 ret = regmap_update_bits(rk808->regmap,
1267 RK817_SYS_CFG(3),
1268 RK817_SLPPOL_MSK,
1269 RK817_SLPPOL_H);
1270 if (ret) {
1271 dev_err(dev, "suspend: config RK817_SLPPOL_H error!\n");
1272 return ret;
1273 }
1274
1275 /* pmic need the SCL clock to synchronize register */
1276 regmap_read(rk808->regmap, RK817_SYS_STS, &value);
1277 mdelay(2);
1278 ret = pinctrl_select_state(rk808->pins->p, rk808->pins->sleep);
1279 if (ret) {
1280 dev_err(dev, "failed to act slp pinctrl state\n");
1281 return ret;
1282 }
1283 }
Tony Xie586c1b42019-06-21 06:32:54 -04001284 break;
1285 default:
1286 break;
1287 }
1288
1289 return ret;
1290}
1291
Arnd Bergmann5752bc42019-07-08 14:53:02 +02001292static int __maybe_unused rk8xx_resume(struct device *dev)
Tony Xie586c1b42019-06-21 06:32:54 -04001293{
Robin Murphy08e8c0d2020-01-12 01:55:01 +00001294 struct rk808 *rk808 = i2c_get_clientdata(to_i2c_client(dev));
Tony Xie2dc862f2018-02-07 15:05:03 +08001295 int value;
Joseph Chenf7bff6c2017-11-21 10:27:59 +08001296 int i, ret = 0;
1297
1298 for (i = 0; i < resume_reg_num; i++) {
1299 ret = regmap_update_bits(rk808->regmap,
1300 resume_reg[i].addr,
1301 resume_reg[i].mask,
1302 resume_reg[i].value);
1303 if (ret) {
1304 dev_err(dev, "0x%x write err\n",
1305 resume_reg[i].addr);
1306 return ret;
1307 }
1308 }
Tony Xie586c1b42019-06-21 06:32:54 -04001309
1310 switch (rk808->variant) {
1311 case RK809_ID:
1312 case RK817_ID:
Tony Xie2dc862f2018-02-07 15:05:03 +08001313 if (rk808->pins && rk808->pins->p && rk808->pins->reset) {
1314 ret = regmap_update_bits(rk808->regmap,
1315 RK817_SYS_CFG(3),
1316 RK817_SLPPIN_FUNC_MSK,
1317 SLPPIN_NULL_FUN);
1318 if (ret) {
1319 dev_err(dev, "resume: config SLPPIN_NULL_FUN error!\n");
1320 return ret;
1321 }
1322
1323 ret = regmap_update_bits(rk808->regmap,
1324 RK817_SYS_CFG(3),
1325 RK817_SLPPOL_MSK,
1326 RK817_SLPPOL_L);
1327 if (ret) {
1328 dev_err(dev, "resume: config RK817_SLPPOL_L error!\n");
1329 return ret;
1330 }
1331
1332 /* pmic need the SCL clock to synchronize register */
1333 regmap_read(rk808->regmap, RK817_SYS_STS, &value);
1334 mdelay(2);
1335 ret = pinctrl_select_state(rk808->pins->p, rk808->pins->reset);
1336 if (ret)
1337 dev_dbg(dev, "failed to act reset pinctrl state\n");
1338 }
Tony Xie586c1b42019-06-21 06:32:54 -04001339 break;
1340 default:
1341 break;
1342 }
1343
1344 return ret;
1345}
Joseph Chenf7bff6c2017-11-21 10:27:59 +08001346SIMPLE_DEV_PM_OPS(rk8xx_pm_ops, rk8xx_suspend, rk8xx_resume);
Tony Xie586c1b42019-06-21 06:32:54 -04001347
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001348static struct i2c_driver rk808_i2c_driver = {
1349 .driver = {
1350 .name = "rk808",
1351 .of_match_table = rk808_of_match,
Tony Xie586c1b42019-06-21 06:32:54 -04001352 .pm = &rk8xx_pm_ops,
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001353 },
1354 .probe = rk808_probe,
1355 .remove = rk808_remove,
Robin Murphy90df3a82020-01-12 01:55:02 +00001356 .shutdown = rk8xx_shutdown,
Chris Zhongf69a7cf2014-09-03 21:51:44 +08001357};
1358
1359module_i2c_driver(rk808_i2c_driver);
1360
1361MODULE_LICENSE("GPL");
1362MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
1363MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
Wadim Egorov2eedcbf2016-08-29 13:07:58 +02001364MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
1365MODULE_DESCRIPTION("RK808/RK818 PMIC driver");