xref: /linux/drivers/iio/adc/rockchip_saradc.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
244d6f2efSHeiko Stübner /*
344d6f2efSHeiko Stübner  * Rockchip Successive Approximation Register (SAR) A/D Converter
444d6f2efSHeiko Stübner  * Copyright (C) 2014 ROCKCHIP, Inc.
544d6f2efSHeiko Stübner  */
644d6f2efSHeiko Stübner 
7757953f8SSimon Xue #include <linux/bitfield.h>
844d6f2efSHeiko Stübner #include <linux/module.h>
9bb690935SNuno Sá #include <linux/mutex.h>
1044d6f2efSHeiko Stübner #include <linux/platform_device.h>
1144d6f2efSHeiko Stübner #include <linux/interrupt.h>
1244d6f2efSHeiko Stübner #include <linux/io.h>
1344d6f2efSHeiko Stübner #include <linux/of.h>
1444d6f2efSHeiko Stübner #include <linux/clk.h>
1544d6f2efSHeiko Stübner #include <linux/completion.h>
16543852afSCaesar Wang #include <linux/delay.h>
17543852afSCaesar Wang #include <linux/reset.h>
1844d6f2efSHeiko Stübner #include <linux/regulator/consumer.h>
194e130dc7SSimon Xue #include <linux/iio/buffer.h>
2044d6f2efSHeiko Stübner #include <linux/iio/iio.h>
214e130dc7SSimon Xue #include <linux/iio/trigger_consumer.h>
224e130dc7SSimon Xue #include <linux/iio/triggered_buffer.h>
2344d6f2efSHeiko Stübner 
2444d6f2efSHeiko Stübner #define SARADC_DATA			0x00
2544d6f2efSHeiko Stübner 
2644d6f2efSHeiko Stübner #define SARADC_STAS			0x04
2744d6f2efSHeiko Stübner #define SARADC_STAS_BUSY		BIT(0)
2844d6f2efSHeiko Stübner 
2944d6f2efSHeiko Stübner #define SARADC_CTRL			0x08
3044d6f2efSHeiko Stübner #define SARADC_CTRL_IRQ_STATUS		BIT(6)
3144d6f2efSHeiko Stübner #define SARADC_CTRL_IRQ_ENABLE		BIT(5)
3244d6f2efSHeiko Stübner #define SARADC_CTRL_POWER_CTRL		BIT(3)
3344d6f2efSHeiko Stübner #define SARADC_CTRL_CHN_MASK		0x7
3444d6f2efSHeiko Stübner 
3544d6f2efSHeiko Stübner #define SARADC_DLY_PU_SOC		0x0c
3644d6f2efSHeiko Stübner #define SARADC_DLY_PU_SOC_MASK		0x3f
3744d6f2efSHeiko Stübner 
3844d6f2efSHeiko Stübner #define SARADC_TIMEOUT			msecs_to_jiffies(100)
397786da3bSSimon Xue #define SARADC_MAX_CHANNELS		8
4044d6f2efSHeiko Stübner 
41757953f8SSimon Xue /* v2 registers */
42757953f8SSimon Xue #define SARADC2_CONV_CON		0x000
43757953f8SSimon Xue #define SARADC_T_PD_SOC			0x004
44757953f8SSimon Xue #define SARADC_T_DAS_SOC		0x00c
45757953f8SSimon Xue #define SARADC2_END_INT_EN		0x104
46757953f8SSimon Xue #define SARADC2_ST_CON			0x108
47757953f8SSimon Xue #define SARADC2_STATUS			0x10c
48757953f8SSimon Xue #define SARADC2_END_INT_ST		0x110
49757953f8SSimon Xue #define SARADC2_DATA_BASE		0x120
50757953f8SSimon Xue 
51757953f8SSimon Xue #define SARADC2_EN_END_INT		BIT(0)
52757953f8SSimon Xue #define SARADC2_START			BIT(4)
53757953f8SSimon Xue #define SARADC2_SINGLE_MODE		BIT(5)
54757953f8SSimon Xue 
55b0a4546dSQuentin Schulz #define SARADC2_CONV_CHANNELS GENMASK(3, 0)
56757953f8SSimon Xue 
57fb1c13d5SSimon Xue struct rockchip_saradc;
58fb1c13d5SSimon Xue 
594c21bbb4SHeiko Stübner struct rockchip_saradc_data {
604c21bbb4SHeiko Stübner 	const struct iio_chan_spec	*channels;
614c21bbb4SHeiko Stübner 	int				num_channels;
624c21bbb4SHeiko Stübner 	unsigned long			clk_rate;
63fb1c13d5SSimon Xue 	void (*start)(struct rockchip_saradc *info, int chn);
64fb1c13d5SSimon Xue 	int (*read)(struct rockchip_saradc *info);
65fb1c13d5SSimon Xue 	void (*power_down)(struct rockchip_saradc *info);
664c21bbb4SHeiko Stübner };
674c21bbb4SHeiko Stübner 
6844d6f2efSHeiko Stübner struct rockchip_saradc {
6944d6f2efSHeiko Stübner 	void __iomem		*regs;
7044d6f2efSHeiko Stübner 	struct clk		*pclk;
7144d6f2efSHeiko Stübner 	struct clk		*clk;
7244d6f2efSHeiko Stübner 	struct completion	completion;
7344d6f2efSHeiko Stübner 	struct regulator	*vref;
74bb690935SNuno Sá 	/* lock to protect against multiple access to the device */
75bb690935SNuno Sá 	struct mutex		lock;
76cabd6e9cSDavid Wu 	int			uv_vref;
77543852afSCaesar Wang 	struct reset_control	*reset;
784c21bbb4SHeiko Stübner 	const struct rockchip_saradc_data *data;
7944d6f2efSHeiko Stübner 	u16			last_val;
804e130dc7SSimon Xue 	const struct iio_chan_spec *last_chan;
81cabd6e9cSDavid Wu 	struct notifier_block nb;
8244d6f2efSHeiko Stübner };
8344d6f2efSHeiko Stübner 
84fb1c13d5SSimon Xue static void rockchip_saradc_reset_controller(struct reset_control *reset);
85fb1c13d5SSimon Xue 
rockchip_saradc_start_v1(struct rockchip_saradc * info,int chn)86fb1c13d5SSimon Xue static void rockchip_saradc_start_v1(struct rockchip_saradc *info, int chn)
87fb1c13d5SSimon Xue {
88fb1c13d5SSimon Xue 	/* 8 clock periods as delay between power up and start cmd */
89fb1c13d5SSimon Xue 	writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC);
90fb1c13d5SSimon Xue 	/* Select the channel to be used and trigger conversion */
91fb1c13d5SSimon Xue 	writel(SARADC_CTRL_POWER_CTRL | (chn & SARADC_CTRL_CHN_MASK) |
92fb1c13d5SSimon Xue 	       SARADC_CTRL_IRQ_ENABLE, info->regs + SARADC_CTRL);
93fb1c13d5SSimon Xue }
94fb1c13d5SSimon Xue 
rockchip_saradc_start_v2(struct rockchip_saradc * info,int chn)95757953f8SSimon Xue static void rockchip_saradc_start_v2(struct rockchip_saradc *info, int chn)
96757953f8SSimon Xue {
97757953f8SSimon Xue 	int val;
98757953f8SSimon Xue 
99757953f8SSimon Xue 	if (info->reset)
100757953f8SSimon Xue 		rockchip_saradc_reset_controller(info->reset);
101757953f8SSimon Xue 
102757953f8SSimon Xue 	writel_relaxed(0xc, info->regs + SARADC_T_DAS_SOC);
103757953f8SSimon Xue 	writel_relaxed(0x20, info->regs + SARADC_T_PD_SOC);
104757953f8SSimon Xue 	val = FIELD_PREP(SARADC2_EN_END_INT, 1);
1055b4e4b72SQuentin Schulz 	val |= SARADC2_EN_END_INT << 16;
106757953f8SSimon Xue 	writel_relaxed(val, info->regs + SARADC2_END_INT_EN);
107757953f8SSimon Xue 	val = FIELD_PREP(SARADC2_START, 1) |
108757953f8SSimon Xue 	      FIELD_PREP(SARADC2_SINGLE_MODE, 1) |
109757953f8SSimon Xue 	      FIELD_PREP(SARADC2_CONV_CHANNELS, chn);
1105b4e4b72SQuentin Schulz 	val |= (SARADC2_START | SARADC2_SINGLE_MODE | SARADC2_CONV_CHANNELS) << 16;
111757953f8SSimon Xue 	writel(val, info->regs + SARADC2_CONV_CON);
112757953f8SSimon Xue }
113757953f8SSimon Xue 
rockchip_saradc_start(struct rockchip_saradc * info,int chn)114fb1c13d5SSimon Xue static void rockchip_saradc_start(struct rockchip_saradc *info, int chn)
115fb1c13d5SSimon Xue {
116fb1c13d5SSimon Xue 	info->data->start(info, chn);
117fb1c13d5SSimon Xue }
118fb1c13d5SSimon Xue 
rockchip_saradc_read_v1(struct rockchip_saradc * info)119fb1c13d5SSimon Xue static int rockchip_saradc_read_v1(struct rockchip_saradc *info)
120fb1c13d5SSimon Xue {
121fb1c13d5SSimon Xue 	return readl_relaxed(info->regs + SARADC_DATA);
122fb1c13d5SSimon Xue }
123fb1c13d5SSimon Xue 
rockchip_saradc_read_v2(struct rockchip_saradc * info)124757953f8SSimon Xue static int rockchip_saradc_read_v2(struct rockchip_saradc *info)
125757953f8SSimon Xue {
126757953f8SSimon Xue 	int offset;
127757953f8SSimon Xue 
128757953f8SSimon Xue 	/* Clear irq */
129757953f8SSimon Xue 	writel_relaxed(0x1, info->regs + SARADC2_END_INT_ST);
130757953f8SSimon Xue 
131757953f8SSimon Xue 	offset = SARADC2_DATA_BASE + info->last_chan->channel * 0x4;
132757953f8SSimon Xue 
133757953f8SSimon Xue 	return readl_relaxed(info->regs + offset);
134757953f8SSimon Xue }
135757953f8SSimon Xue 
rockchip_saradc_read(struct rockchip_saradc * info)136fb1c13d5SSimon Xue static int rockchip_saradc_read(struct rockchip_saradc *info)
137fb1c13d5SSimon Xue {
138fb1c13d5SSimon Xue 	return info->data->read(info);
139fb1c13d5SSimon Xue }
140fb1c13d5SSimon Xue 
rockchip_saradc_power_down_v1(struct rockchip_saradc * info)141fb1c13d5SSimon Xue static void rockchip_saradc_power_down_v1(struct rockchip_saradc *info)
142fb1c13d5SSimon Xue {
143fb1c13d5SSimon Xue 	writel_relaxed(0, info->regs + SARADC_CTRL);
144fb1c13d5SSimon Xue }
145fb1c13d5SSimon Xue 
rockchip_saradc_power_down(struct rockchip_saradc * info)1464e130dc7SSimon Xue static void rockchip_saradc_power_down(struct rockchip_saradc *info)
1474e130dc7SSimon Xue {
148fb1c13d5SSimon Xue 	if (info->data->power_down)
149fb1c13d5SSimon Xue 		info->data->power_down(info);
1504e130dc7SSimon Xue }
1514e130dc7SSimon Xue 
rockchip_saradc_conversion(struct rockchip_saradc * info,struct iio_chan_spec const * chan)1524e130dc7SSimon Xue static int rockchip_saradc_conversion(struct rockchip_saradc *info,
1534e130dc7SSimon Xue 				      struct iio_chan_spec const *chan)
1544e130dc7SSimon Xue {
1554e130dc7SSimon Xue 	reinit_completion(&info->completion);
1564e130dc7SSimon Xue 
1574e130dc7SSimon Xue 	info->last_chan = chan;
158fb1c13d5SSimon Xue 	rockchip_saradc_start(info, chan->channel);
1594e130dc7SSimon Xue 
1604e130dc7SSimon Xue 	if (!wait_for_completion_timeout(&info->completion, SARADC_TIMEOUT))
1614e130dc7SSimon Xue 		return -ETIMEDOUT;
1624e130dc7SSimon Xue 
1634e130dc7SSimon Xue 	return 0;
1644e130dc7SSimon Xue }
1654e130dc7SSimon Xue 
rockchip_saradc_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)16644d6f2efSHeiko Stübner static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
16744d6f2efSHeiko Stübner 				    struct iio_chan_spec const *chan,
16844d6f2efSHeiko Stübner 				    int *val, int *val2, long mask)
16944d6f2efSHeiko Stübner {
17044d6f2efSHeiko Stübner 	struct rockchip_saradc *info = iio_priv(indio_dev);
17144d6f2efSHeiko Stübner 	int ret;
17244d6f2efSHeiko Stübner 
17344d6f2efSHeiko Stübner 	switch (mask) {
17444d6f2efSHeiko Stübner 	case IIO_CHAN_INFO_RAW:
175bb690935SNuno Sá 		mutex_lock(&info->lock);
17644d6f2efSHeiko Stübner 
1774e130dc7SSimon Xue 		ret = rockchip_saradc_conversion(info, chan);
1784e130dc7SSimon Xue 		if (ret) {
1794e130dc7SSimon Xue 			rockchip_saradc_power_down(info);
180bb690935SNuno Sá 			mutex_unlock(&info->lock);
1814e130dc7SSimon Xue 			return ret;
18244d6f2efSHeiko Stübner 		}
18344d6f2efSHeiko Stübner 
18444d6f2efSHeiko Stübner 		*val = info->last_val;
185bb690935SNuno Sá 		mutex_unlock(&info->lock);
18644d6f2efSHeiko Stübner 		return IIO_VAL_INT;
18744d6f2efSHeiko Stübner 	case IIO_CHAN_INFO_SCALE:
188cabd6e9cSDavid Wu 		*val = info->uv_vref / 1000;
1894e130dc7SSimon Xue 		*val2 = chan->scan_type.realbits;
19044d6f2efSHeiko Stübner 		return IIO_VAL_FRACTIONAL_LOG2;
19144d6f2efSHeiko Stübner 	default:
19244d6f2efSHeiko Stübner 		return -EINVAL;
19344d6f2efSHeiko Stübner 	}
19444d6f2efSHeiko Stübner }
19544d6f2efSHeiko Stübner 
rockchip_saradc_isr(int irq,void * dev_id)19644d6f2efSHeiko Stübner static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
19744d6f2efSHeiko Stübner {
1980b568b3cSsimran singhal 	struct rockchip_saradc *info = dev_id;
19944d6f2efSHeiko Stübner 
20044d6f2efSHeiko Stübner 	/* Read value */
201fb1c13d5SSimon Xue 	info->last_val = rockchip_saradc_read(info);
2024e130dc7SSimon Xue 	info->last_val &= GENMASK(info->last_chan->scan_type.realbits - 1, 0);
20344d6f2efSHeiko Stübner 
2044e130dc7SSimon Xue 	rockchip_saradc_power_down(info);
20544d6f2efSHeiko Stübner 
20644d6f2efSHeiko Stübner 	complete(&info->completion);
20744d6f2efSHeiko Stübner 
20844d6f2efSHeiko Stübner 	return IRQ_HANDLED;
20944d6f2efSHeiko Stübner }
21044d6f2efSHeiko Stübner 
21144d6f2efSHeiko Stübner static const struct iio_info rockchip_saradc_iio_info = {
21244d6f2efSHeiko Stübner 	.read_raw = rockchip_saradc_read_raw,
21344d6f2efSHeiko Stübner };
21444d6f2efSHeiko Stübner 
2154e130dc7SSimon Xue #define SARADC_CHANNEL(_index, _id, _res) {			\
21644d6f2efSHeiko Stübner 	.type = IIO_VOLTAGE,					\
21744d6f2efSHeiko Stübner 	.indexed = 1,						\
21844d6f2efSHeiko Stübner 	.channel = _index,					\
21944d6f2efSHeiko Stübner 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
22044d6f2efSHeiko Stübner 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
22144d6f2efSHeiko Stübner 	.datasheet_name = _id,					\
2224e130dc7SSimon Xue 	.scan_index = _index,					\
2234e130dc7SSimon Xue 	.scan_type = {						\
2244e130dc7SSimon Xue 		.sign = 'u',					\
2254e130dc7SSimon Xue 		.realbits = _res,				\
2264e130dc7SSimon Xue 		.storagebits = 16,				\
2274e130dc7SSimon Xue 		.endianness = IIO_CPU,				\
2284e130dc7SSimon Xue 	},							\
22944d6f2efSHeiko Stübner }
23044d6f2efSHeiko Stübner 
23144d6f2efSHeiko Stübner static const struct iio_chan_spec rockchip_saradc_iio_channels[] = {
2324e130dc7SSimon Xue 	SARADC_CHANNEL(0, "adc0", 10),
2334e130dc7SSimon Xue 	SARADC_CHANNEL(1, "adc1", 10),
2344e130dc7SSimon Xue 	SARADC_CHANNEL(2, "adc2", 10),
23544d6f2efSHeiko Stübner };
23644d6f2efSHeiko Stübner 
2374c21bbb4SHeiko Stübner static const struct rockchip_saradc_data saradc_data = {
2384c21bbb4SHeiko Stübner 	.channels = rockchip_saradc_iio_channels,
2394c21bbb4SHeiko Stübner 	.num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels),
2404c21bbb4SHeiko Stübner 	.clk_rate = 1000000,
241fb1c13d5SSimon Xue 	.start = rockchip_saradc_start_v1,
242fb1c13d5SSimon Xue 	.read = rockchip_saradc_read_v1,
243fb1c13d5SSimon Xue 	.power_down = rockchip_saradc_power_down_v1,
2444c21bbb4SHeiko Stübner };
2454c21bbb4SHeiko Stübner 
2464c21bbb4SHeiko Stübner static const struct iio_chan_spec rockchip_rk3066_tsadc_iio_channels[] = {
2474e130dc7SSimon Xue 	SARADC_CHANNEL(0, "adc0", 12),
2484e130dc7SSimon Xue 	SARADC_CHANNEL(1, "adc1", 12),
2494c21bbb4SHeiko Stübner };
2504c21bbb4SHeiko Stübner 
2514c21bbb4SHeiko Stübner static const struct rockchip_saradc_data rk3066_tsadc_data = {
2524c21bbb4SHeiko Stübner 	.channels = rockchip_rk3066_tsadc_iio_channels,
2534c21bbb4SHeiko Stübner 	.num_channels = ARRAY_SIZE(rockchip_rk3066_tsadc_iio_channels),
2544c21bbb4SHeiko Stübner 	.clk_rate = 50000,
255fb1c13d5SSimon Xue 	.start = rockchip_saradc_start_v1,
256fb1c13d5SSimon Xue 	.read = rockchip_saradc_read_v1,
257fb1c13d5SSimon Xue 	.power_down = rockchip_saradc_power_down_v1,
2584c21bbb4SHeiko Stübner };
2594c21bbb4SHeiko Stübner 
260ae549a72SDavid Wu static const struct iio_chan_spec rockchip_rk3399_saradc_iio_channels[] = {
2614e130dc7SSimon Xue 	SARADC_CHANNEL(0, "adc0", 10),
2624e130dc7SSimon Xue 	SARADC_CHANNEL(1, "adc1", 10),
2634e130dc7SSimon Xue 	SARADC_CHANNEL(2, "adc2", 10),
2644e130dc7SSimon Xue 	SARADC_CHANNEL(3, "adc3", 10),
2654e130dc7SSimon Xue 	SARADC_CHANNEL(4, "adc4", 10),
2664e130dc7SSimon Xue 	SARADC_CHANNEL(5, "adc5", 10),
267ae549a72SDavid Wu };
268ae549a72SDavid Wu 
269ae549a72SDavid Wu static const struct rockchip_saradc_data rk3399_saradc_data = {
270ae549a72SDavid Wu 	.channels = rockchip_rk3399_saradc_iio_channels,
271ae549a72SDavid Wu 	.num_channels = ARRAY_SIZE(rockchip_rk3399_saradc_iio_channels),
272ae549a72SDavid Wu 	.clk_rate = 1000000,
273fb1c13d5SSimon Xue 	.start = rockchip_saradc_start_v1,
274fb1c13d5SSimon Xue 	.read = rockchip_saradc_read_v1,
275fb1c13d5SSimon Xue 	.power_down = rockchip_saradc_power_down_v1,
276ae549a72SDavid Wu };
277ae549a72SDavid Wu 
2787786da3bSSimon Xue static const struct iio_chan_spec rockchip_rk3568_saradc_iio_channels[] = {
2797786da3bSSimon Xue 	SARADC_CHANNEL(0, "adc0", 10),
2807786da3bSSimon Xue 	SARADC_CHANNEL(1, "adc1", 10),
2817786da3bSSimon Xue 	SARADC_CHANNEL(2, "adc2", 10),
2827786da3bSSimon Xue 	SARADC_CHANNEL(3, "adc3", 10),
2837786da3bSSimon Xue 	SARADC_CHANNEL(4, "adc4", 10),
2847786da3bSSimon Xue 	SARADC_CHANNEL(5, "adc5", 10),
2857786da3bSSimon Xue 	SARADC_CHANNEL(6, "adc6", 10),
2867786da3bSSimon Xue 	SARADC_CHANNEL(7, "adc7", 10),
2877786da3bSSimon Xue };
2887786da3bSSimon Xue 
2897786da3bSSimon Xue static const struct rockchip_saradc_data rk3568_saradc_data = {
2907786da3bSSimon Xue 	.channels = rockchip_rk3568_saradc_iio_channels,
2917786da3bSSimon Xue 	.num_channels = ARRAY_SIZE(rockchip_rk3568_saradc_iio_channels),
2927786da3bSSimon Xue 	.clk_rate = 1000000,
293fb1c13d5SSimon Xue 	.start = rockchip_saradc_start_v1,
294fb1c13d5SSimon Xue 	.read = rockchip_saradc_read_v1,
295fb1c13d5SSimon Xue 	.power_down = rockchip_saradc_power_down_v1,
2967786da3bSSimon Xue };
2977786da3bSSimon Xue 
298757953f8SSimon Xue static const struct iio_chan_spec rockchip_rk3588_saradc_iio_channels[] = {
299757953f8SSimon Xue 	SARADC_CHANNEL(0, "adc0", 12),
300757953f8SSimon Xue 	SARADC_CHANNEL(1, "adc1", 12),
301757953f8SSimon Xue 	SARADC_CHANNEL(2, "adc2", 12),
302757953f8SSimon Xue 	SARADC_CHANNEL(3, "adc3", 12),
303757953f8SSimon Xue 	SARADC_CHANNEL(4, "adc4", 12),
304757953f8SSimon Xue 	SARADC_CHANNEL(5, "adc5", 12),
305757953f8SSimon Xue 	SARADC_CHANNEL(6, "adc6", 12),
306757953f8SSimon Xue 	SARADC_CHANNEL(7, "adc7", 12),
307757953f8SSimon Xue };
308757953f8SSimon Xue 
309757953f8SSimon Xue static const struct rockchip_saradc_data rk3588_saradc_data = {
310757953f8SSimon Xue 	.channels = rockchip_rk3588_saradc_iio_channels,
311757953f8SSimon Xue 	.num_channels = ARRAY_SIZE(rockchip_rk3588_saradc_iio_channels),
312757953f8SSimon Xue 	.clk_rate = 1000000,
313757953f8SSimon Xue 	.start = rockchip_saradc_start_v2,
314757953f8SSimon Xue 	.read = rockchip_saradc_read_v2,
315757953f8SSimon Xue };
316757953f8SSimon Xue 
3174c21bbb4SHeiko Stübner static const struct of_device_id rockchip_saradc_match[] = {
3184c21bbb4SHeiko Stübner 	{
3194c21bbb4SHeiko Stübner 		.compatible = "rockchip,saradc",
3204c21bbb4SHeiko Stübner 		.data = &saradc_data,
3214c21bbb4SHeiko Stübner 	}, {
3224c21bbb4SHeiko Stübner 		.compatible = "rockchip,rk3066-tsadc",
3234c21bbb4SHeiko Stübner 		.data = &rk3066_tsadc_data,
324ae549a72SDavid Wu 	}, {
325ae549a72SDavid Wu 		.compatible = "rockchip,rk3399-saradc",
326ae549a72SDavid Wu 		.data = &rk3399_saradc_data,
3277786da3bSSimon Xue 	}, {
3287786da3bSSimon Xue 		.compatible = "rockchip,rk3568-saradc",
3297786da3bSSimon Xue 		.data = &rk3568_saradc_data,
330757953f8SSimon Xue 	}, {
331757953f8SSimon Xue 		.compatible = "rockchip,rk3588-saradc",
332757953f8SSimon Xue 		.data = &rk3588_saradc_data,
3334c21bbb4SHeiko Stübner 	},
334*09e3bdfeSJonathan Cameron 	{ }
3354c21bbb4SHeiko Stübner };
3364c21bbb4SHeiko Stübner MODULE_DEVICE_TABLE(of, rockchip_saradc_match);
3374c21bbb4SHeiko Stübner 
3382c7c8dceSLee Jones /*
339543852afSCaesar Wang  * Reset SARADC Controller.
340543852afSCaesar Wang  */
rockchip_saradc_reset_controller(struct reset_control * reset)341543852afSCaesar Wang static void rockchip_saradc_reset_controller(struct reset_control *reset)
342543852afSCaesar Wang {
343543852afSCaesar Wang 	reset_control_assert(reset);
344543852afSCaesar Wang 	usleep_range(10, 20);
345543852afSCaesar Wang 	reset_control_deassert(reset);
346543852afSCaesar Wang }
347543852afSCaesar Wang 
rockchip_saradc_regulator_disable(void * data)348d0389d4eSHeiko Stuebner static void rockchip_saradc_regulator_disable(void *data)
349d0389d4eSHeiko Stuebner {
350d0389d4eSHeiko Stuebner 	struct rockchip_saradc *info = data;
351d0389d4eSHeiko Stuebner 
352d0389d4eSHeiko Stuebner 	regulator_disable(info->vref);
353d0389d4eSHeiko Stuebner }
354d0389d4eSHeiko Stuebner 
rockchip_saradc_trigger_handler(int irq,void * p)3554e130dc7SSimon Xue static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
3564e130dc7SSimon Xue {
3574e130dc7SSimon Xue 	struct iio_poll_func *pf = p;
3584e130dc7SSimon Xue 	struct iio_dev *i_dev = pf->indio_dev;
3594e130dc7SSimon Xue 	struct rockchip_saradc *info = iio_priv(i_dev);
3604e130dc7SSimon Xue 	/*
3614e130dc7SSimon Xue 	 * @values: each channel takes an u16 value
3624e130dc7SSimon Xue 	 * @timestamp: will be 8-byte aligned automatically
3634e130dc7SSimon Xue 	 */
3644e130dc7SSimon Xue 	struct {
3654e130dc7SSimon Xue 		u16 values[SARADC_MAX_CHANNELS];
3664e130dc7SSimon Xue 		int64_t timestamp;
3674e130dc7SSimon Xue 	} data;
3684e130dc7SSimon Xue 	int ret;
3694e130dc7SSimon Xue 	int i, j = 0;
3704e130dc7SSimon Xue 
371bb690935SNuno Sá 	mutex_lock(&info->lock);
3724e130dc7SSimon Xue 
37310616c3cSNuno Sa 	iio_for_each_active_channel(i_dev, i) {
3744e130dc7SSimon Xue 		const struct iio_chan_spec *chan = &i_dev->channels[i];
3754e130dc7SSimon Xue 
3764e130dc7SSimon Xue 		ret = rockchip_saradc_conversion(info, chan);
3774e130dc7SSimon Xue 		if (ret) {
3784e130dc7SSimon Xue 			rockchip_saradc_power_down(info);
3794e130dc7SSimon Xue 			goto out;
3804e130dc7SSimon Xue 		}
3814e130dc7SSimon Xue 
3824e130dc7SSimon Xue 		data.values[j] = info->last_val;
3834e130dc7SSimon Xue 		j++;
3844e130dc7SSimon Xue 	}
3854e130dc7SSimon Xue 
3864e130dc7SSimon Xue 	iio_push_to_buffers_with_timestamp(i_dev, &data, iio_get_time_ns(i_dev));
3874e130dc7SSimon Xue out:
388bb690935SNuno Sá 	mutex_unlock(&info->lock);
3894e130dc7SSimon Xue 
3904e130dc7SSimon Xue 	iio_trigger_notify_done(i_dev->trig);
3914e130dc7SSimon Xue 
3924e130dc7SSimon Xue 	return IRQ_HANDLED;
3934e130dc7SSimon Xue }
3944e130dc7SSimon Xue 
rockchip_saradc_volt_notify(struct notifier_block * nb,unsigned long event,void * data)395cabd6e9cSDavid Wu static int rockchip_saradc_volt_notify(struct notifier_block *nb,
39610bec68fSShreeya Patel 				       unsigned long event, void *data)
397cabd6e9cSDavid Wu {
398cabd6e9cSDavid Wu 	struct rockchip_saradc *info =
399cabd6e9cSDavid Wu 			container_of(nb, struct rockchip_saradc, nb);
400cabd6e9cSDavid Wu 
401cabd6e9cSDavid Wu 	if (event & REGULATOR_EVENT_VOLTAGE_CHANGE)
402cabd6e9cSDavid Wu 		info->uv_vref = (unsigned long)data;
403cabd6e9cSDavid Wu 
404cabd6e9cSDavid Wu 	return NOTIFY_OK;
405cabd6e9cSDavid Wu }
406cabd6e9cSDavid Wu 
rockchip_saradc_regulator_unreg_notifier(void * data)407cabd6e9cSDavid Wu static void rockchip_saradc_regulator_unreg_notifier(void *data)
408cabd6e9cSDavid Wu {
409cabd6e9cSDavid Wu 	struct rockchip_saradc *info = data;
410cabd6e9cSDavid Wu 
411cabd6e9cSDavid Wu 	regulator_unregister_notifier(info->vref, &info->nb);
412cabd6e9cSDavid Wu }
413cabd6e9cSDavid Wu 
rockchip_saradc_probe(struct platform_device * pdev)41444d6f2efSHeiko Stübner static int rockchip_saradc_probe(struct platform_device *pdev)
41544d6f2efSHeiko Stübner {
41647902344SShreeya Patel 	const struct rockchip_saradc_data *match_data;
41744d6f2efSHeiko Stübner 	struct rockchip_saradc *info = NULL;
41844d6f2efSHeiko Stübner 	struct device_node *np = pdev->dev.of_node;
41944d6f2efSHeiko Stübner 	struct iio_dev *indio_dev = NULL;
42044d6f2efSHeiko Stübner 	int ret;
42144d6f2efSHeiko Stübner 	int irq;
42244d6f2efSHeiko Stübner 
42344d6f2efSHeiko Stübner 	if (!np)
42444d6f2efSHeiko Stübner 		return -ENODEV;
42544d6f2efSHeiko Stübner 
42644d6f2efSHeiko Stübner 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
4275e63d7a2SShreeya Patel 	if (!indio_dev)
4285e63d7a2SShreeya Patel 		return dev_err_probe(&pdev->dev, -ENOMEM,
4295e63d7a2SShreeya Patel 				     "failed allocating iio device\n");
4305e63d7a2SShreeya Patel 
43144d6f2efSHeiko Stübner 	info = iio_priv(indio_dev);
43244d6f2efSHeiko Stübner 
43347902344SShreeya Patel 	match_data = of_device_get_match_data(&pdev->dev);
4345e63d7a2SShreeya Patel 	if (!match_data)
4355e63d7a2SShreeya Patel 		return dev_err_probe(&pdev->dev, -ENODEV,
4365e63d7a2SShreeya Patel 				     "failed to match device\n");
43736d311bcSGustavo A. R. Silva 
43847902344SShreeya Patel 	info->data = match_data;
4394c21bbb4SHeiko Stübner 
4404e130dc7SSimon Xue 	/* Sanity check for possible later IP variants with more channels */
4415e63d7a2SShreeya Patel 	if (info->data->num_channels > SARADC_MAX_CHANNELS)
4425e63d7a2SShreeya Patel 		return dev_err_probe(&pdev->dev, -EINVAL,
4435e63d7a2SShreeya Patel 				     "max channels exceeded");
4444e130dc7SSimon Xue 
445948b3b3dSCai Huoqing 	info->regs = devm_platform_ioremap_resource(pdev, 0);
44644d6f2efSHeiko Stübner 	if (IS_ERR(info->regs))
44744d6f2efSHeiko Stübner 		return PTR_ERR(info->regs);
44844d6f2efSHeiko Stübner 
449543852afSCaesar Wang 	/*
450543852afSCaesar Wang 	 * The reset should be an optional property, as it should work
451543852afSCaesar Wang 	 * with old devicetrees as well
452543852afSCaesar Wang 	 */
4539443c19cSQuentin Schulz 	info->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
45487587016SPhilipp Zabel 								"saradc-apb");
455543852afSCaesar Wang 	if (IS_ERR(info->reset)) {
456543852afSCaesar Wang 		ret = PTR_ERR(info->reset);
4579443c19cSQuentin Schulz 		return dev_err_probe(&pdev->dev, ret, "failed to get saradc-apb\n");
458543852afSCaesar Wang 	}
459543852afSCaesar Wang 
46044d6f2efSHeiko Stübner 	init_completion(&info->completion);
46144d6f2efSHeiko Stübner 
46244d6f2efSHeiko Stübner 	irq = platform_get_irq(pdev, 0);
4637c279229SStephen Boyd 	if (irq < 0)
464089c1e11SRuan Jinjie 		return irq;
46544d6f2efSHeiko Stübner 
46644d6f2efSHeiko Stübner 	ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr,
46744d6f2efSHeiko Stübner 			       0, dev_name(&pdev->dev), info);
46844d6f2efSHeiko Stübner 	if (ret < 0) {
46944d6f2efSHeiko Stübner 		dev_err(&pdev->dev, "failed requesting irq %d\n", irq);
47044d6f2efSHeiko Stübner 		return ret;
47144d6f2efSHeiko Stübner 	}
47244d6f2efSHeiko Stübner 
47344d6f2efSHeiko Stübner 	info->vref = devm_regulator_get(&pdev->dev, "vref");
4748f46a93bSCai Huoqing 	if (IS_ERR(info->vref))
4758f46a93bSCai Huoqing 		return dev_err_probe(&pdev->dev, PTR_ERR(info->vref),
4768f46a93bSCai Huoqing 				     "failed to get regulator\n");
47744d6f2efSHeiko Stübner 
478543852afSCaesar Wang 	if (info->reset)
479543852afSCaesar Wang 		rockchip_saradc_reset_controller(info->reset);
480543852afSCaesar Wang 
48144d6f2efSHeiko Stübner 	/*
4824c21bbb4SHeiko Stübner 	 * Use a default value for the converter clock.
48344d6f2efSHeiko Stübner 	 * This may become user-configurable in the future.
48444d6f2efSHeiko Stübner 	 */
4854c21bbb4SHeiko Stübner 	ret = clk_set_rate(info->clk, info->data->clk_rate);
4865e63d7a2SShreeya Patel 	if (ret < 0)
4875e63d7a2SShreeya Patel 		return dev_err_probe(&pdev->dev, ret,
4885e63d7a2SShreeya Patel 				     "failed to set adc clk rate\n");
48944d6f2efSHeiko Stübner 
49044d6f2efSHeiko Stübner 	ret = regulator_enable(info->vref);
4915e63d7a2SShreeya Patel 	if (ret < 0)
4925e63d7a2SShreeya Patel 		return dev_err_probe(&pdev->dev, ret,
4935e63d7a2SShreeya Patel 				     "failed to enable vref regulator\n");
4945e63d7a2SShreeya Patel 
495d0389d4eSHeiko Stuebner 	ret = devm_add_action_or_reset(&pdev->dev,
496d0389d4eSHeiko Stuebner 				       rockchip_saradc_regulator_disable, info);
4975e63d7a2SShreeya Patel 	if (ret)
4985e63d7a2SShreeya Patel 		return dev_err_probe(&pdev->dev, ret,
4995e63d7a2SShreeya Patel 				     "failed to register devm action\n");
50044d6f2efSHeiko Stübner 
501cabd6e9cSDavid Wu 	ret = regulator_get_voltage(info->vref);
502cabd6e9cSDavid Wu 	if (ret < 0)
503cabd6e9cSDavid Wu 		return ret;
504cabd6e9cSDavid Wu 
505cabd6e9cSDavid Wu 	info->uv_vref = ret;
506cabd6e9cSDavid Wu 
50797ad10bbSShreeya Patel 	info->pclk = devm_clk_get_enabled(&pdev->dev, "apb_pclk");
50897ad10bbSShreeya Patel 	if (IS_ERR(info->pclk))
50997ad10bbSShreeya Patel 		return dev_err_probe(&pdev->dev, PTR_ERR(info->pclk),
51097ad10bbSShreeya Patel 				     "failed to get pclk\n");
51144d6f2efSHeiko Stübner 
51297ad10bbSShreeya Patel 	info->clk = devm_clk_get_enabled(&pdev->dev, "saradc");
51397ad10bbSShreeya Patel 	if (IS_ERR(info->clk))
51497ad10bbSShreeya Patel 		return dev_err_probe(&pdev->dev, PTR_ERR(info->clk),
51597ad10bbSShreeya Patel 				     "failed to get adc clock\n");
51644d6f2efSHeiko Stübner 
51744d6f2efSHeiko Stübner 	platform_set_drvdata(pdev, indio_dev);
51844d6f2efSHeiko Stübner 
51944d6f2efSHeiko Stübner 	indio_dev->name = dev_name(&pdev->dev);
52044d6f2efSHeiko Stübner 	indio_dev->info = &rockchip_saradc_iio_info;
52144d6f2efSHeiko Stübner 	indio_dev->modes = INDIO_DIRECT_MODE;
52244d6f2efSHeiko Stübner 
5234c21bbb4SHeiko Stübner 	indio_dev->channels = info->data->channels;
5244c21bbb4SHeiko Stübner 	indio_dev->num_channels = info->data->num_channels;
5254e130dc7SSimon Xue 	ret = devm_iio_triggered_buffer_setup(&indio_dev->dev, indio_dev, NULL,
5264e130dc7SSimon Xue 					      rockchip_saradc_trigger_handler,
5274e130dc7SSimon Xue 					      NULL);
5284e130dc7SSimon Xue 	if (ret)
5294e130dc7SSimon Xue 		return ret;
53044d6f2efSHeiko Stübner 
531cabd6e9cSDavid Wu 	info->nb.notifier_call = rockchip_saradc_volt_notify;
532cabd6e9cSDavid Wu 	ret = regulator_register_notifier(info->vref, &info->nb);
533cabd6e9cSDavid Wu 	if (ret)
534cabd6e9cSDavid Wu 		return ret;
535cabd6e9cSDavid Wu 
536cabd6e9cSDavid Wu 	ret = devm_add_action_or_reset(&pdev->dev,
537cabd6e9cSDavid Wu 				       rockchip_saradc_regulator_unreg_notifier,
538cabd6e9cSDavid Wu 				       info);
539cabd6e9cSDavid Wu 	if (ret)
540cabd6e9cSDavid Wu 		return ret;
541cabd6e9cSDavid Wu 
542bb690935SNuno Sá 	mutex_init(&info->lock);
543bb690935SNuno Sá 
544d0389d4eSHeiko Stuebner 	return devm_iio_device_register(&pdev->dev, indio_dev);
54544d6f2efSHeiko Stübner }
54644d6f2efSHeiko Stübner 
rockchip_saradc_suspend(struct device * dev)54744d6f2efSHeiko Stübner static int rockchip_saradc_suspend(struct device *dev)
54844d6f2efSHeiko Stübner {
54944d6f2efSHeiko Stübner 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
55044d6f2efSHeiko Stübner 	struct rockchip_saradc *info = iio_priv(indio_dev);
55144d6f2efSHeiko Stübner 
55244d6f2efSHeiko Stübner 	clk_disable_unprepare(info->clk);
55344d6f2efSHeiko Stübner 	clk_disable_unprepare(info->pclk);
55444d6f2efSHeiko Stübner 	regulator_disable(info->vref);
55544d6f2efSHeiko Stübner 
55644d6f2efSHeiko Stübner 	return 0;
55744d6f2efSHeiko Stübner }
55844d6f2efSHeiko Stübner 
rockchip_saradc_resume(struct device * dev)55944d6f2efSHeiko Stübner static int rockchip_saradc_resume(struct device *dev)
56044d6f2efSHeiko Stübner {
56144d6f2efSHeiko Stübner 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
56244d6f2efSHeiko Stübner 	struct rockchip_saradc *info = iio_priv(indio_dev);
56344d6f2efSHeiko Stübner 	int ret;
56444d6f2efSHeiko Stübner 
56544d6f2efSHeiko Stübner 	ret = regulator_enable(info->vref);
56644d6f2efSHeiko Stübner 	if (ret)
56744d6f2efSHeiko Stübner 		return ret;
56844d6f2efSHeiko Stübner 
56944d6f2efSHeiko Stübner 	ret = clk_prepare_enable(info->pclk);
57044d6f2efSHeiko Stübner 	if (ret)
57144d6f2efSHeiko Stübner 		return ret;
57244d6f2efSHeiko Stübner 
57344d6f2efSHeiko Stübner 	ret = clk_prepare_enable(info->clk);
57444d6f2efSHeiko Stübner 	if (ret)
575560c6b91SQinglang Miao 		clk_disable_unprepare(info->pclk);
57644d6f2efSHeiko Stübner 
57744d6f2efSHeiko Stübner 	return ret;
57844d6f2efSHeiko Stübner }
57944d6f2efSHeiko Stübner 
580cc0595a9SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops,
581cc0595a9SJonathan Cameron 				rockchip_saradc_suspend,
582cc0595a9SJonathan Cameron 				rockchip_saradc_resume);
58344d6f2efSHeiko Stübner 
58444d6f2efSHeiko Stübner static struct platform_driver rockchip_saradc_driver = {
58544d6f2efSHeiko Stübner 	.probe		= rockchip_saradc_probe,
58644d6f2efSHeiko Stübner 	.driver		= {
58744d6f2efSHeiko Stübner 		.name	= "rockchip-saradc",
58844d6f2efSHeiko Stübner 		.of_match_table = rockchip_saradc_match,
589cc0595a9SJonathan Cameron 		.pm	= pm_sleep_ptr(&rockchip_saradc_pm_ops),
59044d6f2efSHeiko Stübner 	},
59144d6f2efSHeiko Stübner };
59244d6f2efSHeiko Stübner 
59344d6f2efSHeiko Stübner module_platform_driver(rockchip_saradc_driver);
594dc7b8d98SHeiko Stuebner 
595dc7b8d98SHeiko Stuebner MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
596dc7b8d98SHeiko Stuebner MODULE_DESCRIPTION("Rockchip SARADC driver");
597dc7b8d98SHeiko Stuebner MODULE_LICENSE("GPL v2");
598