linux/drivers/iio/adc/pac1921.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * IIO driver for PAC1921 High-Side Power/Current Monitor
 *
 * Copyright (C) 2024 Matteo Martelli <[email protected]>
 */

#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
#define PAC1921_REG_INT_CFG
#define PAC1921_REG_CONTROL
#define PAC1921_REG_VBUS
#define PAC1921_REG_VSENSE
#define PAC1921_REG_OVERFLOW_STS
#define PAC1921_REG_VPOWER

/* pac1921 gain configuration bits */
#define PAC1921_GAIN_DI_GAIN_MASK
#define PAC1921_GAIN_DV_GAIN_MASK

/* pac1921 integration configuration bits */
#define PAC1921_INT_CFG_SMPL_MASK
#define PAC1921_INT_CFG_VSFEN
#define PAC1921_INT_CFG_VBFEN
#define PAC1921_INT_CFG_RIOV
#define PAC1921_INT_CFG_INTEN

/* pac1921 control bits */
#define PAC1921_CONTROL_MXSL_MASK
enum pac1921_mxsl {};
#define PAC1921_CONTROL_SLEEP

/* pac1921 result registers mask and resolution */
#define PAC1921_RES_MASK
#define PAC1921_RES_RESOLUTION

/* pac1921 overflow status bits */
#define PAC1921_OVERFLOW_VSOV
#define PAC1921_OVERFLOW_VBOV
#define PAC1921_OVERFLOW_VPOV

/* pac1921 constants */
#define PAC1921_MAX_VSENSE_MV
#define PAC1921_MAX_VBUS_V
/* Time to first communication after power up (tINT_T) */
#define PAC1921_POWERUP_TIME_MS
/* Time from Sleep State to Start of Integration Period (tSLEEP_TO_INT) */
#define PAC1921_SLEEP_TO_INT_TIME_US

/* pac1921 defaults */
#define PAC1921_DEFAULT_DV_GAIN
#define PAC1921_DEFAULT_DI_GAIN
#define PAC1921_DEFAULT_NUM_SAMPLES

/*
 * 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] =;

/*
 * 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] =;

/*
 * 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[] =;

/*
 * 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[] =;

/* pac1921 regmap configuration */
static const struct regmap_range pac1921_regmap_wr_ranges[] =;

static const struct regmap_access_table pac1921_regmap_wr_table =;

static const struct regmap_range pac1921_regmap_rd_ranges[] =;

static const struct regmap_access_table pac1921_regmap_rd_table =;

static const struct regmap_config pac1921_regmap_config =;

enum pac1921_channels {};
#define PAC1921_NUM_MEAS_CHANS

struct pac1921_priv {};

/*
 * Check if first integration after configuration update has completed.
 *
 * Must be called with lock held.
 */
static bool pac1921_data_ready(struct pac1921_priv *priv)
{}

static inline void pac1921_calc_scale(int dividend, int divisor, int *val,
				      int *val2)
{}

/*
 * Fill the table of scale factors for current
 * format: IIO_VAL_INT_PLUS_NANO
 * unit: mA
 *
 * Vsense LSB (nV) = max_vsense (nV) * di_gain / resolution
 * Current scale (mA) = Vsense LSB (nV) / shunt (uOhm)
 *
 * Must be called with held lock when updating after first initialization.
 */
static void pac1921_calc_current_scales(struct pac1921_priv *priv)
{}

/*
 * Check if overflow occurred and if so, push the corresponding events.
 *
 * Must be called with lock held.
 */
static int pac1921_check_push_overflow(struct iio_dev *indio_dev, s64 timestamp)
{}

/*
 * Read the value from a result register
 *
 * Result registers contain the most recent averaged values of Vbus, Vsense and
 * Vpower. Each value is 10 bits wide and spread across two consecutive 8 bit
 * registers, with 6 bit LSB zero padding.
 */
static int pac1921_read_res(struct pac1921_priv *priv, unsigned long reg,
			    u16 *val)
{}

static int pac1921_read_raw(struct iio_dev *indio_dev,
			    struct iio_chan_spec const *chan, int *val,
			    int *val2, long mask)
{}

static int pac1921_read_avail(struct iio_dev *indio_dev,
			      struct iio_chan_spec const *chan,
			      const int **vals, int *type, int *length,
			      long mask)
{}

/*
 * Perform configuration update sequence: set the device into read state, then
 * write the config register and set the device back into integration state.
 * Also reset integration start time and mark first integration to be yet
 * completed.
 *
 * Must be called with lock held.
 */
static int pac1921_update_cfg_reg(struct pac1921_priv *priv, unsigned int reg,
				  unsigned int mask, unsigned int val)
{}

/*
 * Retrieve the index of the given scale (represented by scale_val and
 * scale_val2) from scales_tbl. The returned index (if found) is the log2 of
 * the gain corresponding to the given scale.
 *
 * Must be called with lock held if the scales_tbl can change runtime (e.g. for
 * the current scales table)
 */
