xref: /openbmc/linux/drivers/iio/adc/axp288_adc.c (revision 8e8e69d6)
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 		dev_err(&pdev->dev, "no irq resource?\n");
230 		return info->irq;
231 	}
232 	platform_set_drvdata(pdev, indio_dev);
233 	info->regmap = axp20x->regmap;
234 	/*
235 	 * Set ADC to enabled state at all time, including system suspend.
236 	 * otherwise internal fuel gauge functionality may be affected.
237 	 */
238 	ret = axp288_adc_initialize(info);
239 	if (ret) {
240 		dev_err(&pdev->dev, "unable to enable ADC device\n");
241 		return ret;
242 	}
243 
244 	indio_dev->dev.parent = &pdev->dev;
245 	indio_dev->name = pdev->name;
246 	indio_dev->channels = axp288_adc_channels;
247 	indio_dev->num_channels = ARRAY_SIZE(axp288_adc_channels);
248 	indio_dev->info = &axp288_adc_iio_info;
249 	indio_dev->modes = INDIO_DIRECT_MODE;
250 	ret = iio_map_array_register(indio_dev, axp288_adc_default_maps);
251 	if (ret < 0)
252 		return ret;
253 
254 	ret = iio_device_register(indio_dev);
255 	if (ret < 0) {
256 		dev_err(&pdev->dev, "unable to register iio device\n");
257 		goto err_array_unregister;
258 	}
259 	return 0;
260 
261 err_array_unregister:
262 	iio_map_array_unregister(indio_dev);
263 
264 	return ret;
265 }
266 
267 static int axp288_adc_remove(struct platform_device *pdev)
268 {
269 	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
270 
271 	iio_device_unregister(indio_dev);
272 	iio_map_array_unregister(indio_dev);
273 
274 	return 0;
275 }
276 
277 static const struct platform_device_id axp288_adc_id_table[] = {
278 	{ .name = "axp288_adc" },
279 	{},
280 };
281 
282 static struct platform_driver axp288_adc_driver = {
283 	.probe = axp288_adc_probe,
284 	.remove = axp288_adc_remove,
285 	.id_table = axp288_adc_id_table,
286 	.driver = {
287 		.name = "axp288_adc",
288 	},
289 };
290 
291 MODULE_DEVICE_TABLE(platform, axp288_adc_id_table);
292 
293 module_platform_driver(axp288_adc_driver);
294 
295 MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
296 MODULE_DESCRIPTION("X-Powers AXP288 ADC Driver");
297 MODULE_LICENSE("GPL");
298