// SPDX-License-Identifier: GPL-2.0+
/*
* IIO driver for PAC1921 High-Side Power/Current Monitor
*
* Copyright (C) 2024 Matteo Martelli <matteomartelli3@gmail.com>
*/
#include <linux/unaligned.h>
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/regmap.h>
#include <linux/units.h>
/* pac1921 registers */
#define PAC1921_REG_GAIN_CFG 0x00
#define PAC1921_REG_INT_CFG 0x01
#define PAC1921_REG_CONTROL 0x02
#define PAC1921_REG_VBUS 0x10
#define PAC1921_REG_VSENSE 0x12
#define PAC1921_REG_OVERFLOW_STS 0x1C
#define PAC1921_REG_VPOWER 0x1D
/* pac1921 gain configuration bits */
#define PAC1921_GAIN_DI_GAIN_MASK GENMASK(5, 3)
#define PAC1921_GAIN_DV_GAIN_MASK GENMASK(2, 0)
/* pac1921 integration configuration bits */
#define PAC1921_INT_CFG_SMPL_MASK GENMASK(7, 4)
#define PAC1921_INT_CFG_VSFEN BIT(3)
#define PAC1921_INT_CFG_VBFEN BIT(2)
#define PAC1921_INT_CFG_RIOV BIT(1)
#define PAC1921_INT_CFG_INTEN BIT(0)
/* pac1921 control bits */
#define PAC1921_CONTROL_MXSL_MASK GENMASK(7, 6)
enum pac1921_mxsl {
PAC1921_MXSL_VPOWER_PIN = 0,
PAC1921_MXSL_VSENSE_FREE_RUN = 1,
PAC1921_MXSL_VBUS_FREE_RUN = 2,
PAC1921_MXSL_VPOWER_FREE_RUN = 3,
};
#define PAC1921_CONTROL_SLEEP BIT(2)
/* pac1921 result registers mask and resolution */
#define PAC1921_RES_MASK GENMASK(15, 6)
#define PAC1921_RES_RESOLUTION 1023
/* pac1921 overflow status bits */
#define PAC1921_OVERFLOW_VSOV BIT(2)
#define PAC1921_OVERFLOW_VBOV BIT(1)
#define PAC1921_OVERFLOW_VPOV BIT(0)
/* pac1921 constants */
#define PAC1921_MAX_VSENSE_MV 100
#define PAC1921_MAX_VBUS_V 32
/* Time to first communication after power up (tINT_T) */
#define PAC1921_POWERUP_TIME_MS 20
/* Time from Sleep State to Start of Integration Period (tSLEEP_TO_INT) */
#define PAC1921_SLEEP_TO_INT_TIME_US 86
/* pac1921 defaults */
#define PAC1921_DEFAULT_DV_GAIN 0 /* 2^(value): 1x gain (HW default) */
#define PAC1921_DEFAULT_DI_GAIN 0 /* 2^(value): 1x gain (HW default) */
#define PAC1921_DEFAULT_NUM_SAMPLES 0 /* 2^(value): 1 sample (HW default) */
/*
* Pre-computed scale factors for BUS voltage
* format: IIO_VAL_INT_PLUS_NANO
* unit: mV
*
* Vbus scale (mV) = max_vbus (mV) / dv_gain / resolution
*/
static const int pac1921_vbus_scales[][2] = {
{ 31, 280547409 }, /* dv_gain x1 */
{ 15, 640273704 }, /* dv_gain x2 */
{ 7, 820136852 }, /* dv_gain x4 */
{ 3, 910068426 }, /* dv_gain x8 */
{ 1, 955034213 }, /* dv_gain x16 */
{ 0, 977517106 }, /* dv_gain x32 */
};
/*
* Pre-computed scales for SENSE voltage
* format: IIO_VAL_INT_PLUS_NANO
* unit: mV
*
* Vsense scale (mV) = max_vsense (mV) / di_gain / resolution
*/
static const int pac1921_vsense_scales[][2] = {
{ 0, 97751710 }, /* di_gain x1 */
{ 0, 48875855 }, /* di_gain x2 */
{ 0, 24437927 }, /* di_gain x4 */
{ 0, 12218963 }, /* di_gain x8 */
{ 0, 6109481 }, /* di_gain x16 */
{ 0, 3054740 }, /* di_gain x32 */
{ 0, 1527370 }, /* di_gain x64 */
{ 0, 763685 }, /* di_gain x128 */
};
/*
* Numbers of samples used to integrate measurements at the end of an
* integration period.
*
* Changing the number of samples affects the integration period: higher the
* number of samples, longer the integration period.
*
* These correspond to the oversampling ratios available exposed to userspace.
*/
static const int pac1921_int_num_samples[] = {
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048
};
/*
* The integration period depends on the configuration of number of integration
* samples, measurement resolution and post filters. The following array
* contains integration periods, in microsecs unit, based on table 4-5 from
* datasheet considering power integration mode, 14-Bit resolution and post
* filters on. Each index corresponds to a specific number of samples from 1
* to 2048.
*/
static const unsigned int pac1921_int_periods_usecs[] = {
2720, /* 1 sample */
4050, /* 2 samples */
6790, /* 4 samples */
12200, /* 8 samples */
23000, /* 16 samples */
46000, /* 32 samples */
92000, /* 64 samples */
184000, /* 128 samples */
368000, /* 256 samples */
736000, /* 512 samples */
1471000, /* 1024 samples */
2941000 /* 2048 samples */
};
/* pac1921 regmap configuration */
static const struct regmap_range pac1921_regmap_wr_ranges[] = {
regmap_reg_range(PAC1921_REG_GAIN_CFG, PAC1921_REG_CONTROL),
};
static const struct regmap_access_table pac1921_regmap_wr_table = {
.yes_ranges = pac1921_regmap_wr_ranges,
.n_yes_ranges = ARRAY_SIZE(pac1921_regmap_wr_ranges),
};
static const struct regmap_range pac1921_regmap_rd_ranges[] = {
regmap_reg_range(PAC1921_REG_GAIN_CFG, PAC1921_REG_CONTROL),
regmap_reg_range(PAC1921_REG_VBUS, PAC1921_REG_VPOWER + 1),