Skip to content

Add Pmi632 support to control flash led, get battery and charger status on the fairphone 3#242

Draft
mlainez wants to merge 17 commits into
msm8953-mainline:6.19.5/mainfrom
mlainez:pmi632
Draft

Add Pmi632 support to control flash led, get battery and charger status on the fairphone 3#242
mlainez wants to merge 17 commits into
msm8953-mainline:6.19.5/mainfrom
mlainez:pmi632

Conversation

@mlainez
Copy link
Copy Markdown

@mlainez mlainez commented Mar 13, 2026

Add support for pmi632

@mlainez mlainez marked this pull request as draft March 13, 2026 19:55
@mlainez mlainez changed the title Pmi632 Add Pmi632 support to control flash led, get battery and charger status on the fairphone 3 Mar 13, 2026
@z3ntu
Copy link
Copy Markdown

z3ntu commented Mar 14, 2026

Really nice to se you working on that! :)

One note regarding flash support on PMI632:

On downstream the driver sets POWER_SUPPLY_PROP_FLASH_ACTIVE on the power supply, uses power supply for turning on power, then waits until power is on and then does the normal stuff.

FairphoneMirrors/android_kernel_fairphone_sdm632@1c1e21c

PMI632 flash is driven by the charger in reverse boost (bharger) mode instead of the BoB regulator.

LineageOS/android_kernel_fairphone_sm7225@103b127

On certain PMICs, Flash has a requirement to limit VBUS at 5V
when it is active. This is to prevent the VIN_FLASH from seeing
a high input voltage. Add support for this by forcing VBUS to 5V
when there is a notification from flash driver based on flash_active
power-supply property.

So from my interpretation of those messages, we should really have some interaction between charger and flash driver to not damage the flash LED by supplying it with too high voltage.

Also linking #239 which has similar functionality added (charger & fuel gauge).

@barni2000
Copy link
Copy Markdown
Member

@mlainez Please send upstream what you can, there are smaller trivial changes here what could be accepted there very quick.

mlainez added 14 commits March 17, 2026 08:17
The adc5_chans_pmic[] array is missing an entry for ADC5_BAT_THERM_100K_PU
(channel 0x4a). The zero-initialized entry has info_mask=0 and type=IIO_VOLTAGE,
which means iio_read_channel_processed() returns -EINVAL for this channel since
BIT(IIO_CHAN_INFO_PROCESSED) is not set.

This affects PMICs like the PMI632 that use this channel for battery thermistor
readings via a 100K pull-up. Without this fix, battery temperature cannot be
read through the IIO subsystem.

Add the missing channel definition with SCALE_HW_CALIB_THERM_100K_PULLUP
scaling, consistent with the other thermistor channels in the array.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
The PMI632 flash LED controller reports subtype 0x05, which is not recognized
by the driver. The hardware uses the same 3-channel register layout as
PMI8998 (subtype 0x03) and PM8150 (subtype 0x04), with 2 flash channels and
2 torch channels.

Add FLASH_SUBTYPE_3CH_PMI632_VAL (0x05) and include it in the 3-channel
detection path so the driver probes successfully on PMI632.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Add device tree binding documentation for the QGauge (QG) fuel gauge
block found in the Qualcomm PMI632 PMIC. This hardware provides battery
voltage and current FIFO sampling, open circuit voltage measurement,
and coulomb counting for battery state estimation.

The binding requires a monitored-battery phandle (simple-battery node)
for OCV-to-capacity lookup tables, and optionally accepts an IIO channel
for battery thermistor temperature readings.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Add a driver for the QGauge (QG) fuel gauge block in the Qualcomm
PMI632 PMIC. The QG hardware provides FIFO-based voltage and current
sampling, open circuit voltage (OCV) measurement during sleep states,
and accumulator-based coulomb counting.

This is a minimal mainline implementation that exposes battery state
via the power_supply subsystem:

  - Voltage from last ADC register and FIFO averaging
  - Current from burst average register with hold/release protocol
  - OCV from power-on (S7) and sleep (S3) hardware measurements
  - Temperature via IIO ADC channel (battery thermistor)
  - SOC computed in-kernel using power_supply_batinfo_ocv2cap()
    with OCV-to-capacity tables from the monitored-battery DT node

