There's a Linux driver that controls the MCP23017 IO expander, ZeroPhone uses such an expander for system management functions. We have a problem with it - among all things, the MCP23017 controls a ZeroPhone power switch (active low), which is able to power off the Raspberry Pi Zero. In hardware, the switch is set to "default off", meaning that, in order to power the ZeroPhone up, you need to either plug the charger in or hold a button on the back.
Right now, control of this switch is done in userspace from a systemd script, and only on bootup - it remains on after shutdown, so after ZeroPhone shuts down, there's no way to turn it back on without replugging the batteries (whereas, if the switch were to turn off automatically after shutdown, it'd be enough to hold the power button to power the phone back on).
Additionally, starting from Delta, there's a feature that should technically allow to sense the state of power button while still using a single GPIO. To do that, the GPIO has to be turned off for a short period and set as input with a pullup, so that the actual state of the button can be read - and once it's read, set it to output low again. However, this can't be done from userspace, as the period has to be rather short - if exceeded, the phone will turn off or glitch due to a brownout on the Pi Zero power input, so the period has to be of a reliable length, too (something harder to achieve from userspace). This hardware feature wasn't yet tested, either, so it might happen that, say, capacitor value is insufficient.
For a start, the power switch management needs to be done in a driver, so that:
the power switch is turned on as early in the boot process as possible (so that users don't need to hold the button for too long, current script can take from 10 to 20 seconds from boot start to execution)
the switch can be turned off at shutdown, by registering a handler like pm_power_off (but care needs to be taken so that it doesn't trigger on reboot).
the driver can sense the button state, as described above.
non-root users can't shut off the ZeroPhone if they have GPIO access
Here's a schematic of the MCP23017 pinout (on Delta boards):
Here's a schematic for the power switch circuit (including the circuitry allowing to sense the power switch state):
ZeroPhone uses the ID EEPROM mechanism, which should allow us to load drivers automatically depending on the values flashed into the EEPROM. So, we will likely make different drivers (one per hardware revision) and then flash the driver&overlay names in the EEPROM once the hardware is done.
TODO:
[ ] Isolate the power switch GPIO, make it inaccessible from userspace
[ ] Add a hook that will switch the GPIO on (make it low) as soon as the driver is loaded
[ ] Add a hook that will switch the GPIO off (make it high) after shutdown
[ ] Look into button state sensing (I will test the hardware the next opportunity that I get)
[ ] Package the resulting driver using DKMS and distribute it in a GH repository of ours
Features that could be added to the driver, but might not have to be:
[ ] For features that might change GPIOs from version (mainly so that routing is easier), it might make sense to add name aliases in sysfs - so that applications can rely on a path like "/sys/class/leds/green_led" instead of a hardware-dependent version number. Alternatively, it could be done with additional device tree overlay descriptions (like the gpio-led driver&overlay, for example) to be loaded into the EEPROM.
[ ] Make the GPIO accessible from userspace using a root-owned file, for security purposes ("wipe RAM, SD and hard shut down" scenario)
There's a Linux driver that controls the MCP23017 IO expander, ZeroPhone uses such an expander for system management functions. We have a problem with it - among all things, the MCP23017 controls a ZeroPhone power switch (active low), which is able to power off the Raspberry Pi Zero. In hardware, the switch is set to "default off", meaning that, in order to power the ZeroPhone up, you need to either plug the charger in or hold a button on the back.
Right now, control of this switch is done in userspace from a systemd script, and only on bootup - it remains on after shutdown, so after ZeroPhone shuts down, there's no way to turn it back on without replugging the batteries (whereas, if the switch were to turn off automatically after shutdown, it'd be enough to hold the power button to power the phone back on).
Additionally, starting from Delta, there's a feature that should technically allow to sense the state of power button while still using a single GPIO. To do that, the GPIO has to be turned off for a short period and set as input with a pullup, so that the actual state of the button can be read - and once it's read, set it to output low again. However, this can't be done from userspace, as the period has to be rather short - if exceeded, the phone will turn off or glitch due to a brownout on the Pi Zero power input, so the period has to be of a reliable length, too (something harder to achieve from userspace). This hardware feature wasn't yet tested, either, so it might happen that, say, capacitor value is insufficient.
For a start, the power switch management needs to be done in a driver, so that:
Here's a schematic of the MCP23017 pinout (on Delta boards):
Here's a schematic for the power switch circuit (including the circuitry allowing to sense the power switch state):
ZeroPhone uses the ID EEPROM mechanism, which should allow us to load drivers automatically depending on the values flashed into the EEPROM. So, we will likely make different drivers (one per hardware revision) and then flash the driver&overlay names in the EEPROM once the hardware is done.
TODO:
Features that could be added to the driver, but might not have to be:
Links: