#include <asm/smp_plat.h>
#include <uapi/linux/psci.h>
+#ifdef CONFIG_64BIT
+#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name
+#else
+#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name
+#endif
+
#define SIZE_PAGE(n) ((n) << 12)
static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id,
return res.a0;
}
+int rk_psci_virtual_poweroff(void)
+{
+ struct arm_smccc_res res;
+
+ res = __invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND),
+ 0, 0, 0);
+ return res.a0;
+}
+
static u64 ft_fiq_mem_phy;
static void __iomem *ft_fiq_mem_base;
static void (*psci_fiq_debugger_uart_irq_tf)(void *reg_base, u64 sp_el1);
#include <linux/regulator/machine.h>
#include <linux/rockchip/rockchip_sip.h>
#include <linux/suspend.h>
+#include <dt-bindings/input/input.h>
#define PM_INVALID_GPIO 0xffff
{ },
};
+#define MAX_PWRKEY_NUMS 20
+#define MAX_NUM_KEYS 60
+
+struct rkxx_remote_key_table {
+ int scancode;
+ int keycode;
+};
+
+static int parse_ir_pwrkeys(unsigned int *pwrkey, int size, int *nkey)
+{
+ struct device_node *node;
+ struct device_node *child_node;
+ struct rkxx_remote_key_table key_table[MAX_NUM_KEYS];
+ int i;
+ int len = 0, nbuttons;
+ int num = 0;
+ u32 usercode, scancode;
+
+ for_each_node_by_name(node, "pwm") {
+ for_each_child_of_node(node, child_node) {
+ if (of_property_read_u32(child_node,
+ "rockchip,usercode",
+ &usercode))
+ break;
+
+ if (of_get_property(child_node,
+ "rockchip,key_table",
+ &len) == NULL ||
+ len <= 0)
+ break;
+
+ len = len < sizeof(key_table) ? len : sizeof(key_table);
+ len /= sizeof(u32);
+ if (of_property_read_u32_array(child_node,
+ "rockchip,key_table",
+ (u32 *)key_table,
+ len))
+ break;
+
+ nbuttons = len / 2;
+ for (i = 0; i < nbuttons && num < size; ++i) {
+ if (key_table[i].keycode == KEY_POWER) {
+ scancode = key_table[i].scancode;
+ pr_debug("usercode=%x, key=%x\n",
+ usercode, scancode);
+ pwrkey[num] = (usercode & 0xffff) << 16;
+ pwrkey[num] |= (scancode & 0xff) << 8;
+ ++num;
+ }
+ }
+ }
+ }
+
+ *nkey = num;
+
+ return num ? 0 : -1;
+}
+
+static void rockchip_pm_virt_pwroff_prepare(void)
+{
+ int error;
+ int i, nkey;
+ u32 power_key[MAX_PWRKEY_NUMS];
+
+ if ((parse_ir_pwrkeys(power_key, ARRAY_SIZE(power_key), &nkey))) {
+ pr_err("Parse ir powerkey code failed!\n");
+ return;
+ }
+
+ for (i = 0; i < nkey; ++i)
+ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 1, power_key[i]);
+
+ regulator_suspend_prepare(PM_SUSPEND_MEM);
+
+ error = disable_nonboot_cpus();
+ if (error) {
+ pr_err("Disable nonboot cpus failed!\n");
+ return;
+ }
+
+ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1);
+ rk_psci_virtual_poweroff();
+}
+
static int __init pm_config_init(struct platform_device *pdev)
{
const struct of_device_id *match_id;
int gpio_temp[10];
u32 sleep_debug_en = 0;
u32 apios_suspend = 0;
+ u32 virtual_poweroff_en = 0;
enum of_gpio_flags flags;
int i = 0;
int length;
apios_suspend,
0);
+ if (!of_property_read_u32_array(node,
+ "rockchip,virtual-poweroff",
+ &virtual_poweroff_en, 1) &&
+ virtual_poweroff_en)
+ pm_power_off_prepare = rockchip_pm_virt_pwroff_prepare;
+
return 0;
}
#define GPIO_POWER_CONFIG 0x04
#define SUSPEND_DEBUG_ENABLE 0x05
#define APIOS_SUSPEND_CONFIG 0x06
+#define VIRTUAL_POWEROFF 0x07
/* struct arm_smccc_res: a0: error code; a1~a3: data */
/* SMC32 Calls */
int sip_smc_set_suspend_mode(u32 ctrl,
u32 config1,
u32 config2);
+int rk_psci_virtual_poweroff(void);
+
struct arm_smccc_res sip_smc_get_call_count(void);
struct arm_smccc_res sip_smc_get_atf_version(void);
struct arm_smccc_res sip_smc_get_sip_version(void);