• 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, S5P64X0, S5PC100 */
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 = kzalloc(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 = regulator_get(dev, "vdd");
359 	if (IS_ERR(adc->vdd)) {
360 		dev_err(dev, "operating without regulator \"vdd\" .\n");
361 		ret = PTR_ERR(adc->vdd);
362 		goto err_alloc;
363 	}
364 
365 	adc->irq = platform_get_irq(pdev, 1);
366 	if (adc->irq <= 0) {
367 		dev_err(dev, "failed to get adc irq\n");
368 		ret = -ENOENT;
369 		goto err_reg;
370 	}
371 
372 	ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
373 	if (ret < 0) {
374 		dev_err(dev, "failed to attach adc irq\n");
375 		goto err_reg;
376 	}
377 
378 	adc->clk = clk_get(dev, "adc");
379 	if (IS_ERR(adc->clk)) {
380 		dev_err(dev, "failed to get adc clock\n");
381 		ret = PTR_ERR(adc->clk);
382 		goto err_irq;
383 	}
384 
385 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
386 	if (!regs) {
387 		dev_err(dev, "failed to find registers\n");
388 		ret = -ENXIO;
389 		goto err_clk;
390 	}
391 
392 	adc->regs = ioremap(regs->start, resource_size(regs));
393 	if (!adc->regs) {
394 		dev_err(dev, "failed to map registers\n");
395 		ret = -ENXIO;
396 		goto err_clk;
397 	}
398 
399 	ret = regulator_enable(adc->vdd);
400 	if (ret)
401 		goto err_ioremap;
402 
403 	clk_enable(adc->clk);
404 
405 	tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
406 
407 	/* Enable 12-bit ADC resolution */
408 	if (cpu == TYPE_ADCV12)
409 		tmp |= S3C2416_ADCCON_RESSEL;
410 	if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
411 		tmp |= S3C64XX_ADCCON_RESSEL;
412 
413 	writel(tmp, adc->regs + S3C2410_ADCCON);
414 
415 	dev_info(dev, "attached adc driver\n");
416 
417 	platform_set_drvdata(pdev, adc);
418 	adc_dev = adc;
419 
420 	return 0;
421 
422  err_ioremap:
423 	iounmap(adc->regs);
424  err_clk:
425 	clk_put(adc->clk);
426 
427  err_irq:
428 	free_irq(adc->irq, adc);
429  err_reg:
430 	regulator_put(adc->vdd);
431  err_alloc:
432 	kfree(adc);
433 	return ret;
434 }
435 
s3c_adc_remove(struct platform_device * pdev)436 static int __devexit s3c_adc_remove(struct platform_device *pdev)
437 {
438 	struct adc_device *adc = platform_get_drvdata(pdev);
439 
440 	iounmap(adc->regs);
441 	free_irq(adc->irq, adc);
442 	clk_disable(adc->clk);
443 	regulator_disable(adc->vdd);
444 	regulator_put(adc->vdd);
445 	clk_put(adc->clk);
446 	kfree(adc);
447 
448 	return 0;
449 }
450 
451 #ifdef CONFIG_PM
s3c_adc_suspend(struct device * dev)452 static int s3c_adc_suspend(struct device *dev)
453 {
454 	struct platform_device *pdev = container_of(dev,
455 			struct platform_device, dev);
456 	struct adc_device *adc = platform_get_drvdata(pdev);
457 	unsigned long flags;
458 	u32 con;
459 
460 	spin_lock_irqsave(&adc->lock, flags);
461 
462 	con = readl(adc->regs + S3C2410_ADCCON);
463 	con |= S3C2410_ADCCON_STDBM;
464 	writel(con, adc->regs + S3C2410_ADCCON);
465 
466 	disable_irq(adc->irq);
467 	spin_unlock_irqrestore(&adc->lock, flags);
468 	clk_disable(adc->clk);
469 	regulator_disable(adc->vdd);
470 
471 	return 0;
472 }
473 
s3c_adc_resume(struct device * dev)474 static int s3c_adc_resume(struct device *dev)
475 {
476 	struct platform_device *pdev = container_of(dev,
477 			struct platform_device, dev);
478 	struct adc_device *adc = platform_get_drvdata(pdev);
479 	enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data;
480 	int ret;
481 	unsigned long tmp;
482 
483 	ret = regulator_enable(adc->vdd);
484 	if (ret)
485 		return ret;
486 	clk_enable(adc->clk);
487 	enable_irq(adc->irq);
488 
489 	tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
490 
491 	/* Enable 12-bit ADC resolution */
492 	if (cpu == TYPE_ADCV12)
493 		tmp |= S3C2416_ADCCON_RESSEL;
494 	if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
495 		tmp |= S3C64XX_ADCCON_RESSEL;
496 
497 	writel(tmp, adc->regs + S3C2410_ADCCON);
498 
499 	return 0;
500 }
501 
502 #else
503 #define s3c_adc_suspend NULL
504 #define s3c_adc_resume NULL
505 #endif
506 
507 static struct platform_device_id s3c_adc_driver_ids[] = {
508 	{
509 		.name           = "s3c24xx-adc",
510 		.driver_data    = TYPE_ADCV1,
511 	}, {
512 		.name		= "s3c2443-adc",
513 		.driver_data	= TYPE_ADCV11,
514 	}, {
515 		.name		= "s3c2416-adc",
516 		.driver_data	= TYPE_ADCV12,
517 	}, {
518 		.name           = "s3c64xx-adc",
519 		.driver_data    = TYPE_ADCV2,
520 	}, {
521 		.name		= "samsung-adc-v3",
522 		.driver_data	= TYPE_ADCV3,
523 	},
524 	{ }
525 };
526 MODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids);
527 
528 static const struct dev_pm_ops adc_pm_ops = {
529 	.suspend	= s3c_adc_suspend,
530 	.resume		= s3c_adc_resume,
531 };
532 
533 static struct platform_driver s3c_adc_driver = {
534 	.id_table	= s3c_adc_driver_ids,
535 	.driver		= {
536 		.name	= "s3c-adc",
537 		.owner	= THIS_MODULE,
538 		.pm	= &adc_pm_ops,
539 	},
540 	.probe		= s3c_adc_probe,
541 	.remove		= __devexit_p(s3c_adc_remove),
542 };
543 
adc_init(void)544 static int __init adc_init(void)
545 {
546 	int ret;
547 
548 	ret = platform_driver_register(&s3c_adc_driver);
549 	if (ret)
550 		printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
551 
552 	return ret;
553 }
554 
555 module_init(adc_init);
556