Home | Projects | Notes | Misc | Events | Gitea/Github/Codeberg | Instagram

Misc Fixes for Linux on the ThinkPad L13 Yoga (Gen4)

In October I bought I ThinkPad L13 Yoga G4 to replace my ThinkPad Yoga 370. More and more MATLAB and other compute-heavy work for Uni was starting to show the limits of the 2C/4T CPU and the single channel RAM on that laptop (don’t get me started at how long it took for a single compile of MarlinFW for the Delta 2040 at the FabLab). Usually when I need to do compute-heavy stuff I remote into my Ryzen 7 3700X/64GB RAM/RTX 3060 desktop back at home and do the job there (also to save on battery life on the laptop), but that’s not always possible when I’m in uni and the quality of the internet connection there is very hit-or-miss on a per-room basis.

I snagged the laptop for about 480€ used on ebay, basically mint conditions apart from some light marks on the display which really are not noticeable if not in very low light and with low brightness on the screen. It was also a graduation gift (for my bachelor degree) from myself (and my parents) to myself.

The new laptop is a 2-in-1, meaning I can flip the screen over and use it as a tablet and as a graphics tablet since it has an integrated Wacom Pen. Really nice way to take notes in uni, especially considering how often I rewrite entire sections or proofs or little comments to my notes. Paper is good to review and understand, but you just can’t beat the versatility of the graphics tablet when it comes to having neatly organized notes. Many of my colleagues and friends use an iPad with the Apple Pen for that, but I really couldn’t justify the purchase of a device I’d only use for uni and note taking, while my laptop is arguably the piece of tech I use the most. Besides, I don’t like the feel of an iPad+Apple Pen.

Anyhow, the laptop is supposed to recognize when it is flipped into tablet mode, like my old laptop did. The old one in fact had a SW_TABLET_MODE switch that sent a ACPI message to KDE to disable the keyboard and enter tablet mode (bigger icons and buttons, auto rotation, etc). Alas, the new one doesn’t do the same thing. I spent a bit of time trying to figure out why, with no success. It works on Windows, I tried. I suspect it’s something to do with some kind of I2C/SMBus sensor not being recognized by the kernel, given this error message in dmesg and given on Windows tablet mode works only after installing SMBus drivers.

[    3.698460] thinkpad_acpi: Unknown/reserved multi mode value 0x0000 for type 4, please report this to ibm-acpi-devel@lists.sourceforge.net
...
[    3.843302] i2c i2c-3: SMBus Timeout!
[    3.843320] i2c i2c-3: Failed reset at end of transaction (01)
[    3.843378] i2c i2c-3: Failed! (01)

I could only find a set of workarounds to enable and disable tablet-mode manually.

Obligatory I use Arch btw, hence why the use of yay and pacman. The AUR is really nice when it comes to availability of packages. Actually I use EndeavourOS.

Disable inputs when in tablet mode

First of all, disable the keyboard, touchpad and trackpoint when in tablet mode. Also, switch back to laptop mode after closing the lid or when entering suspend, just to be sure I can unlock the laptop with the keyboard on wake. Luckily there’s the tablet-mode script for that. On Arch, it’s on the AUR.

yay -S tablet-mode

with the config file /etc/tablet-mode.json

{
    "tablet": [
        "/dev/input/by-path/platform-i8042-serio-0-event-kbd",
        "/dev/input/by-path/platform-i8042-serio-1-event-mouse",
        "/dev/input/by-path/platform-AMDI0010:02-event-mouse"
    ],
    "notify": true
}

Tablet/Laptop modes can be set using the commands setsysmode tablet/laptop/toggle. The current user needs to be in the input group to use the command.

I then used the Run Command widget for Plasma (needs to be installed from “Get New”) to add two buttons to my panel, one turning into tablet mode, the other into laptop mode.

Enter Plasma Tablet Mode

Tablet Mode in plasma makes icons and window buttons bigger for easier use with a touchscreen and enables autorotation (if enabled in the settings). As an added bonus, when disabling tablet mode the screen rotation is automatically reverted to normal (landscape, no rotation).

Tablet Mode can be toggled with this script I found on the KDE forums. I’m copying it here for archival purposes.

I took the lazy way out and simply made three copies of the script, each one turning tablet mode on or off or toggling it

/opt/tabletscripts/tableton.py
---
#!/usr/bin/env python3

import subprocess
import gi

gi.require_version('Gio', '2.0')
from gi.repository import Gio, GLib

KDE_VERSION = 6
OBJECT_PATH = '/kwinrc'
INTERFACE_NAME = 'org.kde.kconfig.notify'
SIGNAL_NAME = 'ConfigChanged'

subprocess.check_call([f"kwriteconfig{KDE_VERSION}", "--file", "kwinrc", "--group", "Input", "--key", "TabletMode", "on"])

connection = Gio.bus_get_sync(Gio.BusType.SESSION, None)
Gio.DBusConnection.emit_signal(connection, None, OBJECT_PATH, INTERFACE_NAME, SIGNAL_NAME, GLib.Variant.new_tuple(GLib.Variant('a{saay}', {'Input': [b'TabletMode']})))
/opt/tabletscripts/tabletoff.py
---
#!/usr/bin/env python3

