[Feature][API-732][lpm] add common framework for suspend/resume actions in lpm
Change-Id: Id7c1fe9d5f1d58aed459f7271d974edf4f340531
diff --git a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts
index 973fcfd..33798e2 100755
--- a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts
+++ b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts
@@ -1574,5 +1574,31 @@
};
/*Lxf add in 2022/12/2 for gpio init end*/
+/*youchen@2023-01-05 add for lpm suspend actions begin*/
+&lynq_lpm_gpio_actions {
+ wifi_power_202: gpio@202 {
+ valid_absence_of_module = "bcmdhd";
+ gpio_num = <202>;
+ actions_suspend_202: suspend@202{
+ gpio_value = <0>;
+ };
+ actions_resume_202: resume@202 {
+ gpio_value = <1>;
+ post_mdelay_time = <10>;
+ };
+ };
+ wifi_power_182: gpio@182 {
+ valid_absence_of_module = "bcmdhd";
+ gpio_num = <182>;
+ actions_suspend_182: suspend@182{
+ gpio_value = <0>;
+ };
+ actions_resume_182: resume@182 {
+ gpio_value = <1>;
+ post_mdelay_time = <1>;
+ };
+ };
+};
+/*youchen@2023-01-05 add for lpm suspend actions end*/
#include <mediatek/evb6890v1_64_cpe/cust.dtsi>
/*End of this file, DO NOT ADD ANYTHING HERE*/
diff --git a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi
index 3c8adf4..6b11ec6 100644
--- a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi
+++ b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi
@@ -4505,6 +4505,11 @@
compatible = "linux,gpio_init";
};
/*Lxf add in 2022/12/2 for gpio init end*/
+/*youchen@2023-01-05 add for lpm suspend actions begin*/
+ lynq_lpm_gpio_actions: lynq_lpm_gpio_actions {
+ compatible = "linux,lynq_lpm_gpio_actions";
+ };
+/*youchen@2023-01-05 add for lpm suspend actions end*/
firmware {
optee {
compatible = "linaro,optee-tz";
diff --git a/src/kernel/linux/v4.19/arch/arm64/configs/auto2735evb_defconfig b/src/kernel/linux/v4.19/arch/arm64/configs/auto2735evb_defconfig
index fe4ef53..b6185c1 100644
--- a/src/kernel/linux/v4.19/arch/arm64/configs/auto2735evb_defconfig
+++ b/src/kernel/linux/v4.19/arch/arm64/configs/auto2735evb_defconfig
@@ -825,3 +825,5 @@
CONFIG_SMI230_GYRO=y
CONFIG_SMI230_GYRO_I2C=y
#dongyu@2022.11.03 Add imu/smi230 sensor end
+#you.chen@2023-01-05 add for lpm suspend actions
+CONFIG_LYNQ_LPM_SUSPEND_SUPPORT=y
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/Kconfig b/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/Kconfig
index 65e6234..1842bb0 100644
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/Kconfig
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/Kconfig
@@ -32,3 +32,10 @@
Set Y to select this feature for specific platform-mt6779.
If unsure, set N to disable.
+config LYNQ_LPM_SUSPEND_SUPPORT
+ bool "Mobiletek Low Power Module Suspend support"
+ depends on MTK_LOW_POWER_MODULE
+ help
+ Select LYNQ_LPM_SUSPEND_SUPPORT then low module
+ feature of Mobiletck suspend will be enabled.
+
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/Makefile b/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/Makefile
index ca3cdd3..74ca59b 100755
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/Makefile
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/Makefile
@@ -23,3 +23,9 @@
obj-y += mtk_lp_plat_pll.o
obj-y += suspend/mtk_suspend.o
+#you.chen@2023-01-05 add for lpm suspend actions begin
+ifeq ($(CONFIG_LYNQ_LPM_SUSPEND_SUPPORT), y)
+ccflags-y += -I$(srctree)/drivers/pinctrl/mediatek/
+obj-y += suspend/lynq_suspend.o
+endif
+#you.chen@2023-01-05 add for lpm suspend actions end
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/suspend/lynq_suspend.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/suspend/lynq_suspend.c
new file mode 100644
index 0000000..0aa4b7c
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/suspend/lynq_suspend.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Mobiletek Inc.
+ */
+
+#include <linux/cpuidle.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/cpu_pm.h>
+#include <linux/syscore_ops.h>
+#include <linux/suspend.h>
+#include <linux/rtc.h>
+#include <asm/cpuidle.h>
+#include <asm/suspend.h>
+#include <linux/delay.h>
+
+#include <linux/platform_device.h>
+#include <pinctrl-mtk-common-v2.h>
+#include <lynq_suspend.h>
+extern struct mtk_pinctrl* mtk_gpio_find_mtk_pinctrl_dev_hw(void);
+
+#define SUSPEND_GPIO_MAX 16
+
+#undef printk_deferred
+#define printk_deferred printk
+#define DEBUG printk
+
+enum e_gpio_suspend_resume_flag{
+ ACT_SUSPEND=0,
+ ACT_RESUME,
+ ACT_MAX
+};
+
+struct gpio_action{
+ int gpio_mode;
+ int gpio_dir;
+ int gpio_value;
+ int pre_mdelay_time;
+ int post_mdelay_time;
+};
+
+struct gpio_action_node{
+ char valid_absence_of_module[16];
+ int gpio_num;
+ int need_action;
+ struct gpio_action actions[ACT_MAX];
+};
+
+struct gpio_action_node * lpm_gpio_list[SUSPEND_GPIO_MAX] = {0};
+
+static inline void __inner_init_action(struct gpio_action *act)
+{
+ if (act == NULL)
+ return;
+ act->gpio_mode = -1;
+ act->gpio_dir = -1;
+ act->gpio_value = -1;
+ act->pre_mdelay_time = -1;
+ act->post_mdelay_time = -1;
+}
+
+static inline struct gpio_action_node * __inner_alloc_gpio_action_node(void)
+{
+ int i;
+ struct gpio_action_node * node;
+ node = kmalloc(sizeof(struct gpio_action_node), GFP_KERNEL);
+ if (node == NULL)
+ return NULL;
+ memset(node->valid_absence_of_module, 0, sizeof(node->valid_absence_of_module));
+ node->gpio_num = -1;
+ node->need_action = 0;
+ for(i=0; i<ACT_MAX; i++)
+ {
+ __inner_init_action(&node->actions[i]);
+ }
+ return node;
+}
+
+static inline void prepare_action_with_condition(void)
+{
+ int i;
+
+ for(i=0; i< SUSPEND_GPIO_MAX; i++)
+ {
+ if (lpm_gpio_list[i] == NULL)
+ break;
+ if (lpm_gpio_list[i]->gpio_num <= 0 || lpm_gpio_list[i]->valid_absence_of_module[0] == '\0')
+ continue;
+ if (find_module(lpm_gpio_list[i]->valid_absence_of_module) == NULL)
+ {
+ lpm_gpio_list[i]->need_action = 1;
+ }
+ else
+ {
+ lpm_gpio_list[i]->need_action = 0;
+ }
+ }
+}
+
+static inline void process_one_action(struct gpio_action * act, struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc)
+{
+ int ret;
+ unsigned int gpio_dir;
+
+ if (act == NULL || hw == NULL || hw->soc == NULL)
+ return;
+
+ if (act->pre_mdelay_time > 0)
+ {
+ DEBUG("to delay %d\n", act->pre_mdelay_time);
+ mdelay(act->pre_mdelay_time);
+ }
+
+ if (act->gpio_mode >= 0)
+ {
+ DEBUG("to set gpio mode %d\n", act->gpio_mode);
+ ret = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, act->gpio_mode);
+ if (ret != 0)
+ return;
+ }
+
+ if (act->gpio_dir == 0 || act->gpio_dir == 1)
+ {
+ DEBUG("to set gpio dir %d\n", act->gpio_dir);
+ ret = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, act->gpio_dir);
+ if (ret != 0)
+ return;
+ }
+
+ if (act->gpio_value == 0 || act->gpio_value == 1)
+ {
+ gpio_dir = -1;
+ if (act->gpio_dir == 0 || act->gpio_dir == 1)
+ gpio_dir = act->gpio_dir;
+ else
+ ret = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &gpio_dir);
+
+ if (gpio_dir == 1)
+ {
+ DEBUG("to set gpio dir %d value %d\n", gpio_dir, act->gpio_value);
+ ret = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, act->gpio_value);
+ }
+ else if (gpio_dir == 0)
+ {
+ DEBUG("to set gpio dir2 %d value %d\n", gpio_dir, act->gpio_value);
+ ret = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DI, act->gpio_value);
+ }
+ else
+ {
+ printk("unkown gpio dir %d\n", gpio_dir);
+ }
+ }
+
+ if (act->post_mdelay_time > 0)
+ {
+ DEBUG("post delay %d\n", act->post_mdelay_time);
+ mdelay(act->post_mdelay_time);
+ }
+}
+
+int lynq_suspend_common_enter(unsigned int *susp_status)
+{
+ int i;
+ struct mtk_pinctrl *hw;
+ const struct mtk_pin_desc *desc;
+
+ printk_deferred("lynq_suspend_common_enter\n");
+
+ prepare_action_with_condition();
+
+ hw = mtk_gpio_find_mtk_pinctrl_dev_hw();
+
+ for(i=0; i< SUSPEND_GPIO_MAX; i++)
+ {
+ if (lpm_gpio_list[i] == NULL)
+ break;
+ if (lpm_gpio_list[i]->gpio_num <= 0 || lpm_gpio_list[i]->need_action != 1)
+ continue;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[lpm_gpio_list[i]->gpio_num];
+
+ printk("to do suspend of gpio %d\n", lpm_gpio_list[i]->gpio_num);
+ process_one_action(&lpm_gpio_list[i]->actions[ACT_SUSPEND], hw, desc);
+ }
+
+ return 0;
+}
+
+
+int lynq_suspend_common_resume(unsigned int susp_status)
+{
+ int i;
+ struct mtk_pinctrl *hw;
+ const struct mtk_pin_desc *desc;
+
+ printk_deferred("lynq_suspend_common_resume\n");
+ /* Implement suspend common flow here */
+
+ hw = mtk_gpio_find_mtk_pinctrl_dev_hw();
+
+ for(i=SUSPEND_GPIO_MAX-1; i>= 0; i--)
+ {
+ if (lpm_gpio_list[i] == NULL || lpm_gpio_list[i]->gpio_num <= 0 || lpm_gpio_list[i]->need_action != 1)
+ continue;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[lpm_gpio_list[i]->gpio_num];
+
+ printk("to do resume of gpio %d\n", lpm_gpio_list[i]->gpio_num);
+ process_one_action(&lpm_gpio_list[i]->actions[ACT_RESUME], hw, desc);
+ }
+
+ return 0;
+}
+
+static inline int read_one_action(struct device_node *gpio_node, struct gpio_action *action_node)
+{
+ int ret;
+ unsigned int gpio_mode, gpio_dir, gpio_value, pre_mdelay_time, post_mdelay_time;
+
+ ret = of_property_read_u32(gpio_node, "gpio_mode", &gpio_mode);
+ if(ret == 0)
+ {
+ printk("read_one_node: the gpio_mode is %u", gpio_mode);
+ if(gpio_mode >= 0 && gpio_mode <= 7)
+ {
+ action_node->gpio_mode = gpio_mode;
+ }
+ }
+
+ ret = of_property_read_u32(gpio_node, "gpio_dir", &gpio_dir);
+ if(ret == 0)
+ {
+ printk("read_one_node: the gpio_dir is %u", gpio_dir);
+ if(gpio_dir == 0 || gpio_dir == 1)
+ {
+ action_node->gpio_dir = gpio_dir;
+ }
+ }
+
+ ret = of_property_read_u32(gpio_node, "gpio_value", &gpio_value);
+ if(ret == 0)
+ {
+ printk("read_one_node: the gpio_value is %u", gpio_value);
+ if(gpio_value == 0 || gpio_value == 1)
+ {
+ action_node->gpio_value = gpio_value;
+ }
+ }
+
+ ret = of_property_read_u32(gpio_node, "pre_mdelay_time", &pre_mdelay_time);
+ if(ret == 0)
+ {
+ printk("read_one_node: the pre_mdelay is %u", pre_mdelay_time);
+ if(pre_mdelay_time < 1000*100)
+ {
+ action_node->pre_mdelay_time = pre_mdelay_time;
+ }
+ }
+
+ ret = of_property_read_u32(gpio_node, "post_mdelay_time", &post_mdelay_time);
+ if(ret == 0)
+ {
+ printk("read_one_node: the post_mdelay is %u", post_mdelay_time);
+ if(post_mdelay_time < 1000*100)
+ {
+ action_node->post_mdelay_time = post_mdelay_time;
+ }
+ }
+
+ return 0;
+}
+
+static inline int read_one_node(struct device_node *gpio_node, struct gpio_action_node * action_node)
+{
+ int ret;
+ unsigned int gpio_num;
+ const char * valid_absence_of_module;
+ struct device_node *gpio_next_node;
+
+ printk("read_one_node\n");
+ ret = of_property_read_u32(gpio_node, "gpio_num", &gpio_num);
+
+ if(ret == -EINVAL || ret == -ENODATA)
+ {
+ printk("no value or no node");
+ return -1;
+ }
+ else if(ret < 0)
+ {
+ printk("read_one_node:READ ERROR: %d", ret);
+ return ret;
+ }
+ action_node->gpio_num = gpio_num;
+
+ valid_absence_of_module = NULL;
+ ret = of_property_read_string(gpio_node, "valid_absence_of_module", &valid_absence_of_module);
+
+ if (ret == 0 && valid_absence_of_module != NULL)
+ {
+ strncpy(action_node->valid_absence_of_module, valid_absence_of_module, sizeof(action_node->valid_absence_of_module));
+ printk("read module %s\n", action_node->valid_absence_of_module);
+ }
+
+ printk("to find act_suspend\n");
+ gpio_next_node = of_find_node_by_name(gpio_node, "suspend");
+ if (gpio_next_node == NULL)
+ printk("no act_suspend node found\n");
+ else
+ printk("find act_suspend\n");
+ read_one_action(gpio_next_node, &action_node->actions[ACT_SUSPEND]);
+ gpio_next_node = of_find_node_by_name(gpio_node, "resume");
+ if (gpio_next_node == NULL)
+ printk("no act_resume node found\n");
+ else
+ printk("find act_resume\n");
+ read_one_action(gpio_next_node, &action_node->actions[ACT_RESUME]);
+
+ return 0;
+}
+
+static int __init lynq_suspend_init(void)
+{
+ int node_num, i;
+ struct device_node *gpio_device_node, *gpio_next_node;
+
+ gpio_device_node = of_find_node_by_path("/lynq_lpm_gpio_actions");
+ //gpio_device_node = of_find_node_by_path("/gpio_init");
+ if(gpio_device_node == NULL)
+ {
+ printk_deferred("lynq_suspend_init: get DTS property failed!\n");
+ return 0;
+ }
+
+ node_num = of_get_child_count(gpio_device_node);
+ if(node_num > SUSPEND_GPIO_MAX)
+ {
+ node_num = SUSPEND_GPIO_MAX;
+ printk("lynq_suspend_init: over the max number");
+ }
+ else
+ {
+ printk("lynq_suspend_init: node number: %d", node_num);
+ }
+
+ gpio_next_node = NULL;
+
+ for(i = 0; i < node_num; i++)
+ {
+ gpio_next_node = of_get_next_child(gpio_device_node, gpio_next_node);
+ if(!gpio_next_node)
+ {
+ printk("no more node");
+ break;
+ }
+ lpm_gpio_list[i] = __inner_alloc_gpio_action_node();
+ read_one_node(gpio_next_node, lpm_gpio_list[i]);
+ printk("read one node finish\n");
+ }
+
+ printk_deferred("[name:lynq_spm&][%s:%d] - suspend init\n",
+ __func__, __LINE__);
+
+ return 0;
+}
+
+late_initcall(lynq_suspend_init);
+
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/suspend/lynq_suspend.h b/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/suspend/lynq_suspend.h
new file mode 100644
index 0000000..82d862e
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/suspend/lynq_suspend.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 Mobiletek Inc.
+ */
+
+#ifndef __LYNQ_SUSPEND_H__
+#define __LYNQ_SUSPEND_H__
+
+int lynq_suspend_common_enter(unsigned int *susp_status);
+
+int lynq_suspend_common_resume(unsigned int susp_status);
+
+#endif
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/suspend/mtk_suspend.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/suspend/mtk_suspend.c
index 0fdc558..a155a10 100644
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/suspend/mtk_suspend.c
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/lpm/modules/platform/mt6880/suspend/mtk_suspend.c
@@ -30,9 +30,11 @@
#ifdef CONFIG_MTK_CCCI_DEVICES
#include <mt-plat/mtk_ccci_common.h>
#endif
-#include <linux/gpio.h>
-
-#define MTK_GSW_WG870_GPIO_PWR_RST
+//you.chen@2023-01-05 add for lpm suspend actions begin
+#ifdef CONFIG_LYNQ_LPM_SUSPEND_SUPPORT
+#include <lynq_suspend.h>
+#endif
+//you.chen@2023-01-05 add for lpm suspend actions end
unsigned int mtk_suspend_status;
u64 before_md_sleep_time;
@@ -95,19 +97,16 @@
| PLAT_PMIC_VCORE_SRCLKEN0
| PLAT_SUSPEND;
+//you.chen@2023-01-05 add for lpm suspend actions begin
+#ifdef CONFIG_LYNQ_LPM_SUSPEND_SUPPORT
+ lynq_suspend_common_enter(susp_status);
+#endif
+//you.chen@2023-01-05 add for lpm suspend actions end
+
/* maybe need to stop sspm/mcupm mcdi task here */
if (susp_status)
*susp_status = status;
- //you.chen@2022-07-15 add for shutdown wifi power when suspend begin(for temp)
-#if defined(MTK_GSW_WG870_GPIO_PWR_RST)
- /* Control GPIO182 for turn off WIFI chip */
- printk_deferred("mt_spm_suspend_enter\n");
- gpio_set_value(202+268, 0);
- gpio_set_value(182+268, 0);
-#endif
- //you.chen@2022-07-15 add for shutdown wifi power when suspend end(for temp)
-
return 0;
}
@@ -115,19 +114,11 @@
static inline int mtk_suspend_common_resume(unsigned int susp_status)
{
/* Implement suspend common flow here */
- //you.chen@2022-07-15 add for shutdown wifi power when suspend begin(for temp)
-#if defined(MTK_GSW_WG870_GPIO_PWR_RST)
- /* Control GPIO182 for turn on WIFI chip */
- gpio_set_value(182+268, 1);
- mdelay(1);
- gpio_set_value(202+268, 1);
-
- /* Waiting for WIFI chip done*/
- mdelay(10);
- printk_deferred("mt_spm_suspend_resume\n");
+//you.chen@2023-01-05 add for lpm suspend actions begin
+#ifdef CONFIG_LYNQ_LPM_SUSPEND_SUPPORT
+ return lynq_suspend_common_resume(susp_status);
#endif
- //you.chen@2022-07-15 add for shutdown wifi power when suspend end(for temp)
-
+//you.chen@2023-01-05 add for lpm suspend actions end
return 0;
}