Skip to content

Commit 2abf589

Browse files
greatgitsbyclaude
andauthored
kernel/system: bringup gpio (#58)
- TLMM GPIO base is dynamic on mainline (512 vs 0 on downstream), look it up at runtime in gpio.sh, lte.sh, and power_drop_monitor.py - include pm8998.dtsi/pmi8998.dtsi for PMIC GPIO chips - enable I2C_QCOM_GENI=y, SENSORS_INA2XX=y, GPIO_SYSFS=y - add INA231 on i2c10 in DTS - dynamically discover PM8998 GPIO base, INA231 hwmon and i2c bus - re-add POWER ALERT pin export (PM8998_GPIO4) in gpio.sh Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * gpio: extract shared gpio_base.sh and fix unclosed file handles Deduplicate TLMM/PM8998 base lookup and gpio() function into gpio_base.sh, sourced by gpio.sh and lte.sh. Fix unclosed file handles in power_drop_monitor.py and move glob import to top level. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 698b29f commit 2abf589

File tree

6 files changed

+118
-22
lines changed

6 files changed

+118
-22
lines changed

kernel/configs/vamos.config

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,14 @@ CONFIG_PHY_QCOM_QUSB2=y
1515
CONFIG_TYPEC=y
1616
CONFIG_USB_CONFIGFS=y
1717

18+
# I2C
19+
CONFIG_I2C_QCOM_GENI=y
20+
21+
# Power monitoring (INA231)
22+
CONFIG_SENSORS_INA2XX=y
23+
24+
# GPIO
25+
# TODO: migrate gpio.sh, lte.sh, and power_drop_monitor.py to chardev (libgpiod)
26+
# and remove GPIO_SYSFS (deprecated)
27+
CONFIG_EXPERT=y
28+
CONFIG_GPIO_SYSFS=y

kernel/dts/sdm845-comma-common.dtsi

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
44
#include "sdm845.dtsi"
5+
#include "pm8998.dtsi"
6+
#include "pmi8998.dtsi"
57

68
/ {
79
aliases {
@@ -349,6 +351,17 @@
349351
status = "okay";
350352
};
351353

354+
&i2c10 {
355+
status = "okay";
356+
clock-frequency = <100000>;
357+
358+
ina231@40 {
359+
compatible = "ti,ina231";
360+
reg = <0x40>;
361+
shunt-resistor = <30000>;
362+
};
363+
};
364+
352365
&ufs_mem_hc {
353366
status = "okay";
354367

userspace/root/usr/comma/gpio.sh

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
#!/bin/bash
2-
3-
function gpio {
4-
echo "out" > /sys/class/gpio/gpio$1/direction
5-
echo $2 > /sys/class/gpio/gpio$1/value
6-
}
2+
source /usr/comma/gpio_base.sh
73

84
pins=(
95
# 27 # SW_3V3_EN
@@ -19,27 +15,37 @@ pins=(
1915
33 # GPS_SAFEBOOT_N
2016
32 # GPS_RST_N
2117
52 # LTE_BOOT
22-
1264 # POWER ALERT
2318
)
2419

20+
# PM8998 GPIO4 = INA231 POWER ALERT (not a TLMM pin, separate GPIO chip)
21+
if [ "$PM8998_BASE" -gt 0 ]; then
22+
POWER_ALERT_PIN=$((PM8998_BASE + 3))
23+
echo "POWER_ALERT (gpio$POWER_ALERT_PIN)"
24+
echo $POWER_ALERT_PIN > /sys/class/gpio/export
25+
until [ -d /sys/class/gpio/gpio$POWER_ALERT_PIN ]; do sleep .05; done
26+
chown root:gpio /sys/class/gpio/gpio$POWER_ALERT_PIN/direction /sys/class/gpio/gpio$POWER_ALERT_PIN/value 2>/dev/null
27+
chmod 660 /sys/class/gpio/gpio$POWER_ALERT_PIN/direction /sys/class/gpio/gpio$POWER_ALERT_PIN/value 2>/dev/null
28+
fi
29+
2530
for p in ${pins[@]}; do
26-
echo $p
31+
pin=$((TLMM_BASE + p))
32+
echo "$p (gpio$pin)"
2733

2834
# this is SSD_3v3 EN on tici
2935
if [ "$p" -eq 41 ] && grep -q "comma tici" /sys/firmware/devicetree/base/model; then
3036
echo "Skipping $p"
3137
continue
3238
fi
3339

34-
echo $p > /sys/class/gpio/export
35-
until [ -d /sys/class/gpio/gpio$p ]
40+
echo $pin > /sys/class/gpio/export
41+
until [ -d /sys/class/gpio/gpio$pin ]
3642
do
3743
sleep .05
3844
done
3945
# eudev doesn't apply GROUP/MODE from udev rules to sysfs GPIO files
4046
# like systemd-udevd does, so set permissions manually after export
41-
chown root:gpio /sys/class/gpio/gpio$p/direction /sys/class/gpio/gpio$p/value 2>/dev/null
42-
chmod 660 /sys/class/gpio/gpio$p/direction /sys/class/gpio/gpio$p/value 2>/dev/null
47+
chown root:gpio /sys/class/gpio/gpio$pin/direction /sys/class/gpio/gpio$pin/value 2>/dev/null
48+
chmod 660 /sys/class/gpio/gpio$pin/direction /sys/class/gpio/gpio$pin/value 2>/dev/null
4349
done
4450

4551

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash
2+
3+
# Get TLMM GPIO chip base (dynamic on mainline, was 0 on downstream)
4+
TLMM_BASE=$(cat /sys/bus/platform/devices/3400000.pinctrl/gpio/*/base 2>/dev/null | head -1)
5+
TLMM_BASE=${TLMM_BASE:-0}
6+
7+
# Get PM8998 GPIO chip base (SPMI USID 0, GPIO @ 0xc000)
8+
for chip in /sys/class/gpio/gpiochip*/; do
9+
label=$(cat "$chip/label" 2>/dev/null)
10+
if [[ "$label" == *"spmi"*"pmic@0"*"gpio"* ]] || [[ "$label" == *"pm8998"*"gpio"* ]]; then
11+
PM8998_BASE=$(cat "$chip/base")
12+
break
13+
fi
14+
done
15+
PM8998_BASE=${PM8998_BASE:-0}
16+
17+
function gpio {
18+
local pin=$((TLMM_BASE + $1))
19+
echo "out" > /sys/class/gpio/gpio$pin/direction
20+
echo $2 > /sys/class/gpio/gpio$pin/value
21+
}

userspace/root/usr/comma/lte/lte.sh

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
#!/bin/bash
2-
3-
function gpio {
4-
echo "out" > /sys/class/gpio/gpio$1/direction
5-
echo $2 > /sys/class/gpio/gpio$1/value
6-
}
2+
source /usr/comma/gpio_base.sh
73

84
HUB_RST_N=30
95
LTE_RST_N=50

userspace/root/usr/comma/power_drop_monitor.py

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env python
2+
import glob
23
import os
34
import signal
45
import time
@@ -9,14 +10,59 @@
910

1011
ALERT_VOLTAGE_THRESHOLD_mV = 4000
1112

12-
POWER_ALERT_GPIO_PIN = 1264
13-
INA231_BUS = 0
13+
def get_tlmm_base():
14+
bases = glob.glob("/sys/bus/platform/devices/3400000.pinctrl/gpio/*/base")
15+
if bases:
16+
with open(bases[0]) as f:
17+
return int(f.read().strip())
18+
return 0
19+
20+
TLMM_BASE = get_tlmm_base()
21+
22+
def get_pm8998_base():
23+
"""Find PM8998 PMIC GPIO chip base (SPMI USID 0, GPIO @ 0xc000)"""
24+
for chip in sorted(glob.glob("/sys/class/gpio/gpiochip*")):
25+
try:
26+
with open(os.path.join(chip, "label")) as f:
27+
label = f.read().strip()
28+
if ("spmi" in label and "pmic@0" in label and "gpio" in label) or ("pm8998" in label and "gpio" in label):
29+
with open(os.path.join(chip, "base")) as f:
30+
return int(f.read().strip())
31+
except (IOError, ValueError):
32+
continue
33+
return 0
34+
35+
PM8998_BASE = get_pm8998_base()
36+
POWER_ALERT_GPIO_PIN = PM8998_BASE + 3 # PM8998_GPIO4 (0-indexed offset 3)
1437
INA231_ADDRESS = 0x40
1538
INA231_MASK_REG = 0x06
1639
INA231_LIMIT_REG = 0x07
1740
INA231_MASK_CONFIG = (1 << 12) # Bus undervoltage, not latching
1841
INA231_BUS_VOLTAGE_LSB_mV = 1.25
19-
VOLTAGE_FILE = "/sys/class/hwmon/hwmon1/in1_input"
42+
43+
def find_ina231_hwmon():
44+
for hwmon in sorted(glob.glob("/sys/class/hwmon/hwmon*")):
45+
try:
46+
with open(os.path.join(hwmon, "name")) as f:
47+
if f.read().strip() == "ina231":
48+
return hwmon
49+
except (IOError, ValueError):
50+
continue
51+
return None
52+
53+
def find_ina231_i2c_bus():
54+
for dev in sorted(glob.glob("/sys/bus/i2c/devices/*-0040")):
55+
try:
56+
with open(os.path.join(dev, "name")) as f:
57+
if f.read().strip() == "ina231":
58+
return int(os.path.basename(dev).split("-")[0])
59+
except (IOError, ValueError):
60+
continue
61+
return 0
62+
63+
INA231_BUS = find_ina231_i2c_bus()
64+
INA231_HWMON = find_ina231_hwmon()
65+
VOLTAGE_FILE = os.path.join(INA231_HWMON, "in1_input") if INA231_HWMON else "/sys/class/hwmon/hwmon1/in1_input"
2066
PARAM_FILE = "/data/params/d/LastPowerDropDetected"
2167
COMMA_CGROUP_PROCS = "/sys/fs/cgroup/comma/cgroup.procs"
2268
COMMA_SV_CONTROL = "/run/runit/service/comma/supervise/control"
@@ -51,8 +97,10 @@ def read_voltage_mV():
5197
with open(VOLTAGE_FILE, "r") as f:
5298
return int(f.read().strip())
5399

100+
CURRENT_FILE = os.path.join(INA231_HWMON, "curr1_input") if INA231_HWMON else "/sys/class/hwmon/hwmon1/curr1_input"
101+
54102
def read_current_mA():
55-
with open("/sys/class/hwmon/hwmon1/curr1_input", "r") as f:
103+
with open(CURRENT_FILE, "r") as f:
56104
return int(f.read().strip())
57105

58106
def update_param(stage, v_initial, i_initial, v_final, i_final):
@@ -107,8 +155,9 @@ def perform_controlled_shutdown():
107155
# SIGKILL all processes in the comma cgroup (comma/run puts all openpilot procs in this cgroup)
108156
[os.kill(int(p), signal.SIGKILL) for p in open(COMMA_CGROUP_PROCS).read().split() if p.strip()]
109157
# Tell panda SoC is off so it doesn't spin up the fan
110-
write_once("/sys/class/gpio/gpio49/direction", "out")
111-
write_once("/sys/class/gpio/gpio49/value", "0")
158+
som_st_io = TLMM_BASE + 49
159+
write_once(f"/sys/class/gpio/gpio{som_st_io}/direction", "out")
160+
write_once(f"/sys/class/gpio/gpio{som_st_io}/value", "0")
112161
# Wait for all processes to fully exit before syncing (kernel resource cleanup takes ~150-400ms)
113162
while open(COMMA_CGROUP_PROCS).read().strip():
114163
time.sleep(0.001)

0 commit comments

Comments
 (0)