1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* ADC driver for AXP20X and AXP22X PMICs
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (c) 2016 Free Electrons NextThing Co.
5*4882a593Smuzhiyun * Quentin Schulz <quentin.schulz@free-electrons.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/completion.h>
9*4882a593Smuzhiyun #include <linux/interrupt.h>
10*4882a593Smuzhiyun #include <linux/io.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/mod_devicetable.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/pm_runtime.h>
15*4882a593Smuzhiyun #include <linux/property.h>
16*4882a593Smuzhiyun #include <linux/regmap.h>
17*4882a593Smuzhiyun #include <linux/thermal.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <linux/iio/iio.h>
20*4882a593Smuzhiyun #include <linux/iio/driver.h>
21*4882a593Smuzhiyun #include <linux/iio/machine.h>
22*4882a593Smuzhiyun #include <linux/mfd/axp20x.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define AXP20X_ADC_EN1_MASK GENMASK(7, 0)
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7))
27*4882a593Smuzhiyun #define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0))
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0)
30*4882a593Smuzhiyun #define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1)
31*4882a593Smuzhiyun #define AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(x) ((x) & BIT(0))
32*4882a593Smuzhiyun #define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x) (((x) & BIT(0)) << 1)
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #define AXP20X_ADC_RATE_MASK GENMASK(7, 6)
35*4882a593Smuzhiyun #define AXP813_V_I_ADC_RATE_MASK GENMASK(5, 4)
36*4882a593Smuzhiyun #define AXP813_ADC_RATE_MASK (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK)
37*4882a593Smuzhiyun #define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
38*4882a593Smuzhiyun #define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
39*4882a593Smuzhiyun #define AXP813_TS_GPIO0_ADC_RATE_HZ(x) AXP20X_ADC_RATE_HZ(x)
40*4882a593Smuzhiyun #define AXP813_V_I_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 4) & AXP813_V_I_ADC_RATE_MASK)
41*4882a593Smuzhiyun #define AXP813_ADC_RATE_HZ(x) (AXP20X_ADC_RATE_HZ(x) | AXP813_V_I_ADC_RATE_HZ(x))
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg) \
44*4882a593Smuzhiyun { \
45*4882a593Smuzhiyun .type = _type, \
46*4882a593Smuzhiyun .indexed = 1, \
47*4882a593Smuzhiyun .channel = _channel, \
48*4882a593Smuzhiyun .address = _reg, \
49*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
50*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE), \
51*4882a593Smuzhiyun .datasheet_name = _name, \
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun #define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \
55*4882a593Smuzhiyun { \
56*4882a593Smuzhiyun .type = _type, \
57*4882a593Smuzhiyun .indexed = 1, \
58*4882a593Smuzhiyun .channel = _channel, \
59*4882a593Smuzhiyun .address = _reg, \
60*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
61*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE) |\
62*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_OFFSET),\
63*4882a593Smuzhiyun .datasheet_name = _name, \
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun struct axp_data;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun struct axp20x_adc_iio {
69*4882a593Smuzhiyun struct regmap *regmap;
70*4882a593Smuzhiyun const struct axp_data *data;
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun enum axp20x_adc_channel_v {
74*4882a593Smuzhiyun AXP20X_ACIN_V = 0,
75*4882a593Smuzhiyun AXP20X_VBUS_V,
76*4882a593Smuzhiyun AXP20X_TS_IN,
77*4882a593Smuzhiyun AXP20X_GPIO0_V,
78*4882a593Smuzhiyun AXP20X_GPIO1_V,
79*4882a593Smuzhiyun AXP20X_IPSOUT_V,
80*4882a593Smuzhiyun AXP20X_BATT_V,
81*4882a593Smuzhiyun };
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun enum axp20x_adc_channel_i {
84*4882a593Smuzhiyun AXP20X_ACIN_I = 0,
85*4882a593Smuzhiyun AXP20X_VBUS_I,
86*4882a593Smuzhiyun AXP20X_BATT_CHRG_I,
87*4882a593Smuzhiyun AXP20X_BATT_DISCHRG_I,
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun enum axp22x_adc_channel_v {
91*4882a593Smuzhiyun AXP22X_TS_IN = 0,
92*4882a593Smuzhiyun AXP22X_BATT_V,
93*4882a593Smuzhiyun };
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun enum axp22x_adc_channel_i {
96*4882a593Smuzhiyun AXP22X_BATT_CHRG_I = 1,
97*4882a593Smuzhiyun AXP22X_BATT_DISCHRG_I,
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun enum axp813_adc_channel_v {
101*4882a593Smuzhiyun AXP813_TS_IN = 0,
102*4882a593Smuzhiyun AXP813_GPIO0_V,
103*4882a593Smuzhiyun AXP813_BATT_V,
104*4882a593Smuzhiyun };
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun static struct iio_map axp20x_maps[] = {
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun .consumer_dev_name = "axp20x-usb-power-supply",
109*4882a593Smuzhiyun .consumer_channel = "vbus_v",
110*4882a593Smuzhiyun .adc_channel_label = "vbus_v",
111*4882a593Smuzhiyun }, {
112*4882a593Smuzhiyun .consumer_dev_name = "axp20x-usb-power-supply",
113*4882a593Smuzhiyun .consumer_channel = "vbus_i",
114*4882a593Smuzhiyun .adc_channel_label = "vbus_i",
115*4882a593Smuzhiyun }, {
116*4882a593Smuzhiyun .consumer_dev_name = "axp20x-ac-power-supply",
117*4882a593Smuzhiyun .consumer_channel = "acin_v",
118*4882a593Smuzhiyun .adc_channel_label = "acin_v",
119*4882a593Smuzhiyun }, {
120*4882a593Smuzhiyun .consumer_dev_name = "axp20x-ac-power-supply",
121*4882a593Smuzhiyun .consumer_channel = "acin_i",
122*4882a593Smuzhiyun .adc_channel_label = "acin_i",
123*4882a593Smuzhiyun }, {
124*4882a593Smuzhiyun .consumer_dev_name = "axp20x-battery-power-supply",
125*4882a593Smuzhiyun .consumer_channel = "batt_v",
126*4882a593Smuzhiyun .adc_channel_label = "batt_v",
127*4882a593Smuzhiyun }, {
128*4882a593Smuzhiyun .consumer_dev_name = "axp20x-battery-power-supply",
129*4882a593Smuzhiyun .consumer_channel = "batt_chrg_i",
130*4882a593Smuzhiyun .adc_channel_label = "batt_chrg_i",
131*4882a593Smuzhiyun }, {
132*4882a593Smuzhiyun .consumer_dev_name = "axp20x-battery-power-supply",
133*4882a593Smuzhiyun .consumer_channel = "batt_dischrg_i",
134*4882a593Smuzhiyun .adc_channel_label = "batt_dischrg_i",
135*4882a593Smuzhiyun }, { /* sentinel */ }
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun static struct iio_map axp22x_maps[] = {
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun .consumer_dev_name = "axp20x-battery-power-supply",
141*4882a593Smuzhiyun .consumer_channel = "batt_v",
142*4882a593Smuzhiyun .adc_channel_label = "batt_v",
143*4882a593Smuzhiyun }, {
144*4882a593Smuzhiyun .consumer_dev_name = "axp20x-battery-power-supply",
145*4882a593Smuzhiyun .consumer_channel = "batt_chrg_i",
146*4882a593Smuzhiyun .adc_channel_label = "batt_chrg_i",
147*4882a593Smuzhiyun }, {
148*4882a593Smuzhiyun .consumer_dev_name = "axp20x-battery-power-supply",
149*4882a593Smuzhiyun .consumer_channel = "batt_dischrg_i",
150*4882a593Smuzhiyun .adc_channel_label = "batt_dischrg_i",
151*4882a593Smuzhiyun }, { /* sentinel */ }
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun /*
155*4882a593Smuzhiyun * Channels are mapped by physical system. Their channels share the same index.
156*4882a593Smuzhiyun * i.e. acin_i is in_current0_raw and acin_v is in_voltage0_raw.
157*4882a593Smuzhiyun * The only exception is for the battery. batt_v will be in_voltage6_raw and
158*4882a593Smuzhiyun * charge current in_current6_raw and discharge current will be in_current7_raw.
159*4882a593Smuzhiyun */
160*4882a593Smuzhiyun static const struct iio_chan_spec axp20x_adc_channels[] = {
161*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE,
162*4882a593Smuzhiyun AXP20X_ACIN_V_ADC_H),
163*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP20X_ACIN_I, "acin_i", IIO_CURRENT,
164*4882a593Smuzhiyun AXP20X_ACIN_I_ADC_H),
165*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP20X_VBUS_V, "vbus_v", IIO_VOLTAGE,
166*4882a593Smuzhiyun AXP20X_VBUS_V_ADC_H),
167*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP20X_VBUS_I, "vbus_i", IIO_CURRENT,
168*4882a593Smuzhiyun AXP20X_VBUS_I_ADC_H),
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun .type = IIO_TEMP,
171*4882a593Smuzhiyun .address = AXP20X_TEMP_ADC_H,
172*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
173*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE) |
174*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_OFFSET),
175*4882a593Smuzhiyun .datasheet_name = "pmic_temp",
176*4882a593Smuzhiyun },
177*4882a593Smuzhiyun AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
178*4882a593Smuzhiyun AXP20X_GPIO0_V_ADC_H),
179*4882a593Smuzhiyun AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO1_V, "gpio1_v", IIO_VOLTAGE,
180*4882a593Smuzhiyun AXP20X_GPIO1_V_ADC_H),
181*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP20X_IPSOUT_V, "ipsout_v", IIO_VOLTAGE,
182*4882a593Smuzhiyun AXP20X_IPSOUT_V_HIGH_H),
183*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP20X_BATT_V, "batt_v", IIO_VOLTAGE,
184*4882a593Smuzhiyun AXP20X_BATT_V_H),
185*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP20X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
186*4882a593Smuzhiyun AXP20X_BATT_CHRG_I_H),
187*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP20X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
188*4882a593Smuzhiyun AXP20X_BATT_DISCHRG_I_H),
189*4882a593Smuzhiyun };
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun static const struct iio_chan_spec axp22x_adc_channels[] = {
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun .type = IIO_TEMP,
194*4882a593Smuzhiyun .address = AXP22X_PMIC_TEMP_H,
195*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
196*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE) |
197*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_OFFSET),
198*4882a593Smuzhiyun .datasheet_name = "pmic_temp",
199*4882a593Smuzhiyun },
200*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP22X_BATT_V, "batt_v", IIO_VOLTAGE,
201*4882a593Smuzhiyun AXP20X_BATT_V_H),
202*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
203*4882a593Smuzhiyun AXP20X_BATT_CHRG_I_H),
204*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
205*4882a593Smuzhiyun AXP20X_BATT_DISCHRG_I_H),
206*4882a593Smuzhiyun };
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun static const struct iio_chan_spec axp813_adc_channels[] = {
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun .type = IIO_TEMP,
211*4882a593Smuzhiyun .address = AXP22X_PMIC_TEMP_H,
212*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
213*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE) |
214*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_OFFSET),
215*4882a593Smuzhiyun .datasheet_name = "pmic_temp",
216*4882a593Smuzhiyun },
217*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP813_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
218*4882a593Smuzhiyun AXP288_GP_ADC_H),
219*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP813_BATT_V, "batt_v", IIO_VOLTAGE,
220*4882a593Smuzhiyun AXP20X_BATT_V_H),
221*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
222*4882a593Smuzhiyun AXP20X_BATT_CHRG_I_H),
223*4882a593Smuzhiyun AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
224*4882a593Smuzhiyun AXP20X_BATT_DISCHRG_I_H),
225*4882a593Smuzhiyun };
226*4882a593Smuzhiyun
axp20x_adc_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val)227*4882a593Smuzhiyun static int axp20x_adc_raw(struct iio_dev *indio_dev,
228*4882a593Smuzhiyun struct iio_chan_spec const *chan, int *val)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun struct axp20x_adc_iio *info = iio_priv(indio_dev);
231*4882a593Smuzhiyun int size = 12;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun /*
234*4882a593Smuzhiyun * N.B.: Unlike the Chinese datasheets tell, the charging current is
235*4882a593Smuzhiyun * stored on 12 bits, not 13 bits. Only discharging current is on 13
236*4882a593Smuzhiyun * bits.
237*4882a593Smuzhiyun */
238*4882a593Smuzhiyun if (chan->type == IIO_CURRENT && chan->channel == AXP20X_BATT_DISCHRG_I)
239*4882a593Smuzhiyun size = 13;
240*4882a593Smuzhiyun else
241*4882a593Smuzhiyun size = 12;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun *val = axp20x_read_variable_width(info->regmap, chan->address, size);
244*4882a593Smuzhiyun if (*val < 0)
245*4882a593Smuzhiyun return *val;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun return IIO_VAL_INT;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun
axp22x_adc_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val)250*4882a593Smuzhiyun static int axp22x_adc_raw(struct iio_dev *indio_dev,
251*4882a593Smuzhiyun struct iio_chan_spec const *chan, int *val)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun struct axp20x_adc_iio *info = iio_priv(indio_dev);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun *val = axp20x_read_variable_width(info->regmap, chan->address, 12);
256*4882a593Smuzhiyun if (*val < 0)
257*4882a593Smuzhiyun return *val;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun return IIO_VAL_INT;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
axp813_adc_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val)262*4882a593Smuzhiyun static int axp813_adc_raw(struct iio_dev *indio_dev,
263*4882a593Smuzhiyun struct iio_chan_spec const *chan, int *val)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun struct axp20x_adc_iio *info = iio_priv(indio_dev);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun *val = axp20x_read_variable_width(info->regmap, chan->address, 12);
268*4882a593Smuzhiyun if (*val < 0)
269*4882a593Smuzhiyun return *val;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun return IIO_VAL_INT;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
axp20x_adc_scale_voltage(int channel,int * val,int * val2)274*4882a593Smuzhiyun static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun switch (channel) {
277*4882a593Smuzhiyun case AXP20X_ACIN_V:
278*4882a593Smuzhiyun case AXP20X_VBUS_V:
279*4882a593Smuzhiyun *val = 1;
280*4882a593Smuzhiyun *val2 = 700000;
281*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun case AXP20X_GPIO0_V:
284*4882a593Smuzhiyun case AXP20X_GPIO1_V:
285*4882a593Smuzhiyun *val = 0;
286*4882a593Smuzhiyun *val2 = 500000;
287*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun case AXP20X_BATT_V:
290*4882a593Smuzhiyun *val = 1;
291*4882a593Smuzhiyun *val2 = 100000;
292*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun case AXP20X_IPSOUT_V:
295*4882a593Smuzhiyun *val = 1;
296*4882a593Smuzhiyun *val2 = 400000;
297*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun default:
300*4882a593Smuzhiyun return -EINVAL;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
axp813_adc_scale_voltage(int channel,int * val,int * val2)304*4882a593Smuzhiyun static int axp813_adc_scale_voltage(int channel, int *val, int *val2)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun switch (channel) {
307*4882a593Smuzhiyun case AXP813_GPIO0_V:
308*4882a593Smuzhiyun *val = 0;
309*4882a593Smuzhiyun *val2 = 800000;
310*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun case AXP813_BATT_V:
313*4882a593Smuzhiyun *val = 1;
314*4882a593Smuzhiyun *val2 = 100000;
315*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun default:
318*4882a593Smuzhiyun return -EINVAL;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
axp20x_adc_scale_current(int channel,int * val,int * val2)322*4882a593Smuzhiyun static int axp20x_adc_scale_current(int channel, int *val, int *val2)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun switch (channel) {
325*4882a593Smuzhiyun case AXP20X_ACIN_I:
326*4882a593Smuzhiyun *val = 0;
327*4882a593Smuzhiyun *val2 = 625000;
328*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun case AXP20X_VBUS_I:
331*4882a593Smuzhiyun *val = 0;
332*4882a593Smuzhiyun *val2 = 375000;
333*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun case AXP20X_BATT_DISCHRG_I:
336*4882a593Smuzhiyun case AXP20X_BATT_CHRG_I:
337*4882a593Smuzhiyun *val = 0;
338*4882a593Smuzhiyun *val2 = 500000;
339*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun default:
342*4882a593Smuzhiyun return -EINVAL;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
axp20x_adc_scale(struct iio_chan_spec const * chan,int * val,int * val2)346*4882a593Smuzhiyun static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val,
347*4882a593Smuzhiyun int *val2)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun switch (chan->type) {
350*4882a593Smuzhiyun case IIO_VOLTAGE:
351*4882a593Smuzhiyun return axp20x_adc_scale_voltage(chan->channel, val, val2);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun case IIO_CURRENT:
354*4882a593Smuzhiyun return axp20x_adc_scale_current(chan->channel, val, val2);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun case IIO_TEMP:
357*4882a593Smuzhiyun *val = 100;
358*4882a593Smuzhiyun return IIO_VAL_INT;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun default:
361*4882a593Smuzhiyun return -EINVAL;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
axp22x_adc_scale(struct iio_chan_spec const * chan,int * val,int * val2)365*4882a593Smuzhiyun static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
366*4882a593Smuzhiyun int *val2)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun switch (chan->type) {
369*4882a593Smuzhiyun case IIO_VOLTAGE:
370*4882a593Smuzhiyun if (chan->channel != AXP22X_BATT_V)
371*4882a593Smuzhiyun return -EINVAL;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun *val = 1;
374*4882a593Smuzhiyun *val2 = 100000;
375*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun case IIO_CURRENT:
378*4882a593Smuzhiyun *val = 1;
379*4882a593Smuzhiyun return IIO_VAL_INT;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun case IIO_TEMP:
382*4882a593Smuzhiyun *val = 100;
383*4882a593Smuzhiyun return IIO_VAL_INT;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun default:
386*4882a593Smuzhiyun return -EINVAL;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
axp813_adc_scale(struct iio_chan_spec const * chan,int * val,int * val2)390*4882a593Smuzhiyun static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val,
391*4882a593Smuzhiyun int *val2)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun switch (chan->type) {
394*4882a593Smuzhiyun case IIO_VOLTAGE:
395*4882a593Smuzhiyun return axp813_adc_scale_voltage(chan->channel, val, val2);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun case IIO_CURRENT:
398*4882a593Smuzhiyun *val = 1;
399*4882a593Smuzhiyun return IIO_VAL_INT;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun case IIO_TEMP:
402*4882a593Smuzhiyun *val = 100;
403*4882a593Smuzhiyun return IIO_VAL_INT;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun default:
406*4882a593Smuzhiyun return -EINVAL;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
axp20x_adc_offset_voltage(struct iio_dev * indio_dev,int channel,int * val)410*4882a593Smuzhiyun static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
411*4882a593Smuzhiyun int *val)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun struct axp20x_adc_iio *info = iio_priv(indio_dev);
414*4882a593Smuzhiyun int ret;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, val);
417*4882a593Smuzhiyun if (ret < 0)
418*4882a593Smuzhiyun return ret;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun switch (channel) {
421*4882a593Smuzhiyun case AXP20X_GPIO0_V:
422*4882a593Smuzhiyun *val &= AXP20X_GPIO10_IN_RANGE_GPIO0;
423*4882a593Smuzhiyun break;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun case AXP20X_GPIO1_V:
426*4882a593Smuzhiyun *val &= AXP20X_GPIO10_IN_RANGE_GPIO1;
427*4882a593Smuzhiyun break;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun default:
430*4882a593Smuzhiyun return -EINVAL;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun *val = *val ? 700000 : 0;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun return IIO_VAL_INT;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
axp20x_adc_offset(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val)438*4882a593Smuzhiyun static int axp20x_adc_offset(struct iio_dev *indio_dev,
439*4882a593Smuzhiyun struct iio_chan_spec const *chan, int *val)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun switch (chan->type) {
442*4882a593Smuzhiyun case IIO_VOLTAGE:
443*4882a593Smuzhiyun return axp20x_adc_offset_voltage(indio_dev, chan->channel, val);
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun case IIO_TEMP:
446*4882a593Smuzhiyun *val = -1447;
447*4882a593Smuzhiyun return IIO_VAL_INT;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun default:
450*4882a593Smuzhiyun return -EINVAL;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
axp20x_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)454*4882a593Smuzhiyun static int axp20x_read_raw(struct iio_dev *indio_dev,
455*4882a593Smuzhiyun struct iio_chan_spec const *chan, int *val,
456*4882a593Smuzhiyun int *val2, long mask)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun switch (mask) {
459*4882a593Smuzhiyun case IIO_CHAN_INFO_OFFSET:
460*4882a593Smuzhiyun return axp20x_adc_offset(indio_dev, chan, val);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun case IIO_CHAN_INFO_SCALE:
463*4882a593Smuzhiyun return axp20x_adc_scale(chan, val, val2);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
466*4882a593Smuzhiyun return axp20x_adc_raw(indio_dev, chan, val);
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun default:
469*4882a593Smuzhiyun return -EINVAL;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
axp22x_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)473*4882a593Smuzhiyun static int axp22x_read_raw(struct iio_dev *indio_dev,
474*4882a593Smuzhiyun struct iio_chan_spec const *chan, int *val,
475*4882a593Smuzhiyun int *val2, long mask)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun switch (mask) {
478*4882a593Smuzhiyun case IIO_CHAN_INFO_OFFSET:
479*4882a593Smuzhiyun *val = -2677;
480*4882a593Smuzhiyun return IIO_VAL_INT;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun case IIO_CHAN_INFO_SCALE:
483*4882a593Smuzhiyun return axp22x_adc_scale(chan, val, val2);
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
486*4882a593Smuzhiyun return axp22x_adc_raw(indio_dev, chan, val);
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun default:
489*4882a593Smuzhiyun return -EINVAL;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun
axp813_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)493*4882a593Smuzhiyun static int axp813_read_raw(struct iio_dev *indio_dev,
494*4882a593Smuzhiyun struct iio_chan_spec const *chan, int *val,
495*4882a593Smuzhiyun int *val2, long mask)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun switch (mask) {
498*4882a593Smuzhiyun case IIO_CHAN_INFO_OFFSET:
499*4882a593Smuzhiyun *val = -2667;
500*4882a593Smuzhiyun return IIO_VAL_INT;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun case IIO_CHAN_INFO_SCALE:
503*4882a593Smuzhiyun return axp813_adc_scale(chan, val, val2);
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
506*4882a593Smuzhiyun return axp813_adc_raw(indio_dev, chan, val);
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun default:
509*4882a593Smuzhiyun return -EINVAL;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
axp20x_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)513*4882a593Smuzhiyun static int axp20x_write_raw(struct iio_dev *indio_dev,
514*4882a593Smuzhiyun struct iio_chan_spec const *chan, int val, int val2,
515*4882a593Smuzhiyun long mask)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun struct axp20x_adc_iio *info = iio_priv(indio_dev);
518*4882a593Smuzhiyun unsigned int reg, regval;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun /*
521*4882a593Smuzhiyun * The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets
522*4882a593Smuzhiyun * for (independently) GPIO0 and GPIO1 when in ADC mode.
523*4882a593Smuzhiyun */
524*4882a593Smuzhiyun if (mask != IIO_CHAN_INFO_OFFSET)
525*4882a593Smuzhiyun return -EINVAL;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if (val != 0 && val != 700000)
528*4882a593Smuzhiyun return -EINVAL;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun val = val ? 1 : 0;
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun switch (chan->channel) {
533*4882a593Smuzhiyun case AXP20X_GPIO0_V:
534*4882a593Smuzhiyun reg = AXP20X_GPIO10_IN_RANGE_GPIO0;
535*4882a593Smuzhiyun regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(val);
536*4882a593Smuzhiyun break;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun case AXP20X_GPIO1_V:
539*4882a593Smuzhiyun reg = AXP20X_GPIO10_IN_RANGE_GPIO1;
540*4882a593Smuzhiyun regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(val);
541*4882a593Smuzhiyun break;
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun default:
544*4882a593Smuzhiyun return -EINVAL;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, reg,
548*4882a593Smuzhiyun regval);
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun static const struct iio_info axp20x_adc_iio_info = {
552*4882a593Smuzhiyun .read_raw = axp20x_read_raw,
553*4882a593Smuzhiyun .write_raw = axp20x_write_raw,
554*4882a593Smuzhiyun };
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun static const struct iio_info axp22x_adc_iio_info = {
557*4882a593Smuzhiyun .read_raw = axp22x_read_raw,
558*4882a593Smuzhiyun };
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun static const struct iio_info axp813_adc_iio_info = {
561*4882a593Smuzhiyun .read_raw = axp813_read_raw,
562*4882a593Smuzhiyun };
563*4882a593Smuzhiyun
axp20x_adc_rate(struct axp20x_adc_iio * info,int rate)564*4882a593Smuzhiyun static int axp20x_adc_rate(struct axp20x_adc_iio *info, int rate)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun return regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
567*4882a593Smuzhiyun AXP20X_ADC_RATE_MASK,
568*4882a593Smuzhiyun AXP20X_ADC_RATE_HZ(rate));
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun
axp22x_adc_rate(struct axp20x_adc_iio * info,int rate)571*4882a593Smuzhiyun static int axp22x_adc_rate(struct axp20x_adc_iio *info, int rate)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun return regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
574*4882a593Smuzhiyun AXP20X_ADC_RATE_MASK,
575*4882a593Smuzhiyun AXP22X_ADC_RATE_HZ(rate));
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
axp813_adc_rate(struct axp20x_adc_iio * info,int rate)578*4882a593Smuzhiyun static int axp813_adc_rate(struct axp20x_adc_iio *info, int rate)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun return regmap_update_bits(info->regmap, AXP813_ADC_RATE,
581*4882a593Smuzhiyun AXP813_ADC_RATE_MASK,
582*4882a593Smuzhiyun AXP813_ADC_RATE_HZ(rate));
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun struct axp_data {
586*4882a593Smuzhiyun const struct iio_info *iio_info;
587*4882a593Smuzhiyun int num_channels;
588*4882a593Smuzhiyun struct iio_chan_spec const *channels;
589*4882a593Smuzhiyun unsigned long adc_en1_mask;
590*4882a593Smuzhiyun int (*adc_rate)(struct axp20x_adc_iio *info,
591*4882a593Smuzhiyun int rate);
592*4882a593Smuzhiyun bool adc_en2;
593*4882a593Smuzhiyun struct iio_map *maps;
594*4882a593Smuzhiyun };
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun static const struct axp_data axp20x_data = {
597*4882a593Smuzhiyun .iio_info = &axp20x_adc_iio_info,
598*4882a593Smuzhiyun .num_channels = ARRAY_SIZE(axp20x_adc_channels),
599*4882a593Smuzhiyun .channels = axp20x_adc_channels,
600*4882a593Smuzhiyun .adc_en1_mask = AXP20X_ADC_EN1_MASK,
601*4882a593Smuzhiyun .adc_rate = axp20x_adc_rate,
602*4882a593Smuzhiyun .adc_en2 = true,
603*4882a593Smuzhiyun .maps = axp20x_maps,
604*4882a593Smuzhiyun };
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun static const struct axp_data axp22x_data = {
607*4882a593Smuzhiyun .iio_info = &axp22x_adc_iio_info,
608*4882a593Smuzhiyun .num_channels = ARRAY_SIZE(axp22x_adc_channels),
609*4882a593Smuzhiyun .channels = axp22x_adc_channels,
610*4882a593Smuzhiyun .adc_en1_mask = AXP22X_ADC_EN1_MASK,
611*4882a593Smuzhiyun .adc_rate = axp22x_adc_rate,
612*4882a593Smuzhiyun .adc_en2 = false,
613*4882a593Smuzhiyun .maps = axp22x_maps,
614*4882a593Smuzhiyun };
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun static const struct axp_data axp813_data = {
617*4882a593Smuzhiyun .iio_info = &axp813_adc_iio_info,
618*4882a593Smuzhiyun .num_channels = ARRAY_SIZE(axp813_adc_channels),
619*4882a593Smuzhiyun .channels = axp813_adc_channels,
620*4882a593Smuzhiyun .adc_en1_mask = AXP22X_ADC_EN1_MASK,
621*4882a593Smuzhiyun .adc_rate = axp813_adc_rate,
622*4882a593Smuzhiyun .adc_en2 = false,
623*4882a593Smuzhiyun .maps = axp22x_maps,
624*4882a593Smuzhiyun };
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun static const struct of_device_id axp20x_adc_of_match[] = {
627*4882a593Smuzhiyun { .compatible = "x-powers,axp209-adc", .data = (void *)&axp20x_data, },
628*4882a593Smuzhiyun { .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, },
629*4882a593Smuzhiyun { .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, },
630*4882a593Smuzhiyun { /* sentinel */ }
631*4882a593Smuzhiyun };
632*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, axp20x_adc_of_match);
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun static const struct platform_device_id axp20x_adc_id_match[] = {
635*4882a593Smuzhiyun { .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
636*4882a593Smuzhiyun { .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
637*4882a593Smuzhiyun { .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, },
638*4882a593Smuzhiyun { /* sentinel */ },
639*4882a593Smuzhiyun };
640*4882a593Smuzhiyun MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);
641*4882a593Smuzhiyun
axp20x_probe(struct platform_device * pdev)642*4882a593Smuzhiyun static int axp20x_probe(struct platform_device *pdev)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun struct axp20x_adc_iio *info;
645*4882a593Smuzhiyun struct iio_dev *indio_dev;
646*4882a593Smuzhiyun struct axp20x_dev *axp20x_dev;
647*4882a593Smuzhiyun int ret;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun axp20x_dev = dev_get_drvdata(pdev->dev.parent);
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
652*4882a593Smuzhiyun if (!indio_dev)
653*4882a593Smuzhiyun return -ENOMEM;
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun info = iio_priv(indio_dev);
656*4882a593Smuzhiyun platform_set_drvdata(pdev, indio_dev);
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun info->regmap = axp20x_dev->regmap;
659*4882a593Smuzhiyun indio_dev->modes = INDIO_DIRECT_MODE;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun if (!dev_fwnode(&pdev->dev)) {
662*4882a593Smuzhiyun const struct platform_device_id *id;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun id = platform_get_device_id(pdev);
665*4882a593Smuzhiyun info->data = (const struct axp_data *)id->driver_data;
666*4882a593Smuzhiyun } else {
667*4882a593Smuzhiyun struct device *dev = &pdev->dev;
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun info->data = device_get_match_data(dev);
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun indio_dev->name = platform_get_device_id(pdev)->name;
673*4882a593Smuzhiyun indio_dev->info = info->data->iio_info;
674*4882a593Smuzhiyun indio_dev->num_channels = info->data->num_channels;
675*4882a593Smuzhiyun indio_dev->channels = info->data->channels;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun /* Enable the ADCs on IP */
678*4882a593Smuzhiyun regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun if (info->data->adc_en2)
681*4882a593Smuzhiyun /* Enable GPIO0/1 and internal temperature ADCs */
682*4882a593Smuzhiyun regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
683*4882a593Smuzhiyun AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun /* Configure ADCs rate */
686*4882a593Smuzhiyun info->data->adc_rate(info, 100);
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun ret = iio_map_array_register(indio_dev, info->data->maps);
689*4882a593Smuzhiyun if (ret < 0) {
690*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to register IIO maps: %d\n", ret);
691*4882a593Smuzhiyun goto fail_map;
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun ret = iio_device_register(indio_dev);
695*4882a593Smuzhiyun if (ret < 0) {
696*4882a593Smuzhiyun dev_err(&pdev->dev, "could not register the device\n");
697*4882a593Smuzhiyun goto fail_register;
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun return 0;
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun fail_register:
703*4882a593Smuzhiyun iio_map_array_unregister(indio_dev);
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun fail_map:
706*4882a593Smuzhiyun regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun if (info->data->adc_en2)
709*4882a593Smuzhiyun regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun return ret;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
axp20x_remove(struct platform_device * pdev)714*4882a593Smuzhiyun static int axp20x_remove(struct platform_device *pdev)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun struct iio_dev *indio_dev = platform_get_drvdata(pdev);
717*4882a593Smuzhiyun struct axp20x_adc_iio *info = iio_priv(indio_dev);
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun iio_device_unregister(indio_dev);
720*4882a593Smuzhiyun iio_map_array_unregister(indio_dev);
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun if (info->data->adc_en2)
725*4882a593Smuzhiyun regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun return 0;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun static struct platform_driver axp20x_adc_driver = {
731*4882a593Smuzhiyun .driver = {
732*4882a593Smuzhiyun .name = "axp20x-adc",
733*4882a593Smuzhiyun .of_match_table = axp20x_adc_of_match,
734*4882a593Smuzhiyun },
735*4882a593Smuzhiyun .id_table = axp20x_adc_id_match,
736*4882a593Smuzhiyun .probe = axp20x_probe,
737*4882a593Smuzhiyun .remove = axp20x_remove,
738*4882a593Smuzhiyun };
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun module_platform_driver(axp20x_adc_driver);
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun MODULE_DESCRIPTION("ADC driver for AXP20X and AXP22X PMICs");
743*4882a593Smuzhiyun MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
744*4882a593Smuzhiyun MODULE_LICENSE("GPL");
745