overlay-jedi: Userspace power sequence for Rolling Wireless LTE module

1.Add lte_power_control enable flags
2.Control power sequence (gpios) from userspace upstart script

BUG=b:440194776
TEST=emerge-jedi lte_power_control

Change-Id: I4cc4a27b58991fe47c59ea332c4a5b2a376d3914
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/overlays/board-overlays/+/6869511
Commit-Queue: zhao wang <wangzhao5@huaqin.corp-partner.google.com>
Reviewed-by: Oscar Liu <oscarliu@google.com>
Reviewed-by: Knox Chiou <knoxchiou@chromium.org>
Tested-by: zhao wang <wangzhao5@huaqin.corp-partner.google.com>
Reviewed-by: Zhengqiao Xia <xiazhengqiao@huaqin.corp-partner.google.com>
diff --git a/overlay-jedi/chromeos-base/chromeos-bsp-jedi/chromeos-bsp-jedi-9999.ebuild b/overlay-jedi/chromeos-base/chromeos-bsp-jedi/chromeos-bsp-jedi-9999.ebuild
index d91ab6f..de09d3d 100644
--- a/overlay-jedi/chromeos-base/chromeos-bsp-jedi/chromeos-bsp-jedi-9999.ebuild
+++ b/overlay-jedi/chromeos-base/chromeos-bsp-jedi/chromeos-bsp-jedi-9999.ebuild
@@ -24,6 +24,7 @@
 RDEPEND="
 	chromeos-base/chromeos-config
 	chromeos-base/chromeos-bsp-baseboard-skywalker
+	chromeos-base/lte_power_control
 "
 DEPEND="
 		${RDEPEND}
