diff options
-rw-r--r-- | arch/arm/mach-s3c2410/include/mach/gta02-pm-wlan.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/mach-gta02.c | 16 | ||||
-rw-r--r-- | arch/arm/mach-s3c6410/mach-om-gta03.c | 4 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/gta02_pm_wlan.c | 16 | ||||
-rw-r--r-- | drivers/ar6000/hif/hif2.c | 70 | ||||
-rw-r--r-- | drivers/input/touchscreen/s3c2410_ts.c | 102 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter.c | 3 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_mean.c | 6 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_median.c | 3 |
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 = >a02_usb_info; s3c_device_nand.dev.platform_data = >a02_nand_info; + s3c_device_sdi.dev.platform_data = >a02_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); } |