static int pac1921_lookup_scale(const int (*const scales_tbl)[2], size_t size,
				int scale_val, int scale_val2)
{}

/*
 * Configure device with the given gain (only if changed)
 *
 * Must be called with lock held.
 */
static int pac1921_update_gain(struct pac1921_priv *priv, u8 *priv_val, u8 gain,
			       unsigned int mask)
{}

/*
 * Given a scale factor represented by scale_val and scale_val2 with format
 * IIO_VAL_INT_PLUS_NANO, find the corresponding gain value and write it to the
 * device.
 *
 * Must be called with lock held.
 */
static int pac1921_update_gain_from_scale(struct pac1921_priv *priv,
					  struct iio_chan_spec const *chan,
					  int scale_val, int scale_val2)
{}

/*
 * Retrieve the index of the given number of samples from the constant table.
 * The returned index (if found) is the log2 of the given num_samples.
 */
static int pac1921_lookup_int_num_samples(int num_samples)
{}

/*
 * Update the device with the given number of integration samples.
 *
 * Must be called with lock held.
 */
static int pac1921_update_int_num_samples(struct pac1921_priv *priv,
					  int num_samples)
{}

static int pac1921_write_raw_get_fmt(struct iio_dev *indio_dev,
				     struct iio_chan_spec const *chan,
				     long info)
{}

static int pac1921_write_raw(struct iio_dev *indio_dev,
			     struct iio_chan_spec const *chan, int val,
			     int val2, long mask)
{}

static int pac1921_read_label(struct iio_dev *indio_dev,
			      struct iio_chan_spec const *chan, char *label)
{}

static int pac1921_read_event_config(struct iio_dev *indio_dev,
				     const struct iio_chan_spec *chan,
				     enum iio_event_type type,
				     enum iio_event_direction dir)
{}

static int pac1921_write_event_config(struct iio_dev *indio_dev,
				      const struct iio_chan_spec *chan,
				      enum iio_event_type type,
				      enum iio_event_direction dir, int state)
{}

static int pac1921_read_event_value(struct iio_dev *indio_dev,
				    const struct iio_chan_spec *chan,
				    enum iio_event_type type,
				    enum iio_event_direction dir,
				    enum iio_event_info info, int *val,
				    int *val2)
{}

static const struct iio_info pac1921_iio =;

static ssize_t pac1921_read_shunt_resistor(struct iio_dev *indio_dev,
					    uintptr_t private,
					    const struct iio_chan_spec *chan,
					    char *buf)
{}

static ssize_t pac1921_write_shunt_resistor(struct iio_dev *indio_dev,
					    uintptr_t private,
					    const struct iio_chan_spec *chan,
					    const char *buf, size_t len)
{}

/*
 * Emit on sysfs the list of available scales contained in scales_tbl
 *
 * TODO:: this function can be replaced with iio_format_avail_list() if the
 * latter will ever be exported.
 *
 * Must be called with lock held if the scales_tbl can change runtime (e.g. for
 * the current scales table)
 */
static ssize_t pac1921_format_scale_avail(const int (*const scales_tbl)[2],
					  size_t size, char *buf)
{}

/*
 * Read available scales for a specific channel
 *
 * NOTE: using extended info insted of iio.read_avail() because access to
 * current scales must be locked as they depend on shunt resistor which may
 * change runtime. Caller of iio.read_avail() would access the table unlocked
 * instead.
 */
static ssize_t pac1921_read_scale_avail(struct iio_dev *indio_dev,
					uintptr_t private,
					const struct iio_chan_spec *chan,
					char *buf)
{}

#define PAC1921_EXT_INFO_SCALE_AVAIL

static const struct iio_chan_spec_ext_info pac1921_ext_info_voltage[] =;

static const struct iio_chan_spec_ext_info pac1921_ext_info_current[] =;

static const struct iio_event_spec pac1921_overflow_event[] =;

static const struct iio_chan_spec pac1921_channels[] =;

static irqreturn_t pac1921_trigger_handler(int irq, void *p)
{}

/*
 * Initialize device by writing initial configuration and putting it into
 * integration state.
 *
 * Must be called with lock held when called after first initialization
 * (e.g. from pm resume)
 */
static int pac1921_init(struct pac1921_priv *priv)
{}

static int pac1921_suspend(struct device *dev)
{}

static int pac1921_resume(struct device *dev)
{}

static DEFINE_SIMPLE_DEV_PM_OPS(pac1921_pm_ops, pac1921_suspend,
				pac1921_resume);

static void pac1921_regulator_disable(void *data)
{}

static int pac1921_probe(struct i2c_client *client)
{}

static const struct i2c_device_id pac1921_id[] =;
MODULE_DEVICE_TABLE(i2c, pac1921_id);

static const struct of_device_id pac1921_of_match[] =;
MODULE_DEVICE_TABLE(of, pac1921_of_match);

static struct i2c_driver pac1921_driver =;

module_i2c_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();