diff --git a/overlay-jedi/chromeos-base/lte_power_control/files/lte_power_control b/overlay-jedi/chromeos-base/lte_power_control/files/lte_power_control
new file mode 100644
index 0000000..1d18975
--- /dev/null
+++ b/overlay-jedi/chromeos-base/lte_power_control/files/lte_power_control
@@ -0,0 +1,153 @@
+#!/bin/bash
+# Copyright 2025 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Init gpio for Rolling Wireless LTE module
+
+readonly GPIO_DIR="/sys/class/gpio"
+
+declare -A RW135
+
+# RW135 GPIO Device and offset values
+RW135["GPIO_DEVICE"]="10005000.pinctrl"
+RW135["LTE_W_DISABLE_OFFSET"]=148
+RW135["LTE_SAR_DETECT_OFFSET"]=124
+RW135["LTE_EN_OFFSET"]=121
+RW135["LTE_PWR_OFF_OFFSET"]=147
+RW135["LTE_RESET_OFFSET"]=10
+RW135["DISABLE_RESET_SLEEP"]=0.02
+RW135["DISABLE_PWR_SLEEP"]=0.1
+RW135["SLEEP_AFTER_ENABLE"]=0.002
+RW135["SLEEP_AFTER_ENABLE_PWR"]=0.014
+
+declare -A RW101
+
+# RW101 GPIO Device and offset values
+RW101["GPIO_DEVICE"]="10005000.pinctrl"
+RW101["LTE_W_DISABLE_OFFSET"]=148
+RW101["LTE_SAR_DETECT_OFFSET"]=124
+RW101["LTE_EN_OFFSET"]=121
+RW101["LTE_PWR_OFF_OFFSET"]=147
+RW101["LTE_RESET_OFFSET"]=10
+RW101["DISABLE_RESET_SLEEP"]=0.02
+RW101["DISABLE_PWR_SLEEP"]=0.1
+RW101["SLEEP_AFTER_ENABLE"]=0.002
+RW101["SLEEP_AFTER_ENABLE_PWR"]=0.014
+
+get_gpio_base() {
+  local GPIO_DEVICE="${1}"
+  dir_list=$(find /sys/class/gpio -type l -name "gpiochip*")
+  for d in ${dir_list}; do
+    DEVICE=$(basename "$(readlink "${d}/device")")
+    if [ "${DEVICE}" = "${GPIO_DEVICE}" ]; then
+      BASE=$(cat "${d}/base")
+      break
+    fi
+  done
+  if [ -z "${BASE}" ]; then
+    # Base not set, exiting.
+    exit 0
+  fi
+  echo "${BASE}"
+}
+
+disable_modem() {
+  local -n MODEM=${1}
+  local BASE
+  BASE=$(get_gpio_base "${MODEM[GPIO_DEVICE]}")
+  # lte-w-disable
+  disable_gpio $((BASE + MODEM["LTE_W_DISABLE_OFFSET"]))
+
+  # sar-detect
+  disable_gpio $((BASE + MODEM["LTE_SAR_DETECT_OFFSET"]))
+
+  # reset and sleep 20ms
+  disable_gpio $((BASE + MODEM["LTE_RESET_OFFSET"]))
+  sleep "${MODEM[DISABLE_RESET_SLEEP]}"
+
+  # poweroff and sleep 100ms
+  disable_gpio $((BASE + MODEM["LTE_PWR_OFF_OFFSET"]))
+  sleep "${MODEM[DISABLE_PWR_SLEEP]}"
+
+  # m2-power
+  disable_gpio $((BASE + MODEM["LTE_EN_OFFSET"]))
+}
+
+enable_modem() {
+  local -n MODEM=${1}
+  local BASE
+  BASE=$(get_gpio_base "${MODEM[GPIO_DEVICE]}")
+  # lte-w-disable
+  echo $((BASE + MODEM["LTE_W_DISABLE_OFFSET"]))
+  enable_gpio $((BASE + MODEM["LTE_W_DISABLE_OFFSET"]))
+
+  # sar-detect"
+  enable_gpio $((BASE + MODEM["LTE_SAR_DETECT_OFFSET"]))
+
+  # m2-power and sleep 2ms
+  enable_gpio $((BASE + MODEM["LTE_EN_OFFSET"]))
+  sleep "${MODEM[SLEEP_AFTER_ENABLE]}"
+
+  # poweroff and sleep 14ms
+  enable_gpio $((BASE + MODEM["LTE_PWR_OFF_OFFSET"]))
+  sleep "${MODEM[SLEEP_AFTER_ENABLE_PWR]}"
+
+  #reset
+  enable_gpio $((BASE + MODEM["LTE_RESET_OFFSET"]))
+}
+
+set_gpio() {
+  local gpio="$1"
+  local gpio_level="$2"
+  local gpio_path
+  gpio_path="${GPIO_DIR}/gpio${gpio}"
+  if [ ! -e "${gpio_path}" ]; then
+    echo "${gpio}" > "${GPIO_DIR}/export"
+    ret="$?"
+    if [ "${ret}" -ne 0 ]; then
+      exit 1
+    fi
+  fi
+  echo "${gpio_level}" > "${gpio_path}/direction"
+  echo "${gpio}" > "${GPIO_DIR}/unexport"
+}
+
+disable_gpio() {
+  local gpio="$1"
+  set_gpio "${gpio}" "low"
+}
+
+enable_gpio() {
+  local gpio="$1"
+  set_gpio "${gpio}" "high"
+}
+
+main() {
+  local fw
+  fw=$(cros_config /modem firmware-variant)
+  if [ -z "${fw}" ]; then
+    exit 0
+  fi
+
+  if [ "$1" = "on" ]; then
+    case ${fw#*_} in
+      "rw135")
+          enable_modem RW135
+          ;;
+      "rw101")
+          enable_modem RW101
+          ;;
+    esac
+  else
+    case ${fw#*_} in
+      "rw135")
+          disable_modem RW135
+          ;;
+      "rw101")
+          disable_modem RW101
+          ;;
+    esac
+  fi
+}
+main "$@"
diff --git a/overlay-jedi/chromeos-base/lte_power_control/files/lte_power_off.conf b/overlay-jedi/chromeos-base/lte_power_control/files/lte_power_off.conf
new file mode 100644
index 0000000..3a91096
--- /dev/null
+++ b/overlay-jedi/chromeos-base/lte_power_control/files/lte_power_off.conf
@@ -0,0 +1,13 @@
+# Copyright 2025 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description     "Shutdown gpio power sequence for Rolling Wireless LTE module"
+author          "chromium-os-dev@chromium.org"
+
+oom score -100
+
+start on starting halt or starting reboot
+task
+
+exec lte_power_control off
diff --git a/overlay-jedi/chromeos-base/lte_power_control/files/lte_power_on.conf b/overlay-jedi/chromeos-base/lte_power_control/files/lte_power_on.conf
new file mode 100644
index 0000000..a017285
--- /dev/null
+++ b/overlay-jedi/chromeos-base/lte_power_control/files/lte_power_on.conf
@@ -0,0 +1,16 @@
+# Copyright 2025 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description     "Init gpio power sequence for Rolling Wireless LTE module"
+author          "chromium-os-dev@chromium.org"
+
+respawn
+respawn limit 3 10
+
+oom score -100
+
+start on starting boot-services
+task
+
+exec lte_power_control on
diff --git a/overlay-jedi/chromeos-base/lte_power_control/lte_power_control-0.0.1-r1.ebuild b/overlay-jedi/chromeos-base/lte_power_control/lte_power_control-0.0.1-r1.ebuild
new file mode 120000
index 0000000..ae32d5c
--- /dev/null
+++ b/overlay-jedi/chromeos-base/lte_power_control/lte_power_control-0.0.1-r1.ebuild
@@ -0,0 +1 @@
+lte_power_control-0.0.1.ebuild
\ No newline at end of file
diff --git a/overlay-jedi/chromeos-base/lte_power_control/lte_power_control-0.0.1.ebuild b/overlay-jedi/chromeos-base/lte_power_control/lte_power_control-0.0.1.ebuild
new file mode 100644
index 0000000..e4a456e
--- /dev/null
+++ b/overlay-jedi/chromeos-base/lte_power_control/lte_power_control-0.0.1.ebuild
@@ -0,0 +1,20 @@
+# Copyright 2025 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+EAPI=7
+
+DESCRIPTION="Init power sequence for Rolling Wireless LTE module"
+
+LICENSE="BSD-Google"
+SLOT="0"
+KEYWORDS="-* arm64 arm"
+IUSE=""
+S="${WORKDIR}"
+
+src_install() {
+	dosbin "${FILESDIR}"/lte_power_control
+	insinto /etc/init
+	doins "${FILESDIR}"/lte_power_on.conf
+	doins "${FILESDIR}"/lte_power_off.conf
+}