• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* arch/arm/plat-samsung/adc.c
2  *
3  * Copyright (c) 2008 Simtec Electronics
4  *	http://armlinux.simtec.co.uk/
5  *	Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
6  *
7  * Samsung ADC device core
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License.
12 */
13 
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/platform_device.h>
17 #include <linux/sched.h>
18 #include <linux/list.h>
19 #include <linux/slab.h>
20 #include <linux/err.h>
21 #include <linux/clk.h>
22 #include <linux/interrupt.h>
23 #include <linux/io.h>
24 #include <linux/regulator/consumer.h>
25 
26 #include <plat/regs-adc.h>
27 #include <plat/adc.h>
28 
29 /* This driver is designed to control the usage of the ADC block between
30  * the touchscreen and any other drivers that may need to use it, such as
31  * the hwmon driver.
32  *
33  * Priority will be given to the touchscreen driver, but as this itself is
34  * rate limited it should not starve other requests which are processed in
35  * order that they are received.
36  *
37  * Each user registers to get a client block which uniquely identifies it
38  * and stores information such as the necessary functions to callback when
39  * action is required.
40  */
41 
42 enum s3c_cpu_type {
43 	TYPE_ADCV1, /* S3C24XX */
44 	TYPE_ADCV11, /* S3C2443 */
45 	TYPE_ADCV12, /* S3C2416, S3C2450 */
46 	TYPE_ADCV2, /* S3C64XX */
47 	TYPE_ADCV3, /* S5PV210, S5PC110, EXYNOS4210 */
48 };
49 
50 struct s3c_adc_client {
51 	struct platform_device	*pdev;
52 	struct list_head	 pend;
53 	wait_queue_head_t	*wait;
54 
55 	unsigned int		 nr_samples;
56 	int			 result;
57 	unsigned char		 is_ts;
58 	unsigned char		 channel;
59 
60 	void	(*select_cb)(struct s3c_adc_client *c, unsigned selected);
61 	void	(*convert_cb)(struct s3c_adc_client *c,
62 			      unsigned val1, unsigned val2,
63 			      unsigned *samples_left);
64 };
65 
66 struct adc_device {
67 	struct platform_device	*pdev;
68 	struct platform_device	*owner;
69 	struct clk		*clk;
70 	struct s3c_adc_client	*cur;
71 	struct s3c_adc_client	*ts_pend;
72 	void __iomem		*regs;
73 	spinlock_t		 lock;
74 
75 	unsigned int		 prescale;
76 
77 	int			 irq;
78 	struct regulator	*vdd;
79 };
80 
81 static struct adc_device *adc_dev;
82 
83 static LIST_HEAD(adc_pending);	/* protected by adc_device.lock */
84 
85 #define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
86 
s3c_adc_convert(struct adc_device * adc)87 static inline void s3c_adc_convert(struct adc_device *adc)
88 {
89 	unsigned con = readl(adc->regs + S3C2410_ADCCON);
90 
91 	con |= S3C2410_ADCCON_ENABLE_START;
92 	writel(con, adc->regs + S3C2410_ADCCON);
93 }
94 
s3c_adc_select(struct adc_device * adc,struct s3c_adc_client * client)95 static inline void s3c_adc_select(struct adc_device *adc,
96 				  struct s3c_adc_client *client)
97 {
98 	unsigned con = readl(adc->regs + S3C2410_ADCCON);
99 	enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
100 
101 	client->select_cb(client, 1);
102 
103 	if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV2)
104 		con &= ~S3C2410_ADCCON_MUXMASK;
105 	con &= ~S3C2410_ADCCON_STDBM;
106 	con &= ~S3C2410_ADCCON_STARTMASK;
107 
108 	if (!client->is_ts) {
109 		if (cpu == TYPE_ADCV3)
110 			writel(client->channel & 0xf, adc->regs + S5P_ADCMUX);
111 		else if (cpu == TYPE_ADCV11 || cpu == TYPE_ADCV12)
112 			writel(client->channel & 0xf,
113 						adc->regs + S3C2443_ADCMUX);
114 		else
115 			con |= S3C2410_ADCCON_SELMUX(client->channel);
116 	}
117 
118 	writel(con, adc->regs + S3C2410_ADCCON);
119 }
120 
s3c_adc_dbgshow(struct adc_device * adc)121 static void s3c_adc_dbgshow(struct adc_device *adc)
122 {
123 	adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
124 		readl(adc->regs + S3C2410_ADCCON),
125 		readl(adc->regs + S3C2410_ADCTSC),
126 		readl(adc->regs + S3C2410_ADCDLY));
127 }
128 
s3c_adc_try(struct adc_device * adc)129 static void s3c_adc_try(struct adc_device *adc)
130 {
131 	struct s3c_adc_client *next = adc->ts_pend;
132 
133 	if (!next && !list_empty(&adc_pending)) {
134 		next = list_first_entry(&adc_pending,
135 					struct s3c_adc_client, pend);
136 		list_del(&next->pend);
137 	} else
138 		adc->ts_pend = NULL;
139 
140 	if (next) {
141 		adc_dbg(adc, "new client is %p\n", next);
142 		adc->cur = next;
143 		s3c_adc_select(adc, next);
144 		s3c_adc_convert(adc);
145 		s3c_adc_dbgshow(adc);
146 	}
147 }
148 
s3c_adc_start(struct s3c_adc_client * client,unsigned int channel,unsigned int nr_samples)149 int s3c_adc_start(struct s3c_adc_client *client,
150 		  unsigned int channel, unsigned int nr_samples)
151 {
152 	struct adc_device *adc = adc_dev;
153 	unsigned long flags;
154 
155 	if (!adc) {
156 		printk(KERN_ERR "%s: failed to find adc\n", __func__);
157 		return -EINVAL;
158 	}
159 
160 	spin_lock_irqsave(&adc->lock, flags);
161 
162 	if (client->is_ts && adc->ts_pend) {
163 		spin_unlock_irqrestore(&adc->lock, flags);
164 		return -EAGAIN;
165 	}
166 
167 	client->channel = channel;
168 	client->nr_samples = nr_samples;
169 
170 	if (client->is_ts)
171 		adc->ts_pend = client;
172 	else
173 		list_add_tail(&client->pend, &adc_pending);
174 
175 	if (!adc->cur)
176 		s3c_adc_try(adc);
177 
178 	spin_unlock_irqrestore(&adc->lock, flags);
179 
180 	return 0;
181 }
182 EXPORT_SYMBOL_GPL(s3c_adc_start);
183 
s3c_convert_done(struct s3c_adc_client * client,unsigned v,unsigned u,unsigned * left)184 static void s3c_convert_done(struct s3c_adc_client *client,
185 			     unsigned v, unsigned u, unsigned *left)
186 {
187 	client->result = v;
188 	wake_up(client->wait);
189 }
190 
s3c_adc_read(struct s3c_adc_client * client,unsigned int ch)191 int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch)
192 {
193 	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
194 	int ret;
195 
196 	client->convert_cb = s3c_convert_done;
197 	client->wait = &wake;
198 	client->result = -1;
199 
200 	ret = s3c_adc_start(client, ch, 1);
201 	if (ret < 0)
202 		goto err;
203 
204 	ret = wait_event_timeout(wake, client->result >= 0, HZ / 2);
205 	if (client->result < 0) {
206 		ret = -ETIMEDOUT;
207 		goto err;
208 	}
209 
210 	client->convert_cb = NULL;
211 	return client->result;
212 
213 err:
214 	return ret;
215 }
216 EXPORT_SYMBOL_GPL(s3c_adc_read);
217 
s3c_adc_default_select(struct s3c_adc_client * client,unsigned select)218 static void s3c_adc_default_select(struct s3c_adc_client *client,
219 				   unsigned select)
220 {
221 }
222 
s3c_adc_register(struct platform_device * pdev,void (* select)(struct s3c_adc_client * client,unsigned int selected),void (* conv)(struct s3c_adc_client * client,unsigned d0,unsigned d1,unsigned * samples_left),unsigned int is_ts)223 struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
224 					void (*select)(struct s3c_adc_client *client,
225 						       unsigned int selected),
226 					void (*conv)(struct s3c_adc_client *client,
227 						     unsigned d0, unsigned d1,
228 						     unsigned *samples_left),
229 					unsigned int is_ts)
230 {
231 	struct s3c_adc_client *client;
232 
233 	WARN_ON(!pdev);
234 
235 	if (!select)
236 		select = s3c_adc_default_select;
237 
238 	if (!pdev)
239 		return ERR_PTR(-EINVAL);
240 
241 	client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL);
242 	if (!client) {
243 		dev_err(&pdev->dev, "no memory for adc client\n");
244 		return ERR_PTR(-ENOMEM);
245 	}
246 
247 	client->pdev = pdev;
248 	client->is_ts = is_ts;
249 	client->select_cb = select;
250 	client->convert_cb = conv;
251 
252 	return client;
253 }
254 EXPORT_SYMBOL_GPL(s3c_adc_register);
255 
s3c_adc_release(struct s3c_adc_client * client)256 void s3c_adc_release(struct s3c_adc_client *client)
257 {
258 	unsigned long flags;
259 
260 	spin_lock_irqsave(&adc_dev->lock, flags);
261 
262 	/* We should really check that nothing is in progress. */
263 	if (adc_dev->cur == client)
264 		adc_dev->cur = NULL;
265 	if (adc_dev->ts_pend == client)
266 		adc_dev->ts_pend = NULL;
267 	else {
268 		struct list_head *p, *n;
269 		struct s3c_adc_client *tmp;
270 
271 		list_for_each_safe(p, n, &adc_pending) {
272 			tmp = list_entry(p, struct s3c_adc_client, pend);
273 			if (tmp == client)
274 				list_del(&tmp->pend);
275 		}
276 	}
277 
278 	if (adc_dev->cur == NULL)
279 		s3c_adc_try(adc_dev);
280 
281 	spin_unlock_irqrestore(&adc_dev->lock, flags);
282 	kfree(client);
283 }
284 EXPORT_SYMBOL_GPL(s3c_adc_release);
285 
s3c_adc_irq(int irq,void * pw)286 static irqreturn_t s3c_adc_irq(int irq, void *pw)
287 {
288 	struct adc_device *adc = pw;
289 	struct s3c_adc_client *client = adc->cur;
290 	enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
291 	unsigned data0, data1;
292 
293 	if (!client) {
294 		dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
295 		goto exit;
296 	}
297 
298 	data0 = readl(adc->regs + S3C2410_ADCDAT0);
299 	data1 = readl(adc->regs + S3C2410_ADCDAT1);
300 	adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
301 
302 	client->nr_samples--;
303 
304 	if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV11) {
305 		data0 &= 0x3ff;
306 		data1 &= 0x3ff;
307 	} else {
308 		/* S3C2416/S3C64XX/S5P ADC resolution is 12-bit */
309 		data0 &= 0xfff;
310 		data1 &= 0xfff;
311 	}
312 
313 	if (client->convert_cb)
314 		(client->convert_cb)(client, data0, data1, &client->nr_samples);
315 
316 	if (client->nr_samples > 0) {
317 		/* fire another conversion for this */
318 
319 		client->select_cb(client, 1);
320 		s3c_adc_convert(adc);
321 	} else {
322 		spin_lock(&adc->lock);
323 		(client->select_cb)(client, 0);
324 		adc->cur = NULL;
325 
326 		s3c_adc_try(adc);
327 		spin_unlock(&adc->lock);
328 	}
329 
330 exit:
331 	if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) {
332 		/* Clear ADC interrupt */
333 		writel(0, adc->regs + S3C64XX_ADCCLRINT);
334 	}
335 	return IRQ_HANDLED;
336 }
337 
s3c_adc_probe(struct platform_device * pdev)338 static int s3c_adc_probe(struct platform_device *pdev)
339 {
340 	struct device *dev = &pdev->dev;
341 	struct adc_device *adc;
342 	struct resource *regs;
343 	enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data;
344 	int ret;
345 	unsigned tmp;
346 
347 	adc = devm_kzalloc(dev, sizeof(struct adc_device), GFP_KERNEL);
348 	if (adc == NULL) {
349 		dev_err(dev, "failed to allocate adc_device\n");
350 		return -ENOMEM;
351 	}
352 
353 	spin_lock_init(&adc->lock);
354 
355 	adc->pdev = pdev;
356 	adc->prescale = S3C2410_ADCCON_PRSCVL(49);
357 
358 	adc->vdd = devm_regulator_get(dev, "vdd");
359 	if (IS_ERR(adc->vdd)) {
360 		dev_err(dev, "operating without regulator \"vdd\" .\n");
361 		return PTR_ERR(adc->vdd);
362 	}
363 
364 	adc->irq = platform_get_irq(pdev, 1);
365 	if (adc->irq <= 0) {
366 		dev_err(dev, "failed to get adc irq\n");
367 		return -ENOENT;
368 	}
369 
370 	ret = devm_request_irq(dev, adc->irq, s3c_adc_irq, 0, dev_name(dev),
371 				adc);
372 	if (ret < 0) {
373 		dev_err(dev, "failed to attach adc irq\n");
374 		return ret;
375 	}
376 
377 	adc->clk = devm_clk_get(dev, "adc");
378 	if (IS_ERR(adc->clk)) {
379 		dev_err(dev, "failed to get adc clock\n");
380 		return PTR_ERR(adc->clk);
381 	}
382 
383 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
384 	adc->regs = devm_ioremap_resource(dev, regs);
385 	if (IS_ERR(adc->regs))
386 		return PTR_ERR(adc->regs);
387 
388 	ret = regulator_enable(adc->vdd);
389 	if (ret)
390 		return ret;
391 
392 	clk_enable(adc->clk);
393 
394 	tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
395 
396 	/* Enable 12-bit ADC resolution */
397 	if (cpu == TYPE_ADCV12)
398 		tmp |= S3C2416_ADCCON_RESSEL;
399 	if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
400 		tmp |= S3C64XX_ADCCON_RESSEL;
401 
402 	writel(tmp, adc->regs + S3C2410_ADCCON);
403 
404 	dev_info(dev, "attached adc driver\n");
405 
406 	platform_set_drvdata(pdev, adc);
407 	adc_dev = adc;
408 
409 	return 0;
410 }
411 
s3c_adc_remove(struct platform_device * pdev)412 static int s3c_adc_remove(struct platform_device *pdev)
413 {
414 	struct adc_device *adc = platform_get_drvdata(pdev);
415 
416 	clk_disable(adc->clk);
417 	regulator_disable(adc->vdd);
418 
419 	return 0;
420 }
421 
422 #ifdef CONFIG_PM
s3c_adc_suspend(struct device * dev)423 static int s3c_adc_suspend(struct device *dev)
424 {
425 	struct platform_device *pdev = container_of(dev,
426 			struct platform_device, dev);
427 	struct adc_device *adc = platform_get_drvdata(pdev);
428 	unsigned long flags;
429 	u32 con;
430 
431 	spin_lock_irqsave(&adc->lock, flags);
432 
433 	con = readl(adc->regs + S3C2410_ADCCON);
434 	con |= S3C2410_ADCCON_STDBM;
435 	writel(con, adc->regs + S3C2410_ADCCON);
436 
437 	disable_irq(adc->irq);
438 	spin_unlock_irqrestore(&adc->lock, flags);
439 	clk_disable(adc->clk);
440 	regulator_disable(adc->vdd);
441 
442 	return 0;
443 }
444 
s3c_adc_resume(struct device * dev)445 static int s3c_adc_resume(struct device *dev)
446 {
447 	struct platform_device *pdev = container_of(dev,
448 			struct platform_device, dev);
449 	struct adc_device *adc = platform_get_drvdata(pdev);
450 	enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data;
451 	int ret;
452 	unsigned long tmp;
453 
454 	ret = regulator_enable(adc->vdd);
455 	if (ret)
456 		return ret;
457 	clk_enable(adc->clk);
458 	enable_irq(adc->irq);
459 
460 	tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
461 
462 	/* Enable 12-bit ADC resolution */
463 	if (cpu == TYPE_ADCV12)
464 		tmp |= S3C2416_ADCCON_RESSEL;
465 	if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
466 		tmp |= S3C64XX_ADCCON_RESSEL;
467 
468 	writel(tmp, adc->regs + S3C2410_ADCCON);
469 
470 	return 0;
471 }
472 
473 #else
474 #define s3c_adc_suspend NULL
475 #define s3c_adc_resume NULL
476 #endif
477 
478 static struct platform_device_id s3c_adc_driver_ids[] = {
479 	{
480 		.name           = "s3c24xx-adc",
481 		.driver_data    = TYPE_ADCV1,
482 	}, {
483 		.name		= "s3c2443-adc",
484 		.driver_data	= TYPE_ADCV11,
485 	}, {
486 		.name		= "s3c2416-adc",
487 		.driver_data	= TYPE_ADCV12,
488 	}, {
489 		.name           = "s3c64xx-adc",
490 		.driver_data    = TYPE_ADCV2,
491 	}, {
492 		.name		= "samsung-adc-v3",
493 		.driver_data	= TYPE_ADCV3,
494 	},
495 	{ }
496 };
497 MODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids);
498 
499 static const struct dev_pm_ops adc_pm_ops = {
500 	.suspend	= s3c_adc_suspend,
501 	.resume		= s3c_adc_resume,
502 };
503 
504 static struct platform_driver s3c_adc_driver = {
505 	.id_table	= s3c_adc_driver_ids,
506 	.driver		= {
507 		.name	= "s3c-adc",
508 		.owner	= THIS_MODULE,
509 		.pm	= &adc_pm_ops,
510 	},
511 	.probe		= s3c_adc_probe,
512 	.remove		= s3c_adc_remove,
513 };
514 
adc_init(void)515 static int __init adc_init(void)
516 {
517 	int ret;
518 
519 	ret = platform_driver_register(&s3c_adc_driver);
520 	if (ret)
521 		printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
522 
523 	return ret;
524 }
525 
526 module_init(adc_init);
527