import subprocess
import gi

gi.require_version('Gio', '2.0')
from gi.repository import Gio, GLib

KDE_VERSION = 6
OBJECT_PATH = '/kwinrc'
INTERFACE_NAME = 'org.kde.kconfig.notify'
SIGNAL_NAME = 'ConfigChanged'

subprocess.check_call([f"kwriteconfig{KDE_VERSION}", "--file", "kwinrc", "--group", "Input", "--key", "TabletMode", "off"])

connection = Gio.bus_get_sync(Gio.BusType.SESSION, None)
Gio.DBusConnection.emit_signal(connection, None, OBJECT_PATH, INTERFACE_NAME, SIGNAL_NAME, GLib.Variant.new_tuple(GLib.Variant('a{saay}', {'Input': [b'TabletMode']})))
/opt/tabletscripts/tablettoggle.py
---
#!/usr/bin/env python3

import subprocess
import gi

gi.require_version('Gio', '2.0')
from gi.repository import Gio, GLib

KDE_VERSION = 6
OBJECT_PATH = '/kwinrc'
INTERFACE_NAME = 'org.kde.kconfig.notify'
SIGNAL_NAME = 'ConfigChanged'

current_mode: str = subprocess.check_output([f"kreadconfig{KDE_VERSION}", "--file", "kwinrc", "--group", "Input", "--key", "TabletMode", "--default", "auto"]).decode(encoding='utf-8').strip()
if current_mode == "on":
    subprocess.check_call([f"kwriteconfig{KDE_VERSION}", "--file", "kwinrc", "--group", "Input", "--key", "TabletMode", "off"])
else:
    subprocess.check_call([f"kwriteconfig{KDE_VERSION}", "--file", "kwinrc", "--group", "Input", "--key", "TabletMode", "on"])

connection = Gio.bus_get_sync(Gio.BusType.SESSION, None)
Gio.DBusConnection.emit_signal(connection, None, OBJECT_PATH, INTERFACE_NAME, SIGNAL_NAME, GLib.Variant.new_tuple(GLib.Variant('a{saay}', {'Input': [b'TabletMode']})))

This three python scripts can be called in conjuction with setsysmode as above. I merged them In a single sh script which is called by the widget.

/opt/tabletscripts/tableton.sh
---
#!/bin/bash
setsysmode tablet
python /opt/tabletscripts/tableton.py
/opt/tabletscripts/tabletoff.sh
---
#!/bin/bash
setsysmode laptop
python /opt/tabletscripts/tabletoff.py
/opt/tabletscripts/tablettoggle.sh
---
#!/bin/bash
setsysmode toggle
python /opt/tabletscripts/tablettoggle.py

Probably they could be mixed at least into a single python script, but I hacked this together late at night and I haven’t come back to it since. It has been holding strong though

Laptop mode on suspend, lid closed

For detecting when the lid gets closed (actually, detecting when it gets opened back) I used acpid

sudo pacman -S acpid

and the handler set to execute the tabletoff.sh script

/etc/acpid/handler.sh
---
#!/bin/bash
# Default acpi script that takes an entry for all actions

case "$1" in
    button/lid)
        case "$3" in
            close)
                logger 'LID closed'
                ;;
            open)
                logger 'LID opened'
                /opt/tabletscripts/tabletoff.sh
                #setsysmode laptop
                ;;
            *)
                logger "ACPI action undefined: $3"
                ;;
    esac
    ;;
    *)
        logger "ACPI group/action undefined: $1 / $2"
        ;;
esac

As for suspend, I created a systemd unit

/etc/systemd/system/tabletoff-on-suspend@.service 
---
[Unit]
Description=Disable tablet mode before suspend
Before=suspend.target hibernate.target hybrid-sleep.target suspend-then-hibernate.target


[Service]
ExecStart=/opt/tabletscripts/tabletoff.sh
User=%I

[Install]
WantedBy=suspend.target hibernate.target hybrid-sleep.target suspend-then-hibernate.target

the scripts need to be called as a user, hence the User=%I line. The unit needs to be enabled using the current user as argument

# systemd enable tabletoff-on-suspend@emamaker.service

Reload accelerometer module after suspend

There’s also this other little problem where the accelerometer stops working after suspend, which means no auto rotation after waking from suspend. If I’m not using it, my laptop is either in suspension or hibernation, so this has to be fixed. I isolated the culprit to the amd_sfh kernel module. Reloading it with modprobe solves the issue. I added a systemd unit

/etc/systemd/system/reload-amd_sfh-after-resume.service
---
[Unit]
Description=Reload the amd_sfh module after suspend to make the accelerometer work again
After=suspend.target hibernate.target hybrid-sleep.target suspend-then-hibernate.target


[Service]
ExecStart=rmmod amd_sfh -s ; modprobe amd_sfh

[Install]
WantedBy=suspend.target hibernate.target hybrid-sleep.target suspend-then-hibernate.target

and enabled

# systemd enable reload-amd_sfh-after-resume.service