linux/drivers/iio/adc/qcom-pm8xxx-xoadc.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Qualcomm PM8xxx PMIC XOADC driver
 *
 * These ADCs are known as HK/XO (house keeping / chrystal oscillator)
 * "XO" in "XOADC" means Chrystal Oscillator. It's a bunch of
 * specific-purpose and general purpose ADC converters and channels.
 *
 * Copyright (C) 2017 Linaro Ltd.
 * Author: Linus Walleij <[email protected]>
 */

#include <linux/iio/adc/qcom-vadc-common.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>

/*
 * Definitions for the "user processor" registers lifted from the v3.4
 * Qualcomm tree. Their kernel has two out-of-tree drivers for the ADC:
 * drivers/misc/pmic8058-xoadc.c
 * drivers/hwmon/pm8xxx-adc.c
 * None of them contain any complete register specification, so this is
 * a best effort of combining the information.
 */

/* These appear to be "battery monitor" registers */
#define ADC_ARB_BTM_CNTRL1
#define ADC_ARB_BTM_CNTRL1_EN_BTM
#define ADC_ARB_BTM_CNTRL1_SEL_OP_MODE
#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL1
#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL2
#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL3
#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL4
#define ADC_ARB_BTM_CNTRL1_EOC
#define ADC_ARB_BTM_CNTRL1_REQ

#define ADC_ARB_BTM_AMUX_CNTRL
#define ADC_ARB_BTM_ANA_PARAM
#define ADC_ARB_BTM_DIG_PARAM
#define ADC_ARB_BTM_RSV
#define ADC_ARB_BTM_DATA1
#define ADC_ARB_BTM_DATA0
#define ADC_ARB_BTM_BAT_COOL_THR1
#define ADC_ARB_BTM_BAT_COOL_THR0
#define ADC_ARB_BTM_BAT_WARM_THR1
#define ADC_ARB_BTM_BAT_WARM_THR0
#define ADC_ARB_BTM_CNTRL2

/* Proper ADC registers */

#define ADC_ARB_USRP_CNTRL
#define ADC_ARB_USRP_CNTRL_EN_ARB
#define ADC_ARB_USRP_CNTRL_RSV1
#define ADC_ARB_USRP_CNTRL_RSV2
#define ADC_ARB_USRP_CNTRL_RSV3
#define ADC_ARB_USRP_CNTRL_RSV4
#define ADC_ARB_USRP_CNTRL_RSV5
#define ADC_ARB_USRP_CNTRL_EOC
#define ADC_ARB_USRP_CNTRL_REQ

#define ADC_ARB_USRP_AMUX_CNTRL
/*
 * The channel mask includes the bits selecting channel mux and prescaler
 * on PM8058, or channel mux and premux on PM8921.
 */
#define ADC_ARB_USRP_AMUX_CNTRL_CHAN_MASK
#define ADC_ARB_USRP_AMUX_CNTRL_RSV0
#define ADC_ARB_USRP_AMUX_CNTRL_RSV1
/* On PM8058 this is prescaling, on PM8921 this is premux */
#define ADC_ARB_USRP_AMUX_CNTRL_PRESCALEMUX0
#define ADC_ARB_USRP_AMUX_CNTRL_PRESCALEMUX1
#define ADC_ARB_USRP_AMUX_CNTRL_SEL0
#define ADC_ARB_USRP_AMUX_CNTRL_SEL1
#define ADC_ARB_USRP_AMUX_CNTRL_SEL2
#define ADC_ARB_USRP_AMUX_CNTRL_SEL3
#define ADC_AMUX_PREMUX_SHIFT
#define ADC_AMUX_SEL_SHIFT

/* We know very little about the bits in this register */
#define ADC_ARB_USRP_ANA_PARAM
#define ADC_ARB_USRP_ANA_PARAM_DIS
#define ADC_ARB_USRP_ANA_PARAM_EN

#define ADC_ARB_USRP_DIG_PARAM
#define ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT0
#define ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT1
#define ADC_ARB_USRP_DIG_PARAM_CLK_RATE0
#define ADC_ARB_USRP_DIG_PARAM_CLK_RATE1
#define ADC_ARB_USRP_DIG_PARAM_EOC
/*
 * On a later ADC the decimation factors are defined as
 * 00 = 512, 01 = 1024, 10 = 2048, 11 = 4096 so assume this
 * holds also for this older XOADC.
 */
