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