xref: /linux/drivers/iio/adc/ingenic-adc.c (revision 6a294b41ab344948bac28fa39f4c1d42c0acdace)
11a78daeaSArtur Rojek // SPDX-License-Identifier: GPL-2.0
21a78daeaSArtur Rojek /*
31a78daeaSArtur Rojek  * ADC driver for the Ingenic JZ47xx SoCs
41a78daeaSArtur Rojek  * Copyright (c) 2019 Artur Rojek <contact@artur-rojek.eu>
51a78daeaSArtur Rojek  *
61a78daeaSArtur Rojek  * based on drivers/mfd/jz4740-adc.c
71a78daeaSArtur Rojek  */
81a78daeaSArtur Rojek 
91a78daeaSArtur Rojek #include <dt-bindings/iio/adc/ingenic,adc.h>
101a78daeaSArtur Rojek #include <linux/clk.h>
111a78daeaSArtur Rojek #include <linux/iio/iio.h>
121a78daeaSArtur Rojek #include <linux/io.h>
131a78daeaSArtur Rojek #include <linux/iopoll.h>
145a304e1aSMaarten ter Huurne #include <linux/kernel.h>
151a78daeaSArtur Rojek #include <linux/module.h>
161a78daeaSArtur Rojek #include <linux/mutex.h>
171a78daeaSArtur Rojek #include <linux/platform_device.h>
181a78daeaSArtur Rojek 
191a78daeaSArtur Rojek #define JZ_ADC_REG_ENABLE		0x00
201a78daeaSArtur Rojek #define JZ_ADC_REG_CFG			0x04
211a78daeaSArtur Rojek #define JZ_ADC_REG_CTRL			0x08
221a78daeaSArtur Rojek #define JZ_ADC_REG_STATUS		0x0c
231a78daeaSArtur Rojek #define JZ_ADC_REG_ADTCH		0x18
241a78daeaSArtur Rojek #define JZ_ADC_REG_ADBDAT		0x1c
251a78daeaSArtur Rojek #define JZ_ADC_REG_ADSDAT		0x20
265a304e1aSMaarten ter Huurne #define JZ_ADC_REG_ADCLK		0x28
271a78daeaSArtur Rojek 
28a515d648SArtur Rojek #define JZ_ADC_REG_ENABLE_PD		BIT(7)
29a515d648SArtur Rojek #define JZ_ADC_REG_CFG_AUX_MD		(BIT(0) | BIT(1))
301a78daeaSArtur Rojek #define JZ_ADC_REG_CFG_BAT_MD		BIT(4)
315a304e1aSMaarten ter Huurne #define JZ_ADC_REG_ADCLK_CLKDIV_LSB	0
32a515d648SArtur Rojek #define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB	16
33a515d648SArtur Rojek #define JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB	8
34a515d648SArtur Rojek #define JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB	16
351a78daeaSArtur Rojek 
361a78daeaSArtur Rojek #define JZ_ADC_AUX_VREF				3300
371a78daeaSArtur Rojek #define JZ_ADC_AUX_VREF_BITS			12
381a78daeaSArtur Rojek #define JZ_ADC_BATTERY_LOW_VREF			2500
391a78daeaSArtur Rojek #define JZ_ADC_BATTERY_LOW_VREF_BITS		12
401a78daeaSArtur Rojek #define JZ4725B_ADC_BATTERY_HIGH_VREF		7500
411a78daeaSArtur Rojek #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS	10
421a78daeaSArtur Rojek #define JZ4740_ADC_BATTERY_HIGH_VREF		(7500 * 0.986)
431a78daeaSArtur Rojek #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS	12
44a515d648SArtur Rojek #define JZ4770_ADC_BATTERY_VREF			6600
45a515d648SArtur Rojek #define JZ4770_ADC_BATTERY_VREF_BITS		12
461a78daeaSArtur Rojek 
475a304e1aSMaarten ter Huurne struct ingenic_adc;
485a304e1aSMaarten ter Huurne 
491a78daeaSArtur Rojek struct ingenic_adc_soc_data {
501a78daeaSArtur Rojek 	unsigned int battery_high_vref;
511a78daeaSArtur Rojek 	unsigned int battery_high_vref_bits;
521a78daeaSArtur Rojek 	const int *battery_raw_avail;
531a78daeaSArtur Rojek 	size_t battery_raw_avail_size;
541a78daeaSArtur Rojek 	const int *battery_scale_avail;
551a78daeaSArtur Rojek 	size_t battery_scale_avail_size;
56a515d648SArtur Rojek 	unsigned int battery_vref_mode: 1;
57a515d648SArtur Rojek 	unsigned int has_aux2: 1;
58*6a294b41SPaul Cercueil 	const struct iio_chan_spec *channels;
59*6a294b41SPaul Cercueil 	unsigned int num_channels;
605a304e1aSMaarten ter Huurne 	int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc);
611a78daeaSArtur Rojek };
621a78daeaSArtur Rojek 
631a78daeaSArtur Rojek struct ingenic_adc {
641a78daeaSArtur Rojek 	void __iomem *base;
651a78daeaSArtur Rojek 	struct clk *clk;
661a78daeaSArtur Rojek 	struct mutex lock;
67a515d648SArtur Rojek 	struct mutex aux_lock;
681a78daeaSArtur Rojek 	const struct ingenic_adc_soc_data *soc_data;
691a78daeaSArtur Rojek 	bool low_vref_mode;
701a78daeaSArtur Rojek };
711a78daeaSArtur Rojek 
721a78daeaSArtur Rojek static void ingenic_adc_set_config(struct ingenic_adc *adc,
731a78daeaSArtur Rojek 				   uint32_t mask,
741a78daeaSArtur Rojek 				   uint32_t val)
751a78daeaSArtur Rojek {
761a78daeaSArtur Rojek 	uint32_t cfg;
771a78daeaSArtur Rojek 
781a78daeaSArtur Rojek 	mutex_lock(&adc->lock);
791a78daeaSArtur Rojek 
801a78daeaSArtur Rojek 	cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask;
811a78daeaSArtur Rojek 	cfg |= val;
821a78daeaSArtur Rojek 	writel(cfg, adc->base + JZ_ADC_REG_CFG);
831a78daeaSArtur Rojek 
841a78daeaSArtur Rojek 	mutex_unlock(&adc->lock);
851a78daeaSArtur Rojek }
861a78daeaSArtur Rojek 
871a78daeaSArtur Rojek static void ingenic_adc_enable(struct ingenic_adc *adc,
881a78daeaSArtur Rojek 			       int engine,
891a78daeaSArtur Rojek 			       bool enabled)
901a78daeaSArtur Rojek {
911a78daeaSArtur Rojek 	u8 val;
921a78daeaSArtur Rojek 
931a78daeaSArtur Rojek 	mutex_lock(&adc->lock);
941a78daeaSArtur Rojek 	val = readb(adc->base + JZ_ADC_REG_ENABLE);
951a78daeaSArtur Rojek 
961a78daeaSArtur Rojek 	if (enabled)
971a78daeaSArtur Rojek 		val |= BIT(engine);
981a78daeaSArtur Rojek 	else
991a78daeaSArtur Rojek 		val &= ~BIT(engine);
1001a78daeaSArtur Rojek 
1011a78daeaSArtur Rojek 	writeb(val, adc->base + JZ_ADC_REG_ENABLE);
1021a78daeaSArtur Rojek 	mutex_unlock(&adc->lock);
1031a78daeaSArtur Rojek }
1041a78daeaSArtur Rojek 
1051a78daeaSArtur Rojek static int ingenic_adc_capture(struct ingenic_adc *adc,
1061a78daeaSArtur Rojek 			       int engine)
1071a78daeaSArtur Rojek {
1081a78daeaSArtur Rojek 	u8 val;
1091a78daeaSArtur Rojek 	int ret;
1101a78daeaSArtur Rojek 
1111a78daeaSArtur Rojek 	ingenic_adc_enable(adc, engine, true);
1121a78daeaSArtur Rojek 	ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val,
1131a78daeaSArtur Rojek 				 !(val & BIT(engine)), 250, 1000);
1141a78daeaSArtur Rojek 	if (ret)
1151a78daeaSArtur Rojek 		ingenic_adc_enable(adc, engine, false);
1161a78daeaSArtur Rojek 
1171a78daeaSArtur Rojek 	return ret;
1181a78daeaSArtur Rojek }
1191a78daeaSArtur Rojek 
1201a78daeaSArtur Rojek static int ingenic_adc_write_raw(struct iio_dev *iio_dev,
1211a78daeaSArtur Rojek 				 struct iio_chan_spec const *chan,
1221a78daeaSArtur Rojek 				 int val,
1231a78daeaSArtur Rojek 				 int val2,
1241a78daeaSArtur Rojek 				 long m)
1251a78daeaSArtur Rojek {
1261a78daeaSArtur Rojek 	struct ingenic_adc *adc = iio_priv(iio_dev);
1271a99dc46SArtur Rojek 	struct device *dev = iio_dev->dev.parent;
1281a99dc46SArtur Rojek 	int ret;
1291a78daeaSArtur Rojek 
1301a78daeaSArtur Rojek 	switch (m) {
1311a78daeaSArtur Rojek 	case IIO_CHAN_INFO_SCALE:
1321a78daeaSArtur Rojek 		switch (chan->channel) {
1331a78daeaSArtur Rojek 		case INGENIC_ADC_BATTERY:
134a515d648SArtur Rojek 			if (!adc->soc_data->battery_vref_mode)
135a515d648SArtur Rojek 				return -EINVAL;
1361a99dc46SArtur Rojek 
1371a99dc46SArtur Rojek 			ret = clk_enable(adc->clk);
1381a99dc46SArtur Rojek 			if (ret) {
1391a99dc46SArtur Rojek 				dev_err(dev, "Failed to enable clock: %d\n",
1401a99dc46SArtur Rojek 					ret);
1411a99dc46SArtur Rojek 				return ret;
1421a99dc46SArtur Rojek 			}
1431a99dc46SArtur Rojek 
1441a78daeaSArtur Rojek 			if (val > JZ_ADC_BATTERY_LOW_VREF) {
1451a78daeaSArtur Rojek 				ingenic_adc_set_config(adc,
1461a78daeaSArtur Rojek 						       JZ_ADC_REG_CFG_BAT_MD,
1471a78daeaSArtur Rojek 						       0);
1481a78daeaSArtur Rojek 				adc->low_vref_mode = false;
1491a78daeaSArtur Rojek 			} else {
1501a78daeaSArtur Rojek 				ingenic_adc_set_config(adc,
1511a78daeaSArtur Rojek 						       JZ_ADC_REG_CFG_BAT_MD,
1521a78daeaSArtur Rojek 						       JZ_ADC_REG_CFG_BAT_MD);
1531a78daeaSArtur Rojek 				adc->low_vref_mode = true;
1541a78daeaSArtur Rojek 			}
1551a99dc46SArtur Rojek 
1561a99dc46SArtur Rojek 			clk_disable(adc->clk);
1571a99dc46SArtur Rojek 
1581a78daeaSArtur Rojek 			return 0;
1591a78daeaSArtur Rojek 		default:
1601a78daeaSArtur Rojek 			return -EINVAL;
1611a78daeaSArtur Rojek 		}
1621a78daeaSArtur Rojek 	default:
1631a78daeaSArtur Rojek 		return -EINVAL;
1641a78daeaSArtur Rojek 	}
1651a78daeaSArtur Rojek }
1661a78daeaSArtur Rojek 
1671a78daeaSArtur Rojek static const int jz4725b_adc_battery_raw_avail[] = {
1681a78daeaSArtur Rojek 	0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
1691a78daeaSArtur Rojek };
1701a78daeaSArtur Rojek 
1711a78daeaSArtur Rojek static const int jz4725b_adc_battery_scale_avail[] = {
1721a78daeaSArtur Rojek 	JZ4725B_ADC_BATTERY_HIGH_VREF, JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
1731a78daeaSArtur Rojek 	JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
1741a78daeaSArtur Rojek };
1751a78daeaSArtur Rojek 
1761a78daeaSArtur Rojek static const int jz4740_adc_battery_raw_avail[] = {
1771a78daeaSArtur Rojek 	0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
1781a78daeaSArtur Rojek };
1791a78daeaSArtur Rojek 
1801a78daeaSArtur Rojek static const int jz4740_adc_battery_scale_avail[] = {
1811a78daeaSArtur Rojek 	JZ4740_ADC_BATTERY_HIGH_VREF, JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
1821a78daeaSArtur Rojek 	JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
1831a78daeaSArtur Rojek };
1841a78daeaSArtur Rojek 
185a515d648SArtur Rojek static const int jz4770_adc_battery_raw_avail[] = {
186a515d648SArtur Rojek 	0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1,
187a515d648SArtur Rojek };
188a515d648SArtur Rojek 
189a515d648SArtur Rojek static const int jz4770_adc_battery_scale_avail[] = {
190a515d648SArtur Rojek 	JZ4770_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS,
191a515d648SArtur Rojek };
192a515d648SArtur Rojek 
1935a304e1aSMaarten ter Huurne static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
1945a304e1aSMaarten ter Huurne {
1955a304e1aSMaarten ter Huurne 	struct clk *parent_clk;
1965a304e1aSMaarten ter Huurne 	unsigned long parent_rate, rate;
1975a304e1aSMaarten ter Huurne 	unsigned int div_main, div_10us;
1985a304e1aSMaarten ter Huurne 
1995a304e1aSMaarten ter Huurne 	parent_clk = clk_get_parent(adc->clk);
2005a304e1aSMaarten ter Huurne 	if (!parent_clk) {
2015a304e1aSMaarten ter Huurne 		dev_err(dev, "ADC clock has no parent\n");
2025a304e1aSMaarten ter Huurne 		return -ENODEV;
2035a304e1aSMaarten ter Huurne 	}
2045a304e1aSMaarten ter Huurne 	parent_rate = clk_get_rate(parent_clk);
2055a304e1aSMaarten ter Huurne 
2065a304e1aSMaarten ter Huurne 	/*
2075a304e1aSMaarten ter Huurne 	 * The JZ4725B ADC works at 500 kHz to 8 MHz.
2085a304e1aSMaarten ter Huurne 	 * We pick the highest rate possible.
2095a304e1aSMaarten ter Huurne 	 * In practice we typically get 6 MHz, half of the 12 MHz EXT clock.
2105a304e1aSMaarten ter Huurne 	 */
2115a304e1aSMaarten ter Huurne 	div_main = DIV_ROUND_UP(parent_rate, 8000000);
2125a304e1aSMaarten ter Huurne 	div_main = clamp(div_main, 1u, 64u);
2135a304e1aSMaarten ter Huurne 	rate = parent_rate / div_main;
2145a304e1aSMaarten ter Huurne 	if (rate < 500000 || rate > 8000000) {
2155a304e1aSMaarten ter Huurne 		dev_err(dev, "No valid divider for ADC main clock\n");
2165a304e1aSMaarten ter Huurne 		return -EINVAL;
2175a304e1aSMaarten ter Huurne 	}
2185a304e1aSMaarten ter Huurne 
2195a304e1aSMaarten ter Huurne 	/* We also need a divider that produces a 10us clock. */
2205a304e1aSMaarten ter Huurne 	div_10us = DIV_ROUND_UP(rate, 100000);
2215a304e1aSMaarten ter Huurne 
222a515d648SArtur Rojek 	writel(((div_10us - 1) << JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB) |
223a515d648SArtur Rojek 	       (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
224a515d648SArtur Rojek 	       adc->base + JZ_ADC_REG_ADCLK);
225a515d648SArtur Rojek 
226a515d648SArtur Rojek 	return 0;
227a515d648SArtur Rojek }
228a515d648SArtur Rojek 
229a515d648SArtur Rojek static int jz4770_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
230a515d648SArtur Rojek {
231a515d648SArtur Rojek 	struct clk *parent_clk;
232a515d648SArtur Rojek 	unsigned long parent_rate, rate;
233a515d648SArtur Rojek 	unsigned int div_main, div_ms, div_10us;
234a515d648SArtur Rojek 
235a515d648SArtur Rojek 	parent_clk = clk_get_parent(adc->clk);
236a515d648SArtur Rojek 	if (!parent_clk) {
237a515d648SArtur Rojek 		dev_err(dev, "ADC clock has no parent\n");
238a515d648SArtur Rojek 		return -ENODEV;
239a515d648SArtur Rojek 	}
240a515d648SArtur Rojek 	parent_rate = clk_get_rate(parent_clk);
241a515d648SArtur Rojek 
242a515d648SArtur Rojek 	/*
243a515d648SArtur Rojek 	 * The JZ4770 ADC works at 20 kHz to 200 kHz.
244a515d648SArtur Rojek 	 * We pick the highest rate possible.
245a515d648SArtur Rojek 	 */
246a515d648SArtur Rojek 	div_main = DIV_ROUND_UP(parent_rate, 200000);
247a515d648SArtur Rojek 	div_main = clamp(div_main, 1u, 256u);
248a515d648SArtur Rojek 	rate = parent_rate / div_main;
249a515d648SArtur Rojek 	if (rate < 20000 || rate > 200000) {
250a515d648SArtur Rojek 		dev_err(dev, "No valid divider for ADC main clock\n");
251a515d648SArtur Rojek 		return -EINVAL;
252a515d648SArtur Rojek 	}
253a515d648SArtur Rojek 
254a515d648SArtur Rojek 	/* We also need a divider that produces a 10us clock. */
255a515d648SArtur Rojek 	div_10us = DIV_ROUND_UP(rate, 10000);
256a515d648SArtur Rojek 	/* And another, which produces a 1ms clock. */
257a515d648SArtur Rojek 	div_ms = DIV_ROUND_UP(rate, 1000);
258a515d648SArtur Rojek 
259a515d648SArtur Rojek 	writel(((div_ms - 1) << JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB) |
260a515d648SArtur Rojek 	       ((div_10us - 1) << JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB) |
2615a304e1aSMaarten ter Huurne 	       (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
2625a304e1aSMaarten ter Huurne 	       adc->base + JZ_ADC_REG_ADCLK);
2635a304e1aSMaarten ter Huurne 
2645a304e1aSMaarten ter Huurne 	return 0;
2655a304e1aSMaarten ter Huurne }
2665a304e1aSMaarten ter Huurne 
267*6a294b41SPaul Cercueil static const struct iio_chan_spec jz4740_channels[] = {
268*6a294b41SPaul Cercueil 	{
269*6a294b41SPaul Cercueil 		.extend_name = "aux",
270*6a294b41SPaul Cercueil 		.type = IIO_VOLTAGE,
271*6a294b41SPaul Cercueil 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
272*6a294b41SPaul Cercueil 				      BIT(IIO_CHAN_INFO_SCALE),
273*6a294b41SPaul Cercueil 		.indexed = 1,
274*6a294b41SPaul Cercueil 		.channel = INGENIC_ADC_AUX,
275*6a294b41SPaul Cercueil 		.scan_index = -1,
276*6a294b41SPaul Cercueil 	},
277*6a294b41SPaul Cercueil 	{
278*6a294b41SPaul Cercueil 		.extend_name = "battery",
279*6a294b41SPaul Cercueil 		.type = IIO_VOLTAGE,
280*6a294b41SPaul Cercueil 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
281*6a294b41SPaul Cercueil 				      BIT(IIO_CHAN_INFO_SCALE),
282*6a294b41SPaul Cercueil 		.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) |
283*6a294b41SPaul Cercueil 						BIT(IIO_CHAN_INFO_SCALE),
284*6a294b41SPaul Cercueil 		.indexed = 1,
285*6a294b41SPaul Cercueil 		.channel = INGENIC_ADC_BATTERY,
286*6a294b41SPaul Cercueil 		.scan_index = -1,
287*6a294b41SPaul Cercueil 	},
288*6a294b41SPaul Cercueil };
289*6a294b41SPaul Cercueil 
290*6a294b41SPaul Cercueil static const struct iio_chan_spec jz4770_channels[] = {
291*6a294b41SPaul Cercueil 	{
292*6a294b41SPaul Cercueil 		.extend_name = "aux",
293*6a294b41SPaul Cercueil 		.type = IIO_VOLTAGE,
294*6a294b41SPaul Cercueil 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
295*6a294b41SPaul Cercueil 				      BIT(IIO_CHAN_INFO_SCALE),
296*6a294b41SPaul Cercueil 		.indexed = 1,
297*6a294b41SPaul Cercueil 		.channel = INGENIC_ADC_AUX,
298*6a294b41SPaul Cercueil 		.scan_index = -1,
299*6a294b41SPaul Cercueil 	},
300*6a294b41SPaul Cercueil 	{
301*6a294b41SPaul Cercueil 		.extend_name = "battery",
302*6a294b41SPaul Cercueil 		.type = IIO_VOLTAGE,
303*6a294b41SPaul Cercueil 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
304*6a294b41SPaul Cercueil 				      BIT(IIO_CHAN_INFO_SCALE),
305*6a294b41SPaul Cercueil 		.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) |
306*6a294b41SPaul Cercueil 						BIT(IIO_CHAN_INFO_SCALE),
307*6a294b41SPaul Cercueil 		.indexed = 1,
308*6a294b41SPaul Cercueil 		.channel = INGENIC_ADC_BATTERY,
309*6a294b41SPaul Cercueil 		.scan_index = -1,
310*6a294b41SPaul Cercueil 	},
311*6a294b41SPaul Cercueil 	{
312*6a294b41SPaul Cercueil 		.extend_name = "aux2",
313*6a294b41SPaul Cercueil 		.type = IIO_VOLTAGE,
314*6a294b41SPaul Cercueil 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
315*6a294b41SPaul Cercueil 				      BIT(IIO_CHAN_INFO_SCALE),
316*6a294b41SPaul Cercueil 		.indexed = 1,
317*6a294b41SPaul Cercueil 		.channel = INGENIC_ADC_AUX2,
318*6a294b41SPaul Cercueil 		.scan_index = -1,
319*6a294b41SPaul Cercueil 	},
320*6a294b41SPaul Cercueil };
321*6a294b41SPaul Cercueil 
3221a78daeaSArtur Rojek static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
3231a78daeaSArtur Rojek 	.battery_high_vref = JZ4725B_ADC_BATTERY_HIGH_VREF,
3241a78daeaSArtur Rojek 	.battery_high_vref_bits = JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
3251a78daeaSArtur Rojek 	.battery_raw_avail = jz4725b_adc_battery_raw_avail,
3261a78daeaSArtur Rojek 	.battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail),
3271a78daeaSArtur Rojek 	.battery_scale_avail = jz4725b_adc_battery_scale_avail,
3281a78daeaSArtur Rojek 	.battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
329a515d648SArtur Rojek 	.battery_vref_mode = true,
330a515d648SArtur Rojek 	.has_aux2 = false,
331*6a294b41SPaul Cercueil 	.channels = jz4740_channels,
332*6a294b41SPaul Cercueil 	.num_channels = ARRAY_SIZE(jz4740_channels),
3335a304e1aSMaarten ter Huurne 	.init_clk_div = jz4725b_adc_init_clk_div,
3341a78daeaSArtur Rojek };
3351a78daeaSArtur Rojek 
3361a78daeaSArtur Rojek static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
3371a78daeaSArtur Rojek 	.battery_high_vref = JZ4740_ADC_BATTERY_HIGH_VREF,
3381a78daeaSArtur Rojek 	.battery_high_vref_bits = JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
3391a78daeaSArtur Rojek 	.battery_raw_avail = jz4740_adc_battery_raw_avail,
3401a78daeaSArtur Rojek 	.battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail),
3411a78daeaSArtur Rojek 	.battery_scale_avail = jz4740_adc_battery_scale_avail,
3421a78daeaSArtur Rojek 	.battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
343a515d648SArtur Rojek 	.battery_vref_mode = true,
344a515d648SArtur Rojek 	.has_aux2 = false,
345*6a294b41SPaul Cercueil 	.channels = jz4740_channels,
346*6a294b41SPaul Cercueil 	.num_channels = ARRAY_SIZE(jz4740_channels),
3475a304e1aSMaarten ter Huurne 	.init_clk_div = NULL, /* no ADCLK register on JZ4740 */
3481a78daeaSArtur Rojek };
3491a78daeaSArtur Rojek 
350a515d648SArtur Rojek static const struct ingenic_adc_soc_data jz4770_adc_soc_data = {
351a515d648SArtur Rojek 	.battery_high_vref = JZ4770_ADC_BATTERY_VREF,
352a515d648SArtur Rojek 	.battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS,
353a515d648SArtur Rojek 	.battery_raw_avail = jz4770_adc_battery_raw_avail,
354a515d648SArtur Rojek 	.battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail),
355a515d648SArtur Rojek 	.battery_scale_avail = jz4770_adc_battery_scale_avail,
356a515d648SArtur Rojek 	.battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail),
357a515d648SArtur Rojek 	.battery_vref_mode = false,
358a515d648SArtur Rojek 	.has_aux2 = true,
359*6a294b41SPaul Cercueil 	.channels = jz4770_channels,
360*6a294b41SPaul Cercueil 	.num_channels = ARRAY_SIZE(jz4770_channels),
361a515d648SArtur Rojek 	.init_clk_div = jz4770_adc_init_clk_div,
362a515d648SArtur Rojek };
363a515d648SArtur Rojek 
3641a78daeaSArtur Rojek static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
3651a78daeaSArtur Rojek 				  struct iio_chan_spec const *chan,
3661a78daeaSArtur Rojek 				  const int **vals,
3671a78daeaSArtur Rojek 				  int *type,
3681a78daeaSArtur Rojek 				  int *length,
3691a78daeaSArtur Rojek 				  long m)
3701a78daeaSArtur Rojek {
3711a78daeaSArtur Rojek 	struct ingenic_adc *adc = iio_priv(iio_dev);
3721a78daeaSArtur Rojek 
3731a78daeaSArtur Rojek 	switch (m) {
3741a78daeaSArtur Rojek 	case IIO_CHAN_INFO_RAW:
3751a78daeaSArtur Rojek 		*type = IIO_VAL_INT;
3761a78daeaSArtur Rojek 		*length = adc->soc_data->battery_raw_avail_size;
3771a78daeaSArtur Rojek 		*vals = adc->soc_data->battery_raw_avail;
3781a78daeaSArtur Rojek 		return IIO_AVAIL_RANGE;
3791a78daeaSArtur Rojek 	case IIO_CHAN_INFO_SCALE:
3801a78daeaSArtur Rojek 		*type = IIO_VAL_FRACTIONAL_LOG2;
3811a78daeaSArtur Rojek 		*length = adc->soc_data->battery_scale_avail_size;
3821a78daeaSArtur Rojek 		*vals = adc->soc_data->battery_scale_avail;
3831a78daeaSArtur Rojek 		return IIO_AVAIL_LIST;
3841a78daeaSArtur Rojek 	default:
3851a78daeaSArtur Rojek 		return -EINVAL;
3861a78daeaSArtur Rojek 	};
3871a78daeaSArtur Rojek }
3881a78daeaSArtur Rojek 
3891a99dc46SArtur Rojek static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
3901a78daeaSArtur Rojek 					  struct iio_chan_spec const *chan,
391a515d648SArtur Rojek 					  int *val)
3921a78daeaSArtur Rojek {
393a515d648SArtur Rojek 	int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
3941a99dc46SArtur Rojek 	struct ingenic_adc *adc = iio_priv(iio_dev);
3951a99dc46SArtur Rojek 
3961a99dc46SArtur Rojek 	ret = clk_enable(adc->clk);
3971a99dc46SArtur Rojek 	if (ret) {
3981a99dc46SArtur Rojek 		dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n",
3991a99dc46SArtur Rojek 			ret);
4001a99dc46SArtur Rojek 		return ret;
4011a99dc46SArtur Rojek 	}
4021a78daeaSArtur Rojek 
403a515d648SArtur Rojek 	/* We cannot sample AUX/AUX2 in parallel. */
404a515d648SArtur Rojek 	mutex_lock(&adc->aux_lock);
405a515d648SArtur Rojek 	if (adc->soc_data->has_aux2 && engine == 0) {
406a515d648SArtur Rojek 		bit = BIT(chan->channel == INGENIC_ADC_AUX2);
407a515d648SArtur Rojek 		ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit);
4081a78daeaSArtur Rojek 	}
4091a78daeaSArtur Rojek 
410a515d648SArtur Rojek 	ret = ingenic_adc_capture(adc, engine);
411a515d648SArtur Rojek 	if (ret)
412a515d648SArtur Rojek 		goto out;
413a515d648SArtur Rojek 
4141a78daeaSArtur Rojek 	switch (chan->channel) {
4151a78daeaSArtur Rojek 	case INGENIC_ADC_AUX:
416a515d648SArtur Rojek 	case INGENIC_ADC_AUX2:
4171a78daeaSArtur Rojek 		*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
4181a78daeaSArtur Rojek 		break;
4191a78daeaSArtur Rojek 	case INGENIC_ADC_BATTERY:
4201a78daeaSArtur Rojek 		*val = readw(adc->base + JZ_ADC_REG_ADBDAT);
4211a78daeaSArtur Rojek 		break;
4221a78daeaSArtur Rojek 	}
4231a78daeaSArtur Rojek 
424a515d648SArtur Rojek 	ret = IIO_VAL_INT;
425a515d648SArtur Rojek out:
426a515d648SArtur Rojek 	mutex_unlock(&adc->aux_lock);
4271a99dc46SArtur Rojek 	clk_disable(adc->clk);
4281a78daeaSArtur Rojek 
429a515d648SArtur Rojek 	return ret;
430a515d648SArtur Rojek }
431a515d648SArtur Rojek 
432a515d648SArtur Rojek static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
433a515d648SArtur Rojek 				struct iio_chan_spec const *chan,
434a515d648SArtur Rojek 				int *val,
435a515d648SArtur Rojek 				int *val2,
436a515d648SArtur Rojek 				long m)
437a515d648SArtur Rojek {
438a515d648SArtur Rojek 	struct ingenic_adc *adc = iio_priv(iio_dev);
439a515d648SArtur Rojek 
440a515d648SArtur Rojek 	switch (m) {
441a515d648SArtur Rojek 	case IIO_CHAN_INFO_RAW:
4421a99dc46SArtur Rojek 		return ingenic_adc_read_chan_info_raw(iio_dev, chan, val);
4431a78daeaSArtur Rojek 	case IIO_CHAN_INFO_SCALE:
4441a78daeaSArtur Rojek 		switch (chan->channel) {
4451a78daeaSArtur Rojek 		case INGENIC_ADC_AUX:
446a515d648SArtur Rojek 		case INGENIC_ADC_AUX2:
4471a78daeaSArtur Rojek 			*val = JZ_ADC_AUX_VREF;
4481a78daeaSArtur Rojek 			*val2 = JZ_ADC_AUX_VREF_BITS;
4491a78daeaSArtur Rojek 			break;
4501a78daeaSArtur Rojek 		case INGENIC_ADC_BATTERY:
4511a78daeaSArtur Rojek 			if (adc->low_vref_mode) {
4521a78daeaSArtur Rojek 				*val = JZ_ADC_BATTERY_LOW_VREF;
4531a78daeaSArtur Rojek 				*val2 = JZ_ADC_BATTERY_LOW_VREF_BITS;
4541a78daeaSArtur Rojek 			} else {
4551a78daeaSArtur Rojek 				*val = adc->soc_data->battery_high_vref;
4561a78daeaSArtur Rojek 				*val2 = adc->soc_data->battery_high_vref_bits;
4571a78daeaSArtur Rojek 			}
4581a78daeaSArtur Rojek 			break;
4591a78daeaSArtur Rojek 		}
4601a78daeaSArtur Rojek 
4611a78daeaSArtur Rojek 		return IIO_VAL_FRACTIONAL_LOG2;
4621a78daeaSArtur Rojek 	default:
4631a78daeaSArtur Rojek 		return -EINVAL;
4641a78daeaSArtur Rojek 	}
4651a78daeaSArtur Rojek }
4661a78daeaSArtur Rojek 
467155e41efSArtur Rojek static int ingenic_adc_of_xlate(struct iio_dev *iio_dev,
468155e41efSArtur Rojek 				const struct of_phandle_args *iiospec)
469155e41efSArtur Rojek {
470155e41efSArtur Rojek 	int i;
471155e41efSArtur Rojek 
472155e41efSArtur Rojek 	if (!iiospec->args_count)
473155e41efSArtur Rojek 		return -EINVAL;
474155e41efSArtur Rojek 
475155e41efSArtur Rojek 	for (i = 0; i < iio_dev->num_channels; ++i)
476155e41efSArtur Rojek 		if (iio_dev->channels[i].channel == iiospec->args[0])
477155e41efSArtur Rojek 			return i;
478155e41efSArtur Rojek 
479155e41efSArtur Rojek 	return -EINVAL;
480155e41efSArtur Rojek }
481155e41efSArtur Rojek 
4821a78daeaSArtur Rojek static void ingenic_adc_clk_cleanup(void *data)
4831a78daeaSArtur Rojek {
4841a78daeaSArtur Rojek 	clk_unprepare(data);
4851a78daeaSArtur Rojek }
4861a78daeaSArtur Rojek 
4871a78daeaSArtur Rojek static const struct iio_info ingenic_adc_info = {
4881a78daeaSArtur Rojek 	.write_raw = ingenic_adc_write_raw,
4891a78daeaSArtur Rojek 	.read_raw = ingenic_adc_read_raw,
4901a78daeaSArtur Rojek 	.read_avail = ingenic_adc_read_avail,
491155e41efSArtur Rojek 	.of_xlate = ingenic_adc_of_xlate,
4921a78daeaSArtur Rojek };
4931a78daeaSArtur Rojek 
4941a78daeaSArtur Rojek static int ingenic_adc_probe(struct platform_device *pdev)
4951a78daeaSArtur Rojek {
4961a78daeaSArtur Rojek 	struct device *dev = &pdev->dev;
4971a78daeaSArtur Rojek 	struct iio_dev *iio_dev;
4981a78daeaSArtur Rojek 	struct ingenic_adc *adc;
4991a78daeaSArtur Rojek 	const struct ingenic_adc_soc_data *soc_data;
5001a78daeaSArtur Rojek 	int ret;
5011a78daeaSArtur Rojek 
5021a78daeaSArtur Rojek 	soc_data = device_get_match_data(dev);
5031a78daeaSArtur Rojek 	if (!soc_data)
5041a78daeaSArtur Rojek 		return -EINVAL;
5051a78daeaSArtur Rojek 
5061a78daeaSArtur Rojek 	iio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
5071a78daeaSArtur Rojek 	if (!iio_dev)
5081a78daeaSArtur Rojek 		return -ENOMEM;
5091a78daeaSArtur Rojek 
5101a78daeaSArtur Rojek 	adc = iio_priv(iio_dev);
5111a78daeaSArtur Rojek 	mutex_init(&adc->lock);
512a515d648SArtur Rojek 	mutex_init(&adc->aux_lock);
5131a78daeaSArtur Rojek 	adc->soc_data = soc_data;
5141a78daeaSArtur Rojek 
515f449aa3eSJonathan Cameron 	adc->base = devm_platform_ioremap_resource(pdev, 0);
51676838a8fSWei Yongjun 	if (IS_ERR(adc->base))
5171a78daeaSArtur Rojek 		return PTR_ERR(adc->base);
5181a78daeaSArtur Rojek 
5191a78daeaSArtur Rojek 	adc->clk = devm_clk_get(dev, "adc");
5201a78daeaSArtur Rojek 	if (IS_ERR(adc->clk)) {
5211a78daeaSArtur Rojek 		dev_err(dev, "Unable to get clock\n");
5221a78daeaSArtur Rojek 		return PTR_ERR(adc->clk);
5231a78daeaSArtur Rojek 	}
5241a78daeaSArtur Rojek 
5251a78daeaSArtur Rojek 	ret = clk_prepare_enable(adc->clk);
5261a78daeaSArtur Rojek 	if (ret) {
5271a78daeaSArtur Rojek 		dev_err(dev, "Failed to enable clock\n");
5281a78daeaSArtur Rojek 		return ret;
5291a78daeaSArtur Rojek 	}
5301a78daeaSArtur Rojek 
5315a304e1aSMaarten ter Huurne 	/* Set clock dividers. */
5325a304e1aSMaarten ter Huurne 	if (soc_data->init_clk_div) {
5335a304e1aSMaarten ter Huurne 		ret = soc_data->init_clk_div(dev, adc);
5345a304e1aSMaarten ter Huurne 		if (ret) {
5355a304e1aSMaarten ter Huurne 			clk_disable_unprepare(adc->clk);
5365a304e1aSMaarten ter Huurne 			return ret;
5375a304e1aSMaarten ter Huurne 		}
5385a304e1aSMaarten ter Huurne 	}
5395a304e1aSMaarten ter Huurne 
5401a78daeaSArtur Rojek 	/* Put hardware in a known passive state. */
5411a78daeaSArtur Rojek 	writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
5421a78daeaSArtur Rojek 	writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
543a515d648SArtur Rojek 	usleep_range(2000, 3000); /* Must wait at least 2ms. */
5441a78daeaSArtur Rojek 	clk_disable(adc->clk);
5451a78daeaSArtur Rojek 
5461a78daeaSArtur Rojek 	ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
5471a78daeaSArtur Rojek 	if (ret) {
5481a78daeaSArtur Rojek 		dev_err(dev, "Unable to add action\n");
5491a78daeaSArtur Rojek 		return ret;
5501a78daeaSArtur Rojek 	}
5511a78daeaSArtur Rojek 
5521a78daeaSArtur Rojek 	iio_dev->dev.parent = dev;
5531a78daeaSArtur Rojek 	iio_dev->name = "jz-adc";
5541a78daeaSArtur Rojek 	iio_dev->modes = INDIO_DIRECT_MODE;
555*6a294b41SPaul Cercueil 	iio_dev->channels = soc_data->channels;
556*6a294b41SPaul Cercueil 	iio_dev->num_channels = soc_data->num_channels;
5571a78daeaSArtur Rojek 	iio_dev->info = &ingenic_adc_info;
5581a78daeaSArtur Rojek 
5591a78daeaSArtur Rojek 	ret = devm_iio_device_register(dev, iio_dev);
5601a78daeaSArtur Rojek 	if (ret)
5611a78daeaSArtur Rojek 		dev_err(dev, "Unable to register IIO device\n");
5621a78daeaSArtur Rojek 
5631a78daeaSArtur Rojek 	return ret;
5641a78daeaSArtur Rojek }
5651a78daeaSArtur Rojek 
5661a78daeaSArtur Rojek #ifdef CONFIG_OF
5671a78daeaSArtur Rojek static const struct of_device_id ingenic_adc_of_match[] = {
5681a78daeaSArtur Rojek 	{ .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
5691a78daeaSArtur Rojek 	{ .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
570a515d648SArtur Rojek 	{ .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, },
5711a78daeaSArtur Rojek 	{ },
5721a78daeaSArtur Rojek };
5731a78daeaSArtur Rojek MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);
5741a78daeaSArtur Rojek #endif
5751a78daeaSArtur Rojek 
5761a78daeaSArtur Rojek static struct platform_driver ingenic_adc_driver = {
5771a78daeaSArtur Rojek 	.driver = {
5781a78daeaSArtur Rojek 		.name = "ingenic-adc",
5791a78daeaSArtur Rojek 		.of_match_table = of_match_ptr(ingenic_adc_of_match),
5801a78daeaSArtur Rojek 	},
5811a78daeaSArtur Rojek 	.probe = ingenic_adc_probe,
5821a78daeaSArtur Rojek };
5831a78daeaSArtur Rojek module_platform_driver(ingenic_adc_driver);
5841a78daeaSArtur Rojek MODULE_LICENSE("GPL v2");
585