#define ADC_ARB_USRP_DIG_PARAM_DEC_RATE0
#define ADC_ARB_USRP_DIG_PARAM_DEC_RATE1
#define ADC_ARB_USRP_DIG_PARAM_EN
#define ADC_DIG_PARAM_DEC_SHIFT

#define ADC_ARB_USRP_RSV
#define ADC_ARB_USRP_RSV_RST
#define ADC_ARB_USRP_RSV_DTEST0
#define ADC_ARB_USRP_RSV_DTEST1
#define ADC_ARB_USRP_RSV_OP
#define ADC_ARB_USRP_RSV_IP_SEL0
#define ADC_ARB_USRP_RSV_IP_SEL1
#define ADC_ARB_USRP_RSV_IP_SEL2
#define ADC_ARB_USRP_RSV_TRM
#define ADC_RSV_IP_SEL_SHIFT

#define ADC_ARB_USRP_DATA0
#define ADC_ARB_USRP_DATA1

/*
 * Physical channels which MUST exist on all PM variants in order to provide
 * proper reference points for calibration.
 *
 * @PM8XXX_CHANNEL_INTERNAL: 625mV reference channel
 * @PM8XXX_CHANNEL_125V: 1250mV reference channel
 * @PM8XXX_CHANNEL_INTERNAL_2: 325mV reference channel
 * @PM8XXX_CHANNEL_MUXOFF: channel to reduce input load on mux, apparently also
 * measures XO temperature
 */
#define PM8XXX_CHANNEL_INTERNAL
#define PM8XXX_CHANNEL_125V
#define PM8XXX_CHANNEL_INTERNAL_2
#define PM8XXX_CHANNEL_MUXOFF

/*
 * PM8058 AMUX premux scaling, two bits. This is done of the channel before
 * reaching the AMUX.
 */
#define PM8058_AMUX_PRESCALE_0
#define PM8058_AMUX_PRESCALE_1
#define PM8058_AMUX_PRESCALE_1_DIV3

/* Defines reference voltage for the XOADC */
#define AMUX_RSV0
#define AMUX_RSV1
#define AMUX_RSV2
#define AMUX_RSV3
#define AMUX_RSV4
#define AMUX_RSV5
#define XOADC_RSV_MAX

/**
 * struct xoadc_channel - encodes channel properties and defaults
 * @datasheet_name: the hardwarename of this channel
 * @pre_scale_mux: prescale (PM8058) or premux (PM8921) for selecting
 * this channel. Both this and the amux channel is needed to uniquely
 * identify a channel. Values 0..3.
 * @amux_channel: value of the ADC_ARB_USRP_AMUX_CNTRL register for this
 * channel, bits 4..7, selects the amux, values 0..f
 * @prescale: the channels have hard-coded prescale ratios defined
 * by the hardware, this tells us what it is
 * @type: corresponding IIO channel type, usually IIO_VOLTAGE or
 * IIO_TEMP
 * @scale_fn_type: the liner interpolation etc to convert the
 * ADC code to the value that IIO expects, in uV or millicelsius
 * etc. This scale function can be pretty elaborate if different
 * thermistors are connected or other hardware characteristics are
 * deployed.
 * @amux_ip_rsv: ratiometric scale value used by the analog muxer: this
 * selects the reference voltage for ratiometric scaling
 */
struct xoadc_channel {};

/**
 * struct xoadc_variant - encodes the XOADC variant characteristics
 * @name: name of this PMIC variant
 * @channels: the hardware channels and respective settings and defaults
 * @broken_ratiometric: if the PMIC has broken ratiometric scaling (this
 * is a known problem on PM8058)
 * @prescaling: this variant uses AMUX bits 2 & 3 for prescaling (PM8058)
 * @second_level_mux: this variant uses AMUX bits 2 & 3 for a second level
 * mux
 */
struct xoadc_variant {};

/*
 * XOADC_CHAN macro parameters:
 * _dname: the name of the channel
 * _presmux: prescaler (PM8058) or premux (PM8921) setting for this channel
 * _amux: the value in bits 2..7 of the ADC_ARB_USRP_AMUX_CNTRL register
 * for this channel. On some PMICs some of the bits select a prescaler, and
 * on some PMICs some of the bits select various complex multiplex settings.
 * _type: IIO channel type
 * _prenum: prescaler numerator (dividend)
 * _preden: prescaler denominator (divisor)
 * _scale: scaling function type, this selects how the raw valued is mangled
 * to output the actual processed measurement
 * _amip: analog mux input parent when using ratiometric measurements
 */