Three IRQs are handled: fifo-done (voltage update), good-ocv (new OCV
measurement available), and batt-missing (battery presence change).

The downstream Android driver (~14,000 lines) relies on a userspace
daemon via chardev for SOC calculation and uses several Android-only
frameworks (pmic-voter, qpnp-vadc, of_batterydata). This driver
replaces all of that with standard kernel subsystem APIs.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Add the QGauge (QG) fuel gauge device node at register offset 0x4800
in the PMI632 PMIC. The node defines all 7 hardware interrupts
(batt-missing, vbat-low, vbat-empty, fifo-done, good-ocv,
fsm-state-chg, event) and is disabled by default, to be enabled
by board-level DTS files that provide a monitored-battery reference.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Add a simple-battery node with the Fuji 3000mAh OCV-to-capacity table
(55 data points at 25°C) extracted from the downstream Qualcomm battery
profile. Add a battery thermistor ADC channel (ADC5_BAT_THERM_100K_PU)
to the PMI632 ADC node for temperature readings.

Enable the PMI632 QGauge fuel gauge with a reference to the battery
node and the thermistor IIO channel, providing battery voltage, current,
OCV, temperature, and capacity reporting.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Add qcom,pmi632-flash-led to the list of compatible strings for the
Qualcomm SPMI flash LED controller. The PMI632 flash peripheral uses
the same register layout as the 3-channel variant (PMI8998) but has
only 2 flash and 2 torch channels.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Add the flash LED controller node for the PMI632 PMIC at register base
0xd300 under USID 3. The node uses the qcom,pmi632-flash-led compatible
with fallback to the generic qcom,spmi-flash-led driver.

The node is disabled by default; board DTS files should enable it and
add LED child nodes matching the hardware configuration.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Enable the PMI632 flash LED controller on the Fairphone 3 with two
LED channels (sources 1 and 2), each configured for 300mA torch and
1500mA flash with a maximum timeout of 1.28 seconds.

Enable CONFIG_LEDS_QCOM_FLASH as a module in the FP3 config fragment.

Note: the flash peripheral subtype register value is not yet known.
If the mainline driver does not recognize it on first boot, it will
log the value, which can then be added to leds-qcom-flash.c.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Add device tree binding documentation for the Qualcomm PMI632 SMB5
charger peripheral. The PMI632 integrates an SMB5-class switch-mode
battery charger that supports USB charging with automatic input current
limiting (AICL) and Type-C current detection.

The binding requires charger, DCDC, battery interface, USB input, and
miscellaneous register blocks, along with interrupt descriptors for USB
plug events, battery over-voltage, watchdog bark, and ICL changes. USB
input voltage and current are read via SPMI ADC5 IIO channels.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Add a driver for the SMB5-class charger integrated in the Qualcomm
PMI632 PMIC. This is a standalone implementation separate from the
SMB2 charger driver (qcom_pmi8998_charger.c) due to significant
register layout differences in the SMB5 variant:

- Completely reordered charge status enumeration
- ICL_STATUS and POWER_PATH_STATUS relocated from MISC to DCDC block
- Different current scaling (50mA vs 25mA steps)
- Different float voltage encoding (10mV steps from 3600mV)
- BAT_OV status bit repositioned

The driver supports:
- Battery status, voltage, current, and charge type reporting
- USB online detection with automatic input current limit (AICL)
- Configurable charge current, float voltage, and input current limit
- Battery over-voltage protection
- Watchdog bark handling
- USB input voltage/current monitoring via SPMI ADC5 IIO channels

Battery parameters (charge-full-design-microamp-hours, voltage-max,
voltage-min) are read from a monitored-battery phandle using the
standard simple-battery binding. Type-C handling is left to the
separate pmi632_typec driver.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Add the SMB5 charger device node for the PMI632 PMIC. The charger
block resides at register base 0x1000 on SPMI USID 2 and uses four
interrupts: USB plug/unplug detection, battery over-voltage, watchdog
bark, and USB input current limit change.

USB input voltage and current are monitored via the existing SPMI ADC5
channels (ADC5_USB_IN_I and ADC5_USB_IN_V_16).

