2bfe88c42110fd0000e1601dd73bff3682e609e5 — Michael Forney 8 months ago
Add page about configuring mobile data
1 files changed, 171 insertions(+), 0 deletions(-)

A modem.md
A  => modem.md +171 -0
@@ 1,171 @@
# Modem

The modem on the PinePhone is a Quectel EG25-G, connected through
USB. This is the first Linux system I've used that had a modem, so
there was lots of new things to figure out. This page is a collection
of stuff I've learned.

## Kernel config


## Powering on the modem

Once the system starts up, the modem is not usable until it gets
powerod on. This can be done with the GPIO pins.

The sysfs GPIO interface is deprecated, so I used [libgpiod] to
control the pins via the `gpiochip$N` character devices. libgpiod
is a C library that comes with several handy command-line tools.

Based on postmarketOS's [eg25.initd] init script, I did the following
to power on the modem.

gpioset gpiochip1 68=0 232=0        # turn off RESET_N and W_DISABLE#
gpioset -m time -s 2 gpiochip1 35=1 # turn on PWRKEY for two seconds

After a few seconds, you'll see some new messages in dmesg

usb 3-1: new high-speed USB device number 2 using ehci-platform
option 3-1:1.0: GSM modem (1-port) converter detected
usb 3-1: GSM modem (1-port) converter now attached to ttyUSB0
option 3-1:1.1: GSM modem (1-port) converter detected
usb 3-1: GSM modem (1-port) converter now attached to ttyUSB1
option 3-1:1.2: GSM modem (1-port) converter detected
usb 3-1: GSM modem (1-port) converter now attached to ttyUSB2
option 3-1:1.3: GSM modem (1-port) converter detected
usb 3-1: GSM modem (1-port) converter now attached to ttyUSB3
qmi_wwan 3-1:1.4: cdc-wdm0: USB WDM device
qmi_wwan 3-1:1.4 wwan0: register 'qmi_wwan' at usb-1c1b000.usb-1, WWAN/QMI device, xx:xx:xx:xx:xx:xx

Whoa, that's a lot of new devices.

- `ttyUSB1` is used with the [NMEA protocol] to access the GPS features
  of the modem.
- `ttyUSB2` is used to control the modem with [AT commands].
- `cdc-wdm0` is used to interact with the modem with the [QMI protocol].
- I'm not sure what the others are for.

### Mobile data

It turns out it's fairly easy to setup mobile data on the PinePhone
without running extra daemons like ModemManager and NetworkManager.

My phone carrier is Google Fi, and they will send you a data-only
SIM card for no additional charge. The SIM card I received was in
the nano form-factor so I needed nano (4FF) to micro (3FF) adapter
to get it to fit into the PinePhone.

There are several tools you can use to connect to mobile data,
including [uqmi], qmictl from [libqmi], and [ModemManager] (via
libqmi). I went with uqmi since it didn't have dependencies like
glib and dbus.

First, you can query several pieces of status information from your

$ uqmi -d /dev/cdc-wdm0 --get-signal-info
        "type": "lte",
        "rssi": -85,
        "rsrq": -14,
        "rsrp": -120,
        "snr": -14
$ uqmi -d /dev/cdc-wdm0 --get-current-settings
"Out of call"
$ uqmi -d /dev/cdc-wdm0 --get-data-status

This indicates that the modem is getting an LTE signal, but is not
yet connected.

The QMI service we'll be using is `wds` (wireless data service).
First, we need to get a client ID for the connection.

$ CID=$(uqmi -d /dev/cdc-wdm0 --get-client-id wds) && echo $CID

Now, we can use this client ID to connect to the network. You'll
need the APN (access point name) for your carrier. I'm using Google
Fi, so the APN is `h2g2`.

$ APN=h2g2
$ PDH=$(uqmi -d /dev/cdc-wdm0 --set-client-id wds,$CID --start-network --apn $APN) && echo $PDH

You can also pass `--autoconnect` to the `--start-network` command,
which will cause your modem to connect automatically as soon as the
modem is powered on. This is pretty convenient, but seems to interact
poorly with ModemManager on postmarketOS (I needed to disable
autoconnect to get it to recognize my modem again).

Despite looking like an error, this negative number is just the
two's complement value for the PDH (packet data handle) of the
connection. You should now see that modem is connected.

        "pdp-type": "ipv4-or-ipv6",
        "ip-family": "ipv4",
        "mtu": 1500,
        "ipv4": {
                "ip": "XXX.XXX.XXX.XXX",
                "dns1": "XXX.XXX.XXX.XXX",
                "dns2": "XXX.XXX.XXX.XXX",
                "gateway": "XXX.XXX.XXX.XXX",
                "subnet": ""
        "ipv6": {

        "domain-names": {


You can now apply these settings to your WWAN device manually, or
run a DHCP client. Either way, you'll need to set your `wwan0`
device to `raw_ip` mode, then bring it up.

echo Y >/sys/class/net/wwan0/qmi/raw_ip
ip link set wwan0 up

Now you should be good to go!

To stop the network, you'll need the client ID and PDH from earlier.

uqmi -d /dev/cdc-wdm0 --set-client-id wds,$CID --stop-network $PDH

If you ever get confused, or forget your CID or PDH, you can release
all client IDs (and any associated connections).

uqmi -d /dev/cdc-wdm0 --sync

[libgpiod]: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/README
[eg25.initd]: https://gitlab.com/postmarketOS/pmaports/-/blob/master/device/device-pine64-pinephone/eg25.initd
[AT commands]: https://en.wikipedia.org/wiki/Hayes_command_set
[NMEA protocol]: https://en.wikipedia.org/wiki/NMEA_0183
[QMI protocol]: https://en.wikipedia.org/wiki/Qualcomm_MSM_Interface