diff options
-rw-r--r-- | arch/arm/mach-s3c2442/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/mach-s3c2442/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c2442/gta02-fiq.c | 135 | ||||
-rw-r--r-- | arch/arm/mach-s3c2442/include/mach/gta02-fiq.h | 9 | ||||
-rw-r--r-- | arch/arm/mach-s3c2442/include/mach/gta02.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-s3c2442/mach-gta02.c | 63 |
6 files changed, 212 insertions, 2 deletions
diff --git a/arch/arm/mach-s3c2442/Kconfig b/arch/arm/mach-s3c2442/Kconfig index 2e33904759c..194d128c695 100644 --- a/arch/arm/mach-s3c2442/Kconfig +++ b/arch/arm/mach-s3c2442/Kconfig @@ -34,6 +34,9 @@ config MACH_NEO1973_GTA02 select MACH_NEO1973 select S3C2410_PWM select S3C_DEV_USB_HOST + select FIQ + select S3C_PWM + select S3C24XX_GPIO_EXTRA64 select S3C_DEV_NAND help Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone diff --git a/arch/arm/mach-s3c2442/Makefile b/arch/arm/mach-s3c2442/Makefile index ebe0579c537..6247ca03eae 100644 --- a/arch/arm/mach-s3c2442/Makefile +++ b/arch/arm/mach-s3c2442/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_CPU_S3C2442) += s3c2442.o obj-$(CONFIG_CPU_S3C2442) += clock.o obj-$(CONFIG_MACH_NEO1973_GTA02) += mach-gta02.o \ + gta02-fiq.o \ gta02-pm-bt.o \ gta02-pm-gps.o \ gta02-pm-gsm.o \ diff --git a/arch/arm/mach-s3c2442/gta02-fiq.c b/arch/arm/mach-s3c2442/gta02-fiq.c new file mode 100644 index 00000000000..d91c52341d5 --- /dev/null +++ b/arch/arm/mach-s3c2442/gta02-fiq.c @@ -0,0 +1,135 @@ +#include <linux/kernel.h> + +#include <asm/fiq.h> +#include <mach/regs-irq.h> +#include <plat/regs-timer.h> +#include <mach/irqs.h> +#include <linux/io.h> +#include <linux/pwm.h> +#include <linux/err.h> +#include <linux/hdq.h> + +/* ------------------------------------------------------------------------------- + * GTA02 FIQ related + * + * Calls into vibrator and hdq and based on the return values + * determines if we the FIQ source be kept alive + */ + +#define DIVISOR_FROM_US(x) ((x) << 3) + +#ifdef CONFIG_HDQ_GPIO_BITBANG +#define FIQ_DIVISOR_HDQ DIVISOR_FROM_US(HDQ_SAMPLE_PERIOD_US) +extern int hdq_fiq_handler(void); +#endif + +/* Global data related to our fiq source */ +static uint32_t gta02_fiq_ack_mask; +static const int gta02_gta02_fiq_timer_id = 2; + +struct pwm_device* gta02_fiq_timer; + +void gta02_fiq_handler(void) +{ + unsigned long intmask; + int keep_running = 0; + /* disable further timer interrupts if nobody has any work + * or adjust rate according to who still has work + * + * CAUTION: it means forground code must disable FIQ around + * its own non-atomic S3C2410_INTMSK changes... not common + * thankfully and taken care of by the fiq-basis patch + */ + +#ifdef CONFIG_HDQ_GPIO_BITBANG + keep_running = hdq_fiq_handler(); +#endif + if (!keep_running) { + /* Disable irq */ + intmask = __raw_readl(S3C2410_INTMSK); + intmask |= (gta02_fiq_ack_mask); + __raw_writel(intmask, S3C2410_INTMSK); + } + + __raw_writel(gta02_fiq_ack_mask, S3C2410_SRCPND); +} + +void gta02_fiq_kick(void) +{ + unsigned long flags; + unsigned long intmask; + /* we have to take care about FIQ because this modification is + * non-atomic, FIQ could come in after the read and before the + * writeback and its changes to the register would be lost + * (platform INTMSK mod code is taken care of already) + */ + local_save_flags(flags); + local_fiq_disable(); + + /* allow FIQs to resume */ + intmask = __raw_readl(S3C2410_INTMSK); + intmask &= ~(gta02_fiq_ack_mask); + __raw_writel(intmask, S3C2410_INTMSK); + + local_irq_restore(flags); + +} + +int gta02_fiq_enable(void) +{ + int ret = 0; + + local_fiq_disable(); + + gta02_fiq_timer = pwm_request(gta02_gta02_fiq_timer_id, "fiq timer"); + + if (IS_ERR(gta02_fiq_timer)) { + ret = PTR_ERR(gta02_fiq_timer); + printk("GTA02 FIQ: Could not request fiq timer: %d\n", ret); + return ret; + } + + gta02_fiq_ack_mask = 1 << (IRQ_TIMER0 + gta02_gta02_fiq_timer_id + - S3C2410_CPUIRQ_OFFSET); + + + ret = pwm_config(gta02_fiq_timer, HDQ_SAMPLE_PERIOD_US * 1000, + HDQ_SAMPLE_PERIOD_US * 1000); + if (ret) { + printk("GTA02 FIQ: Could not configure fiq timer: %d\n", ret); + goto err; + } + + set_fiq_c_handler(gta02_fiq_handler); + + __raw_writel(gta02_fiq_ack_mask, S3C2410_INTMOD); + + pwm_enable(gta02_fiq_timer); + + local_fiq_enable(); + + return 0; + +err: + pwm_free(gta02_fiq_timer); + + return ret; +} + +void gta02_fiq_disable(void) +{ + local_fiq_disable(); + + if (!gta02_fiq_timer) + return; + + __raw_writel(0, S3C2410_INTMOD); + set_fiq_c_handler(NULL); + + pwm_disable(gta02_fiq_timer); + + pwm_free(gta02_fiq_timer); + + gta02_fiq_timer = NULL; +} +/* -------------------- /GTA02 FIQ Handler ------------------------------------- */ diff --git a/arch/arm/mach-s3c2442/include/mach/gta02-fiq.h b/arch/arm/mach-s3c2442/include/mach/gta02-fiq.h new file mode 100644 index 00000000000..90de3530595 --- /dev/null +++ b/arch/arm/mach-s3c2442/include/mach/gta02-fiq.h @@ -0,0 +1,9 @@ +#ifndef __GTA02_FIQ_H +#define __GTA02_FIQ_H + +extern void gta02_fiq_handler(void); +extern void gta02_fiq_kick(void); +extern int gta02_fiq_enable(void); +extern void gta02_fiq_disable(void); + +#endif diff --git a/arch/arm/mach-s3c2442/include/mach/gta02.h b/arch/arm/mach-s3c2442/include/mach/gta02.h index 11624c0b926..b67e5ec2919 100644 --- a/arch/arm/mach-s3c2442/include/mach/gta02.h +++ b/arch/arm/mach-s3c2442/include/mach/gta02.h @@ -80,6 +80,9 @@ #define GTA02_PCB_ID2_0 S3C2410_GPD(3) #define GTA02_PCB_ID2_1 S3C2410_GPD(4) +#define GTA02_GPIO_GLAMO_BASE S3C_GPIO_END +#define GTA02_GPIO_GLAMO(x) (GTA02_GPIO_GLAMO_BASE + (x)) + int gta02_get_pcb_revision(void); extern struct pcf50633 *gta02_pcf; diff --git a/arch/arm/mach-s3c2442/mach-gta02.c b/arch/arm/mach-s3c2442/mach-gta02.c index 841dff64e3f..1480881268c 100644 --- a/arch/arm/mach-s3c2442/mach-gta02.c +++ b/arch/arm/mach-s3c2442/mach-gta02.c @@ -109,6 +109,15 @@ #include <linux/platform_battery.h> +#include <mach/ts.h> +#include <linux/input/touchscreen/ts_filter_chain.h> +#ifdef CONFIG_TOUCHSCREEN_FILTER +#include <linux/input/touchscreen/ts_filter_linear.h> +#include <linux/input/touchscreen/ts_filter_mean.h> +#include <linux/input/touchscreen/ts_filter_median.h> +#include <linux/input/touchscreen/ts_filter_group.h> +#endif + struct pcf50633 *gta02_pcf; /* @@ -519,7 +528,8 @@ struct pcf50633_platform_data gta02_pcf_pdata = { .max_uV = 3300000, .valid_modes_mask = REGULATOR_MODE_NORMAL, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | - REGULATOR_CHANGE_STATUS, + REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, }, .num_consumer_supplies = ARRAY_SIZE(hcldo_consumers), .consumer_supplies = hcldo_consumers, @@ -981,6 +991,51 @@ static struct platform_device gta02_pwm_leds_device = { } }; +/* Touchscreen configuration. */ + +#ifdef CONFIG_TOUCHSCREEN_FILTER +const static struct ts_filter_group_configuration gta02_ts_group = { + .length = 12, + .close_enough = 10, + .threshold = 6, /* At least half of the points in a group. */ + .attempts = 10, +}; + +const static struct ts_filter_median_configuration gta02_ts_median = { + .extent = 20, + .decimation_below = 3, + .decimation_threshold = 8 * 3, + .decimation_above = 4, +}; + +const static struct ts_filter_mean_configuration gta02_ts_mean = { + .length = 4, +}; + +const static struct ts_filter_linear_configuration gta02_ts_linear = { + .constants = {1, 0, 0, 0, 1, 0, 1}, /* Don't modify coords. */ + .coord0 = 0, + .coord1 = 1, +}; +#endif + +const static struct ts_filter_chain_configuration gta02_filter_configuration[] = +{ +#ifdef CONFIG_TOUCHSCREEN_FILTER + {&ts_filter_group_api, >a02_ts_group.config}, + {&ts_filter_median_api, >a02_ts_median.config}, + {&ts_filter_mean_api, >a02_ts_mean.config}, + {&ts_filter_linear_api, >a02_ts_linear.config}, +#endif + {NULL, NULL}, +}; + +const static struct s3c2410_ts_mach_info gta02_ts_cfg = { + .delay = 10000, + .presc = 0xff, /* slow as we can go */ + .filter_config = gta02_filter_configuration, +}; + struct hdq_platform_data gta02_hdq_platform_data = { .attach_child_devices = gta02_hdq_attach_child_devices, .gpio_dir_out = gta02_hdq_gpio_direction_out, @@ -1000,7 +1055,7 @@ struct platform_device gta02_hdq_device = { .resource = gta02_hdq_resources, .dev = { .platform_data = >a02_hdq_platform_data, - .parent = &s3c_device_timer[0].dev, + .parent = &s3c_device_timer[2].dev, }, }; @@ -1039,6 +1094,7 @@ static struct platform_device *gta02_devices[] __initdata = { /* These guys DO need to be children of PMU. */ static struct platform_device *gta02_devices_pmu_children[] = { + &s3c_device_ts, >a02_glamo_dev, &s3c_device_timer[2], >a02_hdq_device, @@ -1168,6 +1224,8 @@ static void __init gta02_machine_init(void) /* Set the panic callback to make AUX LED blink at ~5Hz. */ panic_blink = gta02_panic_blink; + s3c_device_ts.name = "s3c2440-ts"; + gta02_hijack_gpb(); gta02_request_gpios(); @@ -1183,6 +1241,7 @@ static void __init gta02_machine_init(void) s3c24xx_udc_set_platdata(>a02_udc_cfg); s3c_i2c0_set_platdata(NULL); + set_s3c2410ts_info(>a02_ts_cfg); i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs)); spi_register_board_info(gta02_spi_board_info, |