firmware: rockchip: update sip interface
[firefly-linux-kernel-4.4.55.git] / drivers / soc / rockchip / rockchip_pm_config.c
index a649d6e7f082f1e296082f57150f4ea65d0cf185..43b2e0f33343bf018959b0e58be57097cf59c272 100644 (file)
@@ -16,6 +16,7 @@
 #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
 
@@ -24,6 +25,90 @@ static const struct of_device_id pm_match_table[] = {
        { },
 };
 
+#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);
+       sip_smc_virtual_poweroff();
+}
+
 static int __init pm_config_init(struct platform_device *pdev)
 {
        const struct of_device_id *match_id;
@@ -34,6 +119,7 @@ static int __init pm_config_init(struct platform_device *pdev)
        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;
@@ -103,6 +189,12 @@ static int __init pm_config_init(struct platform_device *pdev)
                                         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;
 }