drivers: gnss: lcx7g: Refactor power management
The implementation of power management did not account for being on a power domain when initializing, and handling being powered on and off at runtime. The GNSS requires time to start up, which it always does when powered on, before accepting commands. It also requires time after resuming and suspending before accepting commands. This commit implements this timeout, and improves logging to make the power management more transparent, and removes some redundant parenthesis for better readability. Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
This commit is contained in:
parent
a9ffd91294
commit
59b9a86f30
1 changed files with 67 additions and 24 deletions
|
|
@ -22,20 +22,18 @@
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
LOG_MODULE_REGISTER(quectel_lcx6g, CONFIG_GNSS_LOG_LEVEL);
|
LOG_MODULE_REGISTER(quectel_lcx6g, CONFIG_GNSS_LOG_LEVEL);
|
||||||
|
|
||||||
#define QUECTEL_LCX6G_STARTUP_DELAY (K_MSEC(300U))
|
#define QUECTEL_LCX6G_PM_TIMEOUT_MS 500U
|
||||||
#define QUECTEL_LCX6G_STATE_CHANGE_DELAY_MSEC (300LL)
|
#define QUECTEL_LCX6G_SCRIPT_TIMEOUT_S 10U
|
||||||
#define QUECTEL_LCX6G_PAIR_TIMEOUT (K_SECONDS(11))
|
|
||||||
#define QUECTEL_LCX6G_SCRIPT_TIMEOUT_S (10U)
|
|
||||||
|
|
||||||
#define QUECTEL_LCX6G_PAIR_NAV_MODE_STATIONARY (4)
|
#define QUECTEL_LCX6G_PAIR_NAV_MODE_STATIONARY 4
|
||||||
#define QUECTEL_LCX6G_PAIR_NAV_MODE_FITNESS (1)
|
#define QUECTEL_LCX6G_PAIR_NAV_MODE_FITNESS 1
|
||||||
#define QUECTEL_LCX6G_PAIR_NAV_MODE_NORMAL (0)
|
#define QUECTEL_LCX6G_PAIR_NAV_MODE_NORMAL 0
|
||||||
#define QUECTEL_LCX6G_PAIR_NAV_MODE_DRONE (5)
|
#define QUECTEL_LCX6G_PAIR_NAV_MODE_DRONE 5
|
||||||
|
|
||||||
#define QUECTEL_LCX6G_PAIR_PPS_MODE_DISABLED (0)
|
#define QUECTEL_LCX6G_PAIR_PPS_MODE_DISABLED 0
|
||||||
#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED (4)
|
#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED 4
|
||||||
#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_AFTER_LOCK (1)
|
#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_AFTER_LOCK 1
|
||||||
#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_WHILE_LOCKED (2)
|
#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_WHILE_LOCKED 2
|
||||||
|
|
||||||
struct quectel_lcx6g_config {
|
struct quectel_lcx6g_config {
|
||||||
const struct device *uart;
|
const struct device *uart;
|
||||||
|
|
@ -77,6 +75,7 @@ struct quectel_lcx6g_data {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct k_spinlock lock;
|
struct k_spinlock lock;
|
||||||
|
k_timeout_t pm_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(_sym, _script_chats, _callback, _timeout) \
|
#define MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(_sym, _script_chats, _callback, _timeout) \
|
||||||
|
|
@ -173,33 +172,60 @@ static int quectel_lcx6g_configure_pps(const struct device *dev)
|
||||||
return modem_chat_run_script(&data->chat, &data->dynamic_script);
|
return modem_chat_run_script(&data->chat, &data->dynamic_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void quectel_lcx6g_pm_changed(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct quectel_lcx6g_data *data = dev->data;
|
||||||
|
uint32_t pm_ready_at_ms;
|
||||||
|
|
||||||
|
pm_ready_at_ms = k_uptime_get() + QUECTEL_LCX6G_PM_TIMEOUT_MS;
|
||||||
|
data->pm_timeout = K_TIMEOUT_ABS_MS(pm_ready_at_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void quectel_lcx6g_await_pm_ready(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct quectel_lcx6g_data *data = dev->data;
|
||||||
|
|
||||||
|
LOG_INF("Waiting until PM ready");
|
||||||
|
k_sleep(data->pm_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
static int quectel_lcx6g_resume(const struct device *dev)
|
static int quectel_lcx6g_resume(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct quectel_lcx6g_data *data = dev->data;
|
struct quectel_lcx6g_data *data = dev->data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
LOG_INF("Resuming");
|
||||||
|
|
||||||
|
quectel_lcx6g_await_pm_ready(dev);
|
||||||
|
|
||||||
ret = modem_pipe_open(data->uart_pipe);
|
ret = modem_pipe_open(data->uart_pipe);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to open pipe");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = modem_chat_attach(&data->chat, data->uart_pipe);
|
ret = modem_chat_attach(&data->chat, data->uart_pipe);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to attach chat");
|
||||||
modem_pipe_close(data->uart_pipe);
|
modem_pipe_close(data->uart_pipe);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = modem_chat_run_script(&data->chat, &resume_script);
|
ret = modem_chat_run_script(&data->chat, &resume_script);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to initialize GNSS");
|
||||||
modem_pipe_close(data->uart_pipe);
|
modem_pipe_close(data->uart_pipe);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = quectel_lcx6g_configure_pps(dev);
|
ret = quectel_lcx6g_configure_pps(dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to configure PPS");
|
||||||
modem_pipe_close(data->uart_pipe);
|
modem_pipe_close(data->uart_pipe);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_INF("Resumed");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,18 +235,32 @@ static int quectel_lcx6g_suspend(const struct device *dev)
|
||||||
struct quectel_lcx6g_data *data = dev->data;
|
struct quectel_lcx6g_data *data = dev->data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
LOG_INF("Suspending");
|
||||||
|
|
||||||
|
quectel_lcx6g_await_pm_ready(dev);
|
||||||
|
|
||||||
ret = modem_chat_run_script(&data->chat, &suspend_script);
|
ret = modem_chat_run_script(&data->chat, &suspend_script);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to suspend GNSS");
|
||||||
modem_pipe_close(data->uart_pipe);
|
modem_pipe_close(data->uart_pipe);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_INF("Suspended");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void quectel_lcx6g_turn_on(const struct device *dev)
|
||||||
|
{
|
||||||
|
LOG_INF("Powered on");
|
||||||
|
}
|
||||||
|
|
||||||
static int quectel_lcx6g_turn_off(const struct device *dev)
|
static int quectel_lcx6g_turn_off(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct quectel_lcx6g_data *data = dev->data;
|
struct quectel_lcx6g_data *data = dev->data;
|
||||||
|
|
||||||
|
LOG_INF("Powered off");
|
||||||
|
|
||||||
return modem_pipe_close(data->uart_pipe);
|
return modem_pipe_close(data->uart_pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -242,6 +282,7 @@ static int quectel_lcx6g_pm_action(const struct device *dev, enum pm_device_acti
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PM_DEVICE_ACTION_TURN_ON:
|
case PM_DEVICE_ACTION_TURN_ON:
|
||||||
|
quectel_lcx6g_turn_on(dev);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -253,6 +294,8 @@ static int quectel_lcx6g_pm_action(const struct device *dev, enum pm_device_acti
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quectel_lcx6g_pm_changed(dev);
|
||||||
|
|
||||||
k_spin_unlock(&data->lock, key);
|
k_spin_unlock(&data->lock, key);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -717,7 +760,6 @@ static int quectel_lcx6g_init(const struct device *dev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
LOG_INF("Initializing Quectel LCX6G");
|
|
||||||
ret = quectel_lcx6g_init_nmea0183_match(dev);
|
ret = quectel_lcx6g_init_nmea0183_match(dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -732,18 +774,19 @@ static int quectel_lcx6g_init(const struct device *dev)
|
||||||
|
|
||||||
quectel_lcx6g_init_dynamic_script(dev);
|
quectel_lcx6g_init_dynamic_script(dev);
|
||||||
|
|
||||||
#ifdef CONFIG_PM_DEVICE_RUNTIME
|
quectel_lcx6g_pm_changed(dev);
|
||||||
pm_device_init_suspended(dev);
|
|
||||||
#else
|
if (pm_device_is_powered(dev)) {
|
||||||
LOG_INF("Resuming Quectel LCX6G");
|
ret = quectel_lcx6g_resume(dev);
|
||||||
ret = quectel_lcx6g_resume(dev);
|
if (ret < 0) {
|
||||||
if (ret < 0) {
|
return ret;
|
||||||
LOG_ERR("Failed to resume Quectel LCX6G");
|
}
|
||||||
return ret;
|
quectel_lcx6g_pm_changed(dev);
|
||||||
|
} else {
|
||||||
|
pm_device_init_off(dev);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
LOG_INF("Quectel LCX6G initialized");
|
return pm_device_runtime_enable(dev);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LCX6G_INST_NAME(inst, name) \
|
#define LCX6G_INST_NAME(inst, name) \
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue