172c7df85SCaleb Connolly // SPDX-License-Identifier: GPL-2.0-only
272c7df85SCaleb Connolly /*
372c7df85SCaleb Connolly  * Copyright (c) 2016-2017, 2019, The Linux Foundation. All rights reserved.
472c7df85SCaleb Connolly  * Copyright (c) 2022 Linaro Limited.
572c7df85SCaleb Connolly  *  Author: Caleb Connolly <caleb.connolly@linaro.org>
672c7df85SCaleb Connolly  *
772c7df85SCaleb Connolly  * This driver is for the Round Robin ADC found in the pmi8998 and pm660 PMICs.
872c7df85SCaleb Connolly  */
972c7df85SCaleb Connolly 
1072c7df85SCaleb Connolly #include <linux/bitfield.h>
1172c7df85SCaleb Connolly #include <linux/delay.h>
1272c7df85SCaleb Connolly #include <linux/kernel.h>
1372c7df85SCaleb Connolly #include <linux/math64.h>
1472c7df85SCaleb Connolly #include <linux/module.h>
1572c7df85SCaleb Connolly #include <linux/mod_devicetable.h>
1672c7df85SCaleb Connolly #include <linux/platform_device.h>
1772c7df85SCaleb Connolly #include <linux/property.h>
1872c7df85SCaleb Connolly #include <linux/regmap.h>
1972c7df85SCaleb Connolly #include <linux/spmi.h>
2072c7df85SCaleb Connolly #include <linux/types.h>
2172c7df85SCaleb Connolly #include <linux/units.h>
2272c7df85SCaleb Connolly 
2372c7df85SCaleb Connolly #include <asm/unaligned.h>
2472c7df85SCaleb Connolly 
2572c7df85SCaleb Connolly #include <linux/iio/iio.h>
2672c7df85SCaleb Connolly #include <linux/iio/types.h>
2772c7df85SCaleb Connolly 
2872c7df85SCaleb Connolly #include <soc/qcom/qcom-spmi-pmic.h>
2972c7df85SCaleb Connolly 
3072c7df85SCaleb Connolly #define DRIVER_NAME "qcom-spmi-rradc"
3172c7df85SCaleb Connolly 
3272c7df85SCaleb Connolly #define RR_ADC_EN_CTL 0x46
3372c7df85SCaleb Connolly #define RR_ADC_SKIN_TEMP_LSB 0x50
3472c7df85SCaleb Connolly #define RR_ADC_SKIN_TEMP_MSB 0x51
3572c7df85SCaleb Connolly #define RR_ADC_CTL 0x52
3672c7df85SCaleb Connolly #define RR_ADC_CTL_CONTINUOUS_SEL BIT(3)
3772c7df85SCaleb Connolly #define RR_ADC_LOG 0x53
3872c7df85SCaleb Connolly #define RR_ADC_LOG_CLR_CTRL BIT(0)
3972c7df85SCaleb Connolly 
4072c7df85SCaleb Connolly #define RR_ADC_FAKE_BATT_LOW_LSB 0x58
4172c7df85SCaleb Connolly #define RR_ADC_FAKE_BATT_LOW_MSB 0x59
4272c7df85SCaleb Connolly #define RR_ADC_FAKE_BATT_HIGH_LSB 0x5A
4372c7df85SCaleb Connolly #define RR_ADC_FAKE_BATT_HIGH_MSB 0x5B
4472c7df85SCaleb Connolly 
4572c7df85SCaleb Connolly #define RR_ADC_BATT_ID_CTRL 0x60
4672c7df85SCaleb Connolly #define RR_ADC_BATT_ID_CTRL_CHANNEL_CONV BIT(0)
4772c7df85SCaleb Connolly #define RR_ADC_BATT_ID_TRIGGER 0x61
4872c7df85SCaleb Connolly #define RR_ADC_BATT_ID_STS 0x62
4972c7df85SCaleb Connolly #define RR_ADC_BATT_ID_CFG 0x63
5072c7df85SCaleb Connolly #define BATT_ID_SETTLE_MASK GENMASK(7, 5)
5172c7df85SCaleb Connolly #define RR_ADC_BATT_ID_5_LSB 0x66
5272c7df85SCaleb Connolly #define RR_ADC_BATT_ID_5_MSB 0x67
5372c7df85SCaleb Connolly #define RR_ADC_BATT_ID_15_LSB 0x68
5472c7df85SCaleb Connolly #define RR_ADC_BATT_ID_15_MSB 0x69
5572c7df85SCaleb Connolly #define RR_ADC_BATT_ID_150_LSB 0x6A
5672c7df85SCaleb Connolly #define RR_ADC_BATT_ID_150_MSB 0x6B
5772c7df85SCaleb Connolly 
5872c7df85SCaleb Connolly #define RR_ADC_BATT_THERM_CTRL 0x70
5972c7df85SCaleb Connolly #define RR_ADC_BATT_THERM_TRIGGER 0x71
6072c7df85SCaleb Connolly #define RR_ADC_BATT_THERM_STS 0x72
6172c7df85SCaleb Connolly #define RR_ADC_BATT_THERM_CFG 0x73
6272c7df85SCaleb Connolly #define RR_ADC_BATT_THERM_LSB 0x74
6372c7df85SCaleb Connolly #define RR_ADC_BATT_THERM_MSB 0x75
6472c7df85SCaleb Connolly #define RR_ADC_BATT_THERM_FREQ 0x76
6572c7df85SCaleb Connolly 
6672c7df85SCaleb Connolly #define RR_ADC_AUX_THERM_CTRL 0x80
6772c7df85SCaleb Connolly #define RR_ADC_AUX_THERM_TRIGGER 0x81
6872c7df85SCaleb Connolly #define RR_ADC_AUX_THERM_STS 0x82
6972c7df85SCaleb Connolly #define RR_ADC_AUX_THERM_CFG 0x83
7072c7df85SCaleb Connolly #define RR_ADC_AUX_THERM_LSB 0x84
7172c7df85SCaleb Connolly #define RR_ADC_AUX_THERM_MSB 0x85
7272c7df85SCaleb Connolly 
7372c7df85SCaleb Connolly #define RR_ADC_SKIN_HOT 0x86
7472c7df85SCaleb Connolly #define RR_ADC_SKIN_TOO_HOT 0x87
7572c7df85SCaleb Connolly 
7672c7df85SCaleb Connolly #define RR_ADC_AUX_THERM_C1 0x88
7772c7df85SCaleb Connolly #define RR_ADC_AUX_THERM_C2 0x89
7872c7df85SCaleb Connolly #define RR_ADC_AUX_THERM_C3 0x8A
7972c7df85SCaleb Connolly #define RR_ADC_AUX_THERM_HALF_RANGE 0x8B
8072c7df85SCaleb Connolly 
8172c7df85SCaleb Connolly #define RR_ADC_USB_IN_V_CTRL 0x90
8272c7df85SCaleb Connolly #define RR_ADC_USB_IN_V_TRIGGER 0x91
8372c7df85SCaleb Connolly #define RR_ADC_USB_IN_V_STS 0x92
8472c7df85SCaleb Connolly #define RR_ADC_USB_IN_V_LSB 0x94
8572c7df85SCaleb Connolly #define RR_ADC_USB_IN_V_MSB 0x95
8672c7df85SCaleb Connolly #define RR_ADC_USB_IN_I_CTRL 0x98
8772c7df85SCaleb Connolly #define RR_ADC_USB_IN_I_TRIGGER 0x99
8872c7df85SCaleb Connolly #define RR_ADC_USB_IN_I_STS 0x9A
8972c7df85SCaleb Connolly #define RR_ADC_USB_IN_I_LSB 0x9C
9072c7df85SCaleb Connolly #define RR_ADC_USB_IN_I_MSB 0x9D
9172c7df85SCaleb Connolly 
9272c7df85SCaleb Connolly #define RR_ADC_DC_IN_V_CTRL 0xA0
9372c7df85SCaleb Connolly #define RR_ADC_DC_IN_V_TRIGGER 0xA1
9472c7df85SCaleb Connolly #define RR_ADC_DC_IN_V_STS 0xA2
9572c7df85SCaleb Connolly #define RR_ADC_DC_IN_V_LSB 0xA4
9672c7df85SCaleb Connolly #define RR_ADC_DC_IN_V_MSB 0xA5
9772c7df85SCaleb Connolly #define RR_ADC_DC_IN_I_CTRL 0xA8
9872c7df85SCaleb Connolly #define RR_ADC_DC_IN_I_TRIGGER 0xA9
9972c7df85SCaleb Connolly #define RR_ADC_DC_IN_I_STS 0xAA
10072c7df85SCaleb Connolly #define RR_ADC_DC_IN_I_LSB 0xAC
10172c7df85SCaleb Connolly #define RR_ADC_DC_IN_I_MSB 0xAD
10272c7df85SCaleb Connolly 
10372c7df85SCaleb Connolly #define RR_ADC_PMI_DIE_TEMP_CTRL 0xB0
10472c7df85SCaleb Connolly #define RR_ADC_PMI_DIE_TEMP_TRIGGER 0xB1
10572c7df85SCaleb Connolly #define RR_ADC_PMI_DIE_TEMP_STS 0xB2
10672c7df85SCaleb Connolly #define RR_ADC_PMI_DIE_TEMP_CFG 0xB3
10772c7df85SCaleb Connolly #define RR_ADC_PMI_DIE_TEMP_LSB 0xB4
10872c7df85SCaleb Connolly #define RR_ADC_PMI_DIE_TEMP_MSB 0xB5
10972c7df85SCaleb Connolly 
11072c7df85SCaleb Connolly #define RR_ADC_CHARGER_TEMP_CTRL 0xB8
11172c7df85SCaleb Connolly #define RR_ADC_CHARGER_TEMP_TRIGGER 0xB9
11272c7df85SCaleb Connolly #define RR_ADC_CHARGER_TEMP_STS 0xBA
11372c7df85SCaleb Connolly #define RR_ADC_CHARGER_TEMP_CFG 0xBB
11472c7df85SCaleb Connolly #define RR_ADC_CHARGER_TEMP_LSB 0xBC
11572c7df85SCaleb Connolly #define RR_ADC_CHARGER_TEMP_MSB 0xBD
11672c7df85SCaleb Connolly #define RR_ADC_CHARGER_HOT 0xBE
11772c7df85SCaleb Connolly #define RR_ADC_CHARGER_TOO_HOT 0xBF
11872c7df85SCaleb Connolly 
11972c7df85SCaleb Connolly #define RR_ADC_GPIO_CTRL 0xC0
12072c7df85SCaleb Connolly #define RR_ADC_GPIO_TRIGGER 0xC1
12172c7df85SCaleb Connolly #define RR_ADC_GPIO_STS 0xC2
12272c7df85SCaleb Connolly #define RR_ADC_GPIO_LSB 0xC4
12372c7df85SCaleb Connolly #define RR_ADC_GPIO_MSB 0xC5
12472c7df85SCaleb Connolly 
12572c7df85SCaleb Connolly #define RR_ADC_ATEST_CTRL 0xC8
12672c7df85SCaleb Connolly #define RR_ADC_ATEST_TRIGGER 0xC9
12772c7df85SCaleb Connolly #define RR_ADC_ATEST_STS 0xCA
12872c7df85SCaleb Connolly #define RR_ADC_ATEST_LSB 0xCC
12972c7df85SCaleb Connolly #define RR_ADC_ATEST_MSB 0xCD
13072c7df85SCaleb Connolly #define RR_ADC_SEC_ACCESS 0xD0
13172c7df85SCaleb Connolly 
13272c7df85SCaleb Connolly #define RR_ADC_PERPH_RESET_CTL2 0xD9
13372c7df85SCaleb Connolly #define RR_ADC_PERPH_RESET_CTL3 0xDA
13472c7df85SCaleb Connolly #define RR_ADC_PERPH_RESET_CTL4 0xDB
13572c7df85SCaleb Connolly #define RR_ADC_INT_TEST1 0xE0
13672c7df85SCaleb Connolly #define RR_ADC_INT_TEST_VAL 0xE1
13772c7df85SCaleb Connolly 
13872c7df85SCaleb Connolly #define RR_ADC_TM_TRIGGER_CTRLS 0xE2
13972c7df85SCaleb Connolly #define RR_ADC_TM_ADC_CTRLS 0xE3
14072c7df85SCaleb Connolly #define RR_ADC_TM_CNL_CTRL 0xE4
14172c7df85SCaleb Connolly #define RR_ADC_TM_BATT_ID_CTRL 0xE5
14272c7df85SCaleb Connolly #define RR_ADC_TM_THERM_CTRL 0xE6
14372c7df85SCaleb Connolly #define RR_ADC_TM_CONV_STS 0xE7
14472c7df85SCaleb Connolly #define RR_ADC_TM_ADC_READ_LSB 0xE8
14572c7df85SCaleb Connolly #define RR_ADC_TM_ADC_READ_MSB 0xE9
14672c7df85SCaleb Connolly #define RR_ADC_TM_ATEST_MUX_1 0xEA
14772c7df85SCaleb Connolly #define RR_ADC_TM_ATEST_MUX_2 0xEB
14872c7df85SCaleb Connolly #define RR_ADC_TM_REFERENCES 0xED
14972c7df85SCaleb Connolly #define RR_ADC_TM_MISC_CTL 0xEE
15072c7df85SCaleb Connolly #define RR_ADC_TM_RR_CTRL 0xEF
15172c7df85SCaleb Connolly 
15272c7df85SCaleb Connolly #define RR_ADC_TRIGGER_EVERY_CYCLE BIT(7)
15372c7df85SCaleb Connolly #define RR_ADC_TRIGGER_CTL BIT(0)
15472c7df85SCaleb Connolly 
15572c7df85SCaleb Connolly #define RR_ADC_BATT_ID_RANGE 820
15672c7df85SCaleb Connolly 
15772c7df85SCaleb Connolly #define RR_ADC_BITS 10
15872c7df85SCaleb Connolly #define RR_ADC_CHAN_MSB (1 << RR_ADC_BITS)
15972c7df85SCaleb Connolly #define RR_ADC_FS_VOLTAGE_MV 2500
16072c7df85SCaleb Connolly 
16172c7df85SCaleb Connolly /* BATT_THERM 0.25K/LSB */
16272c7df85SCaleb Connolly #define RR_ADC_BATT_THERM_LSB_K 4
16372c7df85SCaleb Connolly 
16472c7df85SCaleb Connolly #define RR_ADC_TEMP_FS_VOLTAGE_NUM 5000000
16572c7df85SCaleb Connolly #define RR_ADC_TEMP_FS_VOLTAGE_DEN 3
16672c7df85SCaleb Connolly #define RR_ADC_DIE_TEMP_OFFSET 601400
16772c7df85SCaleb Connolly #define RR_ADC_DIE_TEMP_SLOPE 2
16872c7df85SCaleb Connolly #define RR_ADC_DIE_TEMP_OFFSET_MILLI_DEGC 25000
16972c7df85SCaleb Connolly 
17072c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_GF_OFFSET_UV 1303168
17172c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_GF_SLOPE_UV_PER_C 3784
17272c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_SMIC_OFFSET_UV 1338433
17372c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_SMIC_SLOPE_UV_PER_C 3655
17472c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_660_GF_OFFSET_UV 1309001
17572c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_660_GF_SLOPE_UV_PER_C 3403
17672c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_660_SMIC_OFFSET_UV 1295898
17772c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_660_SMIC_SLOPE_UV_PER_C 3596
17872c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_660_MGNA_OFFSET_UV 1314779
17972c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_660_MGNA_SLOPE_UV_PER_C 3496
18072c7df85SCaleb Connolly #define RR_ADC_CHG_TEMP_OFFSET_MILLI_DEGC 25000
18172c7df85SCaleb Connolly #define RR_ADC_CHG_THRESHOLD_SCALE 4
18272c7df85SCaleb Connolly 
18372c7df85SCaleb Connolly #define RR_ADC_VOLT_INPUT_FACTOR 8
18472c7df85SCaleb Connolly #define RR_ADC_CURR_INPUT_FACTOR 2000
18572c7df85SCaleb Connolly #define RR_ADC_CURR_USBIN_INPUT_FACTOR_MIL 1886
18672c7df85SCaleb Connolly #define RR_ADC_CURR_USBIN_660_FACTOR_MIL 9
18772c7df85SCaleb Connolly #define RR_ADC_CURR_USBIN_660_UV_VAL 579500
18872c7df85SCaleb Connolly 
18972c7df85SCaleb Connolly #define RR_ADC_GPIO_FS_RANGE 5000
19072c7df85SCaleb Connolly #define RR_ADC_COHERENT_CHECK_RETRY 5
19172c7df85SCaleb Connolly #define RR_ADC_CHAN_MAX_CONTINUOUS_BUFFER_LEN 16
19272c7df85SCaleb Connolly 
19372c7df85SCaleb Connolly #define RR_ADC_STS_CHANNEL_READING_MASK GENMASK(1, 0)
19472c7df85SCaleb Connolly #define RR_ADC_STS_CHANNEL_STS BIT(1)
19572c7df85SCaleb Connolly 
19672c7df85SCaleb Connolly #define RR_ADC_TP_REV_VERSION1 21
19772c7df85SCaleb Connolly #define RR_ADC_TP_REV_VERSION2 29
19872c7df85SCaleb Connolly #define RR_ADC_TP_REV_VERSION3 32
19972c7df85SCaleb Connolly 
20072c7df85SCaleb Connolly #define RRADC_BATT_ID_DELAY_MAX 8
20172c7df85SCaleb Connolly 
20272c7df85SCaleb Connolly enum rradc_channel_id {
20372c7df85SCaleb Connolly 	RR_ADC_BATT_ID = 0,
20472c7df85SCaleb Connolly 	RR_ADC_BATT_THERM,
20572c7df85SCaleb Connolly 	RR_ADC_SKIN_TEMP,
20672c7df85SCaleb Connolly 	RR_ADC_USBIN_I,
20772c7df85SCaleb Connolly 	RR_ADC_USBIN_V,
20872c7df85SCaleb Connolly 	RR_ADC_DCIN_I,
20972c7df85SCaleb Connolly 	RR_ADC_DCIN_V,
21072c7df85SCaleb Connolly 	RR_ADC_DIE_TEMP,
21172c7df85SCaleb Connolly 	RR_ADC_CHG_TEMP,
21272c7df85SCaleb Connolly 	RR_ADC_GPIO,
21372c7df85SCaleb Connolly 	RR_ADC_CHAN_MAX
21472c7df85SCaleb Connolly };
21572c7df85SCaleb Connolly 
21672c7df85SCaleb Connolly struct rradc_chip;
21772c7df85SCaleb Connolly 
21872c7df85SCaleb Connolly /**
21972c7df85SCaleb Connolly  * struct rradc_channel - rradc channel data
22072c7df85SCaleb Connolly  * @label:		channel label
22172c7df85SCaleb Connolly  * @lsb:		Channel least significant byte
22272c7df85SCaleb Connolly  * @status:		Channel status address
22372c7df85SCaleb Connolly  * @size:		number of bytes to read
22472c7df85SCaleb Connolly  * @trigger_addr:	Trigger address, trigger is only used on some channels
22572c7df85SCaleb Connolly  * @trigger_mask:	Trigger mask
22672c7df85SCaleb Connolly  * @scale_fn:		Post process callback for channels which can't be exposed
22772c7df85SCaleb Connolly  *			as offset + scale.
22872c7df85SCaleb Connolly  */
22972c7df85SCaleb Connolly struct rradc_channel {
23072c7df85SCaleb Connolly 	const char *label;
23172c7df85SCaleb Connolly 	u8 lsb;
23272c7df85SCaleb Connolly 	u8 status;
23372c7df85SCaleb Connolly 	int size;
23472c7df85SCaleb Connolly 	int trigger_addr;
23572c7df85SCaleb Connolly 	int trigger_mask;
23672c7df85SCaleb Connolly 	int (*scale_fn)(struct rradc_chip *chip, u16 adc_code, int *result);
23772c7df85SCaleb Connolly };
23872c7df85SCaleb Connolly 
23972c7df85SCaleb Connolly struct rradc_chip {
24072c7df85SCaleb Connolly 	struct device *dev;
24172c7df85SCaleb Connolly 	const struct qcom_spmi_pmic *pmic;
24272c7df85SCaleb Connolly 	/*
24372c7df85SCaleb Connolly 	 * Lock held while doing channel conversion
24472c7df85SCaleb Connolly 	 * involving multiple register read/writes
24572c7df85SCaleb Connolly 	 */
24672c7df85SCaleb Connolly 	struct mutex conversion_lock;
24772c7df85SCaleb Connolly 	struct regmap *regmap;
24872c7df85SCaleb Connolly 	u32 base;
24972c7df85SCaleb Connolly 	int batt_id_delay;
25072c7df85SCaleb Connolly 	u16 batt_id_data;
25172c7df85SCaleb Connolly };
25272c7df85SCaleb Connolly 
25372c7df85SCaleb Connolly static const int batt_id_delays[] = { 0, 1, 4, 12, 20, 40, 60, 80 };
25472c7df85SCaleb Connolly static const struct rradc_channel rradc_chans[RR_ADC_CHAN_MAX];
25572c7df85SCaleb Connolly static const struct iio_chan_spec rradc_iio_chans[RR_ADC_CHAN_MAX];
25672c7df85SCaleb Connolly 
rradc_read(struct rradc_chip * chip,u16 addr,__le16 * buf,int len)25772c7df85SCaleb Connolly static int rradc_read(struct rradc_chip *chip, u16 addr, __le16 *buf, int len)
25872c7df85SCaleb Connolly {
25972c7df85SCaleb Connolly 	int ret, retry_cnt = 0;
26072c7df85SCaleb Connolly 	__le16 data_check[RR_ADC_CHAN_MAX_CONTINUOUS_BUFFER_LEN / 2];
26172c7df85SCaleb Connolly 
26272c7df85SCaleb Connolly 	if (len > RR_ADC_CHAN_MAX_CONTINUOUS_BUFFER_LEN) {
26372c7df85SCaleb Connolly 		dev_err(chip->dev,
26472c7df85SCaleb Connolly 			"Can't read more than %d bytes, but asked to read %d bytes.\n",
26572c7df85SCaleb Connolly 			RR_ADC_CHAN_MAX_CONTINUOUS_BUFFER_LEN, len);
26672c7df85SCaleb Connolly 		return -EINVAL;
26772c7df85SCaleb Connolly 	}
26872c7df85SCaleb Connolly 
26972c7df85SCaleb Connolly 	while (retry_cnt < RR_ADC_COHERENT_CHECK_RETRY) {
27072c7df85SCaleb Connolly 		ret = regmap_bulk_read(chip->regmap, chip->base + addr, buf,
27172c7df85SCaleb Connolly 				       len);
27272c7df85SCaleb Connolly 		if (ret < 0) {
27372c7df85SCaleb Connolly 			dev_err(chip->dev, "rr_adc reg 0x%x failed :%d\n", addr,
27472c7df85SCaleb Connolly 				ret);
27572c7df85SCaleb Connolly 			return ret;
27672c7df85SCaleb Connolly 		}
27772c7df85SCaleb Connolly 
27872c7df85SCaleb Connolly 		ret = regmap_bulk_read(chip->regmap, chip->base + addr,
27972c7df85SCaleb Connolly 				       data_check, len);
28072c7df85SCaleb Connolly 		if (ret < 0) {
28172c7df85SCaleb Connolly 			dev_err(chip->dev, "rr_adc reg 0x%x failed :%d\n", addr,
28272c7df85SCaleb Connolly 				ret);
28372c7df85SCaleb Connolly 			return ret;
28472c7df85SCaleb Connolly 		}
28572c7df85SCaleb Connolly 
28672c7df85SCaleb Connolly 		if (memcmp(buf, data_check, len) != 0) {
28772c7df85SCaleb Connolly 			retry_cnt++;
28872c7df85SCaleb Connolly 			dev_dbg(chip->dev,
28972c7df85SCaleb Connolly 				"coherent read error, retry_cnt:%d\n",
29072c7df85SCaleb Connolly 				retry_cnt);
29172c7df85SCaleb Connolly 			continue;
29272c7df85SCaleb Connolly 		}
29372c7df85SCaleb Connolly 
29472c7df85SCaleb Connolly 		break;
29572c7df85SCaleb Connolly 	}
29672c7df85SCaleb Connolly 
29772c7df85SCaleb Connolly 	if (retry_cnt == RR_ADC_COHERENT_CHECK_RETRY)
298*2a5bf05fSColin Ian King 		dev_err(chip->dev, "Retry exceeded for coherency check\n");
29972c7df85SCaleb Connolly 
30072c7df85SCaleb Connolly 	return ret;
30172c7df85SCaleb Connolly }
30272c7df85SCaleb Connolly 
rradc_get_fab_coeff(struct rradc_chip * chip,int64_t * offset,int64_t * slope)30372c7df85SCaleb Connolly static int rradc_get_fab_coeff(struct rradc_chip *chip, int64_t *offset,
30472c7df85SCaleb Connolly 			       int64_t *slope)
30572c7df85SCaleb Connolly {
30672c7df85SCaleb Connolly 	if (chip->pmic->subtype == PM660_SUBTYPE) {
30772c7df85SCaleb Connolly 		switch (chip->pmic->fab_id) {
30872c7df85SCaleb Connolly 		case PM660_FAB_ID_GF:
30972c7df85SCaleb Connolly 			*offset = RR_ADC_CHG_TEMP_660_GF_OFFSET_UV;
31072c7df85SCaleb Connolly 			*slope = RR_ADC_CHG_TEMP_660_GF_SLOPE_UV_PER_C;
31172c7df85SCaleb Connolly 			return 0;
31272c7df85SCaleb Connolly 		case PM660_FAB_ID_TSMC:
31372c7df85SCaleb Connolly 			*offset = RR_ADC_CHG_TEMP_660_SMIC_OFFSET_UV;
31472c7df85SCaleb Connolly 			*slope = RR_ADC_CHG_TEMP_660_SMIC_SLOPE_UV_PER_C;
31572c7df85SCaleb Connolly 			return 0;
31672c7df85SCaleb Connolly 		default:
31772c7df85SCaleb Connolly 			*offset = RR_ADC_CHG_TEMP_660_MGNA_OFFSET_UV;
31872c7df85SCaleb Connolly 			*slope = RR_ADC_CHG_TEMP_660_MGNA_SLOPE_UV_PER_C;
31972c7df85SCaleb Connolly 		}
32072c7df85SCaleb Connolly 	} else if (chip->pmic->subtype == PMI8998_SUBTYPE) {
32172c7df85SCaleb Connolly 		switch (chip->pmic->fab_id) {
32272c7df85SCaleb Connolly 		case PMI8998_FAB_ID_GF:
32372c7df85SCaleb Connolly 			*offset = RR_ADC_CHG_TEMP_GF_OFFSET_UV;
32472c7df85SCaleb Connolly 			*slope = RR_ADC_CHG_TEMP_GF_SLOPE_UV_PER_C;
32572c7df85SCaleb Connolly 			return 0;
32672c7df85SCaleb Connolly 		case PMI8998_FAB_ID_SMIC:
32772c7df85SCaleb Connolly 			*offset = RR_ADC_CHG_TEMP_SMIC_OFFSET_UV;
32872c7df85SCaleb Connolly 			*slope = RR_ADC_CHG_TEMP_SMIC_SLOPE_UV_PER_C;
32972c7df85SCaleb Connolly 			return 0;
33072c7df85SCaleb Connolly 		default:
33172c7df85SCaleb Connolly 			return -EINVAL;
33272c7df85SCaleb Connolly 		}
33372c7df85SCaleb Connolly 	}
33472c7df85SCaleb Connolly 
33572c7df85SCaleb Connolly 	return -EINVAL;
33672c7df85SCaleb Connolly }
33772c7df85SCaleb Connolly 
33872c7df85SCaleb Connolly /*
33972c7df85SCaleb Connolly  * These functions explicitly cast int64_t to int.
34072c7df85SCaleb Connolly  * They will never overflow, as the values are small enough.
34172c7df85SCaleb Connolly  */
rradc_post_process_batt_id(struct rradc_chip * chip,u16 adc_code,int * result_ohms)34272c7df85SCaleb Connolly static int rradc_post_process_batt_id(struct rradc_chip *chip, u16 adc_code,
34372c7df85SCaleb Connolly 				      int *result_ohms)
34472c7df85SCaleb Connolly {
34572c7df85SCaleb Connolly 	uint32_t current_value;
34672c7df85SCaleb Connolly 	int64_t r_id;
34772c7df85SCaleb Connolly 
34872c7df85SCaleb Connolly 	current_value = chip->batt_id_data;
34972c7df85SCaleb Connolly 	r_id = ((int64_t)adc_code * RR_ADC_FS_VOLTAGE_MV);
35072c7df85SCaleb Connolly 	r_id = div64_s64(r_id, (RR_ADC_CHAN_MSB * current_value));
35172c7df85SCaleb Connolly 	*result_ohms = (int)(r_id * MILLI);
35272c7df85SCaleb Connolly 
35372c7df85SCaleb Connolly 	return 0;
35472c7df85SCaleb Connolly }
35572c7df85SCaleb Connolly 
rradc_enable_continuous_mode(struct rradc_chip * chip)35672c7df85SCaleb Connolly static int rradc_enable_continuous_mode(struct rradc_chip *chip)
35772c7df85SCaleb Connolly {
35872c7df85SCaleb Connolly 	int ret;
35972c7df85SCaleb Connolly 
36072c7df85SCaleb Connolly 	/* Clear channel log */
36172c7df85SCaleb Connolly 	ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_LOG,
36272c7df85SCaleb Connolly 				 RR_ADC_LOG_CLR_CTRL, RR_ADC_LOG_CLR_CTRL);
36372c7df85SCaleb Connolly 	if (ret < 0) {
36472c7df85SCaleb Connolly 		dev_err(chip->dev, "log ctrl update to clear failed:%d\n", ret);
36572c7df85SCaleb Connolly 		return ret;
36672c7df85SCaleb Connolly 	}
36772c7df85SCaleb Connolly 
36872c7df85SCaleb Connolly 	ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_LOG,
36972c7df85SCaleb Connolly 				 RR_ADC_LOG_CLR_CTRL, 0);
37072c7df85SCaleb Connolly 	if (ret < 0) {
37172c7df85SCaleb Connolly 		dev_err(chip->dev, "log ctrl update to not clear failed:%d\n",
37272c7df85SCaleb Connolly 			ret);
37372c7df85SCaleb Connolly 		return ret;
37472c7df85SCaleb Connolly 	}
37572c7df85SCaleb Connolly 
37672c7df85SCaleb Connolly 	/* Switch to continuous mode */
37772c7df85SCaleb Connolly 	ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_CTL,
37872c7df85SCaleb Connolly 				 RR_ADC_CTL_CONTINUOUS_SEL,
37972c7df85SCaleb Connolly 				 RR_ADC_CTL_CONTINUOUS_SEL);
38072c7df85SCaleb Connolly 	if (ret < 0)
38172c7df85SCaleb Connolly 		dev_err(chip->dev, "Update to continuous mode failed:%d\n",
38272c7df85SCaleb Connolly 			ret);
38372c7df85SCaleb Connolly 
38472c7df85SCaleb Connolly 	return ret;
38572c7df85SCaleb Connolly }
38672c7df85SCaleb Connolly 
rradc_disable_continuous_mode(struct rradc_chip * chip)38772c7df85SCaleb Connolly static int rradc_disable_continuous_mode(struct rradc_chip *chip)
38872c7df85SCaleb Connolly {
38972c7df85SCaleb Connolly 	int ret;
39072c7df85SCaleb Connolly 
39172c7df85SCaleb Connolly 	/* Switch to non continuous mode */
39272c7df85SCaleb Connolly 	ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_CTL,
39372c7df85SCaleb Connolly 				 RR_ADC_CTL_CONTINUOUS_SEL, 0);
39472c7df85SCaleb Connolly 	if (ret < 0)
39572c7df85SCaleb Connolly 		dev_err(chip->dev, "Update to non-continuous mode failed:%d\n",
39672c7df85SCaleb Connolly 			ret);
39772c7df85SCaleb Connolly 
39872c7df85SCaleb Connolly 	return ret;
39972c7df85SCaleb Connolly }
40072c7df85SCaleb Connolly 
rradc_is_ready(struct rradc_chip * chip,enum rradc_channel_id chan_address)40172c7df85SCaleb Connolly static bool rradc_is_ready(struct rradc_chip *chip,
40272c7df85SCaleb Connolly 			   enum rradc_channel_id chan_address)
40372c7df85SCaleb Connolly {
40472c7df85SCaleb Connolly 	const struct rradc_channel *chan = &rradc_chans[chan_address];
40572c7df85SCaleb Connolly 	int ret;
40672c7df85SCaleb Connolly 	unsigned int status, mask;
40772c7df85SCaleb Connolly 
40872c7df85SCaleb Connolly 	/* BATT_ID STS bit does not get set initially */
40972c7df85SCaleb Connolly 	switch (chan_address) {
41072c7df85SCaleb Connolly 	case RR_ADC_BATT_ID:
41172c7df85SCaleb Connolly 		mask = RR_ADC_STS_CHANNEL_STS;
41272c7df85SCaleb Connolly 		break;
41372c7df85SCaleb Connolly 	default:
41472c7df85SCaleb Connolly 		mask = RR_ADC_STS_CHANNEL_READING_MASK;
41572c7df85SCaleb Connolly 		break;
41672c7df85SCaleb Connolly 	}
41772c7df85SCaleb Connolly 
41872c7df85SCaleb Connolly 	ret = regmap_read(chip->regmap, chip->base + chan->status, &status);
41972c7df85SCaleb Connolly 	if (ret < 0 || !(status & mask))
42072c7df85SCaleb Connolly 		return false;
42172c7df85SCaleb Connolly 
42272c7df85SCaleb Connolly 	return true;
42372c7df85SCaleb Connolly }
42472c7df85SCaleb Connolly 
rradc_read_status_in_cont_mode(struct rradc_chip * chip,enum rradc_channel_id chan_address)42572c7df85SCaleb Connolly static int rradc_read_status_in_cont_mode(struct rradc_chip *chip,
42672c7df85SCaleb Connolly 					  enum rradc_channel_id chan_address)
42772c7df85SCaleb Connolly {
42872c7df85SCaleb Connolly 	const struct rradc_channel *chan = &rradc_chans[chan_address];
42972c7df85SCaleb Connolly 	const struct iio_chan_spec *iio_chan = &rradc_iio_chans[chan_address];
43072c7df85SCaleb Connolly 	int ret, i;
43172c7df85SCaleb Connolly 
43272c7df85SCaleb Connolly 	if (chan->trigger_mask == 0) {
43372c7df85SCaleb Connolly 		dev_err(chip->dev, "Channel doesn't have a trigger mask\n");
43472c7df85SCaleb Connolly 		return -EINVAL;
43572c7df85SCaleb Connolly 	}
43672c7df85SCaleb Connolly 
43772c7df85SCaleb Connolly 	ret = regmap_update_bits(chip->regmap, chip->base + chan->trigger_addr,
43872c7df85SCaleb Connolly 				 chan->trigger_mask, chan->trigger_mask);
43972c7df85SCaleb Connolly 	if (ret < 0) {
44072c7df85SCaleb Connolly 		dev_err(chip->dev,
44172c7df85SCaleb Connolly 			"Failed to apply trigger for channel '%s' ret=%d\n",
44272c7df85SCaleb Connolly 			iio_chan->extend_name, ret);
44372c7df85SCaleb Connolly 		return ret;
44472c7df85SCaleb Connolly 	}
44572c7df85SCaleb Connolly 
44672c7df85SCaleb Connolly 	ret = rradc_enable_continuous_mode(chip);
44772c7df85SCaleb Connolly 	if (ret < 0) {
44872c7df85SCaleb Connolly 		dev_err(chip->dev, "Failed to switch to continuous mode\n");
44972c7df85SCaleb Connolly 		goto disable_trigger;
45072c7df85SCaleb Connolly 	}
45172c7df85SCaleb Connolly 
45272c7df85SCaleb Connolly 	/*
45372c7df85SCaleb Connolly 	 * The wait/sleep values were found through trial and error,
45472c7df85SCaleb Connolly 	 * this is mostly for the battery ID channel which takes some
45572c7df85SCaleb Connolly 	 * time to settle.
45672c7df85SCaleb Connolly 	 */
45772c7df85SCaleb Connolly 	for (i = 0; i < 5; i++) {
45872c7df85SCaleb Connolly 		if (rradc_is_ready(chip, chan_address))
45972c7df85SCaleb Connolly 			break;
46072c7df85SCaleb Connolly 		usleep_range(50000, 50000 + 500);
46172c7df85SCaleb Connolly 	}
46272c7df85SCaleb Connolly 
46372c7df85SCaleb Connolly 	if (i == 5) {
46472c7df85SCaleb Connolly 		dev_err(chip->dev, "Channel '%s' is not ready\n",
46572c7df85SCaleb Connolly 			iio_chan->extend_name);
46672c7df85SCaleb Connolly 		ret = -ETIMEDOUT;
46772c7df85SCaleb Connolly 	}
46872c7df85SCaleb Connolly 
46972c7df85SCaleb Connolly 	rradc_disable_continuous_mode(chip);
47072c7df85SCaleb Connolly 
47172c7df85SCaleb Connolly disable_trigger:
47272c7df85SCaleb Connolly 	regmap_update_bits(chip->regmap, chip->base + chan->trigger_addr,
47372c7df85SCaleb Connolly 			   chan->trigger_mask, 0);
47472c7df85SCaleb Connolly 
47572c7df85SCaleb Connolly 	return ret;
47672c7df85SCaleb Connolly }
47772c7df85SCaleb Connolly 
rradc_prepare_batt_id_conversion(struct rradc_chip * chip,enum rradc_channel_id chan_address,u16 * data)47872c7df85SCaleb Connolly static int rradc_prepare_batt_id_conversion(struct rradc_chip *chip,
47972c7df85SCaleb Connolly 					    enum rradc_channel_id chan_address,
48072c7df85SCaleb Connolly 					    u16 *data)
48172c7df85SCaleb Connolly {
48272c7df85SCaleb Connolly 	int ret;
48372c7df85SCaleb Connolly 
48472c7df85SCaleb Connolly 	ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL,
48572c7df85SCaleb Connolly 				 RR_ADC_BATT_ID_CTRL_CHANNEL_CONV,
48672c7df85SCaleb Connolly 				 RR_ADC_BATT_ID_CTRL_CHANNEL_CONV);
48772c7df85SCaleb Connolly 	if (ret < 0) {
48872c7df85SCaleb Connolly 		dev_err(chip->dev, "Enabling BATT ID channel failed:%d\n", ret);
48972c7df85SCaleb Connolly 		return ret;
49072c7df85SCaleb Connolly 	}
49172c7df85SCaleb Connolly 
49272c7df85SCaleb Connolly 	ret = regmap_update_bits(chip->regmap,
49372c7df85SCaleb Connolly 				 chip->base + RR_ADC_BATT_ID_TRIGGER,
49472c7df85SCaleb Connolly 				 RR_ADC_TRIGGER_CTL, RR_ADC_TRIGGER_CTL);
49572c7df85SCaleb Connolly 	if (ret < 0) {
49672c7df85SCaleb Connolly 		dev_err(chip->dev, "BATT_ID trigger set failed:%d\n", ret);
49772c7df85SCaleb Connolly 		goto out_disable_batt_id;
49872c7df85SCaleb Connolly 	}
49972c7df85SCaleb Connolly 
50072c7df85SCaleb Connolly 	ret = rradc_read_status_in_cont_mode(chip, chan_address);
50172c7df85SCaleb Connolly 
50272c7df85SCaleb Connolly 	/* Reset registers back to default values */
50372c7df85SCaleb Connolly 	regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_TRIGGER,
50472c7df85SCaleb Connolly 			   RR_ADC_TRIGGER_CTL, 0);
50572c7df85SCaleb Connolly 
50672c7df85SCaleb Connolly out_disable_batt_id:
50772c7df85SCaleb Connolly 	regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL,
50872c7df85SCaleb Connolly 			   RR_ADC_BATT_ID_CTRL_CHANNEL_CONV, 0);
50972c7df85SCaleb Connolly 
51072c7df85SCaleb Connolly 	return ret;
51172c7df85SCaleb Connolly }
51272c7df85SCaleb Connolly 
rradc_do_conversion(struct rradc_chip * chip,enum rradc_channel_id chan_address,u16 * data)51372c7df85SCaleb Connolly static int rradc_do_conversion(struct rradc_chip *chip,
51472c7df85SCaleb Connolly 			       enum rradc_channel_id chan_address, u16 *data)
51572c7df85SCaleb Connolly {
51672c7df85SCaleb Connolly 	const struct rradc_channel *chan = &rradc_chans[chan_address];
51772c7df85SCaleb Connolly 	const struct iio_chan_spec *iio_chan = &rradc_iio_chans[chan_address];
51872c7df85SCaleb Connolly 	int ret;
51972c7df85SCaleb Connolly 	__le16 buf[3];
52072c7df85SCaleb Connolly 
52172c7df85SCaleb Connolly 	mutex_lock(&chip->conversion_lock);
52272c7df85SCaleb Connolly 
52372c7df85SCaleb Connolly 	switch (chan_address) {
52472c7df85SCaleb Connolly 	case RR_ADC_BATT_ID:
52572c7df85SCaleb Connolly 		ret = rradc_prepare_batt_id_conversion(chip, chan_address, data);
52672c7df85SCaleb Connolly 		if (ret < 0) {
52772c7df85SCaleb Connolly 			dev_err(chip->dev, "Battery ID conversion failed:%d\n",
52872c7df85SCaleb Connolly 				ret);
52972c7df85SCaleb Connolly 			goto unlock_out;
53072c7df85SCaleb Connolly 		}
53172c7df85SCaleb Connolly 		break;
53272c7df85SCaleb Connolly 
53372c7df85SCaleb Connolly 	case RR_ADC_USBIN_V:
53472c7df85SCaleb Connolly 	case RR_ADC_DIE_TEMP:
53572c7df85SCaleb Connolly 		ret = rradc_read_status_in_cont_mode(chip, chan_address);
53672c7df85SCaleb Connolly 		if (ret < 0) {
53772c7df85SCaleb Connolly 			dev_err(chip->dev,
53872c7df85SCaleb Connolly 				"Error reading in continuous mode:%d\n", ret);
53972c7df85SCaleb Connolly 			goto unlock_out;
54072c7df85SCaleb Connolly 		}
54172c7df85SCaleb Connolly 		break;
54272c7df85SCaleb Connolly 	default:
54372c7df85SCaleb Connolly 		if (!rradc_is_ready(chip, chan_address)) {
54472c7df85SCaleb Connolly 			/*
54572c7df85SCaleb Connolly 			 * Usually this means the channel isn't attached, for example
54672c7df85SCaleb Connolly 			 * the in_voltage_usbin_v_input channel will not be ready if
54772c7df85SCaleb Connolly 			 * no USB cable is attached
54872c7df85SCaleb Connolly 			 */
54972c7df85SCaleb Connolly 			dev_dbg(chip->dev, "channel '%s' is not ready\n",
55072c7df85SCaleb Connolly 				iio_chan->extend_name);
55172c7df85SCaleb Connolly 			ret = -ENODATA;
55272c7df85SCaleb Connolly 			goto unlock_out;
55372c7df85SCaleb Connolly 		}
55472c7df85SCaleb Connolly 		break;
55572c7df85SCaleb Connolly 	}
55672c7df85SCaleb Connolly 
55772c7df85SCaleb Connolly 	ret = rradc_read(chip, chan->lsb, buf, chan->size);
55872c7df85SCaleb Connolly 	if (ret) {
55972c7df85SCaleb Connolly 		dev_err(chip->dev, "read data failed\n");
56072c7df85SCaleb Connolly 		goto unlock_out;
56172c7df85SCaleb Connolly 	}
56272c7df85SCaleb Connolly 
56372c7df85SCaleb Connolly 	/*
56472c7df85SCaleb Connolly 	 * For the battery ID we read the register for every ID ADC and then
56572c7df85SCaleb Connolly 	 * see which one is actually connected.
56672c7df85SCaleb Connolly 	 */
56772c7df85SCaleb Connolly 	if (chan_address == RR_ADC_BATT_ID) {
56872c7df85SCaleb Connolly 		u16 batt_id_150 = le16_to_cpu(buf[2]);
56972c7df85SCaleb Connolly 		u16 batt_id_15 = le16_to_cpu(buf[1]);
57072c7df85SCaleb Connolly 		u16 batt_id_5 = le16_to_cpu(buf[0]);
57172c7df85SCaleb Connolly 
57272c7df85SCaleb Connolly 		if (!batt_id_150 && !batt_id_15 && !batt_id_5) {
57372c7df85SCaleb Connolly 			dev_err(chip->dev,
57472c7df85SCaleb Connolly 				"Invalid batt_id values with all zeros\n");
57572c7df85SCaleb Connolly 			ret = -EINVAL;
57672c7df85SCaleb Connolly 			goto unlock_out;
57772c7df85SCaleb Connolly 		}
57872c7df85SCaleb Connolly 
57972c7df85SCaleb Connolly 		if (batt_id_150 <= RR_ADC_BATT_ID_RANGE) {
58072c7df85SCaleb Connolly 			*data = batt_id_150;
58172c7df85SCaleb Connolly 			chip->batt_id_data = 150;
58272c7df85SCaleb Connolly 		} else if (batt_id_15 <= RR_ADC_BATT_ID_RANGE) {
58372c7df85SCaleb Connolly 			*data = batt_id_15;
58472c7df85SCaleb Connolly 			chip->batt_id_data = 15;
58572c7df85SCaleb Connolly 		} else {
58672c7df85SCaleb Connolly 			*data = batt_id_5;
58772c7df85SCaleb Connolly 			chip->batt_id_data = 5;
58872c7df85SCaleb Connolly 		}
58972c7df85SCaleb Connolly 	} else {
59072c7df85SCaleb Connolly 		/*
59172c7df85SCaleb Connolly 		 * All of the other channels are either 1 or 2 bytes.
59272c7df85SCaleb Connolly 		 * We can rely on the second byte being 0 for 1-byte channels.
59372c7df85SCaleb Connolly 		 */
59472c7df85SCaleb Connolly 		*data = le16_to_cpu(buf[0]);
59572c7df85SCaleb Connolly 	}
59672c7df85SCaleb Connolly 
59772c7df85SCaleb Connolly unlock_out:
59872c7df85SCaleb Connolly 	mutex_unlock(&chip->conversion_lock);
59972c7df85SCaleb Connolly 
60072c7df85SCaleb Connolly 	return ret;
60172c7df85SCaleb Connolly }
60272c7df85SCaleb Connolly 
rradc_read_scale(struct rradc_chip * chip,int chan_address,int * val,int * val2)60372c7df85SCaleb Connolly static int rradc_read_scale(struct rradc_chip *chip, int chan_address, int *val,
60472c7df85SCaleb Connolly 			    int *val2)
60572c7df85SCaleb Connolly {
60672c7df85SCaleb Connolly 	int64_t fab_offset, fab_slope;
60772c7df85SCaleb Connolly 	int ret;
60872c7df85SCaleb Connolly 
60972c7df85SCaleb Connolly 	ret = rradc_get_fab_coeff(chip, &fab_offset, &fab_slope);
61072c7df85SCaleb Connolly 	if (ret < 0) {
61172c7df85SCaleb Connolly 		dev_err(chip->dev, "Unable to get fab id coefficients\n");
61272c7df85SCaleb Connolly 		return -EINVAL;
61372c7df85SCaleb Connolly 	}
61472c7df85SCaleb Connolly 
61572c7df85SCaleb Connolly 	switch (chan_address) {
61672c7df85SCaleb Connolly 	case RR_ADC_SKIN_TEMP:
61772c7df85SCaleb Connolly 		*val = MILLI;
61872c7df85SCaleb Connolly 		*val2 = RR_ADC_BATT_THERM_LSB_K;
61972c7df85SCaleb Connolly 		return IIO_VAL_FRACTIONAL;
62072c7df85SCaleb Connolly 	case RR_ADC_USBIN_I:
62172c7df85SCaleb Connolly 		*val = RR_ADC_CURR_USBIN_INPUT_FACTOR_MIL *
62272c7df85SCaleb Connolly 		       RR_ADC_FS_VOLTAGE_MV;
62372c7df85SCaleb Connolly 		*val2 = RR_ADC_CHAN_MSB;
62472c7df85SCaleb Connolly 		return IIO_VAL_FRACTIONAL;
62572c7df85SCaleb Connolly 	case RR_ADC_DCIN_I:
62672c7df85SCaleb Connolly 		*val = RR_ADC_CURR_INPUT_FACTOR * RR_ADC_FS_VOLTAGE_MV;
62772c7df85SCaleb Connolly 		*val2 = RR_ADC_CHAN_MSB;
62872c7df85SCaleb Connolly 		return IIO_VAL_FRACTIONAL;
62972c7df85SCaleb Connolly 	case RR_ADC_USBIN_V:
63072c7df85SCaleb Connolly 	case RR_ADC_DCIN_V:
63172c7df85SCaleb Connolly 		*val = RR_ADC_VOLT_INPUT_FACTOR * RR_ADC_FS_VOLTAGE_MV * MILLI;
63272c7df85SCaleb Connolly 		*val2 = RR_ADC_CHAN_MSB;
63372c7df85SCaleb Connolly 		return IIO_VAL_FRACTIONAL;
63472c7df85SCaleb Connolly 	case RR_ADC_GPIO:
63572c7df85SCaleb Connolly 		*val = RR_ADC_GPIO_FS_RANGE;
63672c7df85SCaleb Connolly 		*val2 = RR_ADC_CHAN_MSB;
63772c7df85SCaleb Connolly 		return IIO_VAL_FRACTIONAL;
63872c7df85SCaleb Connolly 	case RR_ADC_CHG_TEMP:
63972c7df85SCaleb Connolly 		/*
64072c7df85SCaleb Connolly 		 * We divide val2 by MILLI instead of multiplying val
64172c7df85SCaleb Connolly 		 * to avoid an integer overflow.
64272c7df85SCaleb Connolly 		 */
64372c7df85SCaleb Connolly 		*val = -RR_ADC_TEMP_FS_VOLTAGE_NUM;
64472c7df85SCaleb Connolly 		*val2 = div64_s64(RR_ADC_TEMP_FS_VOLTAGE_DEN * RR_ADC_CHAN_MSB *
64572c7df85SCaleb Connolly 					  fab_slope,
64672c7df85SCaleb Connolly 				  MILLI);
64772c7df85SCaleb Connolly 
64872c7df85SCaleb Connolly 		return IIO_VAL_FRACTIONAL;
64972c7df85SCaleb Connolly 	case RR_ADC_DIE_TEMP:
65072c7df85SCaleb Connolly 		*val = RR_ADC_TEMP_FS_VOLTAGE_NUM;
65172c7df85SCaleb Connolly 		*val2 = RR_ADC_TEMP_FS_VOLTAGE_DEN * RR_ADC_CHAN_MSB *
65272c7df85SCaleb Connolly 			RR_ADC_DIE_TEMP_SLOPE;
65372c7df85SCaleb Connolly 
65472c7df85SCaleb Connolly 		return IIO_VAL_FRACTIONAL;
65572c7df85SCaleb Connolly 	default:
65672c7df85SCaleb Connolly 		return -EINVAL;
65772c7df85SCaleb Connolly 	}
65872c7df85SCaleb Connolly }
65972c7df85SCaleb Connolly 
rradc_read_offset(struct rradc_chip * chip,int chan_address,int * val)66072c7df85SCaleb Connolly static int rradc_read_offset(struct rradc_chip *chip, int chan_address, int *val)
66172c7df85SCaleb Connolly {
66272c7df85SCaleb Connolly 	int64_t fab_offset, fab_slope;
66372c7df85SCaleb Connolly 	int64_t offset1, offset2;
66472c7df85SCaleb Connolly 	int ret;
66572c7df85SCaleb Connolly 
66672c7df85SCaleb Connolly 	switch (chan_address) {
66772c7df85SCaleb Connolly 	case RR_ADC_SKIN_TEMP:
66872c7df85SCaleb Connolly 		/*
66972c7df85SCaleb Connolly 		 * Offset from kelvin to degC, divided by the
67072c7df85SCaleb Connolly 		 * scale factor (250). We lose some precision here.
67172c7df85SCaleb Connolly 		 * 273150 / 250 = 1092.6
67272c7df85SCaleb Connolly 		 */
67372c7df85SCaleb Connolly 		*val = div64_s64(ABSOLUTE_ZERO_MILLICELSIUS,
67472c7df85SCaleb Connolly 				 (MILLI / RR_ADC_BATT_THERM_LSB_K));
67572c7df85SCaleb Connolly 		return IIO_VAL_INT;
67672c7df85SCaleb Connolly 	case RR_ADC_CHG_TEMP:
67772c7df85SCaleb Connolly 		ret = rradc_get_fab_coeff(chip, &fab_offset, &fab_slope);
67872c7df85SCaleb Connolly 		if (ret < 0) {
67972c7df85SCaleb Connolly 			dev_err(chip->dev,
68072c7df85SCaleb Connolly 				"Unable to get fab id coefficients\n");
68172c7df85SCaleb Connolly 			return -EINVAL;
68272c7df85SCaleb Connolly 		}
68372c7df85SCaleb Connolly 		offset1 = -(fab_offset * RR_ADC_TEMP_FS_VOLTAGE_DEN *
68472c7df85SCaleb Connolly 			    RR_ADC_CHAN_MSB);
68572c7df85SCaleb Connolly 		offset1 += (int64_t)RR_ADC_TEMP_FS_VOLTAGE_NUM / 2ULL;
68672c7df85SCaleb Connolly 		offset1 = div64_s64(offset1,
68772c7df85SCaleb Connolly 				    (int64_t)(RR_ADC_TEMP_FS_VOLTAGE_NUM));
68872c7df85SCaleb Connolly 
68972c7df85SCaleb Connolly 		offset2 = (int64_t)RR_ADC_CHG_TEMP_OFFSET_MILLI_DEGC *
69072c7df85SCaleb Connolly 			  RR_ADC_TEMP_FS_VOLTAGE_DEN * RR_ADC_CHAN_MSB *
69172c7df85SCaleb Connolly 			  (int64_t)fab_slope;
69272c7df85SCaleb Connolly 		offset2 += ((int64_t)MILLI * RR_ADC_TEMP_FS_VOLTAGE_NUM) / 2;
69372c7df85SCaleb Connolly 		offset2 = div64_s64(
69472c7df85SCaleb Connolly 			offset2, ((int64_t)MILLI * RR_ADC_TEMP_FS_VOLTAGE_NUM));
69572c7df85SCaleb Connolly 
69672c7df85SCaleb Connolly 		/*
69772c7df85SCaleb Connolly 		 * The -1 is to compensate for lost precision.
69872c7df85SCaleb Connolly 		 * It should actually be -0.7906976744186046.
69972c7df85SCaleb Connolly 		 * This works out to every value being off
70072c7df85SCaleb Connolly 		 * by about +0.091 degrees C after applying offset and scale.
70172c7df85SCaleb Connolly 		 */
70272c7df85SCaleb Connolly 		*val = (int)(offset1 - offset2 - 1);
70372c7df85SCaleb Connolly 		return IIO_VAL_INT;
70472c7df85SCaleb Connolly 	case RR_ADC_DIE_TEMP:
70572c7df85SCaleb Connolly 		offset1 = -RR_ADC_DIE_TEMP_OFFSET *
70672c7df85SCaleb Connolly 			  (int64_t)RR_ADC_TEMP_FS_VOLTAGE_DEN *
70772c7df85SCaleb Connolly 			  (int64_t)RR_ADC_CHAN_MSB;
70872c7df85SCaleb Connolly 		offset1 = div64_s64(offset1, RR_ADC_TEMP_FS_VOLTAGE_NUM);
70972c7df85SCaleb Connolly 
71072c7df85SCaleb Connolly 		offset2 = -(int64_t)RR_ADC_CHG_TEMP_OFFSET_MILLI_DEGC *
71172c7df85SCaleb Connolly 			  RR_ADC_TEMP_FS_VOLTAGE_DEN * RR_ADC_CHAN_MSB *
71272c7df85SCaleb Connolly 			  RR_ADC_DIE_TEMP_SLOPE;
71372c7df85SCaleb Connolly 		offset2 = div64_s64(offset2,
71472c7df85SCaleb Connolly 				    ((int64_t)RR_ADC_TEMP_FS_VOLTAGE_NUM));
71572c7df85SCaleb Connolly 
71672c7df85SCaleb Connolly 		/*
71772c7df85SCaleb Connolly 		 * The result is -339, it should be -338.69789, this results
71872c7df85SCaleb Connolly 		 * in the calculated die temp being off by
71972c7df85SCaleb Connolly 		 * -0.004 - -0.0175 degrees C
72072c7df85SCaleb Connolly 		 */
72172c7df85SCaleb Connolly 		*val = (int)(offset1 - offset2);
72272c7df85SCaleb Connolly 		return IIO_VAL_INT;
72372c7df85SCaleb Connolly 	default:
72472c7df85SCaleb Connolly 		break;
72572c7df85SCaleb Connolly 	}
72672c7df85SCaleb Connolly 	return -EINVAL;
72772c7df85SCaleb Connolly }
72872c7df85SCaleb Connolly 
rradc_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan_spec,int * val,int * val2,long mask)72972c7df85SCaleb Connolly static int rradc_read_raw(struct iio_dev *indio_dev,
73072c7df85SCaleb Connolly 			  struct iio_chan_spec const *chan_spec, int *val,
73172c7df85SCaleb Connolly 			  int *val2, long mask)
73272c7df85SCaleb Connolly {
73372c7df85SCaleb Connolly 	struct rradc_chip *chip = iio_priv(indio_dev);
73472c7df85SCaleb Connolly 	const struct rradc_channel *chan;
73572c7df85SCaleb Connolly 	int ret;
73672c7df85SCaleb Connolly 	u16 adc_code;
73772c7df85SCaleb Connolly 
73872c7df85SCaleb Connolly 	if (chan_spec->address >= RR_ADC_CHAN_MAX) {
73972c7df85SCaleb Connolly 		dev_err(chip->dev, "Invalid channel index:%lu\n",
74072c7df85SCaleb Connolly 			chan_spec->address);
74172c7df85SCaleb Connolly 		return -EINVAL;
74272c7df85SCaleb Connolly 	}
74372c7df85SCaleb Connolly 
74472c7df85SCaleb Connolly 	switch (mask) {
74572c7df85SCaleb Connolly 	case IIO_CHAN_INFO_SCALE:
74672c7df85SCaleb Connolly 		return rradc_read_scale(chip, chan_spec->address, val, val2);
74772c7df85SCaleb Connolly 	case IIO_CHAN_INFO_OFFSET:
74872c7df85SCaleb Connolly 		return rradc_read_offset(chip, chan_spec->address, val);
74972c7df85SCaleb Connolly 	case IIO_CHAN_INFO_RAW:
75072c7df85SCaleb Connolly 		ret = rradc_do_conversion(chip, chan_spec->address, &adc_code);
75172c7df85SCaleb Connolly 		if (ret < 0)
75272c7df85SCaleb Connolly 			return ret;
75372c7df85SCaleb Connolly 
75472c7df85SCaleb Connolly 		*val = adc_code;
75572c7df85SCaleb Connolly 		return IIO_VAL_INT;
75672c7df85SCaleb Connolly 	case IIO_CHAN_INFO_PROCESSED:
75772c7df85SCaleb Connolly 		chan = &rradc_chans[chan_spec->address];
75872c7df85SCaleb Connolly 		if (!chan->scale_fn)
75972c7df85SCaleb Connolly 			return -EINVAL;
76072c7df85SCaleb Connolly 		ret = rradc_do_conversion(chip, chan_spec->address, &adc_code);
76172c7df85SCaleb Connolly 		if (ret < 0)
76272c7df85SCaleb Connolly 			return ret;
76372c7df85SCaleb Connolly 
76472c7df85SCaleb Connolly 		*val = chan->scale_fn(chip, adc_code, val);
76572c7df85SCaleb Connolly 		return IIO_VAL_INT;
76672c7df85SCaleb Connolly 	default:
76772c7df85SCaleb Connolly 		return -EINVAL;
76872c7df85SCaleb Connolly 	}
76972c7df85SCaleb Connolly }
77072c7df85SCaleb Connolly 
rradc_read_label(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,char * label)77172c7df85SCaleb Connolly static int rradc_read_label(struct iio_dev *indio_dev,
77272c7df85SCaleb Connolly 			    struct iio_chan_spec const *chan, char *label)
77372c7df85SCaleb Connolly {
77472c7df85SCaleb Connolly 	return snprintf(label, PAGE_SIZE, "%s\n",
77572c7df85SCaleb Connolly 			rradc_chans[chan->address].label);
77672c7df85SCaleb Connolly }
77772c7df85SCaleb Connolly 
77872c7df85SCaleb Connolly static const struct iio_info rradc_info = {
77972c7df85SCaleb Connolly 	.read_raw = rradc_read_raw,
78072c7df85SCaleb Connolly 	.read_label = rradc_read_label,
78172c7df85SCaleb Connolly };
78272c7df85SCaleb Connolly 
78372c7df85SCaleb Connolly static const struct rradc_channel rradc_chans[RR_ADC_CHAN_MAX] = {
78472c7df85SCaleb Connolly 	{
78572c7df85SCaleb Connolly 		.label = "batt_id",
78672c7df85SCaleb Connolly 		.scale_fn = rradc_post_process_batt_id,
78772c7df85SCaleb Connolly 		.lsb = RR_ADC_BATT_ID_5_LSB,
78872c7df85SCaleb Connolly 		.status = RR_ADC_BATT_ID_STS,
78972c7df85SCaleb Connolly 		.size = 6,
79072c7df85SCaleb Connolly 		.trigger_addr = RR_ADC_BATT_ID_TRIGGER,
79172c7df85SCaleb Connolly 		.trigger_mask = BIT(0),
79272c7df85SCaleb Connolly 	}, {
79372c7df85SCaleb Connolly 		.label = "batt",
79472c7df85SCaleb Connolly 		.lsb = RR_ADC_BATT_THERM_LSB,
79572c7df85SCaleb Connolly 		.status = RR_ADC_BATT_THERM_STS,
79672c7df85SCaleb Connolly 		.size = 2,
79772c7df85SCaleb Connolly 		.trigger_addr = RR_ADC_BATT_THERM_TRIGGER,
79872c7df85SCaleb Connolly 	}, {
79972c7df85SCaleb Connolly 		.label = "pmi8998_skin",
80072c7df85SCaleb Connolly 		.lsb = RR_ADC_SKIN_TEMP_LSB,
80172c7df85SCaleb Connolly 		.status = RR_ADC_AUX_THERM_STS,
80272c7df85SCaleb Connolly 		.size = 2,
80372c7df85SCaleb Connolly 		.trigger_addr = RR_ADC_AUX_THERM_TRIGGER,
80472c7df85SCaleb Connolly 	}, {
80572c7df85SCaleb Connolly 		.label = "usbin_i",
80672c7df85SCaleb Connolly 		.lsb = RR_ADC_USB_IN_I_LSB,
80772c7df85SCaleb Connolly 		.status = RR_ADC_USB_IN_I_STS,
80872c7df85SCaleb Connolly 		.size = 2,
80972c7df85SCaleb Connolly 		.trigger_addr = RR_ADC_USB_IN_I_TRIGGER,
81072c7df85SCaleb Connolly 	}, {
81172c7df85SCaleb Connolly 		.label = "usbin_v",
81272c7df85SCaleb Connolly 		.lsb = RR_ADC_USB_IN_V_LSB,
81372c7df85SCaleb Connolly 		.status = RR_ADC_USB_IN_V_STS,
81472c7df85SCaleb Connolly 		.size = 2,
81572c7df85SCaleb Connolly 		.trigger_addr = RR_ADC_USB_IN_V_TRIGGER,
81672c7df85SCaleb Connolly 		.trigger_mask = BIT(7),
81772c7df85SCaleb Connolly 	}, {
81872c7df85SCaleb Connolly 		.label = "dcin_i",
81972c7df85SCaleb Connolly 		.lsb = RR_ADC_DC_IN_I_LSB,
82072c7df85SCaleb Connolly 		.status = RR_ADC_DC_IN_I_STS,
82172c7df85SCaleb Connolly 		.size = 2,
82272c7df85SCaleb Connolly 		.trigger_addr = RR_ADC_DC_IN_I_TRIGGER,
82372c7df85SCaleb Connolly 	}, {
82472c7df85SCaleb Connolly 		.label = "dcin_v",
82572c7df85SCaleb Connolly 		.lsb = RR_ADC_DC_IN_V_LSB,
82672c7df85SCaleb Connolly 		.status = RR_ADC_DC_IN_V_STS,
82772c7df85SCaleb Connolly 		.size = 2,
82872c7df85SCaleb Connolly 		.trigger_addr = RR_ADC_DC_IN_V_TRIGGER,
82972c7df85SCaleb Connolly 	}, {
83072c7df85SCaleb Connolly 		.label = "pmi8998_die",
83172c7df85SCaleb Connolly 		.lsb = RR_ADC_PMI_DIE_TEMP_LSB,
83272c7df85SCaleb Connolly 		.status = RR_ADC_PMI_DIE_TEMP_STS,
83372c7df85SCaleb Connolly 		.size = 2,
83472c7df85SCaleb Connolly 		.trigger_addr = RR_ADC_PMI_DIE_TEMP_TRIGGER,
83572c7df85SCaleb Connolly 		.trigger_mask = RR_ADC_TRIGGER_EVERY_CYCLE,
83672c7df85SCaleb Connolly 	}, {
83772c7df85SCaleb Connolly 		.label = "chg",
83872c7df85SCaleb Connolly 		.lsb = RR_ADC_CHARGER_TEMP_LSB,
83972c7df85SCaleb Connolly 		.status = RR_ADC_CHARGER_TEMP_STS,
84072c7df85SCaleb Connolly 		.size = 2,
84172c7df85SCaleb Connolly 		.trigger_addr = RR_ADC_CHARGER_TEMP_TRIGGER,
84272c7df85SCaleb Connolly 	}, {
84372c7df85SCaleb Connolly 		.label = "gpio",
84472c7df85SCaleb Connolly 		.lsb = RR_ADC_GPIO_LSB,
84572c7df85SCaleb Connolly 		.status = RR_ADC_GPIO_STS,
84672c7df85SCaleb Connolly 		.size = 2,
84772c7df85SCaleb Connolly 		.trigger_addr = RR_ADC_GPIO_TRIGGER,
84872c7df85SCaleb Connolly 	},
84972c7df85SCaleb Connolly };
85072c7df85SCaleb Connolly 
85172c7df85SCaleb Connolly static const struct iio_chan_spec rradc_iio_chans[RR_ADC_CHAN_MAX] = {
85272c7df85SCaleb Connolly 	{
85372c7df85SCaleb Connolly 		.type = IIO_RESISTANCE,
85472c7df85SCaleb Connolly 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
85572c7df85SCaleb Connolly 		.address = RR_ADC_BATT_ID,
85672c7df85SCaleb Connolly 		.channel = 0,
85772c7df85SCaleb Connolly 		.indexed = 1,
85872c7df85SCaleb Connolly 	}, {
85972c7df85SCaleb Connolly 		.type = IIO_TEMP,
86072c7df85SCaleb Connolly 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
86172c7df85SCaleb Connolly 		.address = RR_ADC_BATT_THERM,
86272c7df85SCaleb Connolly 		.channel = 0,
86372c7df85SCaleb Connolly 		.indexed = 1,
86472c7df85SCaleb Connolly 	}, {
86572c7df85SCaleb Connolly 		.type = IIO_TEMP,
86672c7df85SCaleb Connolly 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
86772c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_SCALE) |
86872c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_OFFSET),
86972c7df85SCaleb Connolly 		.address = RR_ADC_SKIN_TEMP,
87072c7df85SCaleb Connolly 		.channel = 1,
87172c7df85SCaleb Connolly 		.indexed = 1,
87272c7df85SCaleb Connolly 	}, {
87372c7df85SCaleb Connolly 		.type = IIO_CURRENT,
87472c7df85SCaleb Connolly 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
87572c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_SCALE),
87672c7df85SCaleb Connolly 		.address = RR_ADC_USBIN_I,
87772c7df85SCaleb Connolly 		.channel = 0,
87872c7df85SCaleb Connolly 		.indexed = 1,
87972c7df85SCaleb Connolly 	}, {
88072c7df85SCaleb Connolly 		.type = IIO_VOLTAGE,
88172c7df85SCaleb Connolly 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
88272c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_SCALE),
88372c7df85SCaleb Connolly 		.address = RR_ADC_USBIN_V,
88472c7df85SCaleb Connolly 		.channel = 0,
88572c7df85SCaleb Connolly 		.indexed = 1,
88672c7df85SCaleb Connolly 	}, {
88772c7df85SCaleb Connolly 		.type = IIO_CURRENT,
88872c7df85SCaleb Connolly 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
88972c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_SCALE),
89072c7df85SCaleb Connolly 		.address = RR_ADC_DCIN_I,
89172c7df85SCaleb Connolly 		.channel = 1,
89272c7df85SCaleb Connolly 		.indexed = 1,
89372c7df85SCaleb Connolly 	}, {
89472c7df85SCaleb Connolly 		.type = IIO_VOLTAGE,
89572c7df85SCaleb Connolly 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
89672c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_SCALE),
89772c7df85SCaleb Connolly 		.address = RR_ADC_DCIN_V,
89872c7df85SCaleb Connolly 		.channel = 1,
89972c7df85SCaleb Connolly 		.indexed = 1,
90072c7df85SCaleb Connolly 	}, {
90172c7df85SCaleb Connolly 		.type = IIO_TEMP,
90272c7df85SCaleb Connolly 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
90372c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_SCALE) |
90472c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_OFFSET),
90572c7df85SCaleb Connolly 		.address = RR_ADC_DIE_TEMP,
90672c7df85SCaleb Connolly 		.channel = 2,
90772c7df85SCaleb Connolly 		.indexed = 1,
90872c7df85SCaleb Connolly 	}, {
90972c7df85SCaleb Connolly 		.type = IIO_TEMP,
91072c7df85SCaleb Connolly 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
91172c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_OFFSET) |
91272c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_SCALE),
91372c7df85SCaleb Connolly 		.address = RR_ADC_CHG_TEMP,
91472c7df85SCaleb Connolly 		.channel = 3,
91572c7df85SCaleb Connolly 		.indexed = 1,
91672c7df85SCaleb Connolly 	}, {
91772c7df85SCaleb Connolly 		.type = IIO_VOLTAGE,
91872c7df85SCaleb Connolly 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
91972c7df85SCaleb Connolly 				      BIT(IIO_CHAN_INFO_SCALE),
92072c7df85SCaleb Connolly 		.address = RR_ADC_GPIO,
92172c7df85SCaleb Connolly 		.channel = 2,
92272c7df85SCaleb Connolly 		.indexed = 1,
92372c7df85SCaleb Connolly 	},
92472c7df85SCaleb Connolly };
92572c7df85SCaleb Connolly 
rradc_probe(struct platform_device * pdev)92672c7df85SCaleb Connolly static int rradc_probe(struct platform_device *pdev)
92772c7df85SCaleb Connolly {
92872c7df85SCaleb Connolly 	struct device *dev = &pdev->dev;
92972c7df85SCaleb Connolly 	struct iio_dev *indio_dev;
93072c7df85SCaleb Connolly 	struct rradc_chip *chip;
93172c7df85SCaleb Connolly 	int ret, i, batt_id_delay;
93272c7df85SCaleb Connolly 
93372c7df85SCaleb Connolly 	indio_dev = devm_iio_device_alloc(dev, sizeof(*chip));
93472c7df85SCaleb Connolly 	if (!indio_dev)
93572c7df85SCaleb Connolly 		return -ENOMEM;
93672c7df85SCaleb Connolly 
93772c7df85SCaleb Connolly 	chip = iio_priv(indio_dev);
93872c7df85SCaleb Connolly 	chip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
93972c7df85SCaleb Connolly 	if (!chip->regmap) {
94072c7df85SCaleb Connolly 		dev_err(dev, "Couldn't get parent's regmap\n");
94172c7df85SCaleb Connolly 		return -EINVAL;
94272c7df85SCaleb Connolly 	}
94372c7df85SCaleb Connolly 
94472c7df85SCaleb Connolly 	chip->dev = dev;
94572c7df85SCaleb Connolly 	mutex_init(&chip->conversion_lock);
94672c7df85SCaleb Connolly 
94772c7df85SCaleb Connolly 	ret = device_property_read_u32(dev, "reg", &chip->base);
94872c7df85SCaleb Connolly 	if (ret < 0) {
94972c7df85SCaleb Connolly 		dev_err(chip->dev, "Couldn't find reg address, ret = %d\n",
95072c7df85SCaleb Connolly 			ret);
95172c7df85SCaleb Connolly 		return ret;
95272c7df85SCaleb Connolly 	}
95372c7df85SCaleb Connolly 
95472c7df85SCaleb Connolly 	batt_id_delay = -1;
95572c7df85SCaleb Connolly 	ret = device_property_read_u32(dev, "qcom,batt-id-delay-ms",
95672c7df85SCaleb Connolly 				       &batt_id_delay);
95772c7df85SCaleb Connolly 	if (!ret) {
95872c7df85SCaleb Connolly 		for (i = 0; i < RRADC_BATT_ID_DELAY_MAX; i++) {
95972c7df85SCaleb Connolly 			if (batt_id_delay == batt_id_delays[i])
96072c7df85SCaleb Connolly 				break;
96172c7df85SCaleb Connolly 		}
96272c7df85SCaleb Connolly 		if (i == RRADC_BATT_ID_DELAY_MAX)
96372c7df85SCaleb Connolly 			batt_id_delay = -1;
96472c7df85SCaleb Connolly 	}
96572c7df85SCaleb Connolly 
96672c7df85SCaleb Connolly 	if (batt_id_delay >= 0) {
96772c7df85SCaleb Connolly 		batt_id_delay = FIELD_PREP(BATT_ID_SETTLE_MASK, batt_id_delay);
96872c7df85SCaleb Connolly 		ret = regmap_update_bits(chip->regmap,
96972c7df85SCaleb Connolly 					 chip->base + RR_ADC_BATT_ID_CFG,
97072c7df85SCaleb Connolly 					 batt_id_delay, batt_id_delay);
97172c7df85SCaleb Connolly 		if (ret < 0) {
97272c7df85SCaleb Connolly 			dev_err(chip->dev,
97372c7df85SCaleb Connolly 				"BATT_ID settling time config failed:%d\n",
97472c7df85SCaleb Connolly 				ret);
97572c7df85SCaleb Connolly 		}
97672c7df85SCaleb Connolly 	}
97772c7df85SCaleb Connolly 
97872c7df85SCaleb Connolly 	/* Get the PMIC revision, we need it to handle some varying coefficients */
97972c7df85SCaleb Connolly 	chip->pmic = qcom_pmic_get(chip->dev);
98072c7df85SCaleb Connolly 	if (IS_ERR(chip->pmic)) {
98172c7df85SCaleb Connolly 		dev_err(chip->dev, "Unable to get reference to PMIC device\n");
98272c7df85SCaleb Connolly 		return PTR_ERR(chip->pmic);
98372c7df85SCaleb Connolly 	}
98472c7df85SCaleb Connolly 
98572c7df85SCaleb Connolly 	switch (chip->pmic->subtype) {
98672c7df85SCaleb Connolly 	case PMI8998_SUBTYPE:
98772c7df85SCaleb Connolly 		indio_dev->name = "pmi8998-rradc";
98872c7df85SCaleb Connolly 		break;
98972c7df85SCaleb Connolly 	case PM660_SUBTYPE:
99072c7df85SCaleb Connolly 		indio_dev->name = "pm660-rradc";
99172c7df85SCaleb Connolly 		break;
99272c7df85SCaleb Connolly 	default:
99372c7df85SCaleb Connolly 		indio_dev->name = DRIVER_NAME;
99472c7df85SCaleb Connolly 		break;
99572c7df85SCaleb Connolly 	}
99672c7df85SCaleb Connolly 	indio_dev->modes = INDIO_DIRECT_MODE;
99772c7df85SCaleb Connolly 	indio_dev->info = &rradc_info;
99872c7df85SCaleb Connolly 	indio_dev->channels = rradc_iio_chans;
99972c7df85SCaleb Connolly 	indio_dev->num_channels = ARRAY_SIZE(rradc_iio_chans);
100072c7df85SCaleb Connolly 
100172c7df85SCaleb Connolly 	return devm_iio_device_register(dev, indio_dev);
100272c7df85SCaleb Connolly }
100372c7df85SCaleb Connolly 
100472c7df85SCaleb Connolly static const struct of_device_id rradc_match_table[] = {
100572c7df85SCaleb Connolly 	{ .compatible = "qcom,pm660-rradc" },
100672c7df85SCaleb Connolly 	{ .compatible = "qcom,pmi8998-rradc" },
100772c7df85SCaleb Connolly 	{}
100872c7df85SCaleb Connolly };
100972c7df85SCaleb Connolly MODULE_DEVICE_TABLE(of, rradc_match_table);
101072c7df85SCaleb Connolly 
101172c7df85SCaleb Connolly static struct platform_driver rradc_driver = {
101272c7df85SCaleb Connolly 	.driver		= {
101372c7df85SCaleb Connolly 		.name		= DRIVER_NAME,
101472c7df85SCaleb Connolly 		.of_match_table	= rradc_match_table,
101572c7df85SCaleb Connolly 	},
101672c7df85SCaleb Connolly 	.probe = rradc_probe,
101772c7df85SCaleb Connolly };
101872c7df85SCaleb Connolly module_platform_driver(rradc_driver);
101972c7df85SCaleb Connolly 
102072c7df85SCaleb Connolly MODULE_DESCRIPTION("QCOM SPMI PMIC RR ADC driver");
102172c7df85SCaleb Connolly MODULE_AUTHOR("Caleb Connolly <caleb.connolly@linaro.org>");
102272c7df85SCaleb Connolly MODULE_LICENSE("GPL");
1023