#define XOADC_CHAN(_dname, _presmux, _amux, _type, _prenum, _preden, _scale, _amip)

/*
 * Taken from arch/arm/mach-msm/board-9615.c in the vendor tree:
 * TODO: incomplete, needs testing.
 */
static const struct xoadc_channel pm8018_xoadc_channels[] =;

/*
 * Taken from arch/arm/mach-msm/board-8930-pmic.c in the vendor tree:
 * TODO: needs testing.
 */
static const struct xoadc_channel pm8038_xoadc_channels[] =;

/*
 * This was created by cross-referencing the vendor tree
 * arch/arm/mach-msm/board-msm8x60.c msm_adc_channels_data[]
 * with the "channel types" (first field) to find the right
 * configuration for these channels on an MSM8x60 i.e. PM8058
 * setup.
 */
static const struct xoadc_channel pm8058_xoadc_channels[] =;

/*
 * The PM8921 has some pre-muxing on its channels, this comes from the vendor tree
 * include/linux/mfd/pm8xxx/pm8xxx-adc.h
 * board-flo-pmic.c (Nexus 7) and board-8064-pmic.c
 */
static const struct xoadc_channel pm8921_xoadc_channels[] =;

/**
 * struct pm8xxx_chan_info - ADC channel information
 * @name: name of this channel
 * @hwchan: pointer to hardware channel information (muxing & scaling settings)
 * @calibration: whether to use absolute or ratiometric calibration
 * @decimation: 0,1,2,3
 * @amux_ip_rsv: ratiometric scale value if using ratiometric
 * calibration: 0, 1, 2, 4, 5.
 */
struct pm8xxx_chan_info {};

/**
 * struct pm8xxx_xoadc - state container for the XOADC
 * @dev: pointer to device
 * @map: regmap to access registers
 * @variant: XOADC variant characteristics
 * @vref: reference voltage regulator
 * characteristics of the channels, and sensible default settings
 * @nchans: number of channels, configured by the device tree
 * @chans: the channel information per-channel, configured by the device tree
 * @iio_chans: IIO channel specifiers
 * @graph: linear calibration parameters for absolute and
 * ratiometric measurements
 * @complete: completion to indicate end of conversion
 * @lock: lock to restrict access to the hardware to one client at the time
 */
struct pm8xxx_xoadc {};

static irqreturn_t pm8xxx_eoc_irq(int irq, void *d)
{}

static struct pm8xxx_chan_info *
pm8xxx_get_channel(struct pm8xxx_xoadc *adc, u8 chan)
{}

static int pm8xxx_read_channel_rsv(struct pm8xxx_xoadc *adc,
				   const struct pm8xxx_chan_info *ch,
				   u8 rsv, u16 *adc_code,
				   bool force_ratiometric)
{}

static int pm8xxx_read_channel(struct pm8xxx_xoadc *adc,
			       const struct pm8xxx_chan_info *ch,
			       u16 *adc_code)
{}

static int pm8xxx_calibrate_device(struct pm8xxx_xoadc *adc)
{}

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

static int pm8xxx_fwnode_xlate(struct iio_dev *indio_dev,
			       const struct fwnode_reference_args *iiospec)
{}

static const struct iio_info pm8xxx_xoadc_info =;

static int pm8xxx_xoadc_parse_channel(struct device *dev,
				      struct fwnode_handle *fwnode,
				      const struct xoadc_channel *hw_channels,
				      struct iio_chan_spec *iio_chan,
				      struct pm8xxx_chan_info *ch)
{}

static int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc)
{}

static int pm8xxx_xoadc_probe(struct platform_device *pdev)
{}

static void pm8xxx_xoadc_remove(struct platform_device *pdev)
{}

static const struct xoadc_variant pm8018_variant =;

static const struct xoadc_variant pm8038_variant =;

static const struct xoadc_variant pm8058_variant =;

static const struct xoadc_variant pm8921_variant =;

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

static struct platform_driver pm8xxx_xoadc_driver =;
module_platform_driver();

MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_ALIAS();