Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: adc: Add driver for Marvell 88PM886 PMIC ADC

Marvell's 88PM886 PMIC has a so-called General Purpose ADC used for
monitoring various system voltages and temperatures. Add the relevant
register definitions to the MFD header and a driver for the ADC.

Acked-by: Karel Balej <balejk@matfyz.cz> # for the PMIC
Signed-off-by: Duje Mihanović <duje@dujemihanovic.xyz>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Duje Mihanović and committed by
Jonathan Cameron
3422b4bc 0f06e287

+470
+5
MAINTAINERS
··· 14714 14714 F: drivers/rtc/rtc-88pm886.c 14715 14715 F: include/linux/mfd/88pm886.h 14716 14716 14717 + MARVELL 88PM886 PMIC GPADC DRIVER 14718 + M: Duje Mihanović <duje@dujemihanovic.xyz> 14719 + S: Maintained 14720 + F: drivers/iio/adc/88pm886-gpadc.c 14721 + 14717 14722 MARVELL ARMADA 3700 PHY DRIVERS 14718 14723 M: Miquel Raynal <miquel.raynal@bootlin.com> 14719 14724 S: Maintained
+393
drivers/iio/adc/88pm886-gpadc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright 2025, Duje Mihanović <duje@dujemihanovic.xyz> 4 + */ 5 + 6 + #include <linux/bits.h> 7 + #include <linux/bug.h> 8 + #include <linux/delay.h> 9 + #include <linux/device.h> 10 + #include <linux/err.h> 11 + #include <linux/i2c.h> 12 + #include <linux/math.h> 13 + #include <linux/mod_devicetable.h> 14 + #include <linux/module.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/pm_runtime.h> 17 + #include <linux/regmap.h> 18 + #include <linux/types.h> 19 + #include <linux/units.h> 20 + 21 + #include <asm/byteorder.h> 22 + 23 + #include <linux/iio/iio.h> 24 + #include <linux/iio/types.h> 25 + 26 + #include <linux/mfd/88pm886.h> 27 + 28 + struct pm886_gpadc { 29 + struct regmap *map; 30 + }; 31 + 32 + enum pm886_gpadc_channel { 33 + VSC_CHAN, 34 + VCHG_PWR_CHAN, 35 + VCF_OUT_CHAN, 36 + VBAT_CHAN, 37 + VBAT_SLP_CHAN, 38 + VBUS_CHAN, 39 + 40 + GPADC0_CHAN, 41 + GPADC1_CHAN, 42 + GPADC2_CHAN, 43 + GPADC3_CHAN, 44 + 45 + GND_DET1_CHAN, 46 + GND_DET2_CHAN, 47 + MIC_DET_CHAN, 48 + 49 + TINT_CHAN, 50 + }; 51 + 52 + static const int pm886_gpadc_regs[] = { 53 + [VSC_CHAN] = PM886_REG_GPADC_VSC, 54 + [VCHG_PWR_CHAN] = PM886_REG_GPADC_VCHG_PWR, 55 + [VCF_OUT_CHAN] = PM886_REG_GPADC_VCF_OUT, 56 + [VBAT_CHAN] = PM886_REG_GPADC_VBAT, 57 + [VBAT_SLP_CHAN] = PM886_REG_GPADC_VBAT_SLP, 58 + [VBUS_CHAN] = PM886_REG_GPADC_VBUS, 59 + 60 + [GPADC0_CHAN] = PM886_REG_GPADC_GPADC0, 61 + [GPADC1_CHAN] = PM886_REG_GPADC_GPADC1, 62 + [GPADC2_CHAN] = PM886_REG_GPADC_GPADC2, 63 + [GPADC3_CHAN] = PM886_REG_GPADC_GPADC3, 64 + 65 + [GND_DET1_CHAN] = PM886_REG_GPADC_GND_DET1, 66 + [GND_DET2_CHAN] = PM886_REG_GPADC_GND_DET2, 67 + [MIC_DET_CHAN] = PM886_REG_GPADC_MIC_DET, 68 + 69 + [TINT_CHAN] = PM886_REG_GPADC_TINT, 70 + }; 71 + 72 + #define ADC_CHANNEL_VOLTAGE(index, lsb, name) \ 73 + { \ 74 + .type = IIO_VOLTAGE, \ 75 + .indexed = 1, \ 76 + .channel = index, \ 77 + .address = lsb, \ 78 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 79 + BIT(IIO_CHAN_INFO_SCALE), \ 80 + .datasheet_name = name, \ 81 + } 82 + 83 + #define ADC_CHANNEL_RESISTANCE(index, lsb, name) \ 84 + { \ 85 + .type = IIO_RESISTANCE, \ 86 + .indexed = 1, \ 87 + .channel = index, \ 88 + .address = lsb, \ 89 + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ 90 + .datasheet_name = name, \ 91 + } 92 + 93 + #define ADC_CHANNEL_TEMPERATURE(index, lsb, name) \ 94 + { \ 95 + .type = IIO_TEMP, \ 96 + .indexed = 1, \ 97 + .channel = index, \ 98 + .address = lsb, \ 99 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 100 + BIT(IIO_CHAN_INFO_SCALE) | \ 101 + BIT(IIO_CHAN_INFO_OFFSET), \ 102 + .datasheet_name = name, \ 103 + } 104 + 105 + static const struct iio_chan_spec pm886_gpadc_channels[] = { 106 + ADC_CHANNEL_VOLTAGE(VSC_CHAN, 1367, "vsc"), 107 + ADC_CHANNEL_VOLTAGE(VCHG_PWR_CHAN, 1709, "vchg_pwr"), 108 + ADC_CHANNEL_VOLTAGE(VCF_OUT_CHAN, 1367, "vcf_out"), 109 + ADC_CHANNEL_VOLTAGE(VBAT_CHAN, 1367, "vbat"), 110 + ADC_CHANNEL_VOLTAGE(VBAT_SLP_CHAN, 1367, "vbat_slp"), 111 + ADC_CHANNEL_VOLTAGE(VBUS_CHAN, 1709, "vbus"), 112 + 113 + ADC_CHANNEL_RESISTANCE(GPADC0_CHAN, 342, "gpadc0"), 114 + ADC_CHANNEL_RESISTANCE(GPADC1_CHAN, 342, "gpadc1"), 115 + ADC_CHANNEL_RESISTANCE(GPADC2_CHAN, 342, "gpadc2"), 116 + ADC_CHANNEL_RESISTANCE(GPADC3_CHAN, 342, "gpadc3"), 117 + 118 + ADC_CHANNEL_VOLTAGE(GND_DET1_CHAN, 342, "gnddet1"), 119 + ADC_CHANNEL_VOLTAGE(GND_DET2_CHAN, 342, "gnddet2"), 120 + ADC_CHANNEL_VOLTAGE(MIC_DET_CHAN, 1367, "mic_det"), 121 + 122 + ADC_CHANNEL_TEMPERATURE(TINT_CHAN, 104, "tint"), 123 + }; 124 + 125 + static const struct regmap_config pm886_gpadc_regmap_config = { 126 + .reg_bits = 8, 127 + .val_bits = 8, 128 + .max_register = PM886_GPADC_MAX_REGISTER, 129 + }; 130 + 131 + static int gpadc_get_raw(struct iio_dev *iio, enum pm886_gpadc_channel chan) 132 + { 133 + struct pm886_gpadc *gpadc = iio_priv(iio); 134 + __be16 buf; 135 + int ret; 136 + 137 + ret = regmap_bulk_read(gpadc->map, pm886_gpadc_regs[chan], &buf, sizeof(buf)); 138 + if (ret) 139 + return ret; 140 + 141 + return be16_to_cpu(buf) >> 4; 142 + } 143 + 144 + static int 145 + gpadc_set_bias(struct pm886_gpadc *gpadc, enum pm886_gpadc_channel chan, bool on) 146 + { 147 + unsigned int gpadc_num = chan - GPADC0_CHAN; 148 + unsigned int bits = BIT(gpadc_num + 4) | BIT(gpadc_num); 149 + 150 + return regmap_assign_bits(gpadc->map, PM886_REG_GPADC_CONFIG(0x14), bits, on); 151 + } 152 + 153 + static int 154 + gpadc_find_bias_current(struct iio_dev *iio, struct iio_chan_spec const *chan, 155 + unsigned int *raw_uV, unsigned int *raw_uA) 156 + { 157 + struct pm886_gpadc *gpadc = iio_priv(iio); 158 + unsigned int gpadc_num = chan->channel - GPADC0_CHAN; 159 + unsigned int reg = PM886_REG_GPADC_CONFIG(0xb + gpadc_num); 160 + unsigned long lsb = chan->address; 161 + int ret; 162 + 163 + for (unsigned int i = 0; i < PM886_GPADC_BIAS_LEVELS; i++) { 164 + ret = regmap_update_bits(gpadc->map, reg, GENMASK(3, 0), i); 165 + if (ret) 166 + return ret; 167 + 168 + /* Wait for the new bias level to apply. */ 169 + fsleep(5 * USEC_PER_MSEC); 170 + 171 + *raw_uA = PM886_GPADC_INDEX_TO_BIAS_uA(i); 172 + *raw_uV = gpadc_get_raw(iio, chan->channel) * lsb; 173 + 174 + /* 175 + * Vendor kernel errors out above 1.25 V, but testing shows 176 + * that the resistance of the battery detection channel (GPADC2 177 + * on coreprimevelte) reaches about 1.4 MΩ when the battery is 178 + * removed, which can't be measured with such a low upper 179 + * limit. Therefore, to be able to detect the battery without 180 + * ugly externs as used in the vendor fuel gauge driver, 181 + * increase this limit a bit. 182 + */ 183 + if (WARN_ON(*raw_uV > 1500 * (MICRO / MILLI))) 184 + return -EIO; 185 + 186 + /* 187 + * Vendor kernel errors out under 300 mV, but for the same 188 + * reason as above (except the channel hovers around 3.5 kΩ 189 + * with battery present) reduce this limit. 190 + */ 191 + if (*raw_uV < 200 * (MICRO / MILLI)) { 192 + dev_dbg(&iio->dev, "bad bias for chan %d: %d uA @ %d uV\n", 193 + chan->channel, *raw_uA, *raw_uV); 194 + continue; 195 + } 196 + 197 + dev_dbg(&iio->dev, "good bias for chan %d: %d uA @ %d uV\n", 198 + chan->channel, *raw_uA, *raw_uV); 199 + return 0; 200 + } 201 + 202 + dev_err(&iio->dev, "failed to find good bias for chan %d\n", chan->channel); 203 + return -EINVAL; 204 + } 205 + 206 + static int 207 + gpadc_get_resistance_ohm(struct iio_dev *iio, struct iio_chan_spec const *chan) 208 + { 209 + struct pm886_gpadc *gpadc = iio_priv(iio); 210 + unsigned int raw_uV, raw_uA; 211 + int ret; 212 + 213 + ret = gpadc_set_bias(gpadc, chan->channel, true); 214 + if (ret) 215 + goto out; 216 + 217 + ret = gpadc_find_bias_current(iio, chan, &raw_uV, &raw_uA); 218 + if (ret) 219 + goto out; 220 + 221 + ret = DIV_ROUND_CLOSEST(raw_uV, raw_uA); 222 + out: 223 + gpadc_set_bias(gpadc, chan->channel, false); 224 + return ret; 225 + } 226 + 227 + static int 228 + __pm886_gpadc_read_raw(struct iio_dev *iio, struct iio_chan_spec const *chan, 229 + int *val, int *val2, long mask) 230 + { 231 + unsigned long lsb = chan->address; 232 + 233 + switch (mask) { 234 + case IIO_CHAN_INFO_RAW: 235 + *val = gpadc_get_raw(iio, chan->channel); 236 + if (*val < 0) 237 + return *val; 238 + 239 + return IIO_VAL_INT; 240 + case IIO_CHAN_INFO_SCALE: 241 + *val = lsb; 242 + 243 + if (chan->type == IIO_VOLTAGE) { 244 + *val2 = MILLI; 245 + return IIO_VAL_FRACTIONAL; 246 + } else { 247 + return IIO_VAL_INT; 248 + } 249 + case IIO_CHAN_INFO_OFFSET: 250 + /* Raw value is 104 millikelvin/LSB, convert it to 104 millicelsius/LSB */ 251 + *val = ABSOLUTE_ZERO_MILLICELSIUS; 252 + *val2 = lsb; 253 + return IIO_VAL_FRACTIONAL; 254 + case IIO_CHAN_INFO_PROCESSED: 255 + *val = gpadc_get_resistance_ohm(iio, chan); 256 + if (*val < 0) 257 + return *val; 258 + 259 + return IIO_VAL_INT; 260 + default: 261 + return -EINVAL; 262 + } 263 + } 264 + 265 + static int pm886_gpadc_read_raw(struct iio_dev *iio, struct iio_chan_spec const *chan, 266 + int *val, int *val2, long mask) 267 + { 268 + struct device *dev = iio->dev.parent; 269 + int ret; 270 + 271 + ret = pm_runtime_resume_and_get(dev); 272 + if (ret) 273 + return ret; 274 + 275 + ret = __pm886_gpadc_read_raw(iio, chan, val, val2, mask); 276 + 277 + pm_runtime_put_autosuspend(dev); 278 + return ret; 279 + } 280 + 281 + static int pm886_gpadc_hw_enable(struct regmap *map) 282 + { 283 + const u8 config[] = { 284 + PM886_GPADC_CONFIG1_EN_ALL, 285 + PM886_GPADC_CONFIG2_EN_ALL, 286 + PM886_GPADC_GND_DET2_EN, 287 + }; 288 + int ret; 289 + 290 + /* Enable the ADC block. */ 291 + ret = regmap_set_bits(map, PM886_REG_GPADC_CONFIG(0x6), BIT(0)); 292 + if (ret) 293 + return ret; 294 + 295 + /* Enable all channels. */ 296 + return regmap_bulk_write(map, PM886_REG_GPADC_CONFIG(0x1), config, ARRAY_SIZE(config)); 297 + } 298 + 299 + static int pm886_gpadc_hw_disable(struct regmap *map) 300 + { 301 + return regmap_clear_bits(map, PM886_REG_GPADC_CONFIG(0x6), BIT(0)); 302 + } 303 + 304 + static const struct iio_info pm886_gpadc_iio_info = { 305 + .read_raw = pm886_gpadc_read_raw, 306 + }; 307 + 308 + static int pm886_gpadc_probe(struct platform_device *pdev) 309 + { 310 + struct device *dev = &pdev->dev; 311 + struct pm886_chip *chip = dev_get_drvdata(dev->parent); 312 + struct i2c_client *client = chip->client; 313 + struct pm886_gpadc *gpadc; 314 + struct i2c_client *page; 315 + struct iio_dev *iio; 316 + int ret; 317 + 318 + iio = devm_iio_device_alloc(dev, sizeof(*gpadc)); 319 + if (!iio) 320 + return -ENOMEM; 321 + 322 + gpadc = iio_priv(iio); 323 + dev_set_drvdata(dev, iio); 324 + 325 + page = devm_i2c_new_dummy_device(dev, client->adapter, 326 + client->addr + PM886_PAGE_OFFSET_GPADC); 327 + if (IS_ERR(page)) 328 + return dev_err_probe(dev, PTR_ERR(page), "Failed to initialize GPADC page\n"); 329 + 330 + gpadc->map = devm_regmap_init_i2c(page, &pm886_gpadc_regmap_config); 331 + if (IS_ERR(gpadc->map)) 332 + return dev_err_probe(dev, PTR_ERR(gpadc->map), 333 + "Failed to initialize GPADC regmap\n"); 334 + 335 + iio->name = "88pm886-gpadc"; 336 + iio->modes = INDIO_DIRECT_MODE; 337 + iio->info = &pm886_gpadc_iio_info; 338 + iio->channels = pm886_gpadc_channels; 339 + iio->num_channels = ARRAY_SIZE(pm886_gpadc_channels); 340 + device_set_node(&iio->dev, dev_fwnode(dev->parent)); 341 + 342 + ret = devm_pm_runtime_enable(dev); 343 + if (ret) 344 + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); 345 + 346 + pm_runtime_set_autosuspend_delay(dev, 50); 347 + pm_runtime_use_autosuspend(dev); 348 + ret = devm_iio_device_register(dev, iio); 349 + if (ret) 350 + return dev_err_probe(dev, ret, "Failed to register ADC\n"); 351 + 352 + return 0; 353 + } 354 + 355 + static int pm886_gpadc_runtime_resume(struct device *dev) 356 + { 357 + struct iio_dev *iio = dev_get_drvdata(dev); 358 + struct pm886_gpadc *gpadc = iio_priv(iio); 359 + 360 + return pm886_gpadc_hw_enable(gpadc->map); 361 + } 362 + 363 + static int pm886_gpadc_runtime_suspend(struct device *dev) 364 + { 365 + struct iio_dev *iio = dev_get_drvdata(dev); 366 + struct pm886_gpadc *gpadc = iio_priv(iio); 367 + 368 + return pm886_gpadc_hw_disable(gpadc->map); 369 + } 370 + 371 + static DEFINE_RUNTIME_DEV_PM_OPS(pm886_gpadc_pm_ops, 372 + pm886_gpadc_runtime_suspend, 373 + pm886_gpadc_runtime_resume, NULL); 374 + 375 + static const struct platform_device_id pm886_gpadc_id[] = { 376 + { "88pm886-gpadc" }, 377 + { } 378 + }; 379 + MODULE_DEVICE_TABLE(platform, pm886_gpadc_id); 380 + 381 + static struct platform_driver pm886_gpadc_driver = { 382 + .driver = { 383 + .name = "88pm886-gpadc", 384 + .pm = pm_ptr(&pm886_gpadc_pm_ops), 385 + }, 386 + .probe = pm886_gpadc_probe, 387 + .id_table = pm886_gpadc_id, 388 + }; 389 + module_platform_driver(pm886_gpadc_driver); 390 + 391 + MODULE_AUTHOR("Duje Mihanović <duje@dujemihanovic.xyz>"); 392 + MODULE_DESCRIPTION("Marvell 88PM886 GPADC driver"); 393 + MODULE_LICENSE("GPL");
+13
drivers/iio/adc/Kconfig
··· 9 9 config IIO_ADC_HELPER 10 10 tristate 11 11 12 + config 88PM886_GPADC 13 + tristate "Marvell 88PM886 GPADC driver" 14 + depends on MFD_88PM886_PMIC 15 + default MFD_88PM886_PMIC 16 + help 17 + Say Y here to enable support for the GPADC (General Purpose ADC) 18 + found on the Marvell 88PM886 PMIC. The GPADC measures various 19 + internal voltages and temperatures, including (but not limited to) 20 + system, battery and USB Vbus. 21 + 22 + To compile this driver as a module, choose M here: the module will be 23 + called 88pm886-gpadc. 24 + 12 25 config AB8500_GPADC 13 26 bool "ST-Ericsson AB8500 GPADC driver" 14 27 depends on AB8500_CORE && REGULATOR_AB8500
+1
drivers/iio/adc/Makefile
··· 6 6 obj-$(CONFIG_IIO_ADC_HELPER) += industrialio-adc.o 7 7 8 8 # When adding new entries keep the list in alphabetical order 9 + obj-$(CONFIG_88PM886_GPADC) += 88pm886-gpadc.o 9 10 obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o 10 11 obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o 11 12 obj-$(CONFIG_AD4000) += ad4000.o
+58
include/linux/mfd/88pm886.h
··· 10 10 #define PM886_IRQ_ONKEY 0 11 11 12 12 #define PM886_PAGE_OFFSET_REGULATORS 1 13 + #define PM886_PAGE_OFFSET_GPADC 2 13 14 14 15 #define PM886_REG_ID 0x00 15 16 ··· 70 69 71 70 #define PM886_LDO_VSEL_MASK 0x0f 72 71 #define PM886_BUCK_VSEL_MASK 0x7f 72 + 73 + /* GPADC enable/disable registers */ 74 + #define PM886_REG_GPADC_CONFIG(n) (n) 75 + 76 + #define PM886_GPADC_VSC_EN BIT(0) 77 + #define PM886_GPADC_VBAT_EN BIT(1) 78 + #define PM886_GPADC_GNDDET1_EN BIT(3) 79 + #define PM886_GPADC_VBUS_EN BIT(4) 80 + #define PM886_GPADC_VCHG_PWR_EN BIT(5) 81 + #define PM886_GPADC_VCF_OUT_EN BIT(6) 82 + #define PM886_GPADC_CONFIG1_EN_ALL \ 83 + (PM886_GPADC_VSC_EN | \ 84 + PM886_GPADC_VBAT_EN | \ 85 + PM886_GPADC_GNDDET1_EN | \ 86 + PM886_GPADC_VBUS_EN | \ 87 + PM886_GPADC_VCHG_PWR_EN | \ 88 + PM886_GPADC_VCF_OUT_EN) 89 + 90 + #define PM886_GPADC_TINT_EN BIT(0) 91 + #define PM886_GPADC_PMODE_EN BIT(1) 92 + #define PM886_GPADC_GPADC0_EN BIT(2) 93 + #define PM886_GPADC_GPADC1_EN BIT(3) 94 + #define PM886_GPADC_GPADC2_EN BIT(4) 95 + #define PM886_GPADC_GPADC3_EN BIT(5) 96 + #define PM886_GPADC_MIC_DET_EN BIT(6) 97 + #define PM886_GPADC_CONFIG2_EN_ALL \ 98 + (PM886_GPADC_TINT_EN | \ 99 + PM886_GPADC_GPADC0_EN | \ 100 + PM886_GPADC_GPADC1_EN | \ 101 + PM886_GPADC_GPADC2_EN | \ 102 + PM886_GPADC_GPADC3_EN | \ 103 + PM886_GPADC_MIC_DET_EN) 104 + 105 + /* No CONFIG3_EN_ALL because this is the only bit there. */ 106 + #define PM886_GPADC_GND_DET2_EN BIT(0) 107 + 108 + /* GPADC channel registers */ 109 + #define PM886_REG_GPADC_VSC 0x40 110 + #define PM886_REG_GPADC_VCHG_PWR 0x4c 111 + #define PM886_REG_GPADC_VCF_OUT 0x4e 112 + #define PM886_REG_GPADC_TINT 0x50 113 + #define PM886_REG_GPADC_GPADC0 0x54 114 + #define PM886_REG_GPADC_GPADC1 0x56 115 + #define PM886_REG_GPADC_GPADC2 0x58 116 + #define PM886_REG_GPADC_VBAT 0xa0 117 + #define PM886_REG_GPADC_GND_DET1 0xa4 118 + #define PM886_REG_GPADC_GND_DET2 0xa6 119 + #define PM886_REG_GPADC_VBUS 0xa8 120 + #define PM886_REG_GPADC_GPADC3 0xaa 121 + #define PM886_REG_GPADC_MIC_DET 0xac 122 + #define PM886_REG_GPADC_VBAT_SLP 0xb0 123 + 124 + /* VBAT_SLP is the last register and is 2 bytes wide like other channels. */ 125 + #define PM886_GPADC_MAX_REGISTER (PM886_REG_GPADC_VBAT_SLP + 1) 126 + 127 + #define PM886_GPADC_BIAS_LEVELS 16 128 + #define PM886_GPADC_INDEX_TO_BIAS_uA(i) (1 + (i) * 5) 73 129 74 130 struct pm886_chip { 75 131 struct i2c_client *client;