162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2017 Tony Lindgren <tony@atomide.com>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Rewritten for Linux IIO framework with some code based on
662306a36Sopenharmony_ci * earlier driver found in the Motorola Linux kernel:
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2009-2010 Motorola, Inc.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/device.h>
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/init.h>
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci#include <linux/property.h>
2162306a36Sopenharmony_ci#include <linux/regmap.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/iio/buffer.h>
2462306a36Sopenharmony_ci#include <linux/iio/driver.h>
2562306a36Sopenharmony_ci#include <linux/iio/iio.h>
2662306a36Sopenharmony_ci#include <linux/iio/kfifo_buf.h>
2762306a36Sopenharmony_ci#include <linux/mfd/motorola-cpcap.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* Register CPCAP_REG_ADCC1 bits */
3062306a36Sopenharmony_ci#define CPCAP_BIT_ADEN_AUTO_CLR		BIT(15)	/* Currently unused */
3162306a36Sopenharmony_ci#define CPCAP_BIT_CAL_MODE		BIT(14) /* Set with BIT_RAND0 */
3262306a36Sopenharmony_ci#define CPCAP_BIT_ADC_CLK_SEL1		BIT(13)	/* Currently unused */
3362306a36Sopenharmony_ci#define CPCAP_BIT_ADC_CLK_SEL0		BIT(12)	/* Currently unused */
3462306a36Sopenharmony_ci#define CPCAP_BIT_ATOX			BIT(11)
3562306a36Sopenharmony_ci#define CPCAP_BIT_ATO3			BIT(10)
3662306a36Sopenharmony_ci#define CPCAP_BIT_ATO2			BIT(9)
3762306a36Sopenharmony_ci#define CPCAP_BIT_ATO1			BIT(8)
3862306a36Sopenharmony_ci#define CPCAP_BIT_ATO0			BIT(7)
3962306a36Sopenharmony_ci#define CPCAP_BIT_ADA2			BIT(6)
4062306a36Sopenharmony_ci#define CPCAP_BIT_ADA1			BIT(5)
4162306a36Sopenharmony_ci#define CPCAP_BIT_ADA0			BIT(4)
4262306a36Sopenharmony_ci#define CPCAP_BIT_AD_SEL1		BIT(3)	/* Set for bank1 */
4362306a36Sopenharmony_ci#define CPCAP_BIT_RAND1			BIT(2)	/* Set for channel 16 & 17 */
4462306a36Sopenharmony_ci#define CPCAP_BIT_RAND0			BIT(1)	/* Set with CAL_MODE */
4562306a36Sopenharmony_ci#define CPCAP_BIT_ADEN			BIT(0)	/* Currently unused */
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define CPCAP_REG_ADCC1_DEFAULTS	(CPCAP_BIT_ADEN_AUTO_CLR | \
4862306a36Sopenharmony_ci					 CPCAP_BIT_ADC_CLK_SEL0 |  \
4962306a36Sopenharmony_ci					 CPCAP_BIT_RAND1)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Register CPCAP_REG_ADCC2 bits */
5262306a36Sopenharmony_ci#define CPCAP_BIT_CAL_FACTOR_ENABLE	BIT(15)	/* Currently unused */
5362306a36Sopenharmony_ci#define CPCAP_BIT_BATDETB_EN		BIT(14)	/* Currently unused */
5462306a36Sopenharmony_ci#define CPCAP_BIT_ADTRIG_ONESHOT	BIT(13)	/* Set for !TIMING_IMM */
5562306a36Sopenharmony_ci#define CPCAP_BIT_ASC			BIT(12)	/* Set for TIMING_IMM */
5662306a36Sopenharmony_ci#define CPCAP_BIT_ATOX_PS_FACTOR	BIT(11)
5762306a36Sopenharmony_ci#define CPCAP_BIT_ADC_PS_FACTOR1	BIT(10)
5862306a36Sopenharmony_ci#define CPCAP_BIT_ADC_PS_FACTOR0	BIT(9)
5962306a36Sopenharmony_ci#define CPCAP_BIT_AD4_SELECT		BIT(8)	/* Currently unused */
6062306a36Sopenharmony_ci#define CPCAP_BIT_ADC_BUSY		BIT(7)	/* Currently unused */
6162306a36Sopenharmony_ci#define CPCAP_BIT_THERMBIAS_EN		BIT(6)	/* Bias for AD0_BATTDETB */
6262306a36Sopenharmony_ci#define CPCAP_BIT_ADTRIG_DIS		BIT(5)	/* Disable interrupt */
6362306a36Sopenharmony_ci#define CPCAP_BIT_LIADC			BIT(4)	/* Currently unused */
6462306a36Sopenharmony_ci#define CPCAP_BIT_TS_REFEN		BIT(3)	/* Currently unused */
6562306a36Sopenharmony_ci#define CPCAP_BIT_TS_M2			BIT(2)	/* Currently unused */
6662306a36Sopenharmony_ci#define CPCAP_BIT_TS_M1			BIT(1)	/* Currently unused */
6762306a36Sopenharmony_ci#define CPCAP_BIT_TS_M0			BIT(0)	/* Currently unused */
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define CPCAP_REG_ADCC2_DEFAULTS	(CPCAP_BIT_AD4_SELECT | \
7062306a36Sopenharmony_ci					 CPCAP_BIT_ADTRIG_DIS | \
7162306a36Sopenharmony_ci					 CPCAP_BIT_LIADC | \
7262306a36Sopenharmony_ci					 CPCAP_BIT_TS_M2 | \
7362306a36Sopenharmony_ci					 CPCAP_BIT_TS_M1)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define CPCAP_MAX_TEMP_LVL		27
7662306a36Sopenharmony_ci#define CPCAP_FOUR_POINT_TWO_ADC	801
7762306a36Sopenharmony_ci#define ST_ADC_CAL_CHRGI_HIGH_THRESHOLD	530
7862306a36Sopenharmony_ci#define ST_ADC_CAL_CHRGI_LOW_THRESHOLD	494
7962306a36Sopenharmony_ci#define ST_ADC_CAL_BATTI_HIGH_THRESHOLD	530
8062306a36Sopenharmony_ci#define ST_ADC_CAL_BATTI_LOW_THRESHOLD	494
8162306a36Sopenharmony_ci#define ST_ADC_CALIBRATE_DIFF_THRESHOLD	3
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define CPCAP_ADC_MAX_RETRIES		5	/* Calibration */
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/*
8662306a36Sopenharmony_ci * struct cpcap_adc_ato - timing settings for cpcap adc
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * Unfortunately no cpcap documentation available, please document when
8962306a36Sopenharmony_ci * using these.
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_cistruct cpcap_adc_ato {
9262306a36Sopenharmony_ci	unsigned short ato_in;
9362306a36Sopenharmony_ci	unsigned short atox_in;
9462306a36Sopenharmony_ci	unsigned short adc_ps_factor_in;
9562306a36Sopenharmony_ci	unsigned short atox_ps_factor_in;
9662306a36Sopenharmony_ci	unsigned short ato_out;
9762306a36Sopenharmony_ci	unsigned short atox_out;
9862306a36Sopenharmony_ci	unsigned short adc_ps_factor_out;
9962306a36Sopenharmony_ci	unsigned short atox_ps_factor_out;
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci/**
10362306a36Sopenharmony_ci * struct cpcap_adc - cpcap adc device driver data
10462306a36Sopenharmony_ci * @reg: cpcap regmap
10562306a36Sopenharmony_ci * @dev: struct device
10662306a36Sopenharmony_ci * @vendor: cpcap vendor
10762306a36Sopenharmony_ci * @irq: interrupt
10862306a36Sopenharmony_ci * @lock: mutex
10962306a36Sopenharmony_ci * @ato: request timings
11062306a36Sopenharmony_ci * @wq_data_avail: work queue
11162306a36Sopenharmony_ci * @done: work done
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_cistruct cpcap_adc {
11462306a36Sopenharmony_ci	struct regmap *reg;
11562306a36Sopenharmony_ci	struct device *dev;
11662306a36Sopenharmony_ci	u16 vendor;
11762306a36Sopenharmony_ci	int irq;
11862306a36Sopenharmony_ci	struct mutex lock;	/* ADC register access lock */
11962306a36Sopenharmony_ci	const struct cpcap_adc_ato *ato;
12062306a36Sopenharmony_ci	wait_queue_head_t wq_data_avail;
12162306a36Sopenharmony_ci	bool done;
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/*
12562306a36Sopenharmony_ci * enum cpcap_adc_channel - cpcap adc channels
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_cienum cpcap_adc_channel {
12862306a36Sopenharmony_ci	/* Bank0 channels */
12962306a36Sopenharmony_ci	CPCAP_ADC_AD0,		/* Battery temperature */
13062306a36Sopenharmony_ci	CPCAP_ADC_BATTP,	/* Battery voltage */
13162306a36Sopenharmony_ci	CPCAP_ADC_VBUS,		/* USB VBUS voltage */
13262306a36Sopenharmony_ci	CPCAP_ADC_AD3,		/* Die temperature when charging */
13362306a36Sopenharmony_ci	CPCAP_ADC_BPLUS_AD4,	/* Another battery or system voltage */
13462306a36Sopenharmony_ci	CPCAP_ADC_CHG_ISENSE,	/* Calibrated charge current */
13562306a36Sopenharmony_ci	CPCAP_ADC_BATTI,	/* Calibrated system current */
13662306a36Sopenharmony_ci	CPCAP_ADC_USB_ID,	/* USB OTG ID, unused on droid 4? */
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* Bank1 channels */
13962306a36Sopenharmony_ci	CPCAP_ADC_AD8,		/* Seems unused */
14062306a36Sopenharmony_ci	CPCAP_ADC_AD9,		/* Seems unused */
14162306a36Sopenharmony_ci	CPCAP_ADC_LICELL,	/* Maybe system voltage? Always 3V */
14262306a36Sopenharmony_ci	CPCAP_ADC_HV_BATTP,	/* Another battery detection? */
14362306a36Sopenharmony_ci	CPCAP_ADC_TSX1_AD12,	/* Seems unused, for touchscreen? */
14462306a36Sopenharmony_ci	CPCAP_ADC_TSX2_AD13,	/* Seems unused, for touchscreen? */
14562306a36Sopenharmony_ci	CPCAP_ADC_TSY1_AD14,	/* Seems unused, for touchscreen? */
14662306a36Sopenharmony_ci	CPCAP_ADC_TSY2_AD15,	/* Seems unused, for touchscreen? */
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* Remuxed channels using bank0 entries */
14962306a36Sopenharmony_ci	CPCAP_ADC_BATTP_PI16,	/* Alternative mux mode for BATTP */
15062306a36Sopenharmony_ci	CPCAP_ADC_BATTI_PI17,	/* Alternative mux mode for BATTI */
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	CPCAP_ADC_CHANNEL_NUM,
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/*
15662306a36Sopenharmony_ci * enum cpcap_adc_timing - cpcap adc timing options
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * CPCAP_ADC_TIMING_IMM seems to be immediate with no timings.
15962306a36Sopenharmony_ci * Please document when using.
16062306a36Sopenharmony_ci */
16162306a36Sopenharmony_cienum cpcap_adc_timing {
16262306a36Sopenharmony_ci	CPCAP_ADC_TIMING_IMM,
16362306a36Sopenharmony_ci	CPCAP_ADC_TIMING_IN,
16462306a36Sopenharmony_ci	CPCAP_ADC_TIMING_OUT,
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/**
16862306a36Sopenharmony_ci * struct cpcap_adc_phasing_tbl - cpcap phasing table
16962306a36Sopenharmony_ci * @offset: offset in the phasing table
17062306a36Sopenharmony_ci * @multiplier: multiplier in the phasing table
17162306a36Sopenharmony_ci * @divider: divider in the phasing table
17262306a36Sopenharmony_ci * @min: minimum value
17362306a36Sopenharmony_ci * @max: maximum value
17462306a36Sopenharmony_ci */
17562306a36Sopenharmony_cistruct cpcap_adc_phasing_tbl {
17662306a36Sopenharmony_ci	short offset;
17762306a36Sopenharmony_ci	unsigned short multiplier;
17862306a36Sopenharmony_ci	unsigned short divider;
17962306a36Sopenharmony_ci	short min;
18062306a36Sopenharmony_ci	short max;
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/**
18462306a36Sopenharmony_ci * struct cpcap_adc_conversion_tbl - cpcap conversion table
18562306a36Sopenharmony_ci * @conv_type: conversion type
18662306a36Sopenharmony_ci * @align_offset: align offset
18762306a36Sopenharmony_ci * @conv_offset: conversion offset
18862306a36Sopenharmony_ci * @cal_offset: calibration offset
18962306a36Sopenharmony_ci * @multiplier: conversion multiplier
19062306a36Sopenharmony_ci * @divider: conversion divider
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_cistruct cpcap_adc_conversion_tbl {
19362306a36Sopenharmony_ci	enum iio_chan_info_enum conv_type;
19462306a36Sopenharmony_ci	int align_offset;
19562306a36Sopenharmony_ci	int conv_offset;
19662306a36Sopenharmony_ci	int cal_offset;
19762306a36Sopenharmony_ci	int multiplier;
19862306a36Sopenharmony_ci	int divider;
19962306a36Sopenharmony_ci};
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/**
20262306a36Sopenharmony_ci * struct cpcap_adc_request - cpcap adc request
20362306a36Sopenharmony_ci * @channel: request channel
20462306a36Sopenharmony_ci * @phase_tbl: channel phasing table
20562306a36Sopenharmony_ci * @conv_tbl: channel conversion table
20662306a36Sopenharmony_ci * @bank_index: channel index within the bank
20762306a36Sopenharmony_ci * @timing: timing settings
20862306a36Sopenharmony_ci * @result: result
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_cistruct cpcap_adc_request {
21162306a36Sopenharmony_ci	int channel;
21262306a36Sopenharmony_ci	const struct cpcap_adc_phasing_tbl *phase_tbl;
21362306a36Sopenharmony_ci	const struct cpcap_adc_conversion_tbl *conv_tbl;
21462306a36Sopenharmony_ci	int bank_index;
21562306a36Sopenharmony_ci	enum cpcap_adc_timing timing;
21662306a36Sopenharmony_ci	int result;
21762306a36Sopenharmony_ci};
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci/* Phasing table for channels. Note that channels 16 & 17 use BATTP and BATTI */
22062306a36Sopenharmony_cistatic const struct cpcap_adc_phasing_tbl bank_phasing[] = {
22162306a36Sopenharmony_ci	/* Bank0 */
22262306a36Sopenharmony_ci	[CPCAP_ADC_AD0] =          {0, 0x80, 0x80,    0, 1023},
22362306a36Sopenharmony_ci	[CPCAP_ADC_BATTP] =        {0, 0x80, 0x80,    0, 1023},
22462306a36Sopenharmony_ci	[CPCAP_ADC_VBUS] =         {0, 0x80, 0x80,    0, 1023},
22562306a36Sopenharmony_ci	[CPCAP_ADC_AD3] =          {0, 0x80, 0x80,    0, 1023},
22662306a36Sopenharmony_ci	[CPCAP_ADC_BPLUS_AD4] =    {0, 0x80, 0x80,    0, 1023},
22762306a36Sopenharmony_ci	[CPCAP_ADC_CHG_ISENSE] =   {0, 0x80, 0x80, -512,  511},
22862306a36Sopenharmony_ci	[CPCAP_ADC_BATTI] =        {0, 0x80, 0x80, -512,  511},
22962306a36Sopenharmony_ci	[CPCAP_ADC_USB_ID] =       {0, 0x80, 0x80,    0, 1023},
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/* Bank1 */
23262306a36Sopenharmony_ci	[CPCAP_ADC_AD8] =          {0, 0x80, 0x80,    0, 1023},
23362306a36Sopenharmony_ci	[CPCAP_ADC_AD9] =          {0, 0x80, 0x80,    0, 1023},
23462306a36Sopenharmony_ci	[CPCAP_ADC_LICELL] =       {0, 0x80, 0x80,    0, 1023},
23562306a36Sopenharmony_ci	[CPCAP_ADC_HV_BATTP] =     {0, 0x80, 0x80,    0, 1023},
23662306a36Sopenharmony_ci	[CPCAP_ADC_TSX1_AD12] =    {0, 0x80, 0x80,    0, 1023},
23762306a36Sopenharmony_ci	[CPCAP_ADC_TSX2_AD13] =    {0, 0x80, 0x80,    0, 1023},
23862306a36Sopenharmony_ci	[CPCAP_ADC_TSY1_AD14] =    {0, 0x80, 0x80,    0, 1023},
23962306a36Sopenharmony_ci	[CPCAP_ADC_TSY2_AD15] =    {0, 0x80, 0x80,    0, 1023},
24062306a36Sopenharmony_ci};
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci/*
24362306a36Sopenharmony_ci * Conversion table for channels. Updated during init based on calibration.
24462306a36Sopenharmony_ci * Here too channels 16 & 17 use BATTP and BATTI.
24562306a36Sopenharmony_ci */
24662306a36Sopenharmony_cistatic struct cpcap_adc_conversion_tbl bank_conversion[] = {
24762306a36Sopenharmony_ci	/* Bank0 */
24862306a36Sopenharmony_ci	[CPCAP_ADC_AD0] = {
24962306a36Sopenharmony_ci		IIO_CHAN_INFO_PROCESSED,    0,    0, 0,     1,    1,
25062306a36Sopenharmony_ci	},
25162306a36Sopenharmony_ci	[CPCAP_ADC_BATTP] = {
25262306a36Sopenharmony_ci		IIO_CHAN_INFO_PROCESSED,    0, 2400, 0,  2300, 1023,
25362306a36Sopenharmony_ci	},
25462306a36Sopenharmony_ci	[CPCAP_ADC_VBUS] = {
25562306a36Sopenharmony_ci		IIO_CHAN_INFO_PROCESSED,    0,    0, 0, 10000, 1023,
25662306a36Sopenharmony_ci	},
25762306a36Sopenharmony_ci	[CPCAP_ADC_AD3] = {
25862306a36Sopenharmony_ci		IIO_CHAN_INFO_PROCESSED,    0,    0, 0,     1,    1,
25962306a36Sopenharmony_ci		},
26062306a36Sopenharmony_ci	[CPCAP_ADC_BPLUS_AD4] = {
26162306a36Sopenharmony_ci		IIO_CHAN_INFO_PROCESSED,    0, 2400, 0,  2300, 1023,
26262306a36Sopenharmony_ci	},
26362306a36Sopenharmony_ci	[CPCAP_ADC_CHG_ISENSE] = {
26462306a36Sopenharmony_ci		IIO_CHAN_INFO_PROCESSED, -512,    2, 0,  5000, 1023,
26562306a36Sopenharmony_ci	},
26662306a36Sopenharmony_ci	[CPCAP_ADC_BATTI] = {
26762306a36Sopenharmony_ci		IIO_CHAN_INFO_PROCESSED, -512,    2, 0,  5000, 1023,
26862306a36Sopenharmony_ci	},
26962306a36Sopenharmony_ci	[CPCAP_ADC_USB_ID] = {
27062306a36Sopenharmony_ci		IIO_CHAN_INFO_RAW,          0,    0, 0,     1,    1,
27162306a36Sopenharmony_ci	},
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* Bank1 */
27462306a36Sopenharmony_ci	[CPCAP_ADC_AD8] = {
27562306a36Sopenharmony_ci		IIO_CHAN_INFO_RAW,          0,    0, 0,     1,    1,
27662306a36Sopenharmony_ci	},
27762306a36Sopenharmony_ci	[CPCAP_ADC_AD9] = {
27862306a36Sopenharmony_ci		IIO_CHAN_INFO_RAW,          0,    0, 0,     1,    1,
27962306a36Sopenharmony_ci	},
28062306a36Sopenharmony_ci	[CPCAP_ADC_LICELL] = {
28162306a36Sopenharmony_ci		IIO_CHAN_INFO_PROCESSED,    0,    0, 0,  3400, 1023,
28262306a36Sopenharmony_ci	},
28362306a36Sopenharmony_ci	[CPCAP_ADC_HV_BATTP] = {
28462306a36Sopenharmony_ci		IIO_CHAN_INFO_RAW,          0,    0, 0,     1,    1,
28562306a36Sopenharmony_ci	},
28662306a36Sopenharmony_ci	[CPCAP_ADC_TSX1_AD12] = {
28762306a36Sopenharmony_ci		IIO_CHAN_INFO_RAW,          0,    0, 0,     1,    1,
28862306a36Sopenharmony_ci	},
28962306a36Sopenharmony_ci	[CPCAP_ADC_TSX2_AD13] = {
29062306a36Sopenharmony_ci		IIO_CHAN_INFO_RAW,          0,    0, 0,     1,    1,
29162306a36Sopenharmony_ci	},
29262306a36Sopenharmony_ci	[CPCAP_ADC_TSY1_AD14] = {
29362306a36Sopenharmony_ci		IIO_CHAN_INFO_RAW,          0,    0, 0,     1,    1,
29462306a36Sopenharmony_ci	},
29562306a36Sopenharmony_ci	[CPCAP_ADC_TSY2_AD15] = {
29662306a36Sopenharmony_ci		IIO_CHAN_INFO_RAW,          0,    0, 0,     1,    1,
29762306a36Sopenharmony_ci	},
29862306a36Sopenharmony_ci};
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci/*
30162306a36Sopenharmony_ci * Temperature lookup table of register values to milliCelcius.
30262306a36Sopenharmony_ci * REVISIT: Check the duplicate 0x3ff entry in a freezer
30362306a36Sopenharmony_ci */
30462306a36Sopenharmony_cistatic const int temp_map[CPCAP_MAX_TEMP_LVL][2] = {
30562306a36Sopenharmony_ci	{ 0x03ff, -40000 },
30662306a36Sopenharmony_ci	{ 0x03ff, -35000 },
30762306a36Sopenharmony_ci	{ 0x03ef, -30000 },
30862306a36Sopenharmony_ci	{ 0x03b2, -25000 },
30962306a36Sopenharmony_ci	{ 0x036c, -20000 },
31062306a36Sopenharmony_ci	{ 0x0320, -15000 },
31162306a36Sopenharmony_ci	{ 0x02d0, -10000 },
31262306a36Sopenharmony_ci	{ 0x027f, -5000 },
31362306a36Sopenharmony_ci	{ 0x022f, 0 },
31462306a36Sopenharmony_ci	{ 0x01e4, 5000 },
31562306a36Sopenharmony_ci	{ 0x019f, 10000 },
31662306a36Sopenharmony_ci	{ 0x0161, 15000 },
31762306a36Sopenharmony_ci	{ 0x012b, 20000 },
31862306a36Sopenharmony_ci	{ 0x00fc, 25000 },
31962306a36Sopenharmony_ci	{ 0x00d4, 30000 },
32062306a36Sopenharmony_ci	{ 0x00b2, 35000 },
32162306a36Sopenharmony_ci	{ 0x0095, 40000 },
32262306a36Sopenharmony_ci	{ 0x007d, 45000 },
32362306a36Sopenharmony_ci	{ 0x0069, 50000 },
32462306a36Sopenharmony_ci	{ 0x0059, 55000 },
32562306a36Sopenharmony_ci	{ 0x004b, 60000 },
32662306a36Sopenharmony_ci	{ 0x003f, 65000 },
32762306a36Sopenharmony_ci	{ 0x0036, 70000 },
32862306a36Sopenharmony_ci	{ 0x002e, 75000 },
32962306a36Sopenharmony_ci	{ 0x0027, 80000 },
33062306a36Sopenharmony_ci	{ 0x0022, 85000 },
33162306a36Sopenharmony_ci	{ 0x001d, 90000 },
33262306a36Sopenharmony_ci};
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci#define CPCAP_CHAN(_type, _index, _address, _datasheet_name) {	\
33562306a36Sopenharmony_ci	.type = (_type), \
33662306a36Sopenharmony_ci	.address = (_address), \
33762306a36Sopenharmony_ci	.indexed = 1, \
33862306a36Sopenharmony_ci	.channel = (_index), \
33962306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
34062306a36Sopenharmony_ci			      BIT(IIO_CHAN_INFO_PROCESSED), \
34162306a36Sopenharmony_ci	.scan_index = (_index), \
34262306a36Sopenharmony_ci	.scan_type = { \
34362306a36Sopenharmony_ci		.sign = 'u', \
34462306a36Sopenharmony_ci		.realbits = 10, \
34562306a36Sopenharmony_ci		.storagebits = 16, \
34662306a36Sopenharmony_ci		.endianness = IIO_CPU, \
34762306a36Sopenharmony_ci	}, \
34862306a36Sopenharmony_ci	.datasheet_name = (_datasheet_name), \
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/*
35262306a36Sopenharmony_ci * The datasheet names are from Motorola mapphone Linux kernel except
35362306a36Sopenharmony_ci * for the last two which might be uncalibrated charge voltage and
35462306a36Sopenharmony_ci * current.
35562306a36Sopenharmony_ci */
35662306a36Sopenharmony_cistatic const struct iio_chan_spec cpcap_adc_channels[] = {
35762306a36Sopenharmony_ci	/* Bank0 */
35862306a36Sopenharmony_ci	CPCAP_CHAN(IIO_TEMP,    0, CPCAP_REG_ADCD0,  "battdetb"),
35962306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 1, CPCAP_REG_ADCD1,  "battp"),
36062306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 2, CPCAP_REG_ADCD2,  "vbus"),
36162306a36Sopenharmony_ci	CPCAP_CHAN(IIO_TEMP,    3, CPCAP_REG_ADCD3,  "ad3"),
36262306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 4, CPCAP_REG_ADCD4,  "ad4"),
36362306a36Sopenharmony_ci	CPCAP_CHAN(IIO_CURRENT, 5, CPCAP_REG_ADCD5,  "chg_isense"),
36462306a36Sopenharmony_ci	CPCAP_CHAN(IIO_CURRENT, 6, CPCAP_REG_ADCD6,  "batti"),
36562306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 7, CPCAP_REG_ADCD7,  "usb_id"),
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* Bank1 */
36862306a36Sopenharmony_ci	CPCAP_CHAN(IIO_CURRENT, 8, CPCAP_REG_ADCD0,  "ad8"),
36962306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 9, CPCAP_REG_ADCD1,  "ad9"),
37062306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 10, CPCAP_REG_ADCD2, "licell"),
37162306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 11, CPCAP_REG_ADCD3, "hv_battp"),
37262306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 12, CPCAP_REG_ADCD4, "tsx1_ad12"),
37362306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 13, CPCAP_REG_ADCD5, "tsx2_ad13"),
37462306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 14, CPCAP_REG_ADCD6, "tsy1_ad14"),
37562306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 15, CPCAP_REG_ADCD7, "tsy2_ad15"),
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/* There are two registers with multiplexed functionality */
37862306a36Sopenharmony_ci	CPCAP_CHAN(IIO_VOLTAGE, 16, CPCAP_REG_ADCD0, "chg_vsense"),
37962306a36Sopenharmony_ci	CPCAP_CHAN(IIO_CURRENT, 17, CPCAP_REG_ADCD1, "batti2"),
38062306a36Sopenharmony_ci};
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic irqreturn_t cpcap_adc_irq_thread(int irq, void *data)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct iio_dev *indio_dev = data;
38562306a36Sopenharmony_ci	struct cpcap_adc *ddata = iio_priv(indio_dev);
38662306a36Sopenharmony_ci	int error;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
38962306a36Sopenharmony_ci				   CPCAP_BIT_ADTRIG_DIS,
39062306a36Sopenharmony_ci				   CPCAP_BIT_ADTRIG_DIS);
39162306a36Sopenharmony_ci	if (error)
39262306a36Sopenharmony_ci		return IRQ_NONE;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	ddata->done = true;
39562306a36Sopenharmony_ci	wake_up_interruptible(&ddata->wq_data_avail);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	return IRQ_HANDLED;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci/* ADC calibration functions */
40162306a36Sopenharmony_cistatic void cpcap_adc_setup_calibrate(struct cpcap_adc *ddata,
40262306a36Sopenharmony_ci				      enum cpcap_adc_channel chan)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	unsigned int value = 0;
40562306a36Sopenharmony_ci	unsigned long timeout = jiffies + msecs_to_jiffies(3000);
40662306a36Sopenharmony_ci	int error;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if ((chan != CPCAP_ADC_CHG_ISENSE) &&
40962306a36Sopenharmony_ci	    (chan != CPCAP_ADC_BATTI))
41062306a36Sopenharmony_ci		return;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	value |= CPCAP_BIT_CAL_MODE | CPCAP_BIT_RAND0;
41362306a36Sopenharmony_ci	value |= ((chan << 4) &
41462306a36Sopenharmony_ci		  (CPCAP_BIT_ADA2 | CPCAP_BIT_ADA1 | CPCAP_BIT_ADA0));
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1,
41762306a36Sopenharmony_ci				   CPCAP_BIT_CAL_MODE | CPCAP_BIT_ATOX |
41862306a36Sopenharmony_ci				   CPCAP_BIT_ATO3 | CPCAP_BIT_ATO2 |
41962306a36Sopenharmony_ci				   CPCAP_BIT_ATO1 | CPCAP_BIT_ATO0 |
42062306a36Sopenharmony_ci				   CPCAP_BIT_ADA2 | CPCAP_BIT_ADA1 |
42162306a36Sopenharmony_ci				   CPCAP_BIT_ADA0 | CPCAP_BIT_AD_SEL1 |
42262306a36Sopenharmony_ci				   CPCAP_BIT_RAND1 | CPCAP_BIT_RAND0,
42362306a36Sopenharmony_ci				   value);
42462306a36Sopenharmony_ci	if (error)
42562306a36Sopenharmony_ci		return;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
42862306a36Sopenharmony_ci				   CPCAP_BIT_ATOX_PS_FACTOR |
42962306a36Sopenharmony_ci				   CPCAP_BIT_ADC_PS_FACTOR1 |
43062306a36Sopenharmony_ci				   CPCAP_BIT_ADC_PS_FACTOR0,
43162306a36Sopenharmony_ci				   0);
43262306a36Sopenharmony_ci	if (error)
43362306a36Sopenharmony_ci		return;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
43662306a36Sopenharmony_ci				   CPCAP_BIT_ADTRIG_DIS,
43762306a36Sopenharmony_ci				   CPCAP_BIT_ADTRIG_DIS);
43862306a36Sopenharmony_ci	if (error)
43962306a36Sopenharmony_ci		return;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
44262306a36Sopenharmony_ci				   CPCAP_BIT_ASC,
44362306a36Sopenharmony_ci				   CPCAP_BIT_ASC);
44462306a36Sopenharmony_ci	if (error)
44562306a36Sopenharmony_ci		return;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	do {
44862306a36Sopenharmony_ci		schedule_timeout_uninterruptible(1);
44962306a36Sopenharmony_ci		error = regmap_read(ddata->reg, CPCAP_REG_ADCC2, &value);
45062306a36Sopenharmony_ci		if (error)
45162306a36Sopenharmony_ci			return;
45262306a36Sopenharmony_ci	} while ((value & CPCAP_BIT_ASC) && time_before(jiffies, timeout));
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (value & CPCAP_BIT_ASC)
45562306a36Sopenharmony_ci		dev_err(ddata->dev,
45662306a36Sopenharmony_ci			"Timeout waiting for calibration to complete\n");
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1,
45962306a36Sopenharmony_ci				   CPCAP_BIT_CAL_MODE, 0);
46062306a36Sopenharmony_ci	if (error)
46162306a36Sopenharmony_ci		return;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic int cpcap_adc_calibrate_one(struct cpcap_adc *ddata,
46562306a36Sopenharmony_ci				   int channel,
46662306a36Sopenharmony_ci				   u16 calibration_register,
46762306a36Sopenharmony_ci				   int lower_threshold,
46862306a36Sopenharmony_ci				   int upper_threshold)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	unsigned int calibration_data[2];
47162306a36Sopenharmony_ci	unsigned short cal_data_diff;
47262306a36Sopenharmony_ci	int i, error;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	for (i = 0; i < CPCAP_ADC_MAX_RETRIES; i++) {
47562306a36Sopenharmony_ci		calibration_data[0]  = 0;
47662306a36Sopenharmony_ci		calibration_data[1]  = 0;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		cpcap_adc_setup_calibrate(ddata, channel);
47962306a36Sopenharmony_ci		error = regmap_read(ddata->reg, calibration_register,
48062306a36Sopenharmony_ci				    &calibration_data[0]);
48162306a36Sopenharmony_ci		if (error)
48262306a36Sopenharmony_ci			return error;
48362306a36Sopenharmony_ci		cpcap_adc_setup_calibrate(ddata, channel);
48462306a36Sopenharmony_ci		error = regmap_read(ddata->reg, calibration_register,
48562306a36Sopenharmony_ci				    &calibration_data[1]);
48662306a36Sopenharmony_ci		if (error)
48762306a36Sopenharmony_ci			return error;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci		if (calibration_data[0] > calibration_data[1])
49062306a36Sopenharmony_ci			cal_data_diff =
49162306a36Sopenharmony_ci				calibration_data[0] - calibration_data[1];
49262306a36Sopenharmony_ci		else
49362306a36Sopenharmony_ci			cal_data_diff =
49462306a36Sopenharmony_ci				calibration_data[1] - calibration_data[0];
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci		if (((calibration_data[1] >= lower_threshold) &&
49762306a36Sopenharmony_ci		     (calibration_data[1] <= upper_threshold) &&
49862306a36Sopenharmony_ci		     (cal_data_diff <= ST_ADC_CALIBRATE_DIFF_THRESHOLD)) ||
49962306a36Sopenharmony_ci		    (ddata->vendor == CPCAP_VENDOR_TI)) {
50062306a36Sopenharmony_ci			bank_conversion[channel].cal_offset =
50162306a36Sopenharmony_ci				((short)calibration_data[1] * -1) + 512;
50262306a36Sopenharmony_ci			dev_dbg(ddata->dev, "ch%i calibration complete: %i\n",
50362306a36Sopenharmony_ci				channel, bank_conversion[channel].cal_offset);
50462306a36Sopenharmony_ci			break;
50562306a36Sopenharmony_ci		}
50662306a36Sopenharmony_ci		usleep_range(5000, 10000);
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return 0;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic int cpcap_adc_calibrate(struct cpcap_adc *ddata)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	int error;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	error = cpcap_adc_calibrate_one(ddata, CPCAP_ADC_CHG_ISENSE,
51762306a36Sopenharmony_ci					CPCAP_REG_ADCAL1,
51862306a36Sopenharmony_ci					ST_ADC_CAL_CHRGI_LOW_THRESHOLD,
51962306a36Sopenharmony_ci					ST_ADC_CAL_CHRGI_HIGH_THRESHOLD);
52062306a36Sopenharmony_ci	if (error)
52162306a36Sopenharmony_ci		return error;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	error = cpcap_adc_calibrate_one(ddata, CPCAP_ADC_BATTI,
52462306a36Sopenharmony_ci					CPCAP_REG_ADCAL2,
52562306a36Sopenharmony_ci					ST_ADC_CAL_BATTI_LOW_THRESHOLD,
52662306a36Sopenharmony_ci					ST_ADC_CAL_BATTI_HIGH_THRESHOLD);
52762306a36Sopenharmony_ci	if (error)
52862306a36Sopenharmony_ci		return error;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return 0;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci/* ADC setup, read and scale functions */
53462306a36Sopenharmony_cistatic void cpcap_adc_setup_bank(struct cpcap_adc *ddata,
53562306a36Sopenharmony_ci				 struct cpcap_adc_request *req)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	const struct cpcap_adc_ato *ato = ddata->ato;
53862306a36Sopenharmony_ci	unsigned short value1 = 0;
53962306a36Sopenharmony_ci	unsigned short value2 = 0;
54062306a36Sopenharmony_ci	int error;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (!ato)
54362306a36Sopenharmony_ci		return;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	switch (req->channel) {
54662306a36Sopenharmony_ci	case CPCAP_ADC_AD0:
54762306a36Sopenharmony_ci		value2 |= CPCAP_BIT_THERMBIAS_EN;
54862306a36Sopenharmony_ci		error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
54962306a36Sopenharmony_ci					   CPCAP_BIT_THERMBIAS_EN,
55062306a36Sopenharmony_ci					   value2);
55162306a36Sopenharmony_ci		if (error)
55262306a36Sopenharmony_ci			return;
55362306a36Sopenharmony_ci		usleep_range(800, 1000);
55462306a36Sopenharmony_ci		break;
55562306a36Sopenharmony_ci	case CPCAP_ADC_AD8 ... CPCAP_ADC_TSY2_AD15:
55662306a36Sopenharmony_ci		value1 |= CPCAP_BIT_AD_SEL1;
55762306a36Sopenharmony_ci		break;
55862306a36Sopenharmony_ci	case CPCAP_ADC_BATTP_PI16 ... CPCAP_ADC_BATTI_PI17:
55962306a36Sopenharmony_ci		value1 |= CPCAP_BIT_RAND1;
56062306a36Sopenharmony_ci		break;
56162306a36Sopenharmony_ci	default:
56262306a36Sopenharmony_ci		break;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	switch (req->timing) {
56662306a36Sopenharmony_ci	case CPCAP_ADC_TIMING_IN:
56762306a36Sopenharmony_ci		value1 |= ato->ato_in;
56862306a36Sopenharmony_ci		value1 |= ato->atox_in;
56962306a36Sopenharmony_ci		value2 |= ato->adc_ps_factor_in;
57062306a36Sopenharmony_ci		value2 |= ato->atox_ps_factor_in;
57162306a36Sopenharmony_ci		break;
57262306a36Sopenharmony_ci	case CPCAP_ADC_TIMING_OUT:
57362306a36Sopenharmony_ci		value1 |= ato->ato_out;
57462306a36Sopenharmony_ci		value1 |= ato->atox_out;
57562306a36Sopenharmony_ci		value2 |= ato->adc_ps_factor_out;
57662306a36Sopenharmony_ci		value2 |= ato->atox_ps_factor_out;
57762306a36Sopenharmony_ci		break;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	case CPCAP_ADC_TIMING_IMM:
58062306a36Sopenharmony_ci	default:
58162306a36Sopenharmony_ci		break;
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1,
58562306a36Sopenharmony_ci				   CPCAP_BIT_CAL_MODE | CPCAP_BIT_ATOX |
58662306a36Sopenharmony_ci				   CPCAP_BIT_ATO3 | CPCAP_BIT_ATO2 |
58762306a36Sopenharmony_ci				   CPCAP_BIT_ATO1 | CPCAP_BIT_ATO0 |
58862306a36Sopenharmony_ci				   CPCAP_BIT_ADA2 | CPCAP_BIT_ADA1 |
58962306a36Sopenharmony_ci				   CPCAP_BIT_ADA0 | CPCAP_BIT_AD_SEL1 |
59062306a36Sopenharmony_ci				   CPCAP_BIT_RAND1 | CPCAP_BIT_RAND0,
59162306a36Sopenharmony_ci				   value1);
59262306a36Sopenharmony_ci	if (error)
59362306a36Sopenharmony_ci		return;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
59662306a36Sopenharmony_ci				   CPCAP_BIT_ATOX_PS_FACTOR |
59762306a36Sopenharmony_ci				   CPCAP_BIT_ADC_PS_FACTOR1 |
59862306a36Sopenharmony_ci				   CPCAP_BIT_ADC_PS_FACTOR0 |
59962306a36Sopenharmony_ci				   CPCAP_BIT_THERMBIAS_EN,
60062306a36Sopenharmony_ci				   value2);
60162306a36Sopenharmony_ci	if (error)
60262306a36Sopenharmony_ci		return;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (req->timing == CPCAP_ADC_TIMING_IMM) {
60562306a36Sopenharmony_ci		error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
60662306a36Sopenharmony_ci					   CPCAP_BIT_ADTRIG_DIS,
60762306a36Sopenharmony_ci					   CPCAP_BIT_ADTRIG_DIS);
60862306a36Sopenharmony_ci		if (error)
60962306a36Sopenharmony_ci			return;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
61262306a36Sopenharmony_ci					   CPCAP_BIT_ASC,
61362306a36Sopenharmony_ci					   CPCAP_BIT_ASC);
61462306a36Sopenharmony_ci		if (error)
61562306a36Sopenharmony_ci			return;
61662306a36Sopenharmony_ci	} else {
61762306a36Sopenharmony_ci		error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
61862306a36Sopenharmony_ci					   CPCAP_BIT_ADTRIG_ONESHOT,
61962306a36Sopenharmony_ci					   CPCAP_BIT_ADTRIG_ONESHOT);
62062306a36Sopenharmony_ci		if (error)
62162306a36Sopenharmony_ci			return;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci		error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
62462306a36Sopenharmony_ci					   CPCAP_BIT_ADTRIG_DIS, 0);
62562306a36Sopenharmony_ci		if (error)
62662306a36Sopenharmony_ci			return;
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic int cpcap_adc_start_bank(struct cpcap_adc *ddata,
63162306a36Sopenharmony_ci				struct cpcap_adc_request *req)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	int i, error;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	req->timing = CPCAP_ADC_TIMING_IMM;
63662306a36Sopenharmony_ci	ddata->done = false;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	for (i = 0; i < CPCAP_ADC_MAX_RETRIES; i++) {
63962306a36Sopenharmony_ci		cpcap_adc_setup_bank(ddata, req);
64062306a36Sopenharmony_ci		error = wait_event_interruptible_timeout(ddata->wq_data_avail,
64162306a36Sopenharmony_ci							 ddata->done,
64262306a36Sopenharmony_ci							 msecs_to_jiffies(50));
64362306a36Sopenharmony_ci		if (error > 0)
64462306a36Sopenharmony_ci			return 0;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		if (error == 0) {
64762306a36Sopenharmony_ci			error = -ETIMEDOUT;
64862306a36Sopenharmony_ci			continue;
64962306a36Sopenharmony_ci		}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		if (error < 0)
65262306a36Sopenharmony_ci			return error;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	return error;
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic int cpcap_adc_stop_bank(struct cpcap_adc *ddata)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	int error;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1,
66362306a36Sopenharmony_ci				   0xffff,
66462306a36Sopenharmony_ci				   CPCAP_REG_ADCC1_DEFAULTS);
66562306a36Sopenharmony_ci	if (error)
66662306a36Sopenharmony_ci		return error;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	return regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
66962306a36Sopenharmony_ci				  0xffff,
67062306a36Sopenharmony_ci				  CPCAP_REG_ADCC2_DEFAULTS);
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic void cpcap_adc_phase(struct cpcap_adc_request *req)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	const struct cpcap_adc_conversion_tbl *conv_tbl = req->conv_tbl;
67662306a36Sopenharmony_ci	const struct cpcap_adc_phasing_tbl *phase_tbl = req->phase_tbl;
67762306a36Sopenharmony_ci	int index = req->channel;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	/* Remuxed channels 16 and 17 use BATTP and BATTI entries */
68062306a36Sopenharmony_ci	switch (req->channel) {
68162306a36Sopenharmony_ci	case CPCAP_ADC_BATTP:
68262306a36Sopenharmony_ci	case CPCAP_ADC_BATTP_PI16:
68362306a36Sopenharmony_ci		index = req->bank_index;
68462306a36Sopenharmony_ci		req->result -= phase_tbl[index].offset;
68562306a36Sopenharmony_ci		req->result -= CPCAP_FOUR_POINT_TWO_ADC;
68662306a36Sopenharmony_ci		req->result *= phase_tbl[index].multiplier;
68762306a36Sopenharmony_ci		if (phase_tbl[index].divider == 0)
68862306a36Sopenharmony_ci			return;
68962306a36Sopenharmony_ci		req->result /= phase_tbl[index].divider;
69062306a36Sopenharmony_ci		req->result += CPCAP_FOUR_POINT_TWO_ADC;
69162306a36Sopenharmony_ci		break;
69262306a36Sopenharmony_ci	case CPCAP_ADC_BATTI_PI17:
69362306a36Sopenharmony_ci		index = req->bank_index;
69462306a36Sopenharmony_ci		fallthrough;
69562306a36Sopenharmony_ci	default:
69662306a36Sopenharmony_ci		req->result += conv_tbl[index].cal_offset;
69762306a36Sopenharmony_ci		req->result += conv_tbl[index].align_offset;
69862306a36Sopenharmony_ci		req->result *= phase_tbl[index].multiplier;
69962306a36Sopenharmony_ci		if (phase_tbl[index].divider == 0)
70062306a36Sopenharmony_ci			return;
70162306a36Sopenharmony_ci		req->result /= phase_tbl[index].divider;
70262306a36Sopenharmony_ci		req->result += phase_tbl[index].offset;
70362306a36Sopenharmony_ci		break;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if (req->result < phase_tbl[index].min)
70762306a36Sopenharmony_ci		req->result = phase_tbl[index].min;
70862306a36Sopenharmony_ci	else if (req->result > phase_tbl[index].max)
70962306a36Sopenharmony_ci		req->result = phase_tbl[index].max;
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci/* Looks up temperatures in a table and calculates averages if needed */
71362306a36Sopenharmony_cistatic int cpcap_adc_table_to_millicelcius(unsigned short value)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	int i, result = 0, alpha;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	if (value <= temp_map[CPCAP_MAX_TEMP_LVL - 1][0])
71862306a36Sopenharmony_ci		return temp_map[CPCAP_MAX_TEMP_LVL - 1][1];
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (value >= temp_map[0][0])
72162306a36Sopenharmony_ci		return temp_map[0][1];
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	for (i = 0; i < CPCAP_MAX_TEMP_LVL - 1; i++) {
72462306a36Sopenharmony_ci		if ((value <= temp_map[i][0]) &&
72562306a36Sopenharmony_ci		    (value >= temp_map[i + 1][0])) {
72662306a36Sopenharmony_ci			if (value == temp_map[i][0]) {
72762306a36Sopenharmony_ci				result = temp_map[i][1];
72862306a36Sopenharmony_ci			} else if (value == temp_map[i + 1][0]) {
72962306a36Sopenharmony_ci				result = temp_map[i + 1][1];
73062306a36Sopenharmony_ci			} else {
73162306a36Sopenharmony_ci				alpha = ((value - temp_map[i][0]) * 1000) /
73262306a36Sopenharmony_ci					(temp_map[i + 1][0] - temp_map[i][0]);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci				result = temp_map[i][1] +
73562306a36Sopenharmony_ci					((alpha * (temp_map[i + 1][1] -
73662306a36Sopenharmony_ci						 temp_map[i][1])) / 1000);
73762306a36Sopenharmony_ci			}
73862306a36Sopenharmony_ci			break;
73962306a36Sopenharmony_ci		}
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	return result;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic void cpcap_adc_convert(struct cpcap_adc_request *req)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	const struct cpcap_adc_conversion_tbl *conv_tbl = req->conv_tbl;
74862306a36Sopenharmony_ci	int index = req->channel;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	/* Remuxed channels 16 and 17 use BATTP and BATTI entries */
75162306a36Sopenharmony_ci	switch (req->channel) {
75262306a36Sopenharmony_ci	case CPCAP_ADC_BATTP_PI16:
75362306a36Sopenharmony_ci		index = CPCAP_ADC_BATTP;
75462306a36Sopenharmony_ci		break;
75562306a36Sopenharmony_ci	case CPCAP_ADC_BATTI_PI17:
75662306a36Sopenharmony_ci		index = CPCAP_ADC_BATTI;
75762306a36Sopenharmony_ci		break;
75862306a36Sopenharmony_ci	default:
75962306a36Sopenharmony_ci		break;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/* No conversion for raw channels */
76362306a36Sopenharmony_ci	if (conv_tbl[index].conv_type == IIO_CHAN_INFO_RAW)
76462306a36Sopenharmony_ci		return;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	/* Temperatures use a lookup table instead of conversion table */
76762306a36Sopenharmony_ci	if ((req->channel == CPCAP_ADC_AD0) ||
76862306a36Sopenharmony_ci	    (req->channel == CPCAP_ADC_AD3)) {
76962306a36Sopenharmony_ci		req->result =
77062306a36Sopenharmony_ci			cpcap_adc_table_to_millicelcius(req->result);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		return;
77362306a36Sopenharmony_ci	}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/* All processed channels use a conversion table */
77662306a36Sopenharmony_ci	req->result *= conv_tbl[index].multiplier;
77762306a36Sopenharmony_ci	if (conv_tbl[index].divider == 0)
77862306a36Sopenharmony_ci		return;
77962306a36Sopenharmony_ci	req->result /= conv_tbl[index].divider;
78062306a36Sopenharmony_ci	req->result += conv_tbl[index].conv_offset;
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci/*
78462306a36Sopenharmony_ci * REVISIT: Check if timed sampling can use multiple channels at the
78562306a36Sopenharmony_ci * same time. If not, replace channel_mask with just channel.
78662306a36Sopenharmony_ci */
78762306a36Sopenharmony_cistatic int cpcap_adc_read_bank_scaled(struct cpcap_adc *ddata,
78862306a36Sopenharmony_ci				      struct cpcap_adc_request *req)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	int calibration_data, error, addr;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	if (ddata->vendor == CPCAP_VENDOR_TI) {
79362306a36Sopenharmony_ci		error = regmap_read(ddata->reg, CPCAP_REG_ADCAL1,
79462306a36Sopenharmony_ci				    &calibration_data);
79562306a36Sopenharmony_ci		if (error)
79662306a36Sopenharmony_ci			return error;
79762306a36Sopenharmony_ci		bank_conversion[CPCAP_ADC_CHG_ISENSE].cal_offset =
79862306a36Sopenharmony_ci			((short)calibration_data * -1) + 512;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci		error = regmap_read(ddata->reg, CPCAP_REG_ADCAL2,
80162306a36Sopenharmony_ci				    &calibration_data);
80262306a36Sopenharmony_ci		if (error)
80362306a36Sopenharmony_ci			return error;
80462306a36Sopenharmony_ci		bank_conversion[CPCAP_ADC_BATTI].cal_offset =
80562306a36Sopenharmony_ci			((short)calibration_data * -1) + 512;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	addr = CPCAP_REG_ADCD0 + req->bank_index * 4;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	error = regmap_read(ddata->reg, addr, &req->result);
81162306a36Sopenharmony_ci	if (error)
81262306a36Sopenharmony_ci		return error;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	req->result &= 0x3ff;
81562306a36Sopenharmony_ci	cpcap_adc_phase(req);
81662306a36Sopenharmony_ci	cpcap_adc_convert(req);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	return 0;
81962306a36Sopenharmony_ci}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_cistatic int cpcap_adc_init_request(struct cpcap_adc_request *req,
82262306a36Sopenharmony_ci				  int channel)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	req->channel = channel;
82562306a36Sopenharmony_ci	req->phase_tbl = bank_phasing;
82662306a36Sopenharmony_ci	req->conv_tbl = bank_conversion;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	switch (channel) {
82962306a36Sopenharmony_ci	case CPCAP_ADC_AD0 ... CPCAP_ADC_USB_ID:
83062306a36Sopenharmony_ci		req->bank_index = channel;
83162306a36Sopenharmony_ci		break;
83262306a36Sopenharmony_ci	case CPCAP_ADC_AD8 ... CPCAP_ADC_TSY2_AD15:
83362306a36Sopenharmony_ci		req->bank_index = channel - 8;
83462306a36Sopenharmony_ci		break;
83562306a36Sopenharmony_ci	case CPCAP_ADC_BATTP_PI16:
83662306a36Sopenharmony_ci		req->bank_index = CPCAP_ADC_BATTP;
83762306a36Sopenharmony_ci		break;
83862306a36Sopenharmony_ci	case CPCAP_ADC_BATTI_PI17:
83962306a36Sopenharmony_ci		req->bank_index = CPCAP_ADC_BATTI;
84062306a36Sopenharmony_ci		break;
84162306a36Sopenharmony_ci	default:
84262306a36Sopenharmony_ci		return -EINVAL;
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	return 0;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic int cpcap_adc_read_st_die_temp(struct cpcap_adc *ddata,
84962306a36Sopenharmony_ci				      int addr, int *val)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	int error;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	error = regmap_read(ddata->reg, addr, val);
85462306a36Sopenharmony_ci	if (error)
85562306a36Sopenharmony_ci		return error;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	*val -= 282;
85862306a36Sopenharmony_ci	*val *= 114;
85962306a36Sopenharmony_ci	*val += 25000;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	return 0;
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic int cpcap_adc_read(struct iio_dev *indio_dev,
86562306a36Sopenharmony_ci			  struct iio_chan_spec const *chan,
86662306a36Sopenharmony_ci			  int *val, int *val2, long mask)
86762306a36Sopenharmony_ci{
86862306a36Sopenharmony_ci	struct cpcap_adc *ddata = iio_priv(indio_dev);
86962306a36Sopenharmony_ci	struct cpcap_adc_request req;
87062306a36Sopenharmony_ci	int error;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	error = cpcap_adc_init_request(&req, chan->channel);
87362306a36Sopenharmony_ci	if (error)
87462306a36Sopenharmony_ci		return error;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	switch (mask) {
87762306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
87862306a36Sopenharmony_ci		mutex_lock(&ddata->lock);
87962306a36Sopenharmony_ci		error = cpcap_adc_start_bank(ddata, &req);
88062306a36Sopenharmony_ci		if (error)
88162306a36Sopenharmony_ci			goto err_unlock;
88262306a36Sopenharmony_ci		error = regmap_read(ddata->reg, chan->address, val);
88362306a36Sopenharmony_ci		if (error)
88462306a36Sopenharmony_ci			goto err_unlock;
88562306a36Sopenharmony_ci		error = cpcap_adc_stop_bank(ddata);
88662306a36Sopenharmony_ci		if (error)
88762306a36Sopenharmony_ci			goto err_unlock;
88862306a36Sopenharmony_ci		mutex_unlock(&ddata->lock);
88962306a36Sopenharmony_ci		break;
89062306a36Sopenharmony_ci	case IIO_CHAN_INFO_PROCESSED:
89162306a36Sopenharmony_ci		mutex_lock(&ddata->lock);
89262306a36Sopenharmony_ci		error = cpcap_adc_start_bank(ddata, &req);
89362306a36Sopenharmony_ci		if (error)
89462306a36Sopenharmony_ci			goto err_unlock;
89562306a36Sopenharmony_ci		if ((ddata->vendor == CPCAP_VENDOR_ST) &&
89662306a36Sopenharmony_ci		    (chan->channel == CPCAP_ADC_AD3)) {
89762306a36Sopenharmony_ci			error = cpcap_adc_read_st_die_temp(ddata,
89862306a36Sopenharmony_ci							   chan->address,
89962306a36Sopenharmony_ci							   &req.result);
90062306a36Sopenharmony_ci			if (error)
90162306a36Sopenharmony_ci				goto err_unlock;
90262306a36Sopenharmony_ci		} else {
90362306a36Sopenharmony_ci			error = cpcap_adc_read_bank_scaled(ddata, &req);
90462306a36Sopenharmony_ci			if (error)
90562306a36Sopenharmony_ci				goto err_unlock;
90662306a36Sopenharmony_ci		}
90762306a36Sopenharmony_ci		error = cpcap_adc_stop_bank(ddata);
90862306a36Sopenharmony_ci		if (error)
90962306a36Sopenharmony_ci			goto err_unlock;
91062306a36Sopenharmony_ci		mutex_unlock(&ddata->lock);
91162306a36Sopenharmony_ci		*val = req.result;
91262306a36Sopenharmony_ci		break;
91362306a36Sopenharmony_ci	default:
91462306a36Sopenharmony_ci		return -EINVAL;
91562306a36Sopenharmony_ci	}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	return IIO_VAL_INT;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_cierr_unlock:
92062306a36Sopenharmony_ci	mutex_unlock(&ddata->lock);
92162306a36Sopenharmony_ci	dev_err(ddata->dev, "error reading ADC: %i\n", error);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	return error;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic const struct iio_info cpcap_adc_info = {
92762306a36Sopenharmony_ci	.read_raw = &cpcap_adc_read,
92862306a36Sopenharmony_ci};
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci/*
93162306a36Sopenharmony_ci * Configuration for Motorola mapphone series such as droid 4.
93262306a36Sopenharmony_ci * Copied from the Motorola mapphone kernel tree.
93362306a36Sopenharmony_ci */
93462306a36Sopenharmony_cistatic const struct cpcap_adc_ato mapphone_adc = {
93562306a36Sopenharmony_ci	.ato_in = 0x0480,
93662306a36Sopenharmony_ci	.atox_in = 0,
93762306a36Sopenharmony_ci	.adc_ps_factor_in = 0x0200,
93862306a36Sopenharmony_ci	.atox_ps_factor_in = 0,
93962306a36Sopenharmony_ci	.ato_out = 0,
94062306a36Sopenharmony_ci	.atox_out = 0,
94162306a36Sopenharmony_ci	.adc_ps_factor_out = 0,
94262306a36Sopenharmony_ci	.atox_ps_factor_out = 0,
94362306a36Sopenharmony_ci};
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cistatic const struct of_device_id cpcap_adc_id_table[] = {
94662306a36Sopenharmony_ci	{
94762306a36Sopenharmony_ci		.compatible = "motorola,cpcap-adc",
94862306a36Sopenharmony_ci	},
94962306a36Sopenharmony_ci	{
95062306a36Sopenharmony_ci		.compatible = "motorola,mapphone-cpcap-adc",
95162306a36Sopenharmony_ci		.data = &mapphone_adc,
95262306a36Sopenharmony_ci	},
95362306a36Sopenharmony_ci	{ /* sentinel */ },
95462306a36Sopenharmony_ci};
95562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cpcap_adc_id_table);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic int cpcap_adc_probe(struct platform_device *pdev)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct cpcap_adc *ddata;
96062306a36Sopenharmony_ci	struct iio_dev *indio_dev;
96162306a36Sopenharmony_ci	int error;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*ddata));
96462306a36Sopenharmony_ci	if (!indio_dev) {
96562306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to allocate iio device\n");
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci		return -ENOMEM;
96862306a36Sopenharmony_ci	}
96962306a36Sopenharmony_ci	ddata = iio_priv(indio_dev);
97062306a36Sopenharmony_ci	ddata->ato = device_get_match_data(&pdev->dev);
97162306a36Sopenharmony_ci	if (!ddata->ato)
97262306a36Sopenharmony_ci		return -ENODEV;
97362306a36Sopenharmony_ci	ddata->dev = &pdev->dev;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	mutex_init(&ddata->lock);
97662306a36Sopenharmony_ci	init_waitqueue_head(&ddata->wq_data_avail);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
97962306a36Sopenharmony_ci	indio_dev->channels = cpcap_adc_channels;
98062306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(cpcap_adc_channels);
98162306a36Sopenharmony_ci	indio_dev->name = dev_name(&pdev->dev);
98262306a36Sopenharmony_ci	indio_dev->info = &cpcap_adc_info;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	ddata->reg = dev_get_regmap(pdev->dev.parent, NULL);
98562306a36Sopenharmony_ci	if (!ddata->reg)
98662306a36Sopenharmony_ci		return -ENODEV;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	error = cpcap_get_vendor(ddata->dev, ddata->reg, &ddata->vendor);
98962306a36Sopenharmony_ci	if (error)
99062306a36Sopenharmony_ci		return error;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	platform_set_drvdata(pdev, indio_dev);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	ddata->irq = platform_get_irq_byname(pdev, "adcdone");
99562306a36Sopenharmony_ci	if (ddata->irq < 0)
99662306a36Sopenharmony_ci		return -ENODEV;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	error = devm_request_threaded_irq(&pdev->dev, ddata->irq, NULL,
99962306a36Sopenharmony_ci					  cpcap_adc_irq_thread,
100062306a36Sopenharmony_ci					  IRQF_TRIGGER_NONE | IRQF_ONESHOT,
100162306a36Sopenharmony_ci					  "cpcap-adc", indio_dev);
100262306a36Sopenharmony_ci	if (error) {
100362306a36Sopenharmony_ci		dev_err(&pdev->dev, "could not get irq: %i\n",
100462306a36Sopenharmony_ci			error);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci		return error;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	error = cpcap_adc_calibrate(ddata);
101062306a36Sopenharmony_ci	if (error)
101162306a36Sopenharmony_ci		return error;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	dev_info(&pdev->dev, "CPCAP ADC device probed\n");
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	return devm_iio_device_register(&pdev->dev, indio_dev);
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cistatic struct platform_driver cpcap_adc_driver = {
101962306a36Sopenharmony_ci	.driver = {
102062306a36Sopenharmony_ci		.name = "cpcap_adc",
102162306a36Sopenharmony_ci		.of_match_table = cpcap_adc_id_table,
102262306a36Sopenharmony_ci	},
102362306a36Sopenharmony_ci	.probe = cpcap_adc_probe,
102462306a36Sopenharmony_ci};
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cimodule_platform_driver(cpcap_adc_driver);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ciMODULE_ALIAS("platform:cpcap_adc");
102962306a36Sopenharmony_ciMODULE_DESCRIPTION("CPCAP ADC driver");
103062306a36Sopenharmony_ciMODULE_AUTHOR("Tony Lindgren <tony@atomide.com");
103162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1032