13929e1e76d9116856a4c7a00fcce0539dd8507a0Maurus Cuelenaere/* arch/arm/plat-samsung/adc.c
228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks *
328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * Copyright (c) 2008 Simtec Electronics
428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks *	http://armlinux.simtec.co.uk/
528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks *	Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks *
73929e1e76d9116856a4c7a00fcce0539dd8507a0Maurus Cuelenaere * Samsung ADC device core
828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks *
928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * This program is free software; you can redistribute it and/or modify
1028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * it under the terms of the GNU General Public License as published by
1128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * the Free Software Foundation; either version 2 of the License.
1228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks*/
1328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
1428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#include <linux/module.h>
1528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#include <linux/kernel.h>
1628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#include <linux/platform_device.h>
17d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h>
1828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#include <linux/list.h>
195a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
2028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#include <linux/err.h>
2128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#include <linux/clk.h>
2228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#include <linux/interrupt.h>
2328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#include <linux/io.h>
24f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham#include <linux/regulator/consumer.h>
2528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
2628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#include <plat/regs-adc.h>
2728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#include <plat/adc.h>
2828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
2928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks/* This driver is designed to control the usage of the ADC block between
3028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * the touchscreen and any other drivers that may need to use it, such as
3128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * the hwmon driver.
3228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks *
3328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * Priority will be given to the touchscreen driver, but as this itself is
3428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * rate limited it should not starve other requests which are processed in
3528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * order that they are received.
3628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks *
3728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * Each user registers to get a client block which uniquely identifies it
3828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * and stores information such as the necessary functions to callback when
3928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks * action is required.
4028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks */
4128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
42bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaereenum s3c_cpu_type {
4364df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham	TYPE_ADCV1, /* S3C24XX */
446247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner	TYPE_ADCV11, /* S3C2443 */
4535cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner	TYPE_ADCV12, /* S3C2416, S3C2450 */
46b8529ec1c1b0984d2baeda450c28eeb40efc87feKukjin Kim	TYPE_ADCV2, /* S3C64XX */
4764df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham	TYPE_ADCV3, /* S5PV210, S5PC110, EXYNOS4210 */
48bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere};
49bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere
5028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstruct s3c_adc_client {
5128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct platform_device	*pdev;
5228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct list_head	 pend;
53e170adcb406504b8acd35554c69830c11916be1fBen Dooks	wait_queue_head_t	*wait;
5428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
5528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	unsigned int		 nr_samples;
56e170adcb406504b8acd35554c69830c11916be1fBen Dooks	int			 result;
5728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	unsigned char		 is_ts;
5828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	unsigned char		 channel;
5928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
60e170adcb406504b8acd35554c69830c11916be1fBen Dooks	void	(*select_cb)(struct s3c_adc_client *c, unsigned selected);
61e170adcb406504b8acd35554c69830c11916be1fBen Dooks	void	(*convert_cb)(struct s3c_adc_client *c,
62e170adcb406504b8acd35554c69830c11916be1fBen Dooks			      unsigned val1, unsigned val2,
633f7ea467be1bad860c0f71ba7373dd3cf76b485aNelson Castillo			      unsigned *samples_left);
6428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks};
6528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
6628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstruct adc_device {
6728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct platform_device	*pdev;
6828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct platform_device	*owner;
6928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct clk		*clk;
7028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct s3c_adc_client	*cur;
7128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct s3c_adc_client	*ts_pend;
7228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	void __iomem		*regs;
731f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks	spinlock_t		 lock;
7428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
7528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	unsigned int		 prescale;
7628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
7728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	int			 irq;
78f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham	struct regulator	*vdd;
7928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks};
8028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
8128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstatic struct adc_device *adc_dev;
8228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
831f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooksstatic LIST_HEAD(adc_pending);	/* protected by adc_device.lock */
8428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
8528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
8628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
8728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstatic inline void s3c_adc_convert(struct adc_device *adc)
8828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
8928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	unsigned con = readl(adc->regs + S3C2410_ADCCON);
9028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
9128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	con |= S3C2410_ADCCON_ENABLE_START;
9228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	writel(con, adc->regs + S3C2410_ADCCON);
9328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
9428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
9528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstatic inline void s3c_adc_select(struct adc_device *adc,
9628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks				  struct s3c_adc_client *client)
9728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
9828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	unsigned con = readl(adc->regs + S3C2410_ADCCON);
9964df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham	enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
10028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
101e170adcb406504b8acd35554c69830c11916be1fBen Dooks	client->select_cb(client, 1);
10228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
103df303e0236417ca006e04116f18641dbe4bd704aHeiko Stuebner	if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV2)
104df303e0236417ca006e04116f18641dbe4bd704aHeiko Stuebner		con &= ~S3C2410_ADCCON_MUXMASK;
10528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	con &= ~S3C2410_ADCCON_STDBM;
10628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	con &= ~S3C2410_ADCCON_STARTMASK;
10728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
10864df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham	if (!client->is_ts) {
10964df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham		if (cpu == TYPE_ADCV3)
11064df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham			writel(client->channel & 0xf, adc->regs + S5P_ADCMUX);
11135cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner		else if (cpu == TYPE_ADCV11 || cpu == TYPE_ADCV12)
1126247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner			writel(client->channel & 0xf,
1136247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner						adc->regs + S3C2443_ADCMUX);
11464df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham		else
11564df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham			con |= S3C2410_ADCCON_SELMUX(client->channel);
11664df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham	}
11728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
11828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	writel(con, adc->regs + S3C2410_ADCCON);
11928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
12028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
12128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstatic void s3c_adc_dbgshow(struct adc_device *adc)
12228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
12328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
12428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		readl(adc->regs + S3C2410_ADCCON),
12528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		readl(adc->regs + S3C2410_ADCTSC),
12628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		readl(adc->regs + S3C2410_ADCDLY));
12728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
12828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
129f8c8ac8109ecdd3583b0ac9fd3adf058678a802eBen Dooksstatic void s3c_adc_try(struct adc_device *adc)
13028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
13128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct s3c_adc_client *next = adc->ts_pend;
13228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
13328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (!next && !list_empty(&adc_pending)) {
13428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		next = list_first_entry(&adc_pending,
13528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks					struct s3c_adc_client, pend);
13628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		list_del(&next->pend);
13728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	} else
13828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		adc->ts_pend = NULL;
13928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
14028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (next) {
14128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		adc_dbg(adc, "new client is %p\n", next);
14228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		adc->cur = next;
14328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		s3c_adc_select(adc, next);
14428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		s3c_adc_convert(adc);
14528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		s3c_adc_dbgshow(adc);
14628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	}
14728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
14828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
14928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksint s3c_adc_start(struct s3c_adc_client *client,
15028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		  unsigned int channel, unsigned int nr_samples)
15128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
15228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct adc_device *adc = adc_dev;
15328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	unsigned long flags;
15428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
15528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (!adc) {
15628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		printk(KERN_ERR "%s: failed to find adc\n", __func__);
15728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		return -EINVAL;
15828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	}
15928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
1601f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks	spin_lock_irqsave(&adc->lock, flags);
16128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
1628265981bb439f3ecc5356fb877a6c2a6636ac88aTodd Poynor	if (client->is_ts && adc->ts_pend) {
1638265981bb439f3ecc5356fb877a6c2a6636ac88aTodd Poynor		spin_unlock_irqrestore(&adc->lock, flags);
1648265981bb439f3ecc5356fb877a6c2a6636ac88aTodd Poynor		return -EAGAIN;
1658265981bb439f3ecc5356fb877a6c2a6636ac88aTodd Poynor	}
1668265981bb439f3ecc5356fb877a6c2a6636ac88aTodd Poynor
16728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	client->channel = channel;
16828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	client->nr_samples = nr_samples;
16928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
17028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (client->is_ts)
17128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		adc->ts_pend = client;
17228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	else
17328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		list_add_tail(&client->pend, &adc_pending);
17428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
17528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (!adc->cur)
17628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		s3c_adc_try(adc);
1771f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks
1781f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks	spin_unlock_irqrestore(&adc->lock, flags);
17928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
18028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	return 0;
18128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
18228ab44c5be60a9b91021a7cc7b4e202775c04764Ben DooksEXPORT_SYMBOL_GPL(s3c_adc_start);
18328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
184e170adcb406504b8acd35554c69830c11916be1fBen Dooksstatic void s3c_convert_done(struct s3c_adc_client *client,
185e170adcb406504b8acd35554c69830c11916be1fBen Dooks			     unsigned v, unsigned u, unsigned *left)
186e170adcb406504b8acd35554c69830c11916be1fBen Dooks{
187e170adcb406504b8acd35554c69830c11916be1fBen Dooks	client->result = v;
188e170adcb406504b8acd35554c69830c11916be1fBen Dooks	wake_up(client->wait);
189e170adcb406504b8acd35554c69830c11916be1fBen Dooks}
190e170adcb406504b8acd35554c69830c11916be1fBen Dooks
191e170adcb406504b8acd35554c69830c11916be1fBen Dooksint s3c_adc_read(struct s3c_adc_client *client, unsigned int ch)
192e170adcb406504b8acd35554c69830c11916be1fBen Dooks{
193e170adcb406504b8acd35554c69830c11916be1fBen Dooks	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
194e170adcb406504b8acd35554c69830c11916be1fBen Dooks	int ret;
195e170adcb406504b8acd35554c69830c11916be1fBen Dooks
196e170adcb406504b8acd35554c69830c11916be1fBen Dooks	client->convert_cb = s3c_convert_done;
197e170adcb406504b8acd35554c69830c11916be1fBen Dooks	client->wait = &wake;
198e170adcb406504b8acd35554c69830c11916be1fBen Dooks	client->result = -1;
199e170adcb406504b8acd35554c69830c11916be1fBen Dooks
200e170adcb406504b8acd35554c69830c11916be1fBen Dooks	ret = s3c_adc_start(client, ch, 1);
201e170adcb406504b8acd35554c69830c11916be1fBen Dooks	if (ret < 0)
202e170adcb406504b8acd35554c69830c11916be1fBen Dooks		goto err;
203e170adcb406504b8acd35554c69830c11916be1fBen Dooks
204e170adcb406504b8acd35554c69830c11916be1fBen Dooks	ret = wait_event_timeout(wake, client->result >= 0, HZ / 2);
205e170adcb406504b8acd35554c69830c11916be1fBen Dooks	if (client->result < 0) {
206e170adcb406504b8acd35554c69830c11916be1fBen Dooks		ret = -ETIMEDOUT;
207e170adcb406504b8acd35554c69830c11916be1fBen Dooks		goto err;
208e170adcb406504b8acd35554c69830c11916be1fBen Dooks	}
209e170adcb406504b8acd35554c69830c11916be1fBen Dooks
210e170adcb406504b8acd35554c69830c11916be1fBen Dooks	client->convert_cb = NULL;
211e170adcb406504b8acd35554c69830c11916be1fBen Dooks	return client->result;
212e170adcb406504b8acd35554c69830c11916be1fBen Dooks
213e170adcb406504b8acd35554c69830c11916be1fBen Dookserr:
214e170adcb406504b8acd35554c69830c11916be1fBen Dooks	return ret;
215e170adcb406504b8acd35554c69830c11916be1fBen Dooks}
216d3bf3956c75b38def079fb6db40b5cf3f1466a93Ryan MallonEXPORT_SYMBOL_GPL(s3c_adc_read);
217e170adcb406504b8acd35554c69830c11916be1fBen Dooks
218e170adcb406504b8acd35554c69830c11916be1fBen Dooksstatic void s3c_adc_default_select(struct s3c_adc_client *client,
219e170adcb406504b8acd35554c69830c11916be1fBen Dooks				   unsigned select)
22028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
22128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
22228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
22328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstruct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
224e170adcb406504b8acd35554c69830c11916be1fBen Dooks					void (*select)(struct s3c_adc_client *client,
225e170adcb406504b8acd35554c69830c11916be1fBen Dooks						       unsigned int selected),
226e170adcb406504b8acd35554c69830c11916be1fBen Dooks					void (*conv)(struct s3c_adc_client *client,
227e170adcb406504b8acd35554c69830c11916be1fBen Dooks						     unsigned d0, unsigned d1,
2283f7ea467be1bad860c0f71ba7373dd3cf76b485aNelson Castillo						     unsigned *samples_left),
22928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks					unsigned int is_ts)
23028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
23128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct s3c_adc_client *client;
23228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
23328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	WARN_ON(!pdev);
23428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
23528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (!select)
23628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		select = s3c_adc_default_select;
23728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
238e170adcb406504b8acd35554c69830c11916be1fBen Dooks	if (!pdev)
23928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		return ERR_PTR(-EINVAL);
24028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
24128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL);
24228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (!client) {
24328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		dev_err(&pdev->dev, "no memory for adc client\n");
24428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		return ERR_PTR(-ENOMEM);
24528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	}
24628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
24728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	client->pdev = pdev;
24828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	client->is_ts = is_ts;
24928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	client->select_cb = select;
25028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	client->convert_cb = conv;
25128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
25228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	return client;
25328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
25428ab44c5be60a9b91021a7cc7b4e202775c04764Ben DooksEXPORT_SYMBOL_GPL(s3c_adc_register);
25528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
25628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksvoid s3c_adc_release(struct s3c_adc_client *client)
25728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
2581f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks	unsigned long flags;
2591f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks
2601f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks	spin_lock_irqsave(&adc_dev->lock, flags);
2611f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks
26228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	/* We should really check that nothing is in progress. */
2630c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo	if (adc_dev->cur == client)
2640c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo		adc_dev->cur = NULL;
2650c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo	if (adc_dev->ts_pend == client)
2660c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo		adc_dev->ts_pend = NULL;
2670c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo	else {
2680c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo		struct list_head *p, *n;
2690c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo		struct s3c_adc_client *tmp;
2700c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo
2710c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo		list_for_each_safe(p, n, &adc_pending) {
2720c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo			tmp = list_entry(p, struct s3c_adc_client, pend);
2730c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo			if (tmp == client)
2740c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo				list_del(&tmp->pend);
2750c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo		}
2760c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo	}
2770c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo
2780c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo	if (adc_dev->cur == NULL)
2790c3ee078251b85812e585b5cf5d1635afd73f4e2Ramax Lo		s3c_adc_try(adc_dev);
2801f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks
2811f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks	spin_unlock_irqrestore(&adc_dev->lock, flags);
28228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	kfree(client);
28328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
28428ab44c5be60a9b91021a7cc7b4e202775c04764Ben DooksEXPORT_SYMBOL_GPL(s3c_adc_release);
28528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
28628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstatic irqreturn_t s3c_adc_irq(int irq, void *pw)
28728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
28828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct adc_device *adc = pw;
28928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct s3c_adc_client *client = adc->cur;
29091492b4a04586e7cb191c72de9d1b22545a3ce16Maurus Cuelenaere	enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
29128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	unsigned data0, data1;
29228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
29328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (!client) {
29428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
295bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere		goto exit;
29628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	}
29728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
29828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	data0 = readl(adc->regs + S3C2410_ADCDAT0);
29928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	data1 = readl(adc->regs + S3C2410_ADCDAT1);
30028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
30128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
3023f7ea467be1bad860c0f71ba7373dd3cf76b485aNelson Castillo	client->nr_samples--;
303e170adcb406504b8acd35554c69830c11916be1fBen Dooks
3046247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner	if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV11) {
3056247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner		data0 &= 0x3ff;
3066247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner		data1 &= 0x3ff;
3076247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner	} else {
30835cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner		/* S3C2416/S3C64XX/S5P ADC resolution is 12-bit */
30991492b4a04586e7cb191c72de9d1b22545a3ce16Maurus Cuelenaere		data0 &= 0xfff;
31091492b4a04586e7cb191c72de9d1b22545a3ce16Maurus Cuelenaere		data1 &= 0xfff;
31191492b4a04586e7cb191c72de9d1b22545a3ce16Maurus Cuelenaere	}
31291492b4a04586e7cb191c72de9d1b22545a3ce16Maurus Cuelenaere
313e170adcb406504b8acd35554c69830c11916be1fBen Dooks	if (client->convert_cb)
31491492b4a04586e7cb191c72de9d1b22545a3ce16Maurus Cuelenaere		(client->convert_cb)(client, data0, data1, &client->nr_samples);
31528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
3163f7ea467be1bad860c0f71ba7373dd3cf76b485aNelson Castillo	if (client->nr_samples > 0) {
31728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		/* fire another conversion for this */
31828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
319e170adcb406504b8acd35554c69830c11916be1fBen Dooks		client->select_cb(client, 1);
32028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		s3c_adc_convert(adc);
32128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	} else {
3221f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks		spin_lock(&adc->lock);
323e170adcb406504b8acd35554c69830c11916be1fBen Dooks		(client->select_cb)(client, 0);
32428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		adc->cur = NULL;
32528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
32628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		s3c_adc_try(adc);
3271f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks		spin_unlock(&adc->lock);
32828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	}
32928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
330bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaereexit:
3316247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner	if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) {
332bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere		/* Clear ADC interrupt */
333bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere		writel(0, adc->regs + S3C64XX_ADCCLRINT);
334bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere	}
33528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	return IRQ_HANDLED;
33628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
33728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
33828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstatic int s3c_adc_probe(struct platform_device *pdev)
33928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
34028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct device *dev = &pdev->dev;
34128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct adc_device *adc;
34228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct resource *regs;
34335cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner	enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data;
34428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	int ret;
34591492b4a04586e7cb191c72de9d1b22545a3ce16Maurus Cuelenaere	unsigned tmp;
34628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
3472ee8e6f0e375c68d420c47ddab70485d8e587d95Eunki Kim	adc = devm_kzalloc(dev, sizeof(struct adc_device), GFP_KERNEL);
34828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (adc == NULL) {
34928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		dev_err(dev, "failed to allocate adc_device\n");
35028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		return -ENOMEM;
35128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	}
35228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
3531f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks	spin_lock_init(&adc->lock);
3541f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks
35528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	adc->pdev = pdev;
35628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	adc->prescale = S3C2410_ADCCON_PRSCVL(49);
35728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
3582ee8e6f0e375c68d420c47ddab70485d8e587d95Eunki Kim	adc->vdd = devm_regulator_get(dev, "vdd");
359f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham	if (IS_ERR(adc->vdd)) {
360f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham		dev_err(dev, "operating without regulator \"vdd\" .\n");
3612ee8e6f0e375c68d420c47ddab70485d8e587d95Eunki Kim		return PTR_ERR(adc->vdd);
362f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham	}
363f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham
36428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	adc->irq = platform_get_irq(pdev, 1);
36528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (adc->irq <= 0) {
36628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		dev_err(dev, "failed to get adc irq\n");
3672ee8e6f0e375c68d420c47ddab70485d8e587d95Eunki Kim		return -ENOENT;
36828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	}
36928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
3702ee8e6f0e375c68d420c47ddab70485d8e587d95Eunki Kim	ret = devm_request_irq(dev, adc->irq, s3c_adc_irq, 0, dev_name(dev),
3712ee8e6f0e375c68d420c47ddab70485d8e587d95Eunki Kim				adc);
37228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (ret < 0) {
37328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		dev_err(dev, "failed to attach adc irq\n");
3742ee8e6f0e375c68d420c47ddab70485d8e587d95Eunki Kim		return ret;
37528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	}
37628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
3772ee8e6f0e375c68d420c47ddab70485d8e587d95Eunki Kim	adc->clk = devm_clk_get(dev, "adc");
37828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (IS_ERR(adc->clk)) {
37928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		dev_err(dev, "failed to get adc clock\n");
3802ee8e6f0e375c68d420c47ddab70485d8e587d95Eunki Kim		return PTR_ERR(adc->clk);
38128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	}
38228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
38328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3845857bd98dbd0080e6b27b51087cc9ec24f426e8bThierry Reding	adc->regs = devm_ioremap_resource(dev, regs);
3855857bd98dbd0080e6b27b51087cc9ec24f426e8bThierry Reding	if (IS_ERR(adc->regs))
3865857bd98dbd0080e6b27b51087cc9ec24f426e8bThierry Reding		return PTR_ERR(adc->regs);
38728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
388f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham	ret = regulator_enable(adc->vdd);
389f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham	if (ret)
3902ee8e6f0e375c68d420c47ddab70485d8e587d95Eunki Kim		return ret;
391f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham
39228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	clk_enable(adc->clk);
39328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
39491492b4a04586e7cb191c72de9d1b22545a3ce16Maurus Cuelenaere	tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
39535cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner
39635cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner	/* Enable 12-bit ADC resolution */
39735cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner	if (cpu == TYPE_ADCV12)
39835cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner		tmp |= S3C2416_ADCCON_RESSEL;
39935cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner	if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
40091492b4a04586e7cb191c72de9d1b22545a3ce16Maurus Cuelenaere		tmp |= S3C64XX_ADCCON_RESSEL;
40135cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner
40291492b4a04586e7cb191c72de9d1b22545a3ce16Maurus Cuelenaere	writel(tmp, adc->regs + S3C2410_ADCCON);
40328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
40428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	dev_info(dev, "attached adc driver\n");
40528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
40628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	platform_set_drvdata(pdev, adc);
40728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	adc_dev = adc;
40828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
40928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	return 0;
41028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
41128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
412351a102dbf489d0e9c9b0883f76e2a94d895503dGreg Kroah-Hartmanstatic int s3c_adc_remove(struct platform_device *pdev)
41328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
41428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct adc_device *adc = platform_get_drvdata(pdev);
41528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
41628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	clk_disable(adc->clk);
417f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham	regulator_disable(adc->vdd);
41828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
41928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	return 0;
42028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
42128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
42228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#ifdef CONFIG_PM
42367dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Hamstatic int s3c_adc_suspend(struct device *dev)
42428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
42567dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham	struct platform_device *pdev = container_of(dev,
42667dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham			struct platform_device, dev);
42728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct adc_device *adc = platform_get_drvdata(pdev);
4281f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks	unsigned long flags;
42928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	u32 con;
43028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
4311f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks	spin_lock_irqsave(&adc->lock, flags);
4321f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks
43328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	con = readl(adc->regs + S3C2410_ADCCON);
43428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	con |= S3C2410_ADCCON_STDBM;
43528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	writel(con, adc->regs + S3C2410_ADCCON);
43628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
437a0af8b3c701d254b55fc291150d5320317c0a338Vasily Khoruzhick	disable_irq(adc->irq);
4381f1f584c9a1dd234041573d2d1c42620b3966607Ben Dooks	spin_unlock_irqrestore(&adc->lock, flags);
43928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	clk_disable(adc->clk);
440f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham	regulator_disable(adc->vdd);
44128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
44228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	return 0;
44328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
44428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
44567dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Hamstatic int s3c_adc_resume(struct device *dev)
44628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
44767dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham	struct platform_device *pdev = container_of(dev,
44867dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham			struct platform_device, dev);
44928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	struct adc_device *adc = platform_get_drvdata(pdev);
45035cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner	enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data;
451f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham	int ret;
45267dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham	unsigned long tmp;
45328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
454f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham	ret = regulator_enable(adc->vdd);
455f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham	if (ret)
456f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Ham		return ret;
45728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	clk_enable(adc->clk);
458a0af8b3c701d254b55fc291150d5320317c0a338Vasily Khoruzhick	enable_irq(adc->irq);
45928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
46067dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham	tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
46135cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner
46267dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham	/* Enable 12-bit ADC resolution */
46335cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner	if (cpu == TYPE_ADCV12)
46435cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner		tmp |= S3C2416_ADCCON_RESSEL;
46535cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner	if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
46667dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham		tmp |= S3C64XX_ADCCON_RESSEL;
46735cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner
46867dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham	writel(tmp, adc->regs + S3C2410_ADCCON);
46928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
47028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	return 0;
47128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
47228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
47328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#else
47428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#define s3c_adc_suspend NULL
47528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#define s3c_adc_resume NULL
47628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks#endif
47728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
478bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaerestatic struct platform_device_id s3c_adc_driver_ids[] = {
479bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere	{
480bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere		.name           = "s3c24xx-adc",
48164df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham		.driver_data    = TYPE_ADCV1,
482bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere	}, {
4836247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner		.name		= "s3c2443-adc",
4846247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner		.driver_data	= TYPE_ADCV11,
4856247cea2b9c193a845a01381c36e18f11676fdfbHeiko Stuebner	}, {
48635cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner		.name		= "s3c2416-adc",
48735cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner		.driver_data	= TYPE_ADCV12,
48835cc3cea2c2adb825dbe987000165005d28acaecHeiko Stuebner	}, {
489bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere		.name           = "s3c64xx-adc",
49064df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham		.driver_data    = TYPE_ADCV2,
49164df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham	}, {
49264df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham		.name		= "samsung-adc-v3",
49364df92ea7893d1cfd714c2f6acfd2eb15fbe3279MyungJoo Ham		.driver_data	= TYPE_ADCV3,
494bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere	},
495bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere	{ }
496bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere};
497bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus CuelenaereMODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids);
498bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere
49967dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Hamstatic const struct dev_pm_ops adc_pm_ops = {
50067dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham	.suspend	= s3c_adc_suspend,
50167dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham	.resume		= s3c_adc_resume,
50267dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham};
50367dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham
50428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstatic struct platform_driver s3c_adc_driver = {
505bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere	.id_table	= s3c_adc_driver_ids,
50628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	.driver		= {
507bcedfa98d97e02e95bb023ab93675dbe63c508efMaurus Cuelenaere		.name	= "s3c-adc",
50828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		.owner	= THIS_MODULE,
50967dcaec8d62ab751dbd1d5f9b3f3c1ce4205edf5MyungJoo Ham		.pm	= &adc_pm_ops,
51028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	},
51128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	.probe		= s3c_adc_probe,
512351a102dbf489d0e9c9b0883f76e2a94d895503dGreg Kroah-Hartman	.remove		= s3c_adc_remove,
51328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks};
51428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
51528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooksstatic int __init adc_init(void)
51628ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks{
51728ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	int ret;
51828ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
51928ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	ret = platform_driver_register(&s3c_adc_driver);
52028ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	if (ret)
52128ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks		printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
52228ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
52328ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks	return ret;
52428ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks}
52528ab44c5be60a9b91021a7cc7b4e202775c04764Ben Dooks
526f462904ef1508c0a2cc22c65478a7be0cd89f47aMyungJoo Hammodule_init(adc_init);
527