]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/iio/adc/axp288_adc.c
net: phy: Fix "link partner" information disappear issue
[linux.git] / drivers / iio / adc / axp288_adc.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * axp288_adc.c - X-Powers AXP288 PMIC ADC Driver
4  *
5  * Copyright (C) 2014 Intel Corporation
6  *
7  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8  */
9
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/device.h>
13 #include <linux/regmap.h>
14 #include <linux/mfd/axp20x.h>
15 #include <linux/platform_device.h>
16
17 #include <linux/iio/iio.h>
18 #include <linux/iio/machine.h>
19 #include <linux/iio/driver.h>
20
21 /*
22  * This mask enables all ADCs except for the battery temp-sensor (TS), that is
23  * left as-is to avoid breaking charging on devices without a temp-sensor.
24  */
25 #define AXP288_ADC_EN_MASK                              0xF0
26 #define AXP288_ADC_TS_ENABLE                            0x01
27
28 #define AXP288_ADC_TS_CURRENT_ON_OFF_MASK               GENMASK(1, 0)
29 #define AXP288_ADC_TS_CURRENT_OFF                       (0 << 0)
30 #define AXP288_ADC_TS_CURRENT_ON_WHEN_CHARGING          (1 << 0)
31 #define AXP288_ADC_TS_CURRENT_ON_ONDEMAND               (2 << 0)
32 #define AXP288_ADC_TS_CURRENT_ON                        (3 << 0)
33
34 enum axp288_adc_id {
35         AXP288_ADC_TS,
36         AXP288_ADC_PMIC,
37         AXP288_ADC_GP,
38         AXP288_ADC_BATT_CHRG_I,
39         AXP288_ADC_BATT_DISCHRG_I,
40         AXP288_ADC_BATT_V,
41         AXP288_ADC_NR_CHAN,
42 };
43
44 struct axp288_adc_info {
45         int irq;
46         struct regmap *regmap;
47         bool ts_enabled;
48 };
49
50 static const struct iio_chan_spec axp288_adc_channels[] = {
51         {
52                 .indexed = 1,
53                 .type = IIO_TEMP,
54                 .channel = 0,
55                 .address = AXP288_TS_ADC_H,
56                 .datasheet_name = "TS_PIN",
57                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
58         }, {
59                 .indexed = 1,
60                 .type = IIO_TEMP,
61                 .channel = 1,
62                 .address = AXP288_PMIC_ADC_H,
63                 .datasheet_name = "PMIC_TEMP",
64                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
65         }, {
66                 .indexed = 1,
67                 .type = IIO_TEMP,
68                 .channel = 2,
69                 .address = AXP288_GP_ADC_H,
70                 .datasheet_name = "GPADC",
71                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
72         }, {
73                 .indexed = 1,
74                 .type = IIO_CURRENT,
75                 .channel = 3,
76                 .address = AXP20X_BATT_CHRG_I_H,
77                 .datasheet_name = "BATT_CHG_I",
78                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
79         }, {
80                 .indexed = 1,
81                 .type = IIO_CURRENT,
82                 .channel = 4,
83                 .address = AXP20X_BATT_DISCHRG_I_H,
84                 .datasheet_name = "BATT_DISCHRG_I",
85                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
86         }, {
87                 .indexed = 1,
88                 .type = IIO_VOLTAGE,
89                 .channel = 5,
90                 .address = AXP20X_BATT_V_H,
91                 .datasheet_name = "BATT_V",
92                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
93         },
94 };
95
96 /* for consumer drivers */
97 static struct iio_map axp288_adc_default_maps[] = {
98         IIO_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
99         IIO_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
100         IIO_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
101         IIO_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
102         IIO_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
103         IIO_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
104         {},
105 };
106
107 static int axp288_adc_read_channel(int *val, unsigned long address,
108                                 struct regmap *regmap)
109 {
110         u8 buf[2];
111
112         if (regmap_bulk_read(regmap, address, buf, 2))
113                 return -EIO;
114         *val = (buf[0] << 4) + ((buf[1] >> 4) & 0x0F);
115
116         return IIO_VAL_INT;
117 }
118
119 /*
120  * The current-source used for the battery temp-sensor (TS) is shared
121  * with the GPADC. For proper fuel-gauge and charger operation the TS
122  * current-source needs to be permanently on. But to read the GPADC we
123  * need to temporary switch the TS current-source to ondemand, so that
124  * the GPADC can use it, otherwise we will always read an all 0 value.
125  */
126 static int axp288_adc_set_ts(struct axp288_adc_info *info,
127                              unsigned int mode, unsigned long address)
128 {
129         int ret;
130
131         /* No need to switch the current-source if the TS pin is disabled */
132         if (!info->ts_enabled)
133                 return 0;
134
135         /* Channels other than GPADC do not need the current source */
136         if (address != AXP288_GP_ADC_H)
137                 return 0;
138
139         ret = regmap_update_bits(info->regmap, AXP288_ADC_TS_PIN_CTRL,
140                                  AXP288_ADC_TS_CURRENT_ON_OFF_MASK, mode);
141         if (ret)
142                 return ret;
143
144         /* When switching to the GPADC pin give things some time to settle */
145         if (mode == AXP288_ADC_TS_CURRENT_ON_ONDEMAND)
146                 usleep_range(6000, 10000);
147
148         return 0;
149 }
150
151 static int axp288_adc_read_raw(struct iio_dev *indio_dev,
152                         struct iio_chan_spec const *chan,
153                         int *val, int *val2, long mask)
154 {
155         int ret;
156         struct axp288_adc_info *info = iio_priv(indio_dev);
157
158         mutex_lock(&indio_dev->mlock);
159         switch (mask) {
160         case IIO_CHAN_INFO_RAW:
161                 if (axp288_adc_set_ts(info, AXP288_ADC_TS_CURRENT_ON_ONDEMAND,
162                                         chan->address)) {
163                         dev_err(&indio_dev->dev, "GPADC mode\n");
164                         ret = -EINVAL;
165                         break;
166                 }
167                 ret = axp288_adc_read_channel(val, chan->address, info->regmap);
168                 if (axp288_adc_set_ts(info, AXP288_ADC_TS_CURRENT_ON,
169                                                 chan->address))
170                         dev_err(&indio_dev->dev, "TS pin restore\n");
171                 break;
172         default:
173                 ret = -EINVAL;
174         }
175         mutex_unlock(&indio_dev->mlock);
176
177         return ret;
178 }
179
180 static int axp288_adc_initialize(struct axp288_adc_info *info)
181 {
182         int ret, adc_enable_val;
183
184         /*
185          * Determine if the TS pin is enabled and set the TS current-source
186          * accordingly.
187          */
188         ret = regmap_read(info->regmap, AXP20X_ADC_EN1, &adc_enable_val);
189         if (ret)
190                 return ret;
191
192         if (adc_enable_val & AXP288_ADC_TS_ENABLE) {
193                 info->ts_enabled = true;
194                 ret = regmap_update_bits(info->regmap, AXP288_ADC_TS_PIN_CTRL,
195                                          AXP288_ADC_TS_CURRENT_ON_OFF_MASK,
196                                          AXP288_ADC_TS_CURRENT_ON);
197         } else {
198                 info->ts_enabled = false;
199                 ret = regmap_update_bits(info->regmap, AXP288_ADC_TS_PIN_CTRL,
200                                          AXP288_ADC_TS_CURRENT_ON_OFF_MASK,
201                                          AXP288_ADC_TS_CURRENT_OFF);
202         }
203         if (ret)
204                 return ret;
205
206         /* Turn on the ADC for all channels except TS, leave TS as is */
207         return regmap_update_bits(info->regmap, AXP20X_ADC_EN1,
208                                   AXP288_ADC_EN_MASK, AXP288_ADC_EN_MASK);
209 }
210
211 static const struct iio_info axp288_adc_iio_info = {
212         .read_raw = &axp288_adc_read_raw,
213 };
214
215 static int axp288_adc_probe(struct platform_device *pdev)
216 {
217         int ret;
218         struct axp288_adc_info *info;
219         struct iio_dev *indio_dev;
220         struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
221
222         indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
223         if (!indio_dev)
224                 return -ENOMEM;
225
226         info = iio_priv(indio_dev);
227         info->irq = platform_get_irq(pdev, 0);
228         if (info->irq < 0)
229                 return info->irq;
230         platform_set_drvdata(pdev, indio_dev);
231         info->regmap = axp20x->regmap;
232         /*
233          * Set ADC to enabled state at all time, including system suspend.
234          * otherwise internal fuel gauge functionality may be affected.
235          */
236         ret = axp288_adc_initialize(info);
237         if (ret) {
238                 dev_err(&pdev->dev, "unable to enable ADC device\n");
239                 return ret;
240         }
241
242         indio_dev->dev.parent = &pdev->dev;
243         indio_dev->name = pdev->name;
244         indio_dev->channels = axp288_adc_channels;
245         indio_dev->num_channels = ARRAY_SIZE(axp288_adc_channels);
246         indio_dev->info = &axp288_adc_iio_info;
247         indio_dev->modes = INDIO_DIRECT_MODE;
248         ret = iio_map_array_register(indio_dev, axp288_adc_default_maps);
249         if (ret < 0)
250                 return ret;
251
252         ret = iio_device_register(indio_dev);
253         if (ret < 0) {
254                 dev_err(&pdev->dev, "unable to register iio device\n");
255                 goto err_array_unregister;
256         }
257         return 0;
258
259 err_array_unregister:
260         iio_map_array_unregister(indio_dev);
261
262         return ret;
263 }
264
265 static int axp288_adc_remove(struct platform_device *pdev)
266 {
267         struct iio_dev *indio_dev = platform_get_drvdata(pdev);
268
269         iio_device_unregister(indio_dev);
270         iio_map_array_unregister(indio_dev);
271
272         return 0;
273 }
274
275 static const struct platform_device_id axp288_adc_id_table[] = {
276         { .name = "axp288_adc" },
277         {},
278 };
279
280 static struct platform_driver axp288_adc_driver = {
281         .probe = axp288_adc_probe,
282         .remove = axp288_adc_remove,
283         .id_table = axp288_adc_id_table,
284         .driver = {
285                 .name = "axp288_adc",
286         },
287 };
288
289 MODULE_DEVICE_TABLE(platform, axp288_adc_id_table);
290
291 module_platform_driver(axp288_adc_driver);
292
293 MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
294 MODULE_DESCRIPTION("X-Powers AXP288 ADC Driver");
295 MODULE_LICENSE("GPL");