27
27
#include <linux/iio/machine.h>
28
28
#include <linux/iio/driver.h>
29
29
30
- #define AXP288_ADC_EN_MASK 0xF1
31
- #define AXP288_ADC_TS_PIN_GPADC 0xF2
32
- #define AXP288_ADC_TS_PIN_ON 0xF3
30
+ /*
31
+ * This mask enables all ADCs except for the battery temp-sensor (TS), that is
32
+ * left as-is to avoid breaking charging on devices without a temp-sensor.
33
+ */
34
+ #define AXP288_ADC_EN_MASK 0xF0
35
+ #define AXP288_ADC_TS_ENABLE 0x01
36
+
37
+ #define AXP288_ADC_TS_CURRENT_ON_OFF_MASK GENMASK(1, 0)
38
+ #define AXP288_ADC_TS_CURRENT_OFF (0 << 0)
39
+ #define AXP288_ADC_TS_CURRENT_ON_WHEN_CHARGING (1 << 0)
40
+ #define AXP288_ADC_TS_CURRENT_ON_ONDEMAND (2 << 0)
41
+ #define AXP288_ADC_TS_CURRENT_ON (3 << 0)
33
42
34
43
enum axp288_adc_id {
35
44
AXP288_ADC_TS ,
@@ -44,6 +53,7 @@ enum axp288_adc_id {
44
53
struct axp288_adc_info {
45
54
int irq ;
46
55
struct regmap * regmap ;
56
+ bool ts_enabled ;
47
57
};
48
58
49
59
static const struct iio_chan_spec axp288_adc_channels [] = {
@@ -115,21 +125,33 @@ static int axp288_adc_read_channel(int *val, unsigned long address,
115
125
return IIO_VAL_INT ;
116
126
}
117
127
118
- static int axp288_adc_set_ts (struct regmap * regmap , unsigned int mode ,
119
- unsigned long address )
128
+ /*
129
+ * The current-source used for the battery temp-sensor (TS) is shared
130
+ * with the GPADC. For proper fuel-gauge and charger operation the TS
131
+ * current-source needs to be permanently on. But to read the GPADC we
132
+ * need to temporary switch the TS current-source to ondemand, so that
133
+ * the GPADC can use it, otherwise we will always read an all 0 value.
134
+ */
135
+ static int axp288_adc_set_ts (struct axp288_adc_info * info ,
136
+ unsigned int mode , unsigned long address )
120
137
{
121
138
int ret ;
122
139
123
- /* channels other than GPADC do not need to switch TS pin */
140
+ /* No need to switch the current-source if the TS pin is disabled */
141
+ if (!info -> ts_enabled )
142
+ return 0 ;
143
+
144
+ /* Channels other than GPADC do not need the current source */
124
145
if (address != AXP288_GP_ADC_H )
125
146
return 0 ;
126
147
127
- ret = regmap_write (regmap , AXP288_ADC_TS_PIN_CTRL , mode );
148
+ ret = regmap_update_bits (info -> regmap , AXP288_ADC_TS_PIN_CTRL ,
149
+ AXP288_ADC_TS_CURRENT_ON_OFF_MASK , mode );
128
150
if (ret )
129
151
return ret ;
130
152
131
153
/* When switching to the GPADC pin give things some time to settle */
132
- if (mode == AXP288_ADC_TS_PIN_GPADC )
154
+ if (mode == AXP288_ADC_TS_CURRENT_ON_ONDEMAND )
133
155
usleep_range (6000 , 10000 );
134
156
135
157
return 0 ;
@@ -145,14 +167,14 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev,
145
167
mutex_lock (& indio_dev -> mlock );
146
168
switch (mask ) {
147
169
case IIO_CHAN_INFO_RAW :
148
- if (axp288_adc_set_ts (info -> regmap , AXP288_ADC_TS_PIN_GPADC ,
170
+ if (axp288_adc_set_ts (info , AXP288_ADC_TS_CURRENT_ON_ONDEMAND ,
149
171
chan -> address )) {
150
172
dev_err (& indio_dev -> dev , "GPADC mode\n" );
151
173
ret = - EINVAL ;
152
174
break ;
153
175
}
154
176
ret = axp288_adc_read_channel (val , chan -> address , info -> regmap );
155
- if (axp288_adc_set_ts (info -> regmap , AXP288_ADC_TS_PIN_ON ,
177
+ if (axp288_adc_set_ts (info , AXP288_ADC_TS_CURRENT_ON ,
156
178
chan -> address ))
157
179
dev_err (& indio_dev -> dev , "TS pin restore\n" );
158
180
break ;
@@ -164,13 +186,35 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev,
164
186
return ret ;
165
187
}
166
188
167
- static int axp288_adc_set_state (struct regmap * regmap )
189
+ static int axp288_adc_initialize (struct axp288_adc_info * info )
168
190
{
169
- /* ADC should be always enabled for internal FG to function */
170
- if (regmap_write (regmap , AXP288_ADC_TS_PIN_CTRL , AXP288_ADC_TS_PIN_ON ))
171
- return - EIO ;
191
+ int ret , adc_enable_val ;
192
+
193
+ /*
194
+ * Determine if the TS pin is enabled and set the TS current-source
195
+ * accordingly.
196
+ */
197
+ ret = regmap_read (info -> regmap , AXP20X_ADC_EN1 , & adc_enable_val );
198
+ if (ret )
199
+ return ret ;
200
+
201
+ if (adc_enable_val & AXP288_ADC_TS_ENABLE ) {
202
+ info -> ts_enabled = true;
203
+ ret = regmap_update_bits (info -> regmap , AXP288_ADC_TS_PIN_CTRL ,
204
+ AXP288_ADC_TS_CURRENT_ON_OFF_MASK ,
205
+ AXP288_ADC_TS_CURRENT_ON );
206
+ } else {
207
+ info -> ts_enabled = false;
208
+ ret = regmap_update_bits (info -> regmap , AXP288_ADC_TS_PIN_CTRL ,
209
+ AXP288_ADC_TS_CURRENT_ON_OFF_MASK ,
210
+ AXP288_ADC_TS_CURRENT_OFF );
211
+ }
212
+ if (ret )
213
+ return ret ;
172
214
173
- return regmap_write (regmap , AXP20X_ADC_EN1 , AXP288_ADC_EN_MASK );
215
+ /* Turn on the ADC for all channels except TS, leave TS as is */
216
+ return regmap_update_bits (info -> regmap , AXP20X_ADC_EN1 ,
217
+ AXP288_ADC_EN_MASK , AXP288_ADC_EN_MASK );
174
218
}
175
219
176
220
static const struct iio_info axp288_adc_iio_info = {
@@ -200,7 +244,7 @@ static int axp288_adc_probe(struct platform_device *pdev)
200
244
* Set ADC to enabled state at all time, including system suspend.
201
245
* otherwise internal fuel gauge functionality may be affected.
202
246
*/
203
- ret = axp288_adc_set_state ( axp20x -> regmap );
247
+ ret = axp288_adc_initialize ( info );
204
248
if (ret ) {
205
249
dev_err (& pdev -> dev , "unable to enable ADC device\n" );
206
250
return ret ;
0 commit comments