aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-s3c2410/include/mach/gta02-pm-wlan.h1
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c16
-rw-r--r--arch/arm/mach-s3c6410/mach-om-gta03.c4
-rw-r--r--arch/arm/plat-s3c24xx/gta02_pm_wlan.c16
-rw-r--r--drivers/ar6000/hif/hif2.c70
-rw-r--r--drivers/input/touchscreen/s3c2410_ts.c102
-rw-r--r--drivers/input/touchscreen/ts_filter.c3
-rw-r--r--drivers/input/touchscreen/ts_filter_mean.c6
-rw-r--r--drivers/input/touchscreen/ts_filter_median.c3
9 files changed, 141 insertions, 80 deletions
diff --git a/arch/arm/mach-s3c2410/include/mach/gta02-pm-wlan.h b/arch/arm/mach-s3c2410/include/mach/gta02-pm-wlan.h
new file mode 100644
index 00000000000..8e4ccf241fc
--- /dev/null
+++ b/arch/arm/mach-s3c2410/include/mach/gta02-pm-wlan.h
@@ -0,0 +1 @@
+void gta02_wlan_power(int on);
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index e9a32b5874b..2baf38f9f95 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -88,6 +88,7 @@
#include <plat/iic.h>
#include <asm/plat-s3c24xx/neo1973.h>
#include <mach/neo1973-pm-gsm.h>
+#include <mach/gta02-pm-wlan.h>
#include <linux/jbt6k74.h>
@@ -955,6 +956,20 @@ static struct s3c2410_platform_nand gta02_nand_info = {
.software_ecc = 1,
};
+
+static void gta02_s3c_mmc_set_power(unsigned char power_mode,
+ unsigned short vdd)
+{
+ gta02_wlan_power(
+ power_mode == MMC_POWER_ON ||
+ power_mode == MMC_POWER_UP);
+}
+
+
+static struct s3c24xx_mci_pdata gta02_s3c_mmc_cfg = {
+ .set_power = gta02_s3c_mmc_set_power,
+};
+
static void gta02_udc_command(enum s3c2410_udc_cmd_e cmd)
{
printk(KERN_DEBUG "%s(%d)\n", __func__, cmd);
@@ -1674,6 +1689,7 @@ static void __init gta02_machine_init(void)
s3c_device_usb.dev.platform_data = &gta02_usb_info;
s3c_device_nand.dev.platform_data = &gta02_nand_info;
+ s3c_device_sdi.dev.platform_data = &gta02_s3c_mmc_cfg;
/* acc sensor chip selects */
s3c2410_gpio_setpin(S3C2410_GPD12, 1);
diff --git a/arch/arm/mach-s3c6410/mach-om-gta03.c b/arch/arm/mach-s3c6410/mach-om-gta03.c
index 9306236cb63..02c1c967db9 100644
--- a/arch/arm/mach-s3c6410/mach-om-gta03.c
+++ b/arch/arm/mach-s3c6410/mach-om-gta03.c
@@ -136,8 +136,6 @@ static void __gta03_lis302dl_bitbang(struct lis302dl_info *lis, u8 *tx,
int n;
u8 shifter = 0;
- printk(KERN_INFO "__gta03_lis302dl_bitbang\n");
-
gpio_direction_output(pdata->pin_chip_select, 1);
gpio_direction_output(pdata->pin_clk, 1);
gpio_direction_output(pdata->pin_chip_select, 0);
@@ -225,7 +223,7 @@ void gta03_lis302dl_suspend_io(struct lis302dl_info *lis, int resume)
struct lis302dl_platform_data lis302_pdata = {
.name = "lis302",
- .pin_chip_select= S3C64XX_GPN(15), /* NC */
+ .pin_chip_select= S3C64XX_GPC(3), /* NC */
.pin_clk = GTA03_GPIO_ACCEL_CLK,
.pin_mosi = GTA03_GPIO_ACCEL_MOSI,
.pin_miso = GTA03_GPIO_ACCEL_MISO,
diff --git a/arch/arm/plat-s3c24xx/gta02_pm_wlan.c b/arch/arm/plat-s3c24xx/gta02_pm_wlan.c
index b55ba241494..3a0d24079da 100644
--- a/arch/arm/plat-s3c24xx/gta02_pm_wlan.c
+++ b/arch/arm/plat-s3c24xx/gta02_pm_wlan.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <mach/hardware.h>
@@ -21,13 +22,14 @@
#include <asm/plat-s3c24xx/neo1973.h>
#include <mach/gta02.h>
+#include <mach/gta02-pm-wlan.h>
#include <mach/regs-gpio.h>
#include <mach/regs-gpioj.h>
#include <linux/delay.h>
-static void gta02_wlan_power(int on)
+static void __gta02_wlan_power(int on)
{
if (!on) {
s3c2410_gpio_setpin(GTA02_CHIP_PWD, 1);
@@ -43,7 +45,19 @@ static void gta02_wlan_power(int on)
s3c2410_gpio_setpin(GTA02_CHIP_PWD, 0);
msleep(100);
s3c2410_gpio_setpin(GTA02_GPIO_nWLAN_RESET, 1);
+}
+void gta02_wlan_power(int on)
+{
+ static DEFINE_MUTEX(lock);
+ static int is_on = -1; /* initial state is unknown */
+
+ on = !!on; /* normalize */
+ mutex_lock(&lock);
+ if (on != is_on)
+ __gta02_wlan_power(on);
+ is_on = on;
+ mutex_unlock(&lock);
}
static ssize_t gta02_wlan_read(struct device *dev,
diff --git a/drivers/ar6000/hif/hif2.c b/drivers/ar6000/hif/hif2.c
index 6f2030777c3..8d3095ff1c5 100644
--- a/drivers/ar6000/hif/hif2.c
+++ b/drivers/ar6000/hif/hif2.c
@@ -36,7 +36,6 @@
* KNOWN BUGS:
*
* - HIF_DEVICE_IRQ_ASYNC_SYNC doesn't work yet (gets MMC errors)
- * - driver doesn't remove cleanly yet
* - latency can reach hundreds of ms, probably because of scheduling delays
* - packets go through about three queues before finally hitting the network
*/
@@ -111,6 +110,11 @@ struct hif_request {
static HTC_CALLBACKS htcCallbacks;
+/*
+ * shutdown_lock prevents recursion through HIFShutDownDevice
+ */
+static DEFINE_MUTEX(shutdown_lock);
+
/* ----- Request processing ------------------------------------------------ */
@@ -521,16 +525,21 @@ static void sdio_ar6000_remove(struct sdio_func *func)
HIF_DEVICE *hif = sdio_get_drvdata(func);
int ret;
-#if 0
- /*
- * Funny, Atheros' HIF does this call, but this just puts us in a
- * recursion through HTCShutDown/HIFShutDown if unloading the
- * module.
- */
- ret = htcCallbacks.deviceRemovedHandler(hif->htc_handle, A_OK);
- if (ret != A_OK)
- dev_err(dev, "deviceRemovedHandler: %d\n", ret);
-#endif
+ dev_dbg(dev, "sdio_ar6000_remove\n");
+ if (mutex_trylock(&shutdown_lock)) {
+ /*
+ * Funny, Atheros' HIF does this call, but this just puts us in
+ * a recursion through HTCShutDown/HIFShutDown if unloading the
+ * module.
+ *
+ * However, we need it for suspend/resume. See the comment at
+ * HIFShutDown, below.
+ */
+ ret = htcCallbacks.deviceRemovedHandler(hif->htc_handle, A_OK);
+ if (ret != A_OK)
+ dev_err(dev, "deviceRemovedHandler: %d\n", ret);
+ mutex_unlock(&shutdown_lock);
+ }
wait_queue_empty(hif);
ret = kthread_stop(hif->io_task);
if (ret)
@@ -591,8 +600,45 @@ int HIFInit(HTC_CALLBACKS *callbacks)
}
+/*
+ * We have three possible call chains here:
+ *
+ * System shutdown/reboot:
+ *
+ * kernel_restart_prepare ...> device_shutdown ... > s3cmci_shutdown ->
+ * mmc_remove_host ..> sdio_bus_remove -> sdio_ar6000_remove ->
+ * deviceRemovedHandler (HTCTargetRemovedHandler) -> HIFShutDownDevice
+ *
+ * This is roughly the same sequence as suspend, described below.
+ *
+ * Module removal:
+ *
+ * sys_delete_module -> ar6000_cleanup_module -> HTCShutDown ->
+ * HIFShutDownDevice -> sdio_unregister_driver ...> sdio_bus_remove ->
+ * sdio_ar6000_remove
+ *
+ * In this case, HIFShutDownDevice must call sdio_unregister_driver to
+ * notify the driver about its removal. sdio_ar6000_remove must not call
+ * deviceRemovedHandler, because that would loop back into HIFShutDownDevice.
+ *
+ * Suspend:
+ *
+ * device_suspend ...> s3cmci_suspend ...> sdio_bus_remove ->
+ * sdio_ar6000_remove -> deviceRemovedHandler (HTCTargetRemovedHandler) ->
+ * HIFShutDownDevice
+ *
+ * We must call deviceRemovedHandler to inform the ar6k stack that the device
+ * has been removed. Since HTCTargetRemovedHandler calls back into
+ * HIFShutDownDevice, we must also prevent the call to
+ * sdio_unregister_driver, or we'd end up recursing into the SDIO stack,
+ * eventually deadlocking somewhere.
+ */
+
void HIFShutDownDevice(HIF_DEVICE *hif)
{
/* Beware, HTCShutDown calls us with hif == NULL ! */
- sdio_unregister_driver(&sdio_ar6000_driver);
+ if (mutex_trylock(&shutdown_lock)) {
+ sdio_unregister_driver(&sdio_ar6000_driver);
+ mutex_unlock(&shutdown_lock);
+ }
}
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
index 8f0afc3e023..8e580a833e5 100644
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ b/drivers/input/touchscreen/s3c2410_ts.c
@@ -98,9 +98,10 @@ static char *s3c2410ts_name = "s3c2410 TouchScreen";
struct s3c2410ts {
struct input_dev *dev;
- int flag_first_touch_sent;
struct ts_filter *tsf[MAX_TS_FILTER_CHAIN];
int coords[2]; /* just X and Y for us */
+ int is_down;
+ int need_to_send_first_touch;
};
static struct s3c2410ts ts;
@@ -116,69 +117,58 @@ static inline void s3c2410_ts_connect(void)
s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);
}
-static void touch_timer_fire(unsigned long data)
-{
- unsigned long data0;
- unsigned long data1;
- int updown;
-
- data0 = readl(base_addr + S3C2410_ADCDAT0);
- data1 = readl(base_addr + S3C2410_ADCDAT1);
+enum ts_input_event {IE_DOWN = 0, IE_UP, IE_UPDATE};
- updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
- (!(data1 & S3C2410_ADCDAT0_UPDOWN));
-
- // if we need to send an untouch event, but we haven't yet sent the
- // touch event (this happens if the touchscreen was tapped lightly),
- // send the touch event first
- if (!updown && !ts.flag_first_touch_sent) {
- if (ts.tsf[0])
- (ts.tsf[0]->api->scale)(ts.tsf[0], &ts.coords[0]);
+static void ts_input_report(int event)
+{
+ if (event == IE_DOWN || event == IE_UPDATE) {
input_report_abs(ts.dev, ABS_X, ts.coords[0]);
input_report_abs(ts.dev, ABS_Y, ts.coords[1]);
-
input_report_key(ts.dev, BTN_TOUCH, 1);
input_report_abs(ts.dev, ABS_PRESSURE, 1);
- input_sync(ts.dev);
- ts.flag_first_touch_sent = 1;
+ } else {
+ input_report_key(ts.dev, BTN_TOUCH, 0);
+ input_report_abs(ts.dev, ABS_PRESSURE, 0);
}
- if (updown) {
-
- if (ts.tsf[0])
- (ts.tsf[0]->api->scale)(ts.tsf[0], &ts.coords[0]);
+ input_sync(ts.dev);
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
- {
- struct timeval tv;
-
- do_gettimeofday(&tv);
- printk(DEBUG_LVL "T:%06d, X:%03ld, Y:%03ld\n",
- (int)tv.tv_usec, ts.coords[0], ts.coords[1]);
- }
+ {
+ static char *s[] = {"down", "up", "update"};
+ struct timeval tv;
+ do_gettimeofday(&tv);
+ printk(DEBUG_LVL "T:%06d %6s (X:%03d, Y:%03d)\n",
+ (int)tv.tv_usec, s[event], ts.coords[0], ts.coords[1]);
+ }
#endif
+}
+static void touch_timer_fire(unsigned long data)
+{
+ if (ts.tsf[0])
+ (ts.tsf[0]->api->scale)(ts.tsf[0], &ts.coords[0]);
+
+ if (ts.need_to_send_first_touch) {
+ ts.need_to_send_first_touch = 0;
+ ts_input_report(IE_DOWN);
+ if (!ts.is_down) { /* Do we need this? I think so. */
+ ts_input_report(IE_UPDATE);
+ ts_input_report(IE_UP);
+ }
+ } else if (ts.is_down) {
+ ts_input_report(IE_UPDATE);
+ } else {
+ ts_input_report(IE_UP);
+ }
- input_report_abs(ts.dev, ABS_X, ts.coords[0]);
- input_report_abs(ts.dev, ABS_Y, ts.coords[1]);
-
- input_report_key(ts.dev, BTN_TOUCH, 1);
- input_report_abs(ts.dev, ABS_PRESSURE, 1);
- input_sync(ts.dev);
-
+ if (ts.is_down) {
writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
base_addr+S3C2410_ADCTSC);
writel(readl(base_addr+S3C2410_ADCCON) |
S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
} else {
-
if (ts.tsf[0])
(ts.tsf[0]->api->clear)(ts.tsf[0]);
-
- input_report_key(ts.dev, BTN_TOUCH, 0);
- input_report_abs(ts.dev, ABS_PRESSURE, 0);
- input_sync(ts.dev);
- ts.flag_first_touch_sent = 0;
-
writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
}
}
@@ -190,20 +180,20 @@ static irqreturn_t stylus_updown(int irq, void *dev_id)
{
unsigned long data0;
unsigned long data1;
- int updown;
data0 = readl(base_addr+S3C2410_ADCDAT0);
data1 = readl(base_addr+S3C2410_ADCDAT1);
- updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
+ ts.is_down = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
(!(data1 & S3C2410_ADCDAT0_UPDOWN));
- /* TODO we should never get an interrupt with updown set while
- * the timer is running, but maybe we ought to verify that the
- * timer isn't running anyways. */
-
- if (updown)
- touch_timer_fire(0);
+ if (ts.is_down) {
+ ts.need_to_send_first_touch = 1;
+ writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
+ base_addr+S3C2410_ADCTSC);
+ writel(readl(base_addr+S3C2410_ADCCON) |
+ S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
+ }
return IRQ_HANDLED;
}
@@ -336,7 +326,9 @@ static int __init s3c2410ts_probe(struct platform_device *pdev)
else /* this is OK, just means there won't be any filtering */
dev_info(&pdev->dev, "Unfiltered output selected\n");
- if (!ts.tsf[0])
+ if (ts.tsf[0])
+ (ts.tsf[0]->api->clear)(ts.tsf[0]);
+ else
dev_info(&pdev->dev, "No filtering\n");
/* Get irqs */
diff --git a/drivers/input/touchscreen/ts_filter.c b/drivers/input/touchscreen/ts_filter.c
index f8b2b2f5846..4c650a5c66f 100644
--- a/drivers/input/touchscreen/ts_filter.c
+++ b/drivers/input/touchscreen/ts_filter.c
@@ -49,9 +49,12 @@ EXPORT_SYMBOL_GPL(ts_filter_create_chain);
void ts_filter_destroy_chain(struct ts_filter **list)
{
+ struct ts_filter **first;
+ first = list;
while (*list) {
((*list)->api->destroy)(*list);
list++;
}
+ *first = NULL;
}
EXPORT_SYMBOL_GPL(ts_filter_destroy_chain);
diff --git a/drivers/input/touchscreen/ts_filter_mean.c b/drivers/input/touchscreen/ts_filter_mean.c
index b589bee826f..2322432fc3f 100644
--- a/drivers/input/touchscreen/ts_filter_mean.c
+++ b/drivers/input/touchscreen/ts_filter_mean.c
@@ -94,12 +94,6 @@ static void ts_filter_mean_destroy(struct ts_filter *tsf)
{
struct ts_filter_mean *tsfs = (struct ts_filter_mean *)tsf;
- if (!tsf)
- return;
-
- if (tsf->next) /* chain */
- (tsf->next->api->destroy)(tsf->next);
-
kfree(tsfs->fifo[0]); /* first guy has pointer from kmalloc */
kfree(tsf);
}
diff --git a/drivers/input/touchscreen/ts_filter_median.c b/drivers/input/touchscreen/ts_filter_median.c
index fe1b35f110b..47970da3c6a 100644
--- a/drivers/input/touchscreen/ts_filter_median.c
+++ b/drivers/input/touchscreen/ts_filter_median.c
@@ -119,9 +119,6 @@ static void ts_filter_median_destroy(struct ts_filter *tsf)
{
struct ts_filter_median *tsfm = (struct ts_filter_median *)tsf;
- if (tsf->next) /* chain */
- (tsf->next->api->destroy)(tsf->next);
-
kfree(tsfm->sort[0]); /* first guy has pointer from kmalloc */
kfree(tsf);
}