Toggle the rear flashlight with Volume Up when the display is OFF — for TECNO LJ7 (Pova 7 5G, MT6878 / Dimensity 7020, Android 15).
Locked-with-screen-on does not trigger. Volume Down is never touched. While the display is off, Volume Up is grabbed from the system (EVIOCGRAB) so pressing it only toggles the torch — the volume does not change, the screen stays off, and no volume HUD appears.
On MT6878 the flash LEDs (AW36515) are V4L2 subdevs, not plain sysfs nodes:
/dev/v4l-subdev23= aw36515-led0 (front/screen flash)/dev/v4l-subdev24= aw36515-led1 (rear flash) ← used by default
The module ships a small portable helper (v4lflash, C source included) that
sets the standard V4L2 flash controls (V4L2_CID_FLASH_LED_MODE → TORCH +
V4L2_CID_FLASH_TORCH_INTENSITY). Volume Up is watched event-driven via
getevent on the mtk-kpd device, and the grab lifecycle is driven by the
kernel backlight sysfs (/sys/class/leds/lcd-backlight/brightness, 0 = off) —
instant, cannot hang, zero dumpsys.
While the display is OFF, the module runs volgrab (bundled, C source
included) on the Volume Up device (/dev/input/event1, mtk-kpd) with
EVIOCGRAB — exclusive delivery. The framework therefore never receives
Volume Up presses: no volume increase, no wake, no HUD. volgrab writes the
grabbed presses to a file that a 0.15s poll loop turns into torch toggles
(instant feel; the file instead of a pipe keeps the loop free to check the
screen state without blocking). The moment the display turns on, the loop
kills volgrab by PID (direct kill(2)) and the kernel releases the grab
within 0.15s; Volume Up behaves completely normally again. Volume Down
(mtk-pmic-keys) is never grabbed. Disable with GRAB_ON=0 in the conf
(then Volume Up acts natively and the volume bump returns).
From a release (recommended):
# Download volkey-torch.zip from the Releases tab
# KernelSU Manager -> Modules -> Install from storage -> volkey-torch.zip
# or manual:
# su -c "unzip volkey-torch.zip -d /data/adb/modules/volkey-torch"
# rebootFrom source:
git clone https://github.com/AndyRathaur/volkey-torch
cd volkey-torch
zip -r ../volkey-torch.zip module.prop service.sh v4lflash volgrab README.md
# then install the zip as abovesu -c "cat /data/local/tmp/voltorch.log" # shows found devices
su -c "/data/adb/modules/volkey-torch/v4lflash blink 200000 24" # rear flash test
su -c "/data/adb/modules/volkey-torch/v4lflash blink 200000 23" # front flash testCreate /data/local/tmp/voltorch.conf to override:
VOLDEVS="/dev/input/event0 /dev/input/event1" # volume key devices
VOLUP_DEV=/dev/input/event1 # auto: device reporting 0073
LEDDEV=/dev/v4l-subdev24 # rear (24) or front (23)
LEVEL=200000 # torch intensity uA (10000..500000)
REFRESH_INTERVAL=5 # screen-state refresh seconds
GRAB_ON=1 # 0 disables EVIOCGRAB (volume then bumps)geteventmonitors: ~0% CPU (blocked reads, no wakeups)v4lflash: ~5ms only when you press the keyvolgrab: ~0% CPU (blocked read on the grabbed device; grab is held only while the display is off and is released on screen-on / exit)- While the display is off and the grab is engaged, grab_loop wakes ~7x/sec for a couple of sysfs/file reads (~1-2ms each) — negligible; the process sleeps between polls, so the CPU stays in idle/deep sleep
- Screen-state refresher: one sysfs read per 5s (diagnostics cache + slow release backstop)
- No wakelocks, no network, no dumpsys anywhere in the hot paths
- v3.6.3 — grab lifecycle moved entirely inside grab_loop: own volgrab by
PID, release with a direct
kill(2)(nopkill— the /proc-scanning applets silently fail when KernelSU launches the service, which had left the grab held after unlock). Events go to a file polled every 0.15s, so torch response stays instant while the screen-on release is ~0.15s. - v3.6.2 — top-level watchdog released the grab ~0.5s after display-on (the v3.6.1 in-loop watchdog silently never ran under busybox sh).
- v3.6.1 — screen state from the kernel backlight sysfs (no dumpsys in hot paths; a hung dumpsys had held service locks and delayed the display-off transition by 2-3s).
- v3.6 — defense in depth: live screen verify on every press, power-key release sync, refresher writes every cycle.
- v3.5.1 — removed the FIFO (nothing can block).
- v3.5 — EVIOCGRAB architecture (no volume bump / wake / HUD).
start devs=[]in the log → volume devices not found; setVOLDEVSin the conf- Torch lights but wrong LED → set
LEDDEV=/dev/v4l-subdev23 - Volume still bumps with screen off →
grab ONmissing from the log; checkvolgrabexists/executable, or setGRAB=0and accept the bump - Nothing at all → check
su -c "ls -la /dev/v4l-subdev24"(needs to exist), and run theblinktest above; ifS_CTRL ... FAILEDappears, the camera HAL may hold the subdev — reboot and test again with screen off - On-screen volume behavior unchanged (module only fires when screen off)
- Uninstall: remove module in KernelSU/Magisk manager (grab auto-releases)
- Safe mode (KSU/Magisk): hold Volume Down while booting → modules disabled
- ADB:
su -c "rm -rf /data/adb/modules/volkey-torch" - TWRP: delete
/data/adb/modules/volkey-torch - This module is userspace-only (no boot/init changes), so bootloop risk is minimal
- Trigger: Volume Up press only, and only when the display is OFF
- Display state is cached (battery-friendly); lockscreen-with-screen-on never triggers
- Autorepeat ignored (no rapid toggling when holding the key)
- Torch state is queried live from the driver, so it syncs with the quick-settings tile
- Volume Up is EVIOCGRAB'd while the display is off (no volume bump / wake / HUD); Volume Down is never touched
- Tested working on TECNO LJ7 / Android 15 / KernelSU
MIT — see LICENSE.