aboutsummaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-s3c2410/include/mach/ts.h35
-rw-r--r--arch/arm/plat-s3c/include/plat/devs.h2
-rw-r--r--arch/arm/plat-s3c24xx/adc.c58
-rw-r--r--arch/arm/plat-s3c24xx/devs.c20
4 files changed, 108 insertions, 7 deletions
diff --git a/arch/arm/mach-s3c2410/include/mach/ts.h b/arch/arm/mach-s3c2410/include/mach/ts.h
new file mode 100644
index 00000000000..ac0c727d155
--- /dev/null
+++ b/arch/arm/mach-s3c2410/include/mach/ts.h
@@ -0,0 +1,35 @@
+/* arch/arm/mach-s3c2410/include/mach/ts.h
+ *
+ * Copyright (c) 2005 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ * Changelog:
+ * 24-Mar-2005 RTP Created file
+ * 03-Aug-2005 RTP Renamed to ts.h
+ */
+
+#ifndef __ASM_ARM_TS_H
+#define __ASM_ARM_TS_H
+
+#include <linux/input/touchscreen/ts_filter.h>
+
+struct s3c2410_ts_mach_info {
+ /* Touchscreen delay. */
+ int delay;
+ /* Prescaler value. */
+ int presc;
+ /*
+ * Null-terminated array of pointers to filter APIs and configurations
+ * we want to use. In the same order they will be applied.
+ */
+ const struct ts_filter_chain_configuration *filter_config;
+};
+
+void set_s3c2410ts_info(const struct s3c2410_ts_mach_info *hard_s3c2410ts_info);
+
+#endif /* __ASM_ARM_TS_H */
diff --git a/arch/arm/plat-s3c/include/plat/devs.h b/arch/arm/plat-s3c/include/plat/devs.h
index 0f540ea1e99..50d50a2f086 100644
--- a/arch/arm/plat-s3c/include/plat/devs.h
+++ b/arch/arm/plat-s3c/include/plat/devs.h
@@ -53,6 +53,8 @@ extern struct platform_device s3c_device_nand;
extern struct platform_device s3c_device_usbgadget;
extern struct platform_device s3c_device_usb_hsotg;
+extern struct platform_device s3c_device_ts;
+
/* s3c2440 specific devices */
#ifdef CONFIG_CPU_S3C2440
diff --git a/arch/arm/plat-s3c24xx/adc.c b/arch/arm/plat-s3c24xx/adc.c
index df47322492d..8c443153d05 100644
--- a/arch/arm/plat-s3c24xx/adc.c
+++ b/arch/arm/plat-s3c24xx/adc.c
@@ -46,6 +46,7 @@ struct s3c_adc_client {
int result;
unsigned char is_ts;
unsigned char channel;
+ unsigned int selected;
void (*select_cb)(struct s3c_adc_client *c, unsigned selected);
void (*convert_cb)(struct s3c_adc_client *c,
@@ -62,20 +63,31 @@ struct adc_device {
void __iomem *regs;
unsigned int prescale;
+ unsigned int delay;
int irq;
};
static struct adc_device *adc_dev;
+static struct work_struct resume_work;
+
static LIST_HEAD(adc_pending);
#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
+#define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | \
+ S3C2410_ADCTSC_XP_SEN | S3C2410_ADCTSC_AUTO_PST | \
+ S3C2410_ADCTSC_XY_PST(0))
+
static inline void s3c_adc_convert(struct adc_device *adc)
{
unsigned con = readl(adc->regs + S3C2410_ADCCON);
+ if (adc->cur->is_ts)
+ writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
+ adc->regs + S3C2410_ADCTSC);
+
con |= S3C2410_ADCCON_ENABLE_START;
writel(con, adc->regs + S3C2410_ADCCON);
}
@@ -85,7 +97,10 @@ static inline void s3c_adc_select(struct adc_device *adc,
{
unsigned con = readl(adc->regs + S3C2410_ADCCON);
- client->select_cb(client, 1);
+ if (!client->selected) {
+ client->selected = 1;
+ client->select_cb(client, 1);
+ }
con &= ~S3C2410_ADCCON_MUXMASK;
con &= ~S3C2410_ADCCON_STDBM;
@@ -109,12 +124,9 @@ static void s3c_adc_try(struct adc_device *adc)
{
struct s3c_adc_client *next = adc->ts_pend;
- if (!next && !list_empty(&adc_pending)) {
+ if (!next && !list_empty(&adc_pending))
next = list_first_entry(&adc_pending,
struct s3c_adc_client, pend);
- list_del(&next->pend);
- } else
- adc->ts_pend = NULL;
if (next) {
adc_dbg(adc, "new client is %p\n", next);
@@ -277,14 +289,20 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
if (client->nr_samples > 0) {
/* fire another conversion for this */
-
+ client->selected = 1;
client->select_cb(client, 1);
s3c_adc_convert(adc);
} else {
local_irq_save(flags);
- (client->select_cb)(client, 0);
+ client->selected = 0;
+ if (!adc->cur->is_ts)
+ list_del(&adc->cur->pend);
+ else
+ adc->ts_pend = NULL;
adc->cur = NULL;
+ (client->select_cb)(client, 0);
+
s3c_adc_try(adc);
local_irq_restore(flags);
}
@@ -307,6 +325,7 @@ static int s3c_adc_probe(struct platform_device *pdev)
adc->pdev = pdev;
adc->prescale = S3C2410_ADCCON_PRSCVL(49);
+ adc->delay = 0x2710;
adc->irq = platform_get_irq(pdev, 1);
if (adc->irq <= 0) {
@@ -346,6 +365,7 @@ static int s3c_adc_probe(struct platform_device *pdev)
writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
adc->regs + S3C2410_ADCCON);
+ writel(adc->delay, adc->regs + S3C2410_ADCDLY);
dev_info(dev, "attached adc driver\n");
@@ -389,18 +409,42 @@ static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
writel(con, adc->regs + S3C2410_ADCCON);
clk_disable(adc->clk);
+ disable_irq(IRQ_ADC);
+ if (!list_empty(&adc_pending) || adc->ts_pend)
+ dev_info(&pdev->dev, "We still have adc clients pending\n");
return 0;
}
+/* It seems this is not needed. This is under upstream review now. */
+static void adc_resume_work(struct work_struct *work)
+{
+ if (!adc_dev) /* Have no ADC here */
+ return;
+
+ if (!list_empty(&adc_pending) || adc_dev->ts_pend)
+ /* We still have adc clients pending */
+ s3c_adc_try(adc_dev);
+}
+
static int s3c_adc_resume(struct platform_device *pdev)
{
struct adc_device *adc = platform_get_drvdata(pdev);
+ enable_irq(IRQ_ADC);
clk_enable(adc->clk);
writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
adc->regs + S3C2410_ADCCON);
+ writel(adc->delay, adc->regs + S3C2410_ADCDLY);
+
+ /* Schedule task if there are clients pending. */
+ if (!list_empty(&adc_pending) || adc_dev->ts_pend) {
+ INIT_WORK(&resume_work, adc_resume_work);
+ if (!schedule_work(&resume_work))
+ dev_err(&pdev->dev,
+ "Failed to schedule adc_resume work!\n");
+ }
return 0;
}
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index f52a92ce8dd..9ef0e97d56e 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -30,6 +30,8 @@
#include <mach/irqs.h>
#include <asm/irq.h>
+#include <mach/ts.h>
+
#include <plat/regs-serial.h>
#include <plat/udc.h>
@@ -182,6 +184,24 @@ void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)
}
}
+/* Touchscreen */
+
+struct platform_device s3c_device_ts = {
+ .name = "s3c2410-ts",
+ .id = -1,
+ .dev.parent = &s3c_device_adc.dev,
+};
+
+static struct s3c2410_ts_mach_info s3c2410ts_info;
+
+void set_s3c2410ts_info(const struct s3c2410_ts_mach_info *hard_s3c2410ts_info)
+{
+ memcpy(&s3c2410ts_info, hard_s3c2410ts_info,
+ sizeof(struct s3c2410_ts_mach_info));
+ s3c_device_ts.dev.platform_data = &s3c2410ts_info;
+}
+EXPORT_SYMBOL(set_s3c2410ts_info);
+
/* USB Device (Gadget)*/
static struct resource s3c_usbgadget_resource[] = {