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:
Bjarki Arge Andreasen 2024-01-24 09:06:26 +01:00 committed by Fabio Baltieri
parent a9ffd91294
commit 59b9a86f30

View file

@ -22,20 +22,18 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(quectel_lcx6g, CONFIG_GNSS_LOG_LEVEL);
#define QUECTEL_LCX6G_STARTUP_DELAY (K_MSEC(300U))
#define QUECTEL_LCX6G_STATE_CHANGE_DELAY_MSEC (300LL)
#define QUECTEL_LCX6G_PAIR_TIMEOUT (K_SECONDS(11))
#define QUECTEL_LCX6G_SCRIPT_TIMEOUT_S (10U)
#define QUECTEL_LCX6G_PM_TIMEOUT_MS 500U
#define QUECTEL_LCX6G_SCRIPT_TIMEOUT_S 10U
#define QUECTEL_LCX6G_PAIR_NAV_MODE_STATIONARY (4)
#define QUECTEL_LCX6G_PAIR_NAV_MODE_FITNESS (1)
#define QUECTEL_LCX6G_PAIR_NAV_MODE_NORMAL (0)
#define QUECTEL_LCX6G_PAIR_NAV_MODE_DRONE (5)
#define QUECTEL_LCX6G_PAIR_NAV_MODE_STATIONARY 4
#define QUECTEL_LCX6G_PAIR_NAV_MODE_FITNESS 1
#define QUECTEL_LCX6G_PAIR_NAV_MODE_NORMAL 0
#define QUECTEL_LCX6G_PAIR_NAV_MODE_DRONE 5
#define QUECTEL_LCX6G_PAIR_PPS_MODE_DISABLED (0)
#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_WHILE_LOCKED (2)
#define QUECTEL_LCX6G_PAIR_PPS_MODE_DISABLED 0
#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_WHILE_LOCKED 2
struct quectel_lcx6g_config {
const struct device *uart;
@ -77,6 +75,7 @@ struct quectel_lcx6g_data {
};
struct k_spinlock lock;
k_timeout_t pm_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);
}
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)
{
struct quectel_lcx6g_data *data = dev->data;
int ret;
LOG_INF("Resuming");
quectel_lcx6g_await_pm_ready(dev);
ret = modem_pipe_open(data->uart_pipe);
if (ret < 0) {
LOG_ERR("Failed to open pipe");
return ret;
}
ret = modem_chat_attach(&data->chat, data->uart_pipe);
if (ret < 0) {
LOG_ERR("Failed to attach chat");
modem_pipe_close(data->uart_pipe);
return ret;
}
ret = modem_chat_run_script(&data->chat, &resume_script);
if (ret < 0) {
LOG_ERR("Failed to initialize GNSS");
modem_pipe_close(data->uart_pipe);
return ret;
}
ret = quectel_lcx6g_configure_pps(dev);
if (ret < 0) {
LOG_ERR("Failed to configure PPS");
modem_pipe_close(data->uart_pipe);
return ret;
}
LOG_INF("Resumed");
return ret;
}
@ -209,18 +235,32 @@ static int quectel_lcx6g_suspend(const struct device *dev)
struct quectel_lcx6g_data *data = dev->data;
int ret;
LOG_INF("Suspending");
quectel_lcx6g_await_pm_ready(dev);
ret = modem_chat_run_script(&data->chat, &suspend_script);
if (ret < 0) {
LOG_ERR("Failed to suspend GNSS");
modem_pipe_close(data->uart_pipe);
return ret;
}
LOG_INF("Suspended");
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)
{
struct quectel_lcx6g_data *data = dev->data;
LOG_INF("Powered off");
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;
case PM_DEVICE_ACTION_TURN_ON:
quectel_lcx6g_turn_on(dev);
ret = 0;
break;
@ -253,6 +294,8 @@ static int quectel_lcx6g_pm_action(const struct device *dev, enum pm_device_acti
break;
}
quectel_lcx6g_pm_changed(dev);
k_spin_unlock(&data->lock, key);
return ret;
}
@ -717,7 +760,6 @@ static int quectel_lcx6g_init(const struct device *dev)
{
int ret;
LOG_INF("Initializing Quectel LCX6G");
ret = quectel_lcx6g_init_nmea0183_match(dev);
if (ret < 0) {
return ret;
@ -732,18 +774,19 @@ static int quectel_lcx6g_init(const struct device *dev)
quectel_lcx6g_init_dynamic_script(dev);
#ifdef CONFIG_PM_DEVICE_RUNTIME
pm_device_init_suspended(dev);
#else
LOG_INF("Resuming Quectel LCX6G");
ret = quectel_lcx6g_resume(dev);
if (ret < 0) {
LOG_ERR("Failed to resume Quectel LCX6G");
return ret;
quectel_lcx6g_pm_changed(dev);
if (pm_device_is_powered(dev)) {
ret = quectel_lcx6g_resume(dev);
if (ret < 0) {
return ret;
}
quectel_lcx6g_pm_changed(dev);
} else {
pm_device_init_off(dev);
}
#endif
LOG_INF("Quectel LCX6G initialized");
return 0;
return pm_device_runtime_enable(dev);
}
#define LCX6G_INST_NAME(inst, name) \