The node is disabled by default and must be enabled per-board with a
monitored-battery phandle.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
Enable the PMI632 SMB5 charger on the Fairphone 3 by referencing the
board's battery node and adding CONFIG_CHARGER_QCOM_SMB5 to the FP3
config fragment. The charger uses the same simple-battery node already
defined for the fuel gauge, providing charge voltage and current limits.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
The PMI632 QG hardware reports current with positive values for
discharge and negative for charge. The power_supply sysfs ABI
(Documentation/ABI/testing/sysfs-class-power) specifies the opposite:
positive for charging, negative for discharging.

Negate the raw reading to match the ABI, so that current_now is
positive when the battery is charging and status reports Charging.

Signed-off-by: Marc Lainez <marc.lainez@gmail.com>
mlainez added 3 commits March 17, 2026 10:04
The power_supply_config struct replaced the of_node member with fwnode.
Use dev_fwnode() helper to obtain the firmware node instead.
…onfig

The power_supply_config struct replaced the of_node member with fwnode.
Use dev_fwnode() helper to obtain the firmware node instead.
…lude

The of_device_id struct definition lives in linux/mod_devicetable.h which
was not explicitly included, causing an incomplete type error.
@barni2000 barni2000 changed the base branch from 6.12/main to 6.19.5/main March 17, 2026 13:31
*
* This driver is for the SMB5 switch-mode battery charger found in the
* Qualcomm PMI632 PMIC. It is modeled on the SMB2 driver
* (qcom_pmi8998_charger.c by Caleb Connolly) but adapted for the SMB5
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casey Connolly

@valpackett
Copy link
Copy Markdown

valpackett commented Mar 21, 2026

There's existing work for both SMB5 and QGauge that can be found in e.g. https://github.com/sm7150-mainline/linux/commits/v7.0 which at least for SMB5 is clearly the way to go: it's adding support to the qcom_smbx driver that already existed for SMB2, instead of creating a new driver that's arbitrarily called pmi632_something (when the same block is reused on a bunch of other PMICs).

(upd: qgauge is better here, but for SMB5 better to pick that up, to have it go inside of the SMB2 one)

u16 raw;
int ret, i;

mutex_lock(&qg->lock);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use guard(mutex)(&qg->lock); instead of lock-unlock

return -ENODATA;
ret = qg_read_temperature(qg, &val->intval);
return ret;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing:

  • POWER_SUPPLY_PROP_TECHNOLOGY (return POWER_SUPPLY_TECHNOLOGY_LION at least)
  • POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, and POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN (just from the batt_info)
  • POWER_SUPPLY_PROP_VOLTAGE_AVG (read the avg register 0x80 instead of the last reg 0xc0)
  • POWER_SUPPLY_PROP_CURRENT_AVG (similarly, 0x82 is avg current according to the other driver)
  • POWER_SUPPLY_PROP_CHARGE_FULL (read from SDAM NVMEM.. which also has something something OCV related)

if (ret)
temp_decidegc = 250; /* default 25.0 degC */

*capacity = power_supply_batinfo_ocv2cap(qg->batt_info,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice!!! Overall the qgauge is better here, just call it qcom_qg instead of qcom_pmi632_qg, and add a qcom,pm6150-qg compatible as well

@mlainez
Copy link
Copy Markdown
Author

mlainez commented Mar 21, 2026

@valpackett thanks for reviewing. Much appreciated. To be honest, I didn't even know there was some existing work in another fork, I'm not familiar at all with the whole qcom forks ecosystem so if there is any documentation on where to look, let me know. I'm just trying to make most things work on the fairphone3 and this part felt like something that could be useful for others.

I'll review this whole PR based on your feedback and what's existing in sm7150.

@valpackett
Copy link
Copy Markdown

I'm not familiar at all with the whole qcom forks ecosystem so if there is any documentation on where to look, let me know

Yeah, it's not a super coherent ecosystem, but you can find the forks linked on the postmarketOS wiki and packaged in pmaports, and the only way to know all the stuff is to just be very curious/obsessive and check up on the repos and be in the chatrooms for multiple SoCs and monitor patchwork as well etc. :)

Thanks for discovering the ocv2cap stuff, that really improves things.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep the original formatting, your changes are not visible like this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should send this upstream.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants