xref: /OK3568_Linux_fs/kernel/drivers/soc/rockchip/rockchip_pm_config.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Rockchip Generic power configuration support.
3  *
4  * Copyright (c) 2017 ROCKCHIP, Co. Ltd.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 
11 #include <linux/arm-smccc.h>
12 #include <linux/bitops.h>
13 #include <linux/cpu.h>
14 #include <linux/module.h>
15 #include <linux/of_gpio.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm.h>
18 #include <linux/regulator/driver.h>
19 #include <linux/regulator/machine.h>
20 #include <linux/rockchip/rockchip_sip.h>
21 #include <linux/suspend.h>
22 #include <dt-bindings/input/input.h>
23 #include <../drivers/regulator/internal.h>
24 
25 #define PM_INVALID_GPIO			0xffff
26 #define MAX_ON_OFF_REG_NUM		30
27 #define MAX_ON_OFF_REG_PROP_NAME_LEN	60
28 #define MAX_CONFIG_PROP_NAME_LEN	60
29 
30 enum rk_pm_state {
31 	RK_PM_MEM = 0,
32 	RK_PM_MEM_LITE,
33 	RK_PM_MEM_ULTRA,
34 	RK_PM_STATE_MAX
35 };
36 
37 #ifndef MODULE
38 static const char * const pm_state_str[RK_PM_STATE_MAX] = {
39 	[RK_PM_MEM] = "mem",
40 	[RK_PM_MEM_LITE] = "mem-lite",
41 	[RK_PM_MEM_ULTRA] = "mem-ultra",
42 };
43 
44 static struct rk_on_off_regulator_list {
45 	struct regulator_dev *on_reg_list[MAX_ON_OFF_REG_NUM];
46 	struct regulator_dev *off_reg_list[MAX_ON_OFF_REG_NUM];
47 } on_off_regs_list[RK_PM_STATE_MAX];
48 #endif
49 
50 static struct rk_sleep_config {
51 	u32 mode_config;
52 	u32 wakeup_config;
53 } sleep_config[RK_PM_STATE_MAX];
54 
55 static const struct of_device_id pm_match_table[] = {
56 	{ .compatible = "rockchip,pm-px30",},
57 	{ .compatible = "rockchip,pm-rk1808",},
58 	{ .compatible = "rockchip,pm-rk322x",},
59 	{ .compatible = "rockchip,pm-rk3288",},
60 	{ .compatible = "rockchip,pm-rk3308",},
61 	{ .compatible = "rockchip,pm-rk3328",},
62 	{ .compatible = "rockchip,pm-rk3368",},
63 	{ .compatible = "rockchip,pm-rk3399",},
64 	{ .compatible = "rockchip,pm-rk3528",},
65 	{ .compatible = "rockchip,pm-rk3562",},
66 	{ .compatible = "rockchip,pm-rk3568",},
67 	{ .compatible = "rockchip,pm-rk3588",},
68 	{ .compatible = "rockchip,pm-rv1126",},
69 	{ },
70 };
71 
72 #ifndef MODULE
rockchip_pm_virt_pwroff_prepare(void)73 static void rockchip_pm_virt_pwroff_prepare(void)
74 {
75 	int error;
76 
77 	regulator_suspend_prepare(PM_SUSPEND_MEM);
78 
79 	error = suspend_disable_secondary_cpus();
80 	if (error) {
81 		pr_err("Disable nonboot cpus failed!\n");
82 		return;
83 	}
84 
85 	sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1);
86 	sip_smc_virtual_poweroff();
87 }
88 
parse_sleep_config(struct device_node * node,enum rk_pm_state state)89 static int parse_sleep_config(struct device_node *node, enum rk_pm_state state)
90 {
91 	char mode_prop_name[MAX_CONFIG_PROP_NAME_LEN];
92 	char wkup_prop_name[MAX_CONFIG_PROP_NAME_LEN];
93 	struct rk_sleep_config *config;
94 
95 	if (state == RK_PM_MEM || state >= RK_PM_STATE_MAX)
96 		return -EINVAL;
97 
98 	snprintf(mode_prop_name, sizeof(mode_prop_name),
99 		 "sleep-mode-config-%s", pm_state_str[state]);
100 	snprintf(wkup_prop_name, sizeof(wkup_prop_name),
101 		 "wakeup-config-%s", pm_state_str[state]);
102 
103 	config = &sleep_config[state];
104 
105 	if (of_property_read_u32_array(node,
106 				       mode_prop_name,
107 				       &config->mode_config, 1))
108 		pr_info("%s not set sleep-mode-config for %s\n",
109 			node->name, pm_state_str[state]);
110 
111 	if (of_property_read_u32_array(node,
112 				       wkup_prop_name,
113 				       &config->wakeup_config, 1))
114 		pr_info("%s not set wakeup-config for %s\n",
115 			node->name, pm_state_str[state]);
116 
117 	return 0;
118 }
119 
parse_regulator_list(struct device_node * node,char * prop_name,struct regulator_dev ** out_list)120 static int parse_regulator_list(struct device_node *node,
121 				char *prop_name,
122 				struct regulator_dev **out_list)
123 {
124 	struct device_node *dn;
125 	struct regulator_dev *reg;
126 	int i, j;
127 
128 	if (of_find_property(node, prop_name, NULL)) {
129 		for (i = 0, j = 0;
130 		     (dn = of_parse_phandle(node, prop_name, i)) && j < MAX_ON_OFF_REG_NUM;
131 		     i++) {
132 			reg = of_find_regulator_by_node(dn);
133 			if (reg == NULL) {
134 				pr_warn("failed to find regulator %s for %s\n",
135 					dn->name, prop_name);
136 			} else {
137 				pr_debug("%s %s regulator=%s\n", __func__,
138 					 prop_name,
139 					 reg->desc->name);
140 				out_list[j++] = reg;
141 			}
142 			of_node_put(dn);
143 		}
144 	}
145 
146 	return 0;
147 }
148 
parse_on_off_regulator(struct device_node * node,enum rk_pm_state state)149 static int parse_on_off_regulator(struct device_node *node, enum rk_pm_state state)
150 {
151 	char on_prop_name[MAX_ON_OFF_REG_PROP_NAME_LEN];
152 	char off_prop_name[MAX_ON_OFF_REG_PROP_NAME_LEN];
153 
154 	if (state >= RK_PM_STATE_MAX)
155 		return -EINVAL;
156 
157 	snprintf(on_prop_name, sizeof(on_prop_name),
158 		 "rockchip,regulator-on-in-%s", pm_state_str[state]);
159 	snprintf(off_prop_name, sizeof(off_prop_name),
160 		 "rockchip,regulator-off-in-%s", pm_state_str[state]);
161 
162 	parse_regulator_list(node, on_prop_name, on_off_regs_list[state].on_reg_list);
163 	parse_regulator_list(node, off_prop_name, on_off_regs_list[state].off_reg_list);
164 
165 	return 0;
166 }
167 #endif
168 
pm_config_probe(struct platform_device * pdev)169 static int pm_config_probe(struct platform_device *pdev)
170 {
171 	const struct of_device_id *match_id;
172 	struct device_node *node;
173 	struct rk_sleep_config *config = &sleep_config[RK_PM_MEM];
174 	u32 pwm_regulator_config = 0;
175 	int gpio_temp[10];
176 	u32 sleep_debug_en = 0;
177 	u32 apios_suspend = 0;
178 	u32 io_ret_config = 0;
179 	u32 sleep_pin_config[2] = {0};
180 #ifndef MODULE
181 	u32 virtual_poweroff_en = 0;
182 #endif
183 	enum of_gpio_flags flags;
184 	int i = 0;
185 	int length;
186 	int ret;
187 
188 	match_id = of_match_node(pm_match_table, pdev->dev.of_node);
189 	if (!match_id)
190 		return -ENODEV;
191 
192 	node = of_find_node_by_name(NULL, "rockchip-suspend");
193 
194 	if (IS_ERR_OR_NULL(node)) {
195 		dev_err(&pdev->dev, "%s dev node err\n",  __func__);
196 		return -ENODEV;
197 	}
198 
199 	if (of_property_read_u32_array(node,
200 				       "rockchip,sleep-mode-config",
201 				       &config->mode_config, 1))
202 		dev_warn(&pdev->dev, "not set sleep mode config\n");
203 	else
204 		sip_smc_set_suspend_mode(SUSPEND_MODE_CONFIG, config->mode_config, 0);
205 
206 	if (of_property_read_u32_array(node,
207 				       "rockchip,wakeup-config",
208 				       &config->wakeup_config, 1))
209 		dev_warn(&pdev->dev, "not set wakeup-config\n");
210 	else
211 		sip_smc_set_suspend_mode(WKUP_SOURCE_CONFIG, config->wakeup_config, 0);
212 
213 	if (of_property_read_u32_array(node,
214 				       "rockchip,pwm-regulator-config",
215 				       &pwm_regulator_config, 1))
216 		dev_warn(&pdev->dev, "not set pwm-regulator-config\n");
217 	else
218 		sip_smc_set_suspend_mode(PWM_REGULATOR_CONFIG,
219 					 pwm_regulator_config,
220 					 0);
221 
222 	length = of_gpio_named_count(node, "rockchip,power-ctrl");
223 
224 	if (length > 0 && length < 10) {
225 		for (i = 0; i < length; i++) {
226 			gpio_temp[i] = of_get_named_gpio_flags(node,
227 							     "rockchip,power-ctrl",
228 							     i,
229 							     &flags);
230 			if (!gpio_is_valid(gpio_temp[i]))
231 				break;
232 			sip_smc_set_suspend_mode(GPIO_POWER_CONFIG,
233 						 i,
234 						 gpio_temp[i]);
235 		}
236 	}
237 	sip_smc_set_suspend_mode(GPIO_POWER_CONFIG, i, PM_INVALID_GPIO);
238 
239 	if (!of_property_read_u32_array(node,
240 					"rockchip,sleep-debug-en",
241 					&sleep_debug_en, 1))
242 		sip_smc_set_suspend_mode(SUSPEND_DEBUG_ENABLE,
243 					 sleep_debug_en,
244 					 0);
245 
246 	if (!of_property_read_u32_array(node,
247 					"rockchip,apios-suspend",
248 					&apios_suspend, 1))
249 		sip_smc_set_suspend_mode(APIOS_SUSPEND_CONFIG,
250 					 apios_suspend,
251 					 0);
252 
253 	if (!of_property_read_u32_array(node,
254 					"rockchip,sleep-io-ret-config",
255 					&io_ret_config, 1)) {
256 		ret = sip_smc_set_suspend_mode(SUSPEND_IO_RET_CONFIG, io_ret_config, 0);
257 		if (ret)
258 			dev_warn(&pdev->dev,
259 				 "sleep-io-ret-config failed (%d), check parameters or update trust\n",
260 				 ret);
261 	}
262 
263 	if (!of_property_read_u32_array(node,
264 					"rockchip,sleep-pin-config",
265 					sleep_pin_config, 2)) {
266 		ret = sip_smc_set_suspend_mode(SLEEP_PIN_CONFIG, sleep_pin_config[0], sleep_pin_config[1]);
267 		if (ret)
268 			dev_warn(&pdev->dev,
269 				 "sleep-pin-config failed (%d), check parameters or update trust\n",
270 				 ret);
271 	}
272 
273 #ifndef MODULE
274 	if (!of_property_read_u32_array(node,
275 					"rockchip,virtual-poweroff",
276 					&virtual_poweroff_en, 1) &&
277 	    virtual_poweroff_en)
278 		pm_power_off_prepare = rockchip_pm_virt_pwroff_prepare;
279 
280 	for (i = RK_PM_MEM; i < RK_PM_STATE_MAX; i++) {
281 		parse_sleep_config(node, i);
282 		parse_on_off_regulator(node, i);
283 	}
284 #endif
285 
286 	return 0;
287 }
288 
289 #ifndef MODULE
pm_config_prepare(struct device * dev)290 static int pm_config_prepare(struct device *dev)
291 {
292 	int i;
293 	suspend_state_t suspend_state = mem_sleep_current;
294 	enum rk_pm_state state = suspend_state - PM_SUSPEND_MEM;
295 	struct regulator_dev **on_list;
296 	struct regulator_dev **off_list;
297 	struct rk_sleep_config *config, *def_config = &sleep_config[RK_PM_MEM];
298 
299 	sip_smc_set_suspend_mode(LINUX_PM_STATE,
300 				 suspend_state,
301 				 0);
302 
303 	if (state >= RK_PM_STATE_MAX)
304 		return 0;
305 
306 	config = &sleep_config[state];
307 
308 	if (config->mode_config)
309 		sip_smc_set_suspend_mode(SUSPEND_MODE_CONFIG,
310 					 config->mode_config, 0);
311 	else if (def_config->mode_config)
312 		sip_smc_set_suspend_mode(SUSPEND_MODE_CONFIG,
313 					 def_config->mode_config, 0);
314 
315 	if (config->wakeup_config)
316 		sip_smc_set_suspend_mode(WKUP_SOURCE_CONFIG,
317 					 config->wakeup_config, 0);
318 	else if (def_config->wakeup_config)
319 		sip_smc_set_suspend_mode(WKUP_SOURCE_CONFIG,
320 					 def_config->wakeup_config, 0);
321 
322 	on_list = on_off_regs_list[state].on_reg_list;
323 	off_list = on_off_regs_list[state].off_reg_list;
324 
325 	for (i = 0; i < MAX_ON_OFF_REG_NUM && on_list[i]; i++)
326 		regulator_suspend_enable(on_list[i], PM_SUSPEND_MEM);
327 
328 	for (i = 0; i < MAX_ON_OFF_REG_NUM && off_list[i]; i++)
329 		regulator_suspend_disable(off_list[i], PM_SUSPEND_MEM);
330 
331 	return 0;
332 }
333 
334 static const struct dev_pm_ops rockchip_pm_ops = {
335 	.prepare = pm_config_prepare,
336 };
337 #endif
338 
339 static struct platform_driver pm_driver = {
340 	.probe = pm_config_probe,
341 	.driver = {
342 		.name = "rockchip-pm",
343 		.of_match_table = pm_match_table,
344 #ifndef MODULE
345 		.pm = &rockchip_pm_ops,
346 #endif
347 	},
348 };
349 
rockchip_pm_drv_register(void)350 static int __init rockchip_pm_drv_register(void)
351 {
352 	return platform_driver_register(&pm_driver);
353 }
354 late_initcall_sync(rockchip_pm_drv_register);
355 MODULE_DESCRIPTION("Rockchip suspend mode config");
356 MODULE_LICENSE("GPL");
357