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
42enum 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
50struct 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
66struct 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
81static struct adc_device *adc_dev;
82
83static LIST_HEAD(adc_pending);	/* protected by adc_device.lock */
84
85#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
86
87static 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
95static 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
121static 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
129static 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
149int 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}
182EXPORT_SYMBOL_GPL(s3c_adc_start);
183
184static 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
191int 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
213err:
214	return ret;
215}
216EXPORT_SYMBOL_GPL(s3c_adc_read);
217
218static void s3c_adc_default_select(struct s3c_adc_client *client,
219				   unsigned select)
220{
221}
222
223struct 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}
254EXPORT_SYMBOL_GPL(s3c_adc_register);
255
256void 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}
284EXPORT_SYMBOL_GPL(s3c_adc_release);
285
286static 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
330exit:
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
338static 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
412static 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
423static 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
445static 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
478static 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};
497MODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids);
498
499static const struct dev_pm_ops adc_pm_ops = {
500	.suspend	= s3c_adc_suspend,
501	.resume		= s3c_adc_resume,
502};
503
504static struct platform_driver s3c_adc_driver = {
505	.id_table	= s3c_adc_driver_ids,
506	.driver		= {
507		.name	= "s3c-adc",
508		.pm	= &adc_pm_ops,
509	},
510	.probe		= s3c_adc_probe,
511	.remove		= s3c_adc_remove,
512};
513
514static int __init adc_init(void)
515{
516	int ret;
517
518	ret = platform_driver_register(&s3c_adc_driver);
519	if (ret)
520		printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
521
522	return ret;
523}
524
525module_init(adc_init);
526