162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Qualcomm PM8xxx PMIC XOADC driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * These ADCs are known as HK/XO (house keeping / chrystal oscillator) 662306a36Sopenharmony_ci * "XO" in "XOADC" means Chrystal Oscillator. It's a bunch of 762306a36Sopenharmony_ci * specific-purpose and general purpose ADC converters and channels. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (C) 2017 Linaro Ltd. 1062306a36Sopenharmony_ci * Author: Linus Walleij <linus.walleij@linaro.org> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/iio/adc/qcom-vadc-common.h> 1462306a36Sopenharmony_ci#include <linux/iio/iio.h> 1562306a36Sopenharmony_ci#include <linux/iio/sysfs.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/property.h> 2062306a36Sopenharmony_ci#include <linux/regmap.h> 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/interrupt.h> 2362306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Definitions for the "user processor" registers lifted from the v3.4 2762306a36Sopenharmony_ci * Qualcomm tree. Their kernel has two out-of-tree drivers for the ADC: 2862306a36Sopenharmony_ci * drivers/misc/pmic8058-xoadc.c 2962306a36Sopenharmony_ci * drivers/hwmon/pm8xxx-adc.c 3062306a36Sopenharmony_ci * None of them contain any complete register specification, so this is 3162306a36Sopenharmony_ci * a best effort of combining the information. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* These appear to be "battery monitor" registers */ 3562306a36Sopenharmony_ci#define ADC_ARB_BTM_CNTRL1 0x17e 3662306a36Sopenharmony_ci#define ADC_ARB_BTM_CNTRL1_EN_BTM BIT(0) 3762306a36Sopenharmony_ci#define ADC_ARB_BTM_CNTRL1_SEL_OP_MODE BIT(1) 3862306a36Sopenharmony_ci#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL1 BIT(2) 3962306a36Sopenharmony_ci#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL2 BIT(3) 4062306a36Sopenharmony_ci#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL3 BIT(4) 4162306a36Sopenharmony_ci#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL4 BIT(5) 4262306a36Sopenharmony_ci#define ADC_ARB_BTM_CNTRL1_EOC BIT(6) 4362306a36Sopenharmony_ci#define ADC_ARB_BTM_CNTRL1_REQ BIT(7) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define ADC_ARB_BTM_AMUX_CNTRL 0x17f 4662306a36Sopenharmony_ci#define ADC_ARB_BTM_ANA_PARAM 0x180 4762306a36Sopenharmony_ci#define ADC_ARB_BTM_DIG_PARAM 0x181 4862306a36Sopenharmony_ci#define ADC_ARB_BTM_RSV 0x182 4962306a36Sopenharmony_ci#define ADC_ARB_BTM_DATA1 0x183 5062306a36Sopenharmony_ci#define ADC_ARB_BTM_DATA0 0x184 5162306a36Sopenharmony_ci#define ADC_ARB_BTM_BAT_COOL_THR1 0x185 5262306a36Sopenharmony_ci#define ADC_ARB_BTM_BAT_COOL_THR0 0x186 5362306a36Sopenharmony_ci#define ADC_ARB_BTM_BAT_WARM_THR1 0x187 5462306a36Sopenharmony_ci#define ADC_ARB_BTM_BAT_WARM_THR0 0x188 5562306a36Sopenharmony_ci#define ADC_ARB_BTM_CNTRL2 0x18c 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* Proper ADC registers */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define ADC_ARB_USRP_CNTRL 0x197 6062306a36Sopenharmony_ci#define ADC_ARB_USRP_CNTRL_EN_ARB BIT(0) 6162306a36Sopenharmony_ci#define ADC_ARB_USRP_CNTRL_RSV1 BIT(1) 6262306a36Sopenharmony_ci#define ADC_ARB_USRP_CNTRL_RSV2 BIT(2) 6362306a36Sopenharmony_ci#define ADC_ARB_USRP_CNTRL_RSV3 BIT(3) 6462306a36Sopenharmony_ci#define ADC_ARB_USRP_CNTRL_RSV4 BIT(4) 6562306a36Sopenharmony_ci#define ADC_ARB_USRP_CNTRL_RSV5 BIT(5) 6662306a36Sopenharmony_ci#define ADC_ARB_USRP_CNTRL_EOC BIT(6) 6762306a36Sopenharmony_ci#define ADC_ARB_USRP_CNTRL_REQ BIT(7) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define ADC_ARB_USRP_AMUX_CNTRL 0x198 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * The channel mask includes the bits selecting channel mux and prescaler 7262306a36Sopenharmony_ci * on PM8058, or channel mux and premux on PM8921. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci#define ADC_ARB_USRP_AMUX_CNTRL_CHAN_MASK 0xfc 7562306a36Sopenharmony_ci#define ADC_ARB_USRP_AMUX_CNTRL_RSV0 BIT(0) 7662306a36Sopenharmony_ci#define ADC_ARB_USRP_AMUX_CNTRL_RSV1 BIT(1) 7762306a36Sopenharmony_ci/* On PM8058 this is prescaling, on PM8921 this is premux */ 7862306a36Sopenharmony_ci#define ADC_ARB_USRP_AMUX_CNTRL_PRESCALEMUX0 BIT(2) 7962306a36Sopenharmony_ci#define ADC_ARB_USRP_AMUX_CNTRL_PRESCALEMUX1 BIT(3) 8062306a36Sopenharmony_ci#define ADC_ARB_USRP_AMUX_CNTRL_SEL0 BIT(4) 8162306a36Sopenharmony_ci#define ADC_ARB_USRP_AMUX_CNTRL_SEL1 BIT(5) 8262306a36Sopenharmony_ci#define ADC_ARB_USRP_AMUX_CNTRL_SEL2 BIT(6) 8362306a36Sopenharmony_ci#define ADC_ARB_USRP_AMUX_CNTRL_SEL3 BIT(7) 8462306a36Sopenharmony_ci#define ADC_AMUX_PREMUX_SHIFT 2 8562306a36Sopenharmony_ci#define ADC_AMUX_SEL_SHIFT 4 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* We know very little about the bits in this register */ 8862306a36Sopenharmony_ci#define ADC_ARB_USRP_ANA_PARAM 0x199 8962306a36Sopenharmony_ci#define ADC_ARB_USRP_ANA_PARAM_DIS 0xFE 9062306a36Sopenharmony_ci#define ADC_ARB_USRP_ANA_PARAM_EN 0xFF 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define ADC_ARB_USRP_DIG_PARAM 0x19A 9362306a36Sopenharmony_ci#define ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT0 BIT(0) 9462306a36Sopenharmony_ci#define ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT1 BIT(1) 9562306a36Sopenharmony_ci#define ADC_ARB_USRP_DIG_PARAM_CLK_RATE0 BIT(2) 9662306a36Sopenharmony_ci#define ADC_ARB_USRP_DIG_PARAM_CLK_RATE1 BIT(3) 9762306a36Sopenharmony_ci#define ADC_ARB_USRP_DIG_PARAM_EOC BIT(4) 9862306a36Sopenharmony_ci/* 9962306a36Sopenharmony_ci * On a later ADC the decimation factors are defined as 10062306a36Sopenharmony_ci * 00 = 512, 01 = 1024, 10 = 2048, 11 = 4096 so assume this 10162306a36Sopenharmony_ci * holds also for this older XOADC. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci#define ADC_ARB_USRP_DIG_PARAM_DEC_RATE0 BIT(5) 10462306a36Sopenharmony_ci#define ADC_ARB_USRP_DIG_PARAM_DEC_RATE1 BIT(6) 10562306a36Sopenharmony_ci#define ADC_ARB_USRP_DIG_PARAM_EN BIT(7) 10662306a36Sopenharmony_ci#define ADC_DIG_PARAM_DEC_SHIFT 5 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#define ADC_ARB_USRP_RSV 0x19B 10962306a36Sopenharmony_ci#define ADC_ARB_USRP_RSV_RST BIT(0) 11062306a36Sopenharmony_ci#define ADC_ARB_USRP_RSV_DTEST0 BIT(1) 11162306a36Sopenharmony_ci#define ADC_ARB_USRP_RSV_DTEST1 BIT(2) 11262306a36Sopenharmony_ci#define ADC_ARB_USRP_RSV_OP BIT(3) 11362306a36Sopenharmony_ci#define ADC_ARB_USRP_RSV_IP_SEL0 BIT(4) 11462306a36Sopenharmony_ci#define ADC_ARB_USRP_RSV_IP_SEL1 BIT(5) 11562306a36Sopenharmony_ci#define ADC_ARB_USRP_RSV_IP_SEL2 BIT(6) 11662306a36Sopenharmony_ci#define ADC_ARB_USRP_RSV_TRM BIT(7) 11762306a36Sopenharmony_ci#define ADC_RSV_IP_SEL_SHIFT 4 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#define ADC_ARB_USRP_DATA0 0x19D 12062306a36Sopenharmony_ci#define ADC_ARB_USRP_DATA1 0x19C 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * Physical channels which MUST exist on all PM variants in order to provide 12462306a36Sopenharmony_ci * proper reference points for calibration. 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * @PM8XXX_CHANNEL_INTERNAL: 625mV reference channel 12762306a36Sopenharmony_ci * @PM8XXX_CHANNEL_125V: 1250mV reference channel 12862306a36Sopenharmony_ci * @PM8XXX_CHANNEL_INTERNAL_2: 325mV reference channel 12962306a36Sopenharmony_ci * @PM8XXX_CHANNEL_MUXOFF: channel to reduce input load on mux, apparently also 13062306a36Sopenharmony_ci * measures XO temperature 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci#define PM8XXX_CHANNEL_INTERNAL 0x0c 13362306a36Sopenharmony_ci#define PM8XXX_CHANNEL_125V 0x0d 13462306a36Sopenharmony_ci#define PM8XXX_CHANNEL_INTERNAL_2 0x0e 13562306a36Sopenharmony_ci#define PM8XXX_CHANNEL_MUXOFF 0x0f 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* 13862306a36Sopenharmony_ci * PM8058 AMUX premux scaling, two bits. This is done of the channel before 13962306a36Sopenharmony_ci * reaching the AMUX. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci#define PM8058_AMUX_PRESCALE_0 0x0 /* No scaling on the signal */ 14262306a36Sopenharmony_ci#define PM8058_AMUX_PRESCALE_1 0x1 /* Unity scaling selected by the user */ 14362306a36Sopenharmony_ci#define PM8058_AMUX_PRESCALE_1_DIV3 0x2 /* 1/3 prescaler on the input */ 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* Defines reference voltage for the XOADC */ 14662306a36Sopenharmony_ci#define AMUX_RSV0 0x0 /* XO_IN/XOADC_GND, special selection to read XO temp */ 14762306a36Sopenharmony_ci#define AMUX_RSV1 0x1 /* PMIC_IN/XOADC_GND */ 14862306a36Sopenharmony_ci#define AMUX_RSV2 0x2 /* PMIC_IN/BMS_CSP */ 14962306a36Sopenharmony_ci#define AMUX_RSV3 0x3 /* not used */ 15062306a36Sopenharmony_ci#define AMUX_RSV4 0x4 /* XOADC_GND/XOADC_GND */ 15162306a36Sopenharmony_ci#define AMUX_RSV5 0x5 /* XOADC_VREF/XOADC_GND */ 15262306a36Sopenharmony_ci#define XOADC_RSV_MAX 5 /* 3 bits 0..7, 3 and 6,7 are invalid */ 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/** 15562306a36Sopenharmony_ci * struct xoadc_channel - encodes channel properties and defaults 15662306a36Sopenharmony_ci * @datasheet_name: the hardwarename of this channel 15762306a36Sopenharmony_ci * @pre_scale_mux: prescale (PM8058) or premux (PM8921) for selecting 15862306a36Sopenharmony_ci * this channel. Both this and the amux channel is needed to uniquely 15962306a36Sopenharmony_ci * identify a channel. Values 0..3. 16062306a36Sopenharmony_ci * @amux_channel: value of the ADC_ARB_USRP_AMUX_CNTRL register for this 16162306a36Sopenharmony_ci * channel, bits 4..7, selects the amux, values 0..f 16262306a36Sopenharmony_ci * @prescale: the channels have hard-coded prescale ratios defined 16362306a36Sopenharmony_ci * by the hardware, this tells us what it is 16462306a36Sopenharmony_ci * @type: corresponding IIO channel type, usually IIO_VOLTAGE or 16562306a36Sopenharmony_ci * IIO_TEMP 16662306a36Sopenharmony_ci * @scale_fn_type: the liner interpolation etc to convert the 16762306a36Sopenharmony_ci * ADC code to the value that IIO expects, in uV or millicelsius 16862306a36Sopenharmony_ci * etc. This scale function can be pretty elaborate if different 16962306a36Sopenharmony_ci * thermistors are connected or other hardware characteristics are 17062306a36Sopenharmony_ci * deployed. 17162306a36Sopenharmony_ci * @amux_ip_rsv: ratiometric scale value used by the analog muxer: this 17262306a36Sopenharmony_ci * selects the reference voltage for ratiometric scaling 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cistruct xoadc_channel { 17562306a36Sopenharmony_ci const char *datasheet_name; 17662306a36Sopenharmony_ci u8 pre_scale_mux:2; 17762306a36Sopenharmony_ci u8 amux_channel:4; 17862306a36Sopenharmony_ci const struct u32_fract prescale; 17962306a36Sopenharmony_ci enum iio_chan_type type; 18062306a36Sopenharmony_ci enum vadc_scale_fn_type scale_fn_type; 18162306a36Sopenharmony_ci u8 amux_ip_rsv:3; 18262306a36Sopenharmony_ci}; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/** 18562306a36Sopenharmony_ci * struct xoadc_variant - encodes the XOADC variant characteristics 18662306a36Sopenharmony_ci * @name: name of this PMIC variant 18762306a36Sopenharmony_ci * @channels: the hardware channels and respective settings and defaults 18862306a36Sopenharmony_ci * @broken_ratiometric: if the PMIC has broken ratiometric scaling (this 18962306a36Sopenharmony_ci * is a known problem on PM8058) 19062306a36Sopenharmony_ci * @prescaling: this variant uses AMUX bits 2 & 3 for prescaling (PM8058) 19162306a36Sopenharmony_ci * @second_level_mux: this variant uses AMUX bits 2 & 3 for a second level 19262306a36Sopenharmony_ci * mux 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_cistruct xoadc_variant { 19562306a36Sopenharmony_ci const char name[16]; 19662306a36Sopenharmony_ci const struct xoadc_channel *channels; 19762306a36Sopenharmony_ci bool broken_ratiometric; 19862306a36Sopenharmony_ci bool prescaling; 19962306a36Sopenharmony_ci bool second_level_mux; 20062306a36Sopenharmony_ci}; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* 20362306a36Sopenharmony_ci * XOADC_CHAN macro parameters: 20462306a36Sopenharmony_ci * _dname: the name of the channel 20562306a36Sopenharmony_ci * _presmux: prescaler (PM8058) or premux (PM8921) setting for this channel 20662306a36Sopenharmony_ci * _amux: the value in bits 2..7 of the ADC_ARB_USRP_AMUX_CNTRL register 20762306a36Sopenharmony_ci * for this channel. On some PMICs some of the bits select a prescaler, and 20862306a36Sopenharmony_ci * on some PMICs some of the bits select various complex multiplex settings. 20962306a36Sopenharmony_ci * _type: IIO channel type 21062306a36Sopenharmony_ci * _prenum: prescaler numerator (dividend) 21162306a36Sopenharmony_ci * _preden: prescaler denominator (divisor) 21262306a36Sopenharmony_ci * _scale: scaling function type, this selects how the raw valued is mangled 21362306a36Sopenharmony_ci * to output the actual processed measurement 21462306a36Sopenharmony_ci * _amip: analog mux input parent when using ratiometric measurements 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci#define XOADC_CHAN(_dname, _presmux, _amux, _type, _prenum, _preden, _scale, _amip) \ 21762306a36Sopenharmony_ci { \ 21862306a36Sopenharmony_ci .datasheet_name = __stringify(_dname), \ 21962306a36Sopenharmony_ci .pre_scale_mux = _presmux, \ 22062306a36Sopenharmony_ci .amux_channel = _amux, \ 22162306a36Sopenharmony_ci .prescale = { \ 22262306a36Sopenharmony_ci .numerator = _prenum, .denominator = _preden, \ 22362306a36Sopenharmony_ci }, \ 22462306a36Sopenharmony_ci .type = _type, \ 22562306a36Sopenharmony_ci .scale_fn_type = _scale, \ 22662306a36Sopenharmony_ci .amux_ip_rsv = _amip, \ 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* 23062306a36Sopenharmony_ci * Taken from arch/arm/mach-msm/board-9615.c in the vendor tree: 23162306a36Sopenharmony_ci * TODO: incomplete, needs testing. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_cistatic const struct xoadc_channel pm8018_xoadc_channels[] = { 23462306a36Sopenharmony_ci XOADC_CHAN(VCOIN, 0x00, 0x00, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 23562306a36Sopenharmony_ci XOADC_CHAN(VBAT, 0x00, 0x01, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 23662306a36Sopenharmony_ci XOADC_CHAN(VPH_PWR, 0x00, 0x02, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 23762306a36Sopenharmony_ci XOADC_CHAN(DIE_TEMP, 0x00, 0x0b, IIO_TEMP, 1, 1, SCALE_PMIC_THERM, AMUX_RSV1), 23862306a36Sopenharmony_ci /* Used for battery ID or battery temperature */ 23962306a36Sopenharmony_ci XOADC_CHAN(AMUX8, 0x00, 0x08, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV2), 24062306a36Sopenharmony_ci XOADC_CHAN(INTERNAL, 0x00, 0x0c, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 24162306a36Sopenharmony_ci XOADC_CHAN(125V, 0x00, 0x0d, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 24262306a36Sopenharmony_ci XOADC_CHAN(MUXOFF, 0x00, 0x0f, IIO_TEMP, 1, 1, SCALE_XOTHERM, AMUX_RSV0), 24362306a36Sopenharmony_ci { }, /* Sentinel */ 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* 24762306a36Sopenharmony_ci * Taken from arch/arm/mach-msm/board-8930-pmic.c in the vendor tree: 24862306a36Sopenharmony_ci * TODO: needs testing. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_cistatic const struct xoadc_channel pm8038_xoadc_channels[] = { 25162306a36Sopenharmony_ci XOADC_CHAN(VCOIN, 0x00, 0x00, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 25262306a36Sopenharmony_ci XOADC_CHAN(VBAT, 0x00, 0x01, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 25362306a36Sopenharmony_ci XOADC_CHAN(DCIN, 0x00, 0x02, IIO_VOLTAGE, 1, 6, SCALE_DEFAULT, AMUX_RSV1), 25462306a36Sopenharmony_ci XOADC_CHAN(ICHG, 0x00, 0x03, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 25562306a36Sopenharmony_ci XOADC_CHAN(VPH_PWR, 0x00, 0x04, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 25662306a36Sopenharmony_ci XOADC_CHAN(AMUX5, 0x00, 0x05, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 25762306a36Sopenharmony_ci XOADC_CHAN(AMUX6, 0x00, 0x06, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 25862306a36Sopenharmony_ci XOADC_CHAN(AMUX7, 0x00, 0x07, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 25962306a36Sopenharmony_ci /* AMUX8 used for battery temperature in most cases */ 26062306a36Sopenharmony_ci XOADC_CHAN(AMUX8, 0x00, 0x08, IIO_TEMP, 1, 1, SCALE_THERM_100K_PULLUP, AMUX_RSV2), 26162306a36Sopenharmony_ci XOADC_CHAN(AMUX9, 0x00, 0x09, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 26262306a36Sopenharmony_ci XOADC_CHAN(USB_VBUS, 0x00, 0x0a, IIO_VOLTAGE, 1, 4, SCALE_DEFAULT, AMUX_RSV1), 26362306a36Sopenharmony_ci XOADC_CHAN(DIE_TEMP, 0x00, 0x0b, IIO_TEMP, 1, 1, SCALE_PMIC_THERM, AMUX_RSV1), 26462306a36Sopenharmony_ci XOADC_CHAN(INTERNAL, 0x00, 0x0c, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 26562306a36Sopenharmony_ci XOADC_CHAN(125V, 0x00, 0x0d, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 26662306a36Sopenharmony_ci XOADC_CHAN(INTERNAL_2, 0x00, 0x0e, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 26762306a36Sopenharmony_ci XOADC_CHAN(MUXOFF, 0x00, 0x0f, IIO_TEMP, 1, 1, SCALE_XOTHERM, AMUX_RSV0), 26862306a36Sopenharmony_ci { }, /* Sentinel */ 26962306a36Sopenharmony_ci}; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/* 27262306a36Sopenharmony_ci * This was created by cross-referencing the vendor tree 27362306a36Sopenharmony_ci * arch/arm/mach-msm/board-msm8x60.c msm_adc_channels_data[] 27462306a36Sopenharmony_ci * with the "channel types" (first field) to find the right 27562306a36Sopenharmony_ci * configuration for these channels on an MSM8x60 i.e. PM8058 27662306a36Sopenharmony_ci * setup. 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_cistatic const struct xoadc_channel pm8058_xoadc_channels[] = { 27962306a36Sopenharmony_ci XOADC_CHAN(VCOIN, 0x00, 0x00, IIO_VOLTAGE, 1, 2, SCALE_DEFAULT, AMUX_RSV1), 28062306a36Sopenharmony_ci XOADC_CHAN(VBAT, 0x00, 0x01, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 28162306a36Sopenharmony_ci XOADC_CHAN(DCIN, 0x00, 0x02, IIO_VOLTAGE, 1, 10, SCALE_DEFAULT, AMUX_RSV1), 28262306a36Sopenharmony_ci XOADC_CHAN(ICHG, 0x00, 0x03, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 28362306a36Sopenharmony_ci XOADC_CHAN(VPH_PWR, 0x00, 0x04, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 28462306a36Sopenharmony_ci /* 28562306a36Sopenharmony_ci * AMUX channels 5 thru 9 are referred to as MPP5 thru MPP9 in 28662306a36Sopenharmony_ci * some code and documentation. But they are really just 5 28762306a36Sopenharmony_ci * channels just like any other. They are connected to a switching 28862306a36Sopenharmony_ci * matrix where they can be routed to any of the MPPs, not just 28962306a36Sopenharmony_ci * 1-to-1 onto MPP5 thru 9, so naming them MPP5 thru MPP9 is 29062306a36Sopenharmony_ci * very confusing. 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ci XOADC_CHAN(AMUX5, 0x00, 0x05, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 29362306a36Sopenharmony_ci XOADC_CHAN(AMUX6, 0x00, 0x06, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 29462306a36Sopenharmony_ci XOADC_CHAN(AMUX7, 0x00, 0x07, IIO_VOLTAGE, 1, 2, SCALE_DEFAULT, AMUX_RSV1), 29562306a36Sopenharmony_ci XOADC_CHAN(AMUX8, 0x00, 0x08, IIO_VOLTAGE, 1, 2, SCALE_DEFAULT, AMUX_RSV1), 29662306a36Sopenharmony_ci XOADC_CHAN(AMUX9, 0x00, 0x09, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 29762306a36Sopenharmony_ci XOADC_CHAN(USB_VBUS, 0x00, 0x0a, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 29862306a36Sopenharmony_ci XOADC_CHAN(DIE_TEMP, 0x00, 0x0b, IIO_TEMP, 1, 1, SCALE_PMIC_THERM, AMUX_RSV1), 29962306a36Sopenharmony_ci XOADC_CHAN(INTERNAL, 0x00, 0x0c, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 30062306a36Sopenharmony_ci XOADC_CHAN(125V, 0x00, 0x0d, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 30162306a36Sopenharmony_ci XOADC_CHAN(INTERNAL_2, 0x00, 0x0e, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 30262306a36Sopenharmony_ci XOADC_CHAN(MUXOFF, 0x00, 0x0f, IIO_TEMP, 1, 1, SCALE_XOTHERM, AMUX_RSV0), 30362306a36Sopenharmony_ci /* There are also "unity" and divided by 3 channels (prescaler) but noone is using them */ 30462306a36Sopenharmony_ci { }, /* Sentinel */ 30562306a36Sopenharmony_ci}; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/* 30862306a36Sopenharmony_ci * The PM8921 has some pre-muxing on its channels, this comes from the vendor tree 30962306a36Sopenharmony_ci * include/linux/mfd/pm8xxx/pm8xxx-adc.h 31062306a36Sopenharmony_ci * board-flo-pmic.c (Nexus 7) and board-8064-pmic.c 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_cistatic const struct xoadc_channel pm8921_xoadc_channels[] = { 31362306a36Sopenharmony_ci XOADC_CHAN(VCOIN, 0x00, 0x00, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 31462306a36Sopenharmony_ci XOADC_CHAN(VBAT, 0x00, 0x01, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 31562306a36Sopenharmony_ci XOADC_CHAN(DCIN, 0x00, 0x02, IIO_VOLTAGE, 1, 6, SCALE_DEFAULT, AMUX_RSV1), 31662306a36Sopenharmony_ci /* channel "ICHG" is reserved and not used on PM8921 */ 31762306a36Sopenharmony_ci XOADC_CHAN(VPH_PWR, 0x00, 0x04, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 31862306a36Sopenharmony_ci XOADC_CHAN(IBAT, 0x00, 0x05, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 31962306a36Sopenharmony_ci /* CHAN 6 & 7 (MPP1 & MPP2) are reserved for MPP channels on PM8921 */ 32062306a36Sopenharmony_ci XOADC_CHAN(BATT_THERM, 0x00, 0x08, IIO_TEMP, 1, 1, SCALE_THERM_100K_PULLUP, AMUX_RSV1), 32162306a36Sopenharmony_ci XOADC_CHAN(BATT_ID, 0x00, 0x09, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 32262306a36Sopenharmony_ci XOADC_CHAN(USB_VBUS, 0x00, 0x0a, IIO_VOLTAGE, 1, 4, SCALE_DEFAULT, AMUX_RSV1), 32362306a36Sopenharmony_ci XOADC_CHAN(DIE_TEMP, 0x00, 0x0b, IIO_TEMP, 1, 1, SCALE_PMIC_THERM, AMUX_RSV1), 32462306a36Sopenharmony_ci XOADC_CHAN(INTERNAL, 0x00, 0x0c, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 32562306a36Sopenharmony_ci XOADC_CHAN(125V, 0x00, 0x0d, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 32662306a36Sopenharmony_ci /* FIXME: look into the scaling of this temperature */ 32762306a36Sopenharmony_ci XOADC_CHAN(CHG_TEMP, 0x00, 0x0e, IIO_TEMP, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 32862306a36Sopenharmony_ci XOADC_CHAN(MUXOFF, 0x00, 0x0f, IIO_TEMP, 1, 1, SCALE_XOTHERM, AMUX_RSV0), 32962306a36Sopenharmony_ci /* The following channels have premux bit 0 set to 1 (all end in 4) */ 33062306a36Sopenharmony_ci XOADC_CHAN(ATEST_8, 0x01, 0x00, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 33162306a36Sopenharmony_ci /* Set scaling to 1/2 based on the name for these two */ 33262306a36Sopenharmony_ci XOADC_CHAN(USB_SNS_DIV20, 0x01, 0x01, IIO_VOLTAGE, 1, 2, SCALE_DEFAULT, AMUX_RSV1), 33362306a36Sopenharmony_ci XOADC_CHAN(DCIN_SNS_DIV20, 0x01, 0x02, IIO_VOLTAGE, 1, 2, SCALE_DEFAULT, AMUX_RSV1), 33462306a36Sopenharmony_ci XOADC_CHAN(AMUX3, 0x01, 0x03, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 33562306a36Sopenharmony_ci XOADC_CHAN(AMUX4, 0x01, 0x04, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 33662306a36Sopenharmony_ci XOADC_CHAN(AMUX5, 0x01, 0x05, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 33762306a36Sopenharmony_ci XOADC_CHAN(AMUX6, 0x01, 0x06, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 33862306a36Sopenharmony_ci XOADC_CHAN(AMUX7, 0x01, 0x07, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 33962306a36Sopenharmony_ci XOADC_CHAN(AMUX8, 0x01, 0x08, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 34062306a36Sopenharmony_ci /* Internal test signals, I think */ 34162306a36Sopenharmony_ci XOADC_CHAN(ATEST_1, 0x01, 0x09, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 34262306a36Sopenharmony_ci XOADC_CHAN(ATEST_2, 0x01, 0x0a, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 34362306a36Sopenharmony_ci XOADC_CHAN(ATEST_3, 0x01, 0x0b, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 34462306a36Sopenharmony_ci XOADC_CHAN(ATEST_4, 0x01, 0x0c, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 34562306a36Sopenharmony_ci XOADC_CHAN(ATEST_5, 0x01, 0x0d, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 34662306a36Sopenharmony_ci XOADC_CHAN(ATEST_6, 0x01, 0x0e, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 34762306a36Sopenharmony_ci XOADC_CHAN(ATEST_7, 0x01, 0x0f, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1), 34862306a36Sopenharmony_ci /* The following channels have premux bit 1 set to 1 (all end in 8) */ 34962306a36Sopenharmony_ci /* I guess even ATEST8 will be divided by 3 here */ 35062306a36Sopenharmony_ci XOADC_CHAN(ATEST_8, 0x02, 0x00, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 35162306a36Sopenharmony_ci /* I guess div 2 div 3 becomes div 6 */ 35262306a36Sopenharmony_ci XOADC_CHAN(USB_SNS_DIV20_DIV3, 0x02, 0x01, IIO_VOLTAGE, 1, 6, SCALE_DEFAULT, AMUX_RSV1), 35362306a36Sopenharmony_ci XOADC_CHAN(DCIN_SNS_DIV20_DIV3, 0x02, 0x02, IIO_VOLTAGE, 1, 6, SCALE_DEFAULT, AMUX_RSV1), 35462306a36Sopenharmony_ci XOADC_CHAN(AMUX3_DIV3, 0x02, 0x03, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 35562306a36Sopenharmony_ci XOADC_CHAN(AMUX4_DIV3, 0x02, 0x04, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 35662306a36Sopenharmony_ci XOADC_CHAN(AMUX5_DIV3, 0x02, 0x05, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 35762306a36Sopenharmony_ci XOADC_CHAN(AMUX6_DIV3, 0x02, 0x06, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 35862306a36Sopenharmony_ci XOADC_CHAN(AMUX7_DIV3, 0x02, 0x07, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 35962306a36Sopenharmony_ci XOADC_CHAN(AMUX8_DIV3, 0x02, 0x08, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 36062306a36Sopenharmony_ci XOADC_CHAN(ATEST_1_DIV3, 0x02, 0x09, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 36162306a36Sopenharmony_ci XOADC_CHAN(ATEST_2_DIV3, 0x02, 0x0a, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 36262306a36Sopenharmony_ci XOADC_CHAN(ATEST_3_DIV3, 0x02, 0x0b, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 36362306a36Sopenharmony_ci XOADC_CHAN(ATEST_4_DIV3, 0x02, 0x0c, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 36462306a36Sopenharmony_ci XOADC_CHAN(ATEST_5_DIV3, 0x02, 0x0d, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 36562306a36Sopenharmony_ci XOADC_CHAN(ATEST_6_DIV3, 0x02, 0x0e, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 36662306a36Sopenharmony_ci XOADC_CHAN(ATEST_7_DIV3, 0x02, 0x0f, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1), 36762306a36Sopenharmony_ci { }, /* Sentinel */ 36862306a36Sopenharmony_ci}; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/** 37162306a36Sopenharmony_ci * struct pm8xxx_chan_info - ADC channel information 37262306a36Sopenharmony_ci * @name: name of this channel 37362306a36Sopenharmony_ci * @hwchan: pointer to hardware channel information (muxing & scaling settings) 37462306a36Sopenharmony_ci * @calibration: whether to use absolute or ratiometric calibration 37562306a36Sopenharmony_ci * @scale_fn_type: scaling function type 37662306a36Sopenharmony_ci * @decimation: 0,1,2,3 37762306a36Sopenharmony_ci * @amux_ip_rsv: ratiometric scale value if using ratiometric 37862306a36Sopenharmony_ci * calibration: 0, 1, 2, 4, 5. 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_cistruct pm8xxx_chan_info { 38162306a36Sopenharmony_ci const char *name; 38262306a36Sopenharmony_ci const struct xoadc_channel *hwchan; 38362306a36Sopenharmony_ci enum vadc_calibration calibration; 38462306a36Sopenharmony_ci u8 decimation:2; 38562306a36Sopenharmony_ci u8 amux_ip_rsv:3; 38662306a36Sopenharmony_ci}; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/** 38962306a36Sopenharmony_ci * struct pm8xxx_xoadc - state container for the XOADC 39062306a36Sopenharmony_ci * @dev: pointer to device 39162306a36Sopenharmony_ci * @map: regmap to access registers 39262306a36Sopenharmony_ci * @variant: XOADC variant characteristics 39362306a36Sopenharmony_ci * @vref: reference voltage regulator 39462306a36Sopenharmony_ci * characteristics of the channels, and sensible default settings 39562306a36Sopenharmony_ci * @nchans: number of channels, configured by the device tree 39662306a36Sopenharmony_ci * @chans: the channel information per-channel, configured by the device tree 39762306a36Sopenharmony_ci * @iio_chans: IIO channel specifiers 39862306a36Sopenharmony_ci * @graph: linear calibration parameters for absolute and 39962306a36Sopenharmony_ci * ratiometric measurements 40062306a36Sopenharmony_ci * @complete: completion to indicate end of conversion 40162306a36Sopenharmony_ci * @lock: lock to restrict access to the hardware to one client at the time 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_cistruct pm8xxx_xoadc { 40462306a36Sopenharmony_ci struct device *dev; 40562306a36Sopenharmony_ci struct regmap *map; 40662306a36Sopenharmony_ci const struct xoadc_variant *variant; 40762306a36Sopenharmony_ci struct regulator *vref; 40862306a36Sopenharmony_ci unsigned int nchans; 40962306a36Sopenharmony_ci struct pm8xxx_chan_info *chans; 41062306a36Sopenharmony_ci struct iio_chan_spec *iio_chans; 41162306a36Sopenharmony_ci struct vadc_linear_graph graph[2]; 41262306a36Sopenharmony_ci struct completion complete; 41362306a36Sopenharmony_ci struct mutex lock; 41462306a36Sopenharmony_ci}; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic irqreturn_t pm8xxx_eoc_irq(int irq, void *d) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct iio_dev *indio_dev = d; 41962306a36Sopenharmony_ci struct pm8xxx_xoadc *adc = iio_priv(indio_dev); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci complete(&adc->complete); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return IRQ_HANDLED; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic struct pm8xxx_chan_info * 42762306a36Sopenharmony_cipm8xxx_get_channel(struct pm8xxx_xoadc *adc, u8 chan) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci int i; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci for (i = 0; i < adc->nchans; i++) { 43262306a36Sopenharmony_ci struct pm8xxx_chan_info *ch = &adc->chans[i]; 43362306a36Sopenharmony_ci if (ch->hwchan->amux_channel == chan) 43462306a36Sopenharmony_ci return ch; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci return NULL; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int pm8xxx_read_channel_rsv(struct pm8xxx_xoadc *adc, 44062306a36Sopenharmony_ci const struct pm8xxx_chan_info *ch, 44162306a36Sopenharmony_ci u8 rsv, u16 *adc_code, 44262306a36Sopenharmony_ci bool force_ratiometric) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci int ret; 44562306a36Sopenharmony_ci unsigned int val; 44662306a36Sopenharmony_ci u8 rsvmask, rsvval; 44762306a36Sopenharmony_ci u8 lsb, msb; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci dev_dbg(adc->dev, "read channel \"%s\", amux %d, prescale/mux: %d, rsv %d\n", 45062306a36Sopenharmony_ci ch->name, ch->hwchan->amux_channel, ch->hwchan->pre_scale_mux, rsv); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci mutex_lock(&adc->lock); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* Mux in this channel */ 45562306a36Sopenharmony_ci val = ch->hwchan->amux_channel << ADC_AMUX_SEL_SHIFT; 45662306a36Sopenharmony_ci val |= ch->hwchan->pre_scale_mux << ADC_AMUX_PREMUX_SHIFT; 45762306a36Sopenharmony_ci ret = regmap_write(adc->map, ADC_ARB_USRP_AMUX_CNTRL, val); 45862306a36Sopenharmony_ci if (ret) 45962306a36Sopenharmony_ci goto unlock; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* Set up ratiometric scale value, mask off all bits except these */ 46262306a36Sopenharmony_ci rsvmask = (ADC_ARB_USRP_RSV_RST | ADC_ARB_USRP_RSV_DTEST0 | 46362306a36Sopenharmony_ci ADC_ARB_USRP_RSV_DTEST1 | ADC_ARB_USRP_RSV_OP); 46462306a36Sopenharmony_ci if (adc->variant->broken_ratiometric && !force_ratiometric) { 46562306a36Sopenharmony_ci /* 46662306a36Sopenharmony_ci * Apparently the PM8058 has some kind of bug which is 46762306a36Sopenharmony_ci * reflected in the vendor tree drivers/misc/pmix8058-xoadc.c 46862306a36Sopenharmony_ci * which just hardcodes the RSV selector to SEL1 (0x20) for 46962306a36Sopenharmony_ci * most cases and SEL0 (0x10) for the MUXOFF channel only. 47062306a36Sopenharmony_ci * If we force ratiometric (currently only done when attempting 47162306a36Sopenharmony_ci * to do ratiometric calibration) this doesn't seem to work 47262306a36Sopenharmony_ci * very well and I suspect ratiometric conversion is simply 47362306a36Sopenharmony_ci * broken or not supported on the PM8058. 47462306a36Sopenharmony_ci * 47562306a36Sopenharmony_ci * Maybe IO_SEL2 doesn't exist on PM8058 and bits 4 & 5 select 47662306a36Sopenharmony_ci * the mode alone. 47762306a36Sopenharmony_ci * 47862306a36Sopenharmony_ci * Some PM8058 register documentation would be nice to get 47962306a36Sopenharmony_ci * this right. 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_ci if (ch->hwchan->amux_channel == PM8XXX_CHANNEL_MUXOFF) 48262306a36Sopenharmony_ci rsvval = ADC_ARB_USRP_RSV_IP_SEL0; 48362306a36Sopenharmony_ci else 48462306a36Sopenharmony_ci rsvval = ADC_ARB_USRP_RSV_IP_SEL1; 48562306a36Sopenharmony_ci } else { 48662306a36Sopenharmony_ci if (rsv == 0xff) 48762306a36Sopenharmony_ci rsvval = (ch->amux_ip_rsv << ADC_RSV_IP_SEL_SHIFT) | 48862306a36Sopenharmony_ci ADC_ARB_USRP_RSV_TRM; 48962306a36Sopenharmony_ci else 49062306a36Sopenharmony_ci rsvval = (rsv << ADC_RSV_IP_SEL_SHIFT) | 49162306a36Sopenharmony_ci ADC_ARB_USRP_RSV_TRM; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci ret = regmap_update_bits(adc->map, 49562306a36Sopenharmony_ci ADC_ARB_USRP_RSV, 49662306a36Sopenharmony_ci ~rsvmask, 49762306a36Sopenharmony_ci rsvval); 49862306a36Sopenharmony_ci if (ret) 49962306a36Sopenharmony_ci goto unlock; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci ret = regmap_write(adc->map, ADC_ARB_USRP_ANA_PARAM, 50262306a36Sopenharmony_ci ADC_ARB_USRP_ANA_PARAM_DIS); 50362306a36Sopenharmony_ci if (ret) 50462306a36Sopenharmony_ci goto unlock; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* Decimation factor */ 50762306a36Sopenharmony_ci ret = regmap_write(adc->map, ADC_ARB_USRP_DIG_PARAM, 50862306a36Sopenharmony_ci ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT0 | 50962306a36Sopenharmony_ci ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT1 | 51062306a36Sopenharmony_ci ch->decimation << ADC_DIG_PARAM_DEC_SHIFT); 51162306a36Sopenharmony_ci if (ret) 51262306a36Sopenharmony_ci goto unlock; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci ret = regmap_write(adc->map, ADC_ARB_USRP_ANA_PARAM, 51562306a36Sopenharmony_ci ADC_ARB_USRP_ANA_PARAM_EN); 51662306a36Sopenharmony_ci if (ret) 51762306a36Sopenharmony_ci goto unlock; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* Enable the arbiter, the Qualcomm code does it twice like this */ 52062306a36Sopenharmony_ci ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL, 52162306a36Sopenharmony_ci ADC_ARB_USRP_CNTRL_EN_ARB); 52262306a36Sopenharmony_ci if (ret) 52362306a36Sopenharmony_ci goto unlock; 52462306a36Sopenharmony_ci ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL, 52562306a36Sopenharmony_ci ADC_ARB_USRP_CNTRL_EN_ARB); 52662306a36Sopenharmony_ci if (ret) 52762306a36Sopenharmony_ci goto unlock; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* Fire a request! */ 53162306a36Sopenharmony_ci reinit_completion(&adc->complete); 53262306a36Sopenharmony_ci ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL, 53362306a36Sopenharmony_ci ADC_ARB_USRP_CNTRL_EN_ARB | 53462306a36Sopenharmony_ci ADC_ARB_USRP_CNTRL_REQ); 53562306a36Sopenharmony_ci if (ret) 53662306a36Sopenharmony_ci goto unlock; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* Next the interrupt occurs */ 53962306a36Sopenharmony_ci ret = wait_for_completion_timeout(&adc->complete, 54062306a36Sopenharmony_ci VADC_CONV_TIME_MAX_US); 54162306a36Sopenharmony_ci if (!ret) { 54262306a36Sopenharmony_ci dev_err(adc->dev, "conversion timed out\n"); 54362306a36Sopenharmony_ci ret = -ETIMEDOUT; 54462306a36Sopenharmony_ci goto unlock; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci ret = regmap_read(adc->map, ADC_ARB_USRP_DATA0, &val); 54862306a36Sopenharmony_ci if (ret) 54962306a36Sopenharmony_ci goto unlock; 55062306a36Sopenharmony_ci lsb = val; 55162306a36Sopenharmony_ci ret = regmap_read(adc->map, ADC_ARB_USRP_DATA1, &val); 55262306a36Sopenharmony_ci if (ret) 55362306a36Sopenharmony_ci goto unlock; 55462306a36Sopenharmony_ci msb = val; 55562306a36Sopenharmony_ci *adc_code = (msb << 8) | lsb; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* Turn off the ADC by setting the arbiter to 0 twice */ 55862306a36Sopenharmony_ci ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL, 0); 55962306a36Sopenharmony_ci if (ret) 56062306a36Sopenharmony_ci goto unlock; 56162306a36Sopenharmony_ci ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL, 0); 56262306a36Sopenharmony_ci if (ret) 56362306a36Sopenharmony_ci goto unlock; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ciunlock: 56662306a36Sopenharmony_ci mutex_unlock(&adc->lock); 56762306a36Sopenharmony_ci return ret; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int pm8xxx_read_channel(struct pm8xxx_xoadc *adc, 57162306a36Sopenharmony_ci const struct pm8xxx_chan_info *ch, 57262306a36Sopenharmony_ci u16 *adc_code) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci /* 57562306a36Sopenharmony_ci * Normally we just use the ratiometric scale value (RSV) predefined 57662306a36Sopenharmony_ci * for the channel, but during calibration we need to modify this 57762306a36Sopenharmony_ci * so this wrapper is a helper hiding the more complex version. 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_ci return pm8xxx_read_channel_rsv(adc, ch, 0xff, adc_code, false); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic int pm8xxx_calibrate_device(struct pm8xxx_xoadc *adc) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci const struct pm8xxx_chan_info *ch; 58562306a36Sopenharmony_ci u16 read_1250v; 58662306a36Sopenharmony_ci u16 read_0625v; 58762306a36Sopenharmony_ci u16 read_nomux_rsv5; 58862306a36Sopenharmony_ci u16 read_nomux_rsv4; 58962306a36Sopenharmony_ci int ret; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci adc->graph[VADC_CALIB_ABSOLUTE].dx = VADC_ABSOLUTE_RANGE_UV; 59262306a36Sopenharmony_ci adc->graph[VADC_CALIB_RATIOMETRIC].dx = VADC_RATIOMETRIC_RANGE; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* Common reference channel calibration */ 59562306a36Sopenharmony_ci ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_125V); 59662306a36Sopenharmony_ci if (!ch) 59762306a36Sopenharmony_ci return -ENODEV; 59862306a36Sopenharmony_ci ret = pm8xxx_read_channel(adc, ch, &read_1250v); 59962306a36Sopenharmony_ci if (ret) { 60062306a36Sopenharmony_ci dev_err(adc->dev, "could not read 1.25V reference channel\n"); 60162306a36Sopenharmony_ci return -ENODEV; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_INTERNAL); 60462306a36Sopenharmony_ci if (!ch) 60562306a36Sopenharmony_ci return -ENODEV; 60662306a36Sopenharmony_ci ret = pm8xxx_read_channel(adc, ch, &read_0625v); 60762306a36Sopenharmony_ci if (ret) { 60862306a36Sopenharmony_ci dev_err(adc->dev, "could not read 0.625V reference channel\n"); 60962306a36Sopenharmony_ci return -ENODEV; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci if (read_1250v == read_0625v) { 61262306a36Sopenharmony_ci dev_err(adc->dev, "read same ADC code for 1.25V and 0.625V\n"); 61362306a36Sopenharmony_ci return -ENODEV; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci adc->graph[VADC_CALIB_ABSOLUTE].dy = read_1250v - read_0625v; 61762306a36Sopenharmony_ci adc->graph[VADC_CALIB_ABSOLUTE].gnd = read_0625v; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci dev_info(adc->dev, "absolute calibration dx = %d uV, dy = %d units\n", 62062306a36Sopenharmony_ci VADC_ABSOLUTE_RANGE_UV, adc->graph[VADC_CALIB_ABSOLUTE].dy); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* Ratiometric calibration */ 62362306a36Sopenharmony_ci ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_MUXOFF); 62462306a36Sopenharmony_ci if (!ch) 62562306a36Sopenharmony_ci return -ENODEV; 62662306a36Sopenharmony_ci ret = pm8xxx_read_channel_rsv(adc, ch, AMUX_RSV5, 62762306a36Sopenharmony_ci &read_nomux_rsv5, true); 62862306a36Sopenharmony_ci if (ret) { 62962306a36Sopenharmony_ci dev_err(adc->dev, "could not read MUXOFF reference channel\n"); 63062306a36Sopenharmony_ci return -ENODEV; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci ret = pm8xxx_read_channel_rsv(adc, ch, AMUX_RSV4, 63362306a36Sopenharmony_ci &read_nomux_rsv4, true); 63462306a36Sopenharmony_ci if (ret) { 63562306a36Sopenharmony_ci dev_err(adc->dev, "could not read MUXOFF reference channel\n"); 63662306a36Sopenharmony_ci return -ENODEV; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci adc->graph[VADC_CALIB_RATIOMETRIC].dy = 63962306a36Sopenharmony_ci read_nomux_rsv5 - read_nomux_rsv4; 64062306a36Sopenharmony_ci adc->graph[VADC_CALIB_RATIOMETRIC].gnd = read_nomux_rsv4; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci dev_info(adc->dev, "ratiometric calibration dx = %d, dy = %d units\n", 64362306a36Sopenharmony_ci VADC_RATIOMETRIC_RANGE, 64462306a36Sopenharmony_ci adc->graph[VADC_CALIB_RATIOMETRIC].dy); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return 0; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int pm8xxx_read_raw(struct iio_dev *indio_dev, 65062306a36Sopenharmony_ci struct iio_chan_spec const *chan, 65162306a36Sopenharmony_ci int *val, int *val2, long mask) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct pm8xxx_xoadc *adc = iio_priv(indio_dev); 65462306a36Sopenharmony_ci const struct pm8xxx_chan_info *ch; 65562306a36Sopenharmony_ci u16 adc_code; 65662306a36Sopenharmony_ci int ret; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci switch (mask) { 65962306a36Sopenharmony_ci case IIO_CHAN_INFO_PROCESSED: 66062306a36Sopenharmony_ci ch = pm8xxx_get_channel(adc, chan->address); 66162306a36Sopenharmony_ci if (!ch) { 66262306a36Sopenharmony_ci dev_err(adc->dev, "no such channel %lu\n", 66362306a36Sopenharmony_ci chan->address); 66462306a36Sopenharmony_ci return -EINVAL; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci ret = pm8xxx_read_channel(adc, ch, &adc_code); 66762306a36Sopenharmony_ci if (ret) 66862306a36Sopenharmony_ci return ret; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci ret = qcom_vadc_scale(ch->hwchan->scale_fn_type, 67162306a36Sopenharmony_ci &adc->graph[ch->calibration], 67262306a36Sopenharmony_ci &ch->hwchan->prescale, 67362306a36Sopenharmony_ci (ch->calibration == VADC_CALIB_ABSOLUTE), 67462306a36Sopenharmony_ci adc_code, val); 67562306a36Sopenharmony_ci if (ret) 67662306a36Sopenharmony_ci return ret; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return IIO_VAL_INT; 67962306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 68062306a36Sopenharmony_ci ch = pm8xxx_get_channel(adc, chan->address); 68162306a36Sopenharmony_ci if (!ch) { 68262306a36Sopenharmony_ci dev_err(adc->dev, "no such channel %lu\n", 68362306a36Sopenharmony_ci chan->address); 68462306a36Sopenharmony_ci return -EINVAL; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci ret = pm8xxx_read_channel(adc, ch, &adc_code); 68762306a36Sopenharmony_ci if (ret) 68862306a36Sopenharmony_ci return ret; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci *val = (int)adc_code; 69162306a36Sopenharmony_ci return IIO_VAL_INT; 69262306a36Sopenharmony_ci default: 69362306a36Sopenharmony_ci return -EINVAL; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic int pm8xxx_fwnode_xlate(struct iio_dev *indio_dev, 69862306a36Sopenharmony_ci const struct fwnode_reference_args *iiospec) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct pm8xxx_xoadc *adc = iio_priv(indio_dev); 70162306a36Sopenharmony_ci u8 pre_scale_mux; 70262306a36Sopenharmony_ci u8 amux_channel; 70362306a36Sopenharmony_ci unsigned int i; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* 70662306a36Sopenharmony_ci * First cell is prescaler or premux, second cell is analog 70762306a36Sopenharmony_ci * mux. 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_ci if (iiospec->nargs != 2) { 71062306a36Sopenharmony_ci dev_err(&indio_dev->dev, "wrong number of arguments for %pfwP need 2 got %d\n", 71162306a36Sopenharmony_ci iiospec->fwnode, 71262306a36Sopenharmony_ci iiospec->nargs); 71362306a36Sopenharmony_ci return -EINVAL; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci pre_scale_mux = (u8)iiospec->args[0]; 71662306a36Sopenharmony_ci amux_channel = (u8)iiospec->args[1]; 71762306a36Sopenharmony_ci dev_dbg(&indio_dev->dev, "pre scale/mux: %02x, amux: %02x\n", 71862306a36Sopenharmony_ci pre_scale_mux, amux_channel); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* We need to match exactly on the prescale/premux and channel */ 72162306a36Sopenharmony_ci for (i = 0; i < adc->nchans; i++) 72262306a36Sopenharmony_ci if (adc->chans[i].hwchan->pre_scale_mux == pre_scale_mux && 72362306a36Sopenharmony_ci adc->chans[i].hwchan->amux_channel == amux_channel) 72462306a36Sopenharmony_ci return i; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci return -EINVAL; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic const struct iio_info pm8xxx_xoadc_info = { 73062306a36Sopenharmony_ci .fwnode_xlate = pm8xxx_fwnode_xlate, 73162306a36Sopenharmony_ci .read_raw = pm8xxx_read_raw, 73262306a36Sopenharmony_ci}; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic int pm8xxx_xoadc_parse_channel(struct device *dev, 73562306a36Sopenharmony_ci struct fwnode_handle *fwnode, 73662306a36Sopenharmony_ci const struct xoadc_channel *hw_channels, 73762306a36Sopenharmony_ci struct iio_chan_spec *iio_chan, 73862306a36Sopenharmony_ci struct pm8xxx_chan_info *ch) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci const char *name = fwnode_get_name(fwnode); 74162306a36Sopenharmony_ci const struct xoadc_channel *hwchan; 74262306a36Sopenharmony_ci u32 pre_scale_mux, amux_channel, reg[2]; 74362306a36Sopenharmony_ci u32 rsv, dec; 74462306a36Sopenharmony_ci int ret; 74562306a36Sopenharmony_ci int chid; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci ret = fwnode_property_read_u32_array(fwnode, "reg", reg, 74862306a36Sopenharmony_ci ARRAY_SIZE(reg)); 74962306a36Sopenharmony_ci if (ret) { 75062306a36Sopenharmony_ci dev_err(dev, "invalid pre scale/mux or amux channel number %s\n", 75162306a36Sopenharmony_ci name); 75262306a36Sopenharmony_ci return ret; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci pre_scale_mux = reg[0]; 75662306a36Sopenharmony_ci amux_channel = reg[1]; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* Find the right channel setting */ 75962306a36Sopenharmony_ci chid = 0; 76062306a36Sopenharmony_ci hwchan = &hw_channels[0]; 76162306a36Sopenharmony_ci while (hwchan->datasheet_name) { 76262306a36Sopenharmony_ci if (hwchan->pre_scale_mux == pre_scale_mux && 76362306a36Sopenharmony_ci hwchan->amux_channel == amux_channel) 76462306a36Sopenharmony_ci break; 76562306a36Sopenharmony_ci hwchan++; 76662306a36Sopenharmony_ci chid++; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci /* The sentinel does not have a name assigned */ 76962306a36Sopenharmony_ci if (!hwchan->datasheet_name) { 77062306a36Sopenharmony_ci dev_err(dev, "could not locate channel %02x/%02x\n", 77162306a36Sopenharmony_ci pre_scale_mux, amux_channel); 77262306a36Sopenharmony_ci return -EINVAL; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci ch->name = name; 77562306a36Sopenharmony_ci ch->hwchan = hwchan; 77662306a36Sopenharmony_ci /* Everyone seems to use absolute calibration except in special cases */ 77762306a36Sopenharmony_ci ch->calibration = VADC_CALIB_ABSOLUTE; 77862306a36Sopenharmony_ci /* Everyone seems to use default ("type 2") decimation */ 77962306a36Sopenharmony_ci ch->decimation = VADC_DEF_DECIMATION; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (!fwnode_property_read_u32(fwnode, "qcom,ratiometric", &rsv)) { 78262306a36Sopenharmony_ci ch->calibration = VADC_CALIB_RATIOMETRIC; 78362306a36Sopenharmony_ci if (rsv > XOADC_RSV_MAX) { 78462306a36Sopenharmony_ci dev_err(dev, "%s too large RSV value %d\n", name, rsv); 78562306a36Sopenharmony_ci return -EINVAL; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci if (rsv == AMUX_RSV3) { 78862306a36Sopenharmony_ci dev_err(dev, "%s invalid RSV value %d\n", name, rsv); 78962306a36Sopenharmony_ci return -EINVAL; 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* Optional decimation, if omitted we use the default */ 79462306a36Sopenharmony_ci ret = fwnode_property_read_u32(fwnode, "qcom,decimation", &dec); 79562306a36Sopenharmony_ci if (!ret) { 79662306a36Sopenharmony_ci ret = qcom_vadc_decimation_from_dt(dec); 79762306a36Sopenharmony_ci if (ret < 0) { 79862306a36Sopenharmony_ci dev_err(dev, "%s invalid decimation %d\n", 79962306a36Sopenharmony_ci name, dec); 80062306a36Sopenharmony_ci return ret; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci ch->decimation = ret; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci iio_chan->channel = chid; 80662306a36Sopenharmony_ci iio_chan->address = hwchan->amux_channel; 80762306a36Sopenharmony_ci iio_chan->datasheet_name = hwchan->datasheet_name; 80862306a36Sopenharmony_ci iio_chan->type = hwchan->type; 80962306a36Sopenharmony_ci /* All channels are raw or processed */ 81062306a36Sopenharmony_ci iio_chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 81162306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_PROCESSED); 81262306a36Sopenharmony_ci iio_chan->indexed = 1; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci dev_dbg(dev, 81562306a36Sopenharmony_ci "channel [PRESCALE/MUX: %02x AMUX: %02x] \"%s\" ref voltage: %d, decimation %d prescale %d/%d, scale function %d\n", 81662306a36Sopenharmony_ci hwchan->pre_scale_mux, hwchan->amux_channel, ch->name, 81762306a36Sopenharmony_ci ch->amux_ip_rsv, ch->decimation, hwchan->prescale.numerator, 81862306a36Sopenharmony_ci hwchan->prescale.denominator, hwchan->scale_fn_type); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci return 0; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct fwnode_handle *child; 82662306a36Sopenharmony_ci struct pm8xxx_chan_info *ch; 82762306a36Sopenharmony_ci int ret; 82862306a36Sopenharmony_ci int i; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci adc->nchans = device_get_child_node_count(adc->dev); 83162306a36Sopenharmony_ci if (!adc->nchans) { 83262306a36Sopenharmony_ci dev_err(adc->dev, "no channel children\n"); 83362306a36Sopenharmony_ci return -ENODEV; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci dev_dbg(adc->dev, "found %d ADC channels\n", adc->nchans); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci adc->iio_chans = devm_kcalloc(adc->dev, adc->nchans, 83862306a36Sopenharmony_ci sizeof(*adc->iio_chans), GFP_KERNEL); 83962306a36Sopenharmony_ci if (!adc->iio_chans) 84062306a36Sopenharmony_ci return -ENOMEM; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci adc->chans = devm_kcalloc(adc->dev, adc->nchans, 84362306a36Sopenharmony_ci sizeof(*adc->chans), GFP_KERNEL); 84462306a36Sopenharmony_ci if (!adc->chans) 84562306a36Sopenharmony_ci return -ENOMEM; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci i = 0; 84862306a36Sopenharmony_ci device_for_each_child_node(adc->dev, child) { 84962306a36Sopenharmony_ci ch = &adc->chans[i]; 85062306a36Sopenharmony_ci ret = pm8xxx_xoadc_parse_channel(adc->dev, child, 85162306a36Sopenharmony_ci adc->variant->channels, 85262306a36Sopenharmony_ci &adc->iio_chans[i], 85362306a36Sopenharmony_ci ch); 85462306a36Sopenharmony_ci if (ret) { 85562306a36Sopenharmony_ci fwnode_handle_put(child); 85662306a36Sopenharmony_ci return ret; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci i++; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* Check for required channels */ 86262306a36Sopenharmony_ci ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_125V); 86362306a36Sopenharmony_ci if (!ch) { 86462306a36Sopenharmony_ci dev_err(adc->dev, "missing 1.25V reference channel\n"); 86562306a36Sopenharmony_ci return -ENODEV; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_INTERNAL); 86862306a36Sopenharmony_ci if (!ch) { 86962306a36Sopenharmony_ci dev_err(adc->dev, "missing 0.625V reference channel\n"); 87062306a36Sopenharmony_ci return -ENODEV; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_MUXOFF); 87362306a36Sopenharmony_ci if (!ch) { 87462306a36Sopenharmony_ci dev_err(adc->dev, "missing MUXOFF reference channel\n"); 87562306a36Sopenharmony_ci return -ENODEV; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic int pm8xxx_xoadc_probe(struct platform_device *pdev) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci const struct xoadc_variant *variant; 88462306a36Sopenharmony_ci struct pm8xxx_xoadc *adc; 88562306a36Sopenharmony_ci struct iio_dev *indio_dev; 88662306a36Sopenharmony_ci struct regmap *map; 88762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 88862306a36Sopenharmony_ci int ret; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci variant = device_get_match_data(dev); 89162306a36Sopenharmony_ci if (!variant) 89262306a36Sopenharmony_ci return -ENODEV; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); 89562306a36Sopenharmony_ci if (!indio_dev) 89662306a36Sopenharmony_ci return -ENOMEM; 89762306a36Sopenharmony_ci platform_set_drvdata(pdev, indio_dev); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci adc = iio_priv(indio_dev); 90062306a36Sopenharmony_ci adc->dev = dev; 90162306a36Sopenharmony_ci adc->variant = variant; 90262306a36Sopenharmony_ci init_completion(&adc->complete); 90362306a36Sopenharmony_ci mutex_init(&adc->lock); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci ret = pm8xxx_xoadc_parse_channels(adc); 90662306a36Sopenharmony_ci if (ret) 90762306a36Sopenharmony_ci return ret; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci map = dev_get_regmap(dev->parent, NULL); 91062306a36Sopenharmony_ci if (!map) { 91162306a36Sopenharmony_ci dev_err(dev, "parent regmap unavailable.\n"); 91262306a36Sopenharmony_ci return -ENODEV; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci adc->map = map; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* Bring up regulator */ 91762306a36Sopenharmony_ci adc->vref = devm_regulator_get(dev, "xoadc-ref"); 91862306a36Sopenharmony_ci if (IS_ERR(adc->vref)) 91962306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(adc->vref), 92062306a36Sopenharmony_ci "failed to get XOADC VREF regulator\n"); 92162306a36Sopenharmony_ci ret = regulator_enable(adc->vref); 92262306a36Sopenharmony_ci if (ret) { 92362306a36Sopenharmony_ci dev_err(dev, "failed to enable XOADC VREF regulator\n"); 92462306a36Sopenharmony_ci return ret; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), 92862306a36Sopenharmony_ci pm8xxx_eoc_irq, NULL, 0, variant->name, indio_dev); 92962306a36Sopenharmony_ci if (ret) { 93062306a36Sopenharmony_ci dev_err(dev, "unable to request IRQ\n"); 93162306a36Sopenharmony_ci goto out_disable_vref; 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci indio_dev->name = variant->name; 93562306a36Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 93662306a36Sopenharmony_ci indio_dev->info = &pm8xxx_xoadc_info; 93762306a36Sopenharmony_ci indio_dev->channels = adc->iio_chans; 93862306a36Sopenharmony_ci indio_dev->num_channels = adc->nchans; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci ret = iio_device_register(indio_dev); 94162306a36Sopenharmony_ci if (ret) 94262306a36Sopenharmony_ci goto out_disable_vref; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci ret = pm8xxx_calibrate_device(adc); 94562306a36Sopenharmony_ci if (ret) 94662306a36Sopenharmony_ci goto out_unreg_device; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci dev_info(dev, "%s XOADC driver enabled\n", variant->name); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci return 0; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ciout_unreg_device: 95362306a36Sopenharmony_ci iio_device_unregister(indio_dev); 95462306a36Sopenharmony_ciout_disable_vref: 95562306a36Sopenharmony_ci regulator_disable(adc->vref); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return ret; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic int pm8xxx_xoadc_remove(struct platform_device *pdev) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci struct iio_dev *indio_dev = platform_get_drvdata(pdev); 96362306a36Sopenharmony_ci struct pm8xxx_xoadc *adc = iio_priv(indio_dev); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci iio_device_unregister(indio_dev); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci regulator_disable(adc->vref); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci return 0; 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistatic const struct xoadc_variant pm8018_variant = { 97362306a36Sopenharmony_ci .name = "PM8018-XOADC", 97462306a36Sopenharmony_ci .channels = pm8018_xoadc_channels, 97562306a36Sopenharmony_ci}; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic const struct xoadc_variant pm8038_variant = { 97862306a36Sopenharmony_ci .name = "PM8038-XOADC", 97962306a36Sopenharmony_ci .channels = pm8038_xoadc_channels, 98062306a36Sopenharmony_ci}; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic const struct xoadc_variant pm8058_variant = { 98362306a36Sopenharmony_ci .name = "PM8058-XOADC", 98462306a36Sopenharmony_ci .channels = pm8058_xoadc_channels, 98562306a36Sopenharmony_ci .broken_ratiometric = true, 98662306a36Sopenharmony_ci .prescaling = true, 98762306a36Sopenharmony_ci}; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic const struct xoadc_variant pm8921_variant = { 99062306a36Sopenharmony_ci .name = "PM8921-XOADC", 99162306a36Sopenharmony_ci .channels = pm8921_xoadc_channels, 99262306a36Sopenharmony_ci .second_level_mux = true, 99362306a36Sopenharmony_ci}; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_cistatic const struct of_device_id pm8xxx_xoadc_id_table[] = { 99662306a36Sopenharmony_ci { 99762306a36Sopenharmony_ci .compatible = "qcom,pm8018-adc", 99862306a36Sopenharmony_ci .data = &pm8018_variant, 99962306a36Sopenharmony_ci }, 100062306a36Sopenharmony_ci { 100162306a36Sopenharmony_ci .compatible = "qcom,pm8038-adc", 100262306a36Sopenharmony_ci .data = &pm8038_variant, 100362306a36Sopenharmony_ci }, 100462306a36Sopenharmony_ci { 100562306a36Sopenharmony_ci .compatible = "qcom,pm8058-adc", 100662306a36Sopenharmony_ci .data = &pm8058_variant, 100762306a36Sopenharmony_ci }, 100862306a36Sopenharmony_ci { 100962306a36Sopenharmony_ci .compatible = "qcom,pm8921-adc", 101062306a36Sopenharmony_ci .data = &pm8921_variant, 101162306a36Sopenharmony_ci }, 101262306a36Sopenharmony_ci { }, 101362306a36Sopenharmony_ci}; 101462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pm8xxx_xoadc_id_table); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_cistatic struct platform_driver pm8xxx_xoadc_driver = { 101762306a36Sopenharmony_ci .driver = { 101862306a36Sopenharmony_ci .name = "pm8xxx-adc", 101962306a36Sopenharmony_ci .of_match_table = pm8xxx_xoadc_id_table, 102062306a36Sopenharmony_ci }, 102162306a36Sopenharmony_ci .probe = pm8xxx_xoadc_probe, 102262306a36Sopenharmony_ci .remove = pm8xxx_xoadc_remove, 102362306a36Sopenharmony_ci}; 102462306a36Sopenharmony_cimodule_platform_driver(pm8xxx_xoadc_driver); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ciMODULE_DESCRIPTION("PM8xxx XOADC driver"); 102762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 102862306a36Sopenharmony_ciMODULE_ALIAS("platform:pm8xxx-xoadc"); 1029