xref: /openbmc/linux/drivers/iio/adc/mt6577_auxadc.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ace4cdfeSZhiyong Tao /*
3ace4cdfeSZhiyong Tao  * Copyright (c) 2016 MediaTek Inc.
4ace4cdfeSZhiyong Tao  * Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
5ace4cdfeSZhiyong Tao  */
6ace4cdfeSZhiyong Tao 
7ace4cdfeSZhiyong Tao #include <linux/clk.h>
8ace4cdfeSZhiyong Tao #include <linux/delay.h>
9ace4cdfeSZhiyong Tao #include <linux/err.h>
10ace4cdfeSZhiyong Tao #include <linux/kernel.h>
11ace4cdfeSZhiyong Tao #include <linux/module.h>
1215207a92SFabien Parent #include <linux/mod_devicetable.h>
13ace4cdfeSZhiyong Tao #include <linux/platform_device.h>
1415207a92SFabien Parent #include <linux/property.h>
15ace4cdfeSZhiyong Tao #include <linux/iopoll.h>
16ace4cdfeSZhiyong Tao #include <linux/io.h>
17ace4cdfeSZhiyong Tao #include <linux/iio/iio.h>
18ace4cdfeSZhiyong Tao 
19ace4cdfeSZhiyong Tao /* Register definitions */
20ace4cdfeSZhiyong Tao #define MT6577_AUXADC_CON0                    0x00
21ace4cdfeSZhiyong Tao #define MT6577_AUXADC_CON1                    0x04
22ace4cdfeSZhiyong Tao #define MT6577_AUXADC_CON2                    0x10
23ace4cdfeSZhiyong Tao #define MT6577_AUXADC_STA                     BIT(0)
24ace4cdfeSZhiyong Tao 
25ace4cdfeSZhiyong Tao #define MT6577_AUXADC_DAT0                    0x14
26ace4cdfeSZhiyong Tao #define MT6577_AUXADC_RDY0                    BIT(12)
27ace4cdfeSZhiyong Tao 
28ace4cdfeSZhiyong Tao #define MT6577_AUXADC_MISC                    0x94
29ace4cdfeSZhiyong Tao #define MT6577_AUXADC_PDN_EN                  BIT(14)
30ace4cdfeSZhiyong Tao 
31ace4cdfeSZhiyong Tao #define MT6577_AUXADC_DAT_MASK                0xfff
32ace4cdfeSZhiyong Tao #define MT6577_AUXADC_SLEEP_US                1000
33ace4cdfeSZhiyong Tao #define MT6577_AUXADC_TIMEOUT_US              10000
34ace4cdfeSZhiyong Tao #define MT6577_AUXADC_POWER_READY_MS          1
35ace4cdfeSZhiyong Tao #define MT6577_AUXADC_SAMPLE_READY_US         25
36ace4cdfeSZhiyong Tao 
376d97024dSChun-Hung Wu struct mtk_auxadc_compatible {
386d97024dSChun-Hung Wu 	bool sample_data_cali;
396d97024dSChun-Hung Wu 	bool check_global_idle;
406d97024dSChun-Hung Wu };
416d97024dSChun-Hung Wu 
42ace4cdfeSZhiyong Tao struct mt6577_auxadc_device {
43ace4cdfeSZhiyong Tao 	void __iomem *reg_base;
44ace4cdfeSZhiyong Tao 	struct clk *adc_clk;
45ace4cdfeSZhiyong Tao 	struct mutex lock;
466d97024dSChun-Hung Wu 	const struct mtk_auxadc_compatible *dev_comp;
476d97024dSChun-Hung Wu };
486d97024dSChun-Hung Wu 
49ff04eb47SGuodong Liu static const struct mtk_auxadc_compatible mt8186_compat = {
50ff04eb47SGuodong Liu 	.sample_data_cali = false,
51ff04eb47SGuodong Liu 	.check_global_idle = false,
52ff04eb47SGuodong Liu };
53ff04eb47SGuodong Liu 
546d97024dSChun-Hung Wu static const struct mtk_auxadc_compatible mt8173_compat = {
556d97024dSChun-Hung Wu 	.sample_data_cali = false,
566d97024dSChun-Hung Wu 	.check_global_idle = true,
576d97024dSChun-Hung Wu };
586d97024dSChun-Hung Wu 
596d97024dSChun-Hung Wu static const struct mtk_auxadc_compatible mt6765_compat = {
606d97024dSChun-Hung Wu 	.sample_data_cali = true,
616d97024dSChun-Hung Wu 	.check_global_idle = false,
62ace4cdfeSZhiyong Tao };
63ace4cdfeSZhiyong Tao 
64ace4cdfeSZhiyong Tao #define MT6577_AUXADC_CHANNEL(idx) {				    \
65ace4cdfeSZhiyong Tao 		.type = IIO_VOLTAGE,				    \
66ace4cdfeSZhiyong Tao 		.indexed = 1,					    \
67ace4cdfeSZhiyong Tao 		.channel = (idx),				    \
68ace4cdfeSZhiyong Tao 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
69ace4cdfeSZhiyong Tao }
70ace4cdfeSZhiyong Tao 
71ace4cdfeSZhiyong Tao static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
72ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(0),
73ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(1),
74ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(2),
75ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(3),
76ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(4),
77ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(5),
78ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(6),
79ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(7),
80ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(8),
81ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(9),
82ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(10),
83ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(11),
84ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(12),
85ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(13),
86ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(14),
87ace4cdfeSZhiyong Tao 	MT6577_AUXADC_CHANNEL(15),
88ace4cdfeSZhiyong Tao };
89ace4cdfeSZhiyong Tao 
90c2980c64SHui Liu /* For Voltage calculation */
91c2980c64SHui Liu #define VOLTAGE_FULL_RANGE  1500	/* VA voltage */
92c2980c64SHui Liu #define AUXADC_PRECISE      4096	/* 12 bits */
93c2980c64SHui Liu 
mt_auxadc_get_cali_data(int rawdata,bool enable_cali)946d97024dSChun-Hung Wu static int mt_auxadc_get_cali_data(int rawdata, bool enable_cali)
956d97024dSChun-Hung Wu {
966d97024dSChun-Hung Wu 	return rawdata;
976d97024dSChun-Hung Wu }
986d97024dSChun-Hung Wu 
mt6577_auxadc_mod_reg(void __iomem * reg,u32 or_mask,u32 and_mask)99ace4cdfeSZhiyong Tao static inline void mt6577_auxadc_mod_reg(void __iomem *reg,
100ace4cdfeSZhiyong Tao 					 u32 or_mask, u32 and_mask)
101ace4cdfeSZhiyong Tao {
102ace4cdfeSZhiyong Tao 	u32 val;
103ace4cdfeSZhiyong Tao 
104ace4cdfeSZhiyong Tao 	val = readl(reg);
105ace4cdfeSZhiyong Tao 	val |= or_mask;
106ace4cdfeSZhiyong Tao 	val &= ~and_mask;
107ace4cdfeSZhiyong Tao 	writel(val, reg);
108ace4cdfeSZhiyong Tao }
109ace4cdfeSZhiyong Tao 
mt6577_auxadc_read(struct iio_dev * indio_dev,struct iio_chan_spec const * chan)110ace4cdfeSZhiyong Tao static int mt6577_auxadc_read(struct iio_dev *indio_dev,
111ace4cdfeSZhiyong Tao 			      struct iio_chan_spec const *chan)
112ace4cdfeSZhiyong Tao {
113ace4cdfeSZhiyong Tao 	u32 val;
114ace4cdfeSZhiyong Tao 	void __iomem *reg_channel;
115ace4cdfeSZhiyong Tao 	int ret;
116ace4cdfeSZhiyong Tao 	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
117ace4cdfeSZhiyong Tao 
118ace4cdfeSZhiyong Tao 	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
119ace4cdfeSZhiyong Tao 		      chan->channel * 0x04;
120ace4cdfeSZhiyong Tao 
121ace4cdfeSZhiyong Tao 	mutex_lock(&adc_dev->lock);
122ace4cdfeSZhiyong Tao 
123ace4cdfeSZhiyong Tao 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
124ace4cdfeSZhiyong Tao 			      0, 1 << chan->channel);
125ace4cdfeSZhiyong Tao 
126ace4cdfeSZhiyong Tao 	/* read channel and make sure old ready bit == 0 */
127ace4cdfeSZhiyong Tao 	ret = readl_poll_timeout(reg_channel, val,
128ace4cdfeSZhiyong Tao 				 ((val & MT6577_AUXADC_RDY0) == 0),
129ace4cdfeSZhiyong Tao 				 MT6577_AUXADC_SLEEP_US,
130ace4cdfeSZhiyong Tao 				 MT6577_AUXADC_TIMEOUT_US);
131ace4cdfeSZhiyong Tao 	if (ret < 0) {
132ace4cdfeSZhiyong Tao 		dev_err(indio_dev->dev.parent,
133ace4cdfeSZhiyong Tao 			"wait for channel[%d] ready bit clear time out\n",
134ace4cdfeSZhiyong Tao 			chan->channel);
135ace4cdfeSZhiyong Tao 		goto err_timeout;
136ace4cdfeSZhiyong Tao 	}
137ace4cdfeSZhiyong Tao 
138ace4cdfeSZhiyong Tao 	/* set bit to trigger sample */
139ace4cdfeSZhiyong Tao 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
140ace4cdfeSZhiyong Tao 			      1 << chan->channel, 0);
141ace4cdfeSZhiyong Tao 
142ace4cdfeSZhiyong Tao 	/* we must delay here for hardware sample channel data */
143ace4cdfeSZhiyong Tao 	udelay(MT6577_AUXADC_SAMPLE_READY_US);
144ace4cdfeSZhiyong Tao 
1456d97024dSChun-Hung Wu 	if (adc_dev->dev_comp->check_global_idle) {
146ace4cdfeSZhiyong Tao 		/* check MTK_AUXADC_CON2 if auxadc is idle */
1476d97024dSChun-Hung Wu 		ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2,
1486d97024dSChun-Hung Wu 					 val, ((val & MT6577_AUXADC_STA) == 0),
149ace4cdfeSZhiyong Tao 					 MT6577_AUXADC_SLEEP_US,
150ace4cdfeSZhiyong Tao 					 MT6577_AUXADC_TIMEOUT_US);
151ace4cdfeSZhiyong Tao 		if (ret < 0) {
152ace4cdfeSZhiyong Tao 			dev_err(indio_dev->dev.parent,
153ace4cdfeSZhiyong Tao 				"wait for auxadc idle time out\n");
154ace4cdfeSZhiyong Tao 			goto err_timeout;
155ace4cdfeSZhiyong Tao 		}
1566d97024dSChun-Hung Wu 	}
157ace4cdfeSZhiyong Tao 
158ace4cdfeSZhiyong Tao 	/* read channel and make sure ready bit == 1 */
159ace4cdfeSZhiyong Tao 	ret = readl_poll_timeout(reg_channel, val,
160ace4cdfeSZhiyong Tao 				 ((val & MT6577_AUXADC_RDY0) != 0),
161ace4cdfeSZhiyong Tao 				 MT6577_AUXADC_SLEEP_US,
162ace4cdfeSZhiyong Tao 				 MT6577_AUXADC_TIMEOUT_US);
163ace4cdfeSZhiyong Tao 	if (ret < 0) {
164ace4cdfeSZhiyong Tao 		dev_err(indio_dev->dev.parent,
165ace4cdfeSZhiyong Tao 			"wait for channel[%d] data ready time out\n",
166ace4cdfeSZhiyong Tao 			chan->channel);
167ace4cdfeSZhiyong Tao 		goto err_timeout;
168ace4cdfeSZhiyong Tao 	}
169ace4cdfeSZhiyong Tao 
170ace4cdfeSZhiyong Tao 	/* read data */
171ace4cdfeSZhiyong Tao 	val = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
172ace4cdfeSZhiyong Tao 
173ace4cdfeSZhiyong Tao 	mutex_unlock(&adc_dev->lock);
174ace4cdfeSZhiyong Tao 
175ace4cdfeSZhiyong Tao 	return val;
176ace4cdfeSZhiyong Tao 
177ace4cdfeSZhiyong Tao err_timeout:
178ace4cdfeSZhiyong Tao 
179ace4cdfeSZhiyong Tao 	mutex_unlock(&adc_dev->lock);
180ace4cdfeSZhiyong Tao 
181ace4cdfeSZhiyong Tao 	return -ETIMEDOUT;
182ace4cdfeSZhiyong Tao }
183ace4cdfeSZhiyong Tao 
mt6577_auxadc_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long info)184ace4cdfeSZhiyong Tao static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
185ace4cdfeSZhiyong Tao 				  struct iio_chan_spec const *chan,
186ace4cdfeSZhiyong Tao 				  int *val,
187ace4cdfeSZhiyong Tao 				  int *val2,
188ace4cdfeSZhiyong Tao 				  long info)
189ace4cdfeSZhiyong Tao {
1906d97024dSChun-Hung Wu 	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
1916d97024dSChun-Hung Wu 
192ace4cdfeSZhiyong Tao 	switch (info) {
193ace4cdfeSZhiyong Tao 	case IIO_CHAN_INFO_PROCESSED:
194ace4cdfeSZhiyong Tao 		*val = mt6577_auxadc_read(indio_dev, chan);
195ace4cdfeSZhiyong Tao 		if (*val < 0) {
196ace4cdfeSZhiyong Tao 			dev_err(indio_dev->dev.parent,
197ace4cdfeSZhiyong Tao 				"failed to sample data on channel[%d]\n",
198ace4cdfeSZhiyong Tao 				chan->channel);
199ace4cdfeSZhiyong Tao 			return *val;
200ace4cdfeSZhiyong Tao 		}
2016d97024dSChun-Hung Wu 		if (adc_dev->dev_comp->sample_data_cali)
2026d97024dSChun-Hung Wu 			*val = mt_auxadc_get_cali_data(*val, true);
203c2980c64SHui Liu 
204c2980c64SHui Liu 		/* Convert adc raw data to voltage: 0 - 1500 mV */
205c2980c64SHui Liu 		*val = *val * VOLTAGE_FULL_RANGE / AUXADC_PRECISE;
206c2980c64SHui Liu 
207ace4cdfeSZhiyong Tao 		return IIO_VAL_INT;
208ace4cdfeSZhiyong Tao 
209ace4cdfeSZhiyong Tao 	default:
210ace4cdfeSZhiyong Tao 		return -EINVAL;
211ace4cdfeSZhiyong Tao 	}
212ace4cdfeSZhiyong Tao }
213ace4cdfeSZhiyong Tao 
214ace4cdfeSZhiyong Tao static const struct iio_info mt6577_auxadc_info = {
215ace4cdfeSZhiyong Tao 	.read_raw = &mt6577_auxadc_read_raw,
216ace4cdfeSZhiyong Tao };
217ace4cdfeSZhiyong Tao 
mt6577_auxadc_resume(struct device * dev)218*7ff1d28cSJonathan Cameron static int mt6577_auxadc_resume(struct device *dev)
2195236bbc6SZhiyong Tao {
2205236bbc6SZhiyong Tao 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
2215236bbc6SZhiyong Tao 	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
2225236bbc6SZhiyong Tao 	int ret;
2235236bbc6SZhiyong Tao 
2245236bbc6SZhiyong Tao 	ret = clk_prepare_enable(adc_dev->adc_clk);
2255236bbc6SZhiyong Tao 	if (ret) {
2265236bbc6SZhiyong Tao 		pr_err("failed to enable auxadc clock\n");
2275236bbc6SZhiyong Tao 		return ret;
2285236bbc6SZhiyong Tao 	}
2295236bbc6SZhiyong Tao 
2305236bbc6SZhiyong Tao 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
2315236bbc6SZhiyong Tao 			      MT6577_AUXADC_PDN_EN, 0);
2325236bbc6SZhiyong Tao 	mdelay(MT6577_AUXADC_POWER_READY_MS);
2335236bbc6SZhiyong Tao 
2345236bbc6SZhiyong Tao 	return 0;
2355236bbc6SZhiyong Tao }
2365236bbc6SZhiyong Tao 
mt6577_auxadc_suspend(struct device * dev)237*7ff1d28cSJonathan Cameron static int mt6577_auxadc_suspend(struct device *dev)
2385236bbc6SZhiyong Tao {
2395236bbc6SZhiyong Tao 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
2405236bbc6SZhiyong Tao 	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
2415236bbc6SZhiyong Tao 
2425236bbc6SZhiyong Tao 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
2435236bbc6SZhiyong Tao 			      0, MT6577_AUXADC_PDN_EN);
2445236bbc6SZhiyong Tao 	clk_disable_unprepare(adc_dev->adc_clk);
2455236bbc6SZhiyong Tao 
2465236bbc6SZhiyong Tao 	return 0;
2475236bbc6SZhiyong Tao }
2485236bbc6SZhiyong Tao 
mt6577_auxadc_probe(struct platform_device * pdev)249ace4cdfeSZhiyong Tao static int mt6577_auxadc_probe(struct platform_device *pdev)
250ace4cdfeSZhiyong Tao {
251ace4cdfeSZhiyong Tao 	struct mt6577_auxadc_device *adc_dev;
252ace4cdfeSZhiyong Tao 	unsigned long adc_clk_rate;
253ace4cdfeSZhiyong Tao 	struct iio_dev *indio_dev;
254ace4cdfeSZhiyong Tao 	int ret;
255ace4cdfeSZhiyong Tao 
256ace4cdfeSZhiyong Tao 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
257ace4cdfeSZhiyong Tao 	if (!indio_dev)
258ace4cdfeSZhiyong Tao 		return -ENOMEM;
259ace4cdfeSZhiyong Tao 
260ace4cdfeSZhiyong Tao 	adc_dev = iio_priv(indio_dev);
261ace4cdfeSZhiyong Tao 	indio_dev->name = dev_name(&pdev->dev);
262ace4cdfeSZhiyong Tao 	indio_dev->info = &mt6577_auxadc_info;
263ace4cdfeSZhiyong Tao 	indio_dev->modes = INDIO_DIRECT_MODE;
264ace4cdfeSZhiyong Tao 	indio_dev->channels = mt6577_auxadc_iio_channels;
265ace4cdfeSZhiyong Tao 	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
266ace4cdfeSZhiyong Tao 
26738877a37SJonathan Cameron 	adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
268ace4cdfeSZhiyong Tao 	if (IS_ERR(adc_dev->reg_base)) {
269ace4cdfeSZhiyong Tao 		dev_err(&pdev->dev, "failed to get auxadc base address\n");
270ace4cdfeSZhiyong Tao 		return PTR_ERR(adc_dev->reg_base);
271ace4cdfeSZhiyong Tao 	}
272ace4cdfeSZhiyong Tao 
273ace4cdfeSZhiyong Tao 	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
274ace4cdfeSZhiyong Tao 	if (IS_ERR(adc_dev->adc_clk)) {
275ace4cdfeSZhiyong Tao 		dev_err(&pdev->dev, "failed to get auxadc clock\n");
276ace4cdfeSZhiyong Tao 		return PTR_ERR(adc_dev->adc_clk);
277ace4cdfeSZhiyong Tao 	}
278ace4cdfeSZhiyong Tao 
279ace4cdfeSZhiyong Tao 	ret = clk_prepare_enable(adc_dev->adc_clk);
280ace4cdfeSZhiyong Tao 	if (ret) {
281ace4cdfeSZhiyong Tao 		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
282ace4cdfeSZhiyong Tao 		return ret;
283ace4cdfeSZhiyong Tao 	}
284ace4cdfeSZhiyong Tao 
285ace4cdfeSZhiyong Tao 	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
286ace4cdfeSZhiyong Tao 	if (!adc_clk_rate) {
287ace4cdfeSZhiyong Tao 		ret = -EINVAL;
288ace4cdfeSZhiyong Tao 		dev_err(&pdev->dev, "null clock rate\n");
289ace4cdfeSZhiyong Tao 		goto err_disable_clk;
290ace4cdfeSZhiyong Tao 	}
291ace4cdfeSZhiyong Tao 
29215207a92SFabien Parent 	adc_dev->dev_comp = device_get_match_data(&pdev->dev);
29315207a92SFabien Parent 
294ace4cdfeSZhiyong Tao 	mutex_init(&adc_dev->lock);
295ace4cdfeSZhiyong Tao 
296ace4cdfeSZhiyong Tao 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
297ace4cdfeSZhiyong Tao 			      MT6577_AUXADC_PDN_EN, 0);
298ace4cdfeSZhiyong Tao 	mdelay(MT6577_AUXADC_POWER_READY_MS);
299ace4cdfeSZhiyong Tao 
300ace4cdfeSZhiyong Tao 	platform_set_drvdata(pdev, indio_dev);
301ace4cdfeSZhiyong Tao 
302ace4cdfeSZhiyong Tao 	ret = iio_device_register(indio_dev);
303ace4cdfeSZhiyong Tao 	if (ret < 0) {
304ace4cdfeSZhiyong Tao 		dev_err(&pdev->dev, "failed to register iio device\n");
305ace4cdfeSZhiyong Tao 		goto err_power_off;
306ace4cdfeSZhiyong Tao 	}
307ace4cdfeSZhiyong Tao 
308ace4cdfeSZhiyong Tao 	return 0;
309ace4cdfeSZhiyong Tao 
310ace4cdfeSZhiyong Tao err_power_off:
311ace4cdfeSZhiyong Tao 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
312ace4cdfeSZhiyong Tao 			      0, MT6577_AUXADC_PDN_EN);
313ace4cdfeSZhiyong Tao err_disable_clk:
314ace4cdfeSZhiyong Tao 	clk_disable_unprepare(adc_dev->adc_clk);
315ace4cdfeSZhiyong Tao 	return ret;
316ace4cdfeSZhiyong Tao }
317ace4cdfeSZhiyong Tao 
mt6577_auxadc_remove(struct platform_device * pdev)318ace4cdfeSZhiyong Tao static int mt6577_auxadc_remove(struct platform_device *pdev)
319ace4cdfeSZhiyong Tao {
320ace4cdfeSZhiyong Tao 	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
321ace4cdfeSZhiyong Tao 	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
322ace4cdfeSZhiyong Tao 
323ace4cdfeSZhiyong Tao 	iio_device_unregister(indio_dev);
324ace4cdfeSZhiyong Tao 
325ace4cdfeSZhiyong Tao 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
326ace4cdfeSZhiyong Tao 			      0, MT6577_AUXADC_PDN_EN);
327ace4cdfeSZhiyong Tao 
328ace4cdfeSZhiyong Tao 	clk_disable_unprepare(adc_dev->adc_clk);
329ace4cdfeSZhiyong Tao 
330ace4cdfeSZhiyong Tao 	return 0;
331ace4cdfeSZhiyong Tao }
332ace4cdfeSZhiyong Tao 
333*7ff1d28cSJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(mt6577_auxadc_pm_ops,
3345236bbc6SZhiyong Tao 				mt6577_auxadc_suspend,
3355236bbc6SZhiyong Tao 				mt6577_auxadc_resume);
3365236bbc6SZhiyong Tao 
337ace4cdfeSZhiyong Tao static const struct of_device_id mt6577_auxadc_of_match[] = {
3386d97024dSChun-Hung Wu 	{ .compatible = "mediatek,mt2701-auxadc", .data = &mt8173_compat },
3396d97024dSChun-Hung Wu 	{ .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat },
3406d97024dSChun-Hung Wu 	{ .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat },
3416d97024dSChun-Hung Wu 	{ .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat },
342ff04eb47SGuodong Liu 	{ .compatible = "mediatek,mt8186-auxadc", .data = &mt8186_compat },
3436d97024dSChun-Hung Wu 	{ .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat },
344ace4cdfeSZhiyong Tao 	{ }
345ace4cdfeSZhiyong Tao };
346ace4cdfeSZhiyong Tao MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
347ace4cdfeSZhiyong Tao 
348ace4cdfeSZhiyong Tao static struct platform_driver mt6577_auxadc_driver = {
349ace4cdfeSZhiyong Tao 	.driver = {
350ace4cdfeSZhiyong Tao 		.name   = "mt6577-auxadc",
351ace4cdfeSZhiyong Tao 		.of_match_table = mt6577_auxadc_of_match,
352*7ff1d28cSJonathan Cameron 		.pm = pm_sleep_ptr(&mt6577_auxadc_pm_ops),
353ace4cdfeSZhiyong Tao 	},
354ace4cdfeSZhiyong Tao 	.probe	= mt6577_auxadc_probe,
355ace4cdfeSZhiyong Tao 	.remove	= mt6577_auxadc_remove,
356ace4cdfeSZhiyong Tao };
357ace4cdfeSZhiyong Tao module_platform_driver(mt6577_auxadc_driver);
358ace4cdfeSZhiyong Tao 
359ace4cdfeSZhiyong Tao MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao@mediatek.com>");
360ace4cdfeSZhiyong Tao MODULE_DESCRIPTION("MTK AUXADC Device Driver");
361ace4cdfeSZhiyong Tao MODULE_LICENSE("GPL v2");
362