diff options
Diffstat (limited to 'arch/arm/mach-omap2/board-omap3h1.c')
| -rw-r--r-- | arch/arm/mach-omap2/board-omap3h1.c | 263 |
1 files changed, 251 insertions, 12 deletions
diff --git a/arch/arm/mach-omap2/board-omap3h1.c b/arch/arm/mach-omap2/board-omap3h1.c index 57672948fdb..ef85cf0722f 100644 --- a/arch/arm/mach-omap2/board-omap3h1.c +++ b/arch/arm/mach-omap2/board-omap3h1.c @@ -33,11 +33,16 @@ #include <linux/i2c/atmel_mxt_ts.h> #include <linux/gpio.h> +#include <linux/gpio_keys.h> #include <linux/regulator/machine.h> #include <linux/regulator/fixed.h> #include <linux/mfd/tps65910.h> +#include <linux/kmod.h> /* for call_usermodehelper - not used, remove? */ +#include <linux/wakelock.h> /* used in interrupt, waking up. */ +#include <linux/debugfs.h> + #include <linux/led-lm3530.h> #include <asm/mach-types.h> @@ -62,6 +67,7 @@ #define NAND_CS 0 #define MPUIRQ_GPIO 31 +#define ON_OFF_BUTTON_GPIO 30 #define ATMEL_MXT_GPIO 105 #define USB_IRQ 124 #define USB_ON_ETK_D7 21 @@ -72,7 +78,12 @@ #define LCD_RESET_GPIO 122 #endif - +static struct accelerometer_wake { + int awake; + struct wake_lock lock; + char lock_name[100]; + int user_pid; +} acc_wake; static struct mtd_partition omap3h1_nand_partitions[] = { /* All the partition sizes are listed in terms of NAND block size */ @@ -156,12 +167,20 @@ static int __init omap3h1_spi_init(void) { } +/* + * int_config is interrupt config, INT_ENABLE register. To enable _all_ + * interrupts, set to 0x59. I think. --mfj + * + * Level shifter seems to set power rail between two options - 1 means VDD. + * (0 means VLogic, which I'm not sure what it is). + */ + static struct mpu_platform_data mpu_data = { .int_config = 0x00, - .level_shifter = 0, - .orientation = { -1, 0, 0, + .level_shifter = 1, + .orientation = { -1, 0, 0, 0, 1, 0, - 0, 0, -1 }, + 0, 0, -1 }, }; static struct lm3530_platform_data omap3h1_backlight_platform_data = { @@ -197,6 +216,33 @@ static struct platform_device omap3h1_dmic_codec = { }; /* --------------------------------------------------------------------------- */ +/* Keys / buttons settings + */ + +static struct gpio_keys_button gpio_buttons[] = { + { + .code = KEY_POWER, /* 26 */ + .gpio = ON_OFF_BUTTON_GPIO, + .desc = "accelerometer", + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data gpio_key_info = { + .buttons = gpio_buttons, + .nbuttons = ARRAY_SIZE(gpio_buttons), +}; + +static struct platform_device omap3h1_keys = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &gpio_key_info, + }, +}; + + +/* --------------------------------------------------------------------------- */ /* USB settings */ @@ -515,10 +561,177 @@ static struct i2c_board_info __initdata omap3h1_i2c3_board_info[] = { }, }; +/* --------------------------------------------------------------------------- */ +/* Create debugfs entry + * + * We need to have this so that our wake-up thread can tell us it's PID. + * That PID will then be used when waking the system up. + */ + + +struct dentry * pidfile; + +#define SIG_OLIO_WAKE 44 // we choose 44 as our signal number (real-time signals are in the range of 33 to 64) + +static ssize_t write_pid(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + char mybuf[10]; + int pid = 0; + + /* read the value from user space */ + + if(count > 10) + return -EINVAL; + if (copy_from_user(mybuf, buf, count) != 0) { + /* nothing read?? */ + printk ("OLIO: write_pid: Error??\n"); + return 0; + } + + sscanf(mybuf, "%d", &pid); + + printk("pid read = %d\n", pid); + + acc_wake.user_pid = pid; + + return count; +} + +static ssize_t send_wake_signal (void) { + int ret; + struct siginfo info; + struct task_struct *t; + + /* send the signal */ + + printk ("Now sending signal!\n"); + + memset(&info, 0, sizeof(struct siginfo)); + + /* this is bit of a trickery: SI_QUEUE is normally used by sigqueue from user space, + * and kernel space should use SI_KERNEL. But if SI_KERNEL is used the real_time data + * is not delivered to the user space signal handler function. + */ + + info.si_signo = SIG_OLIO_WAKE; + info.si_code = SI_QUEUE; + + /* real time signals may have 32 bits of data. */ + + info.si_int = 1234; + + rcu_read_lock(); + + t = pid_task(find_pid_ns(acc_wake.user_pid, &init_pid_ns), PIDTYPE_PID); + + if(t == NULL){ + rcu_read_unlock(); + printk("no such pid\n"); + return -ENODEV; + } + + rcu_read_unlock(); + + /* send the signal */ + + ret = send_sig_info(SIG_OLIO_WAKE, &info, t); + + if (ret < 0) { + printk("error sending signal\n"); + } + return ret; +} + +static const struct file_operations h1_fops = { + .write = write_pid, +}; + + + +/*************************************************************************** + * acc_irq_handler - handle interrupt from accelerometer + * + * This routine gets called when an interrupt from the accelerometer + * happens. Time out is in milliseconds. + * + * TODO: BREAK this all out, place it in it's own kernel driver together + * with the configuration stuff for the accelerometer (the low power sleep + * mode stuff). + */ + +#define OLIO_DOUBLE_TAP 800 +#define OLIO_ONE_SECOND 1000 + +static unsigned long previous; + +static irqreturn_t acc_irq_handler_thr(int irq, void * omap3h1_d) { + /* struct platform_device** omap3h1_devs = (struct platform_device **) omap3h1_d; */ + + int ret = 99; + unsigned long now; + + printk (KERN_DEBUG "acc_irq_handler_thr: Entered!\n"); + + now = jiffies; + + if (jiffies_to_msecs(now - previous) < OLIO_DOUBLE_TAP) { + printk (KERN_DEBUG "Double tap detected!\n"); + /* We want to wake up. Take wake lock (and send signal to user space?) + * BT driver only takes wake lock, then lets higher levels handle + * everything ... but what if there's nothing there to take the lock? + */ + + send_wake_signal(); + wake_lock_timeout (&acc_wake.lock, msecs_to_jiffies (2 * OLIO_ONE_SECOND)); + + previous = 0; + } else { + previous = now; + } + + printk (KERN_DEBUG "acc_irq_handler_thr: Leaving! (ret = %d)\n", ret); + + return IRQ_HANDLED; +} + +static irqreturn_t acc_irq_handler(int irq, void * omap3h1_d) { + printk (KERN_DEBUG "acc_irq_handler: Entered!\n"); + + /* nothing to do, other than wake the main thread */ + + printk (KERN_DEBUG "acc_irq_handler: Leaving!\n"); + return IRQ_WAKE_THREAD; +} + +static int __init omap3_acc_irq_init (int irq, void * dev_id) { + irq_set_irq_wake(irq, 1); + + if (request_threaded_irq (irq, acc_irq_handler, + acc_irq_handler_thr, 0x81, "acc_wake", + dev_id)) { + printk (KERN_DEBUG "Couldn't register handler for accelerometer IRQ\n"); + } + + /* Should check the return value ... but if it fails, what do we do? */ + + return 0; +} + + + +/*************************************************************************** + * omap3_h1_i2c_init - init the i2c buses + * + */ static int __init omap3_h1_i2c_init(void) { - /* Ugly hack: In Linux 3.10 we need to request an IRQ through + int acc_irq; + + /* In Linux 3.10 we need to request an IRQ through * gpio_to_irq. This means it can't be set at compile time, and * must be done at runtime. In other words, here. */ @@ -526,15 +739,20 @@ static int __init omap3_h1_i2c_init(void) gpio_request_one(ATMEL_MXT_GPIO, GPIOF_IN, "atmel_mxt_ts CHG"); gpio_request_one(MPUIRQ_GPIO, GPIOF_IN, "mpu6515 IRQ pin"); + gpio_request_one(ON_OFF_BUTTON_GPIO, GPIOF_OUT_INIT_LOW, "on-off button"); + + acc_irq = gpio_to_irq(MPUIRQ_GPIO); + #ifdef CONFIG_MACH_OMAP3_H1_DVT2 omap3h1_i2c2_board_info[2].irq = gpio_to_irq(ATMEL_MXT_GPIO); - omap3h1_i2c2_board_info[0].irq = gpio_to_irq(MPUIRQ_GPIO); + omap3h1_i2c2_board_info[0].irq = acc_irq; #else omap3h1_i2c1_board_info[3].irq = gpio_to_irq(ATMEL_MXT_GPIO); - omap3h1_i2c1_board_info[1].irq = gpio_to_irq(MPUIRQ_GPIO); + omap3h1_i2c1_board_info[1].irq = acc_irq; #endif - gpio_request_one(USB_ON_ETK_D7, GPIOF_OUT_INIT_HIGH, "USB on"); + gpio_request_one(USB_ON_ETK_D7, GPIOF_OUT_INIT_HIGH, "USB on"); + /* Register buses */ omap_register_i2c_bus(1, 400, omap3h1_i2c1_board_info, ARRAY_SIZE(omap3h1_i2c1_board_info)); @@ -556,6 +774,7 @@ static struct platform_device *omap3h1_devices[] __initdata = { &bcm20702_bluetooth_device, &nop_phy_device, &omap3h1_dmic_codec, + &omap3h1_keys, }; #ifdef CONFIG_OMAP_MUX @@ -615,8 +834,9 @@ static struct omap_board_mux board_mux[] __initdata = { #endif /* CONFIG_MACH_OMAP3_H1_DVT */ /* accelerometer */ - - OMAP3_MUX(JTAG_EMU1, (OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT)), + + OMAP3_MUX(JTAG_EMU1, (OMAP_MUX_MODE4 | OMAP_PIN_INPUT + | OMAP_PIN_OFF_WAKEUPENABLE)), /* USB on */ @@ -626,6 +846,18 @@ static struct omap_board_mux board_mux[] __initdata = { }; #endif +static int __init omap3_wake_init (void) { + pidfile = debugfs_create_file("wake_signal_pid", 0200, NULL, NULL, &h1_fops); + acc_wake.user_pid = 0; /* No user thread yet */ + + snprintf(acc_wake.lock_name, sizeof(acc_wake.lock_name), + "Accelerometer"); + wake_lock_init(&acc_wake.lock, WAKE_LOCK_SUSPEND, + acc_wake.lock_name); + return 0; +} + + static void __init omap3_h1_init(void) { omap3_mux_init(board_mux, OMAP_PACKAGE_CBP); @@ -646,9 +878,16 @@ static void __init omap3_h1_init(void) usb_bind_phy("musb-hdrc.0.auto", 0, "nop_usb_xceiv"); /* "tusb-usb-h1" */ usb_musb_init(&musb_board_data); - /* usbhs_init(&usbhs_bdata); */ /* We don't need this */ - /* h1_opp_init(); */ + /* For handling interrupts from the accelerometer */ + + previous = jiffies; + + /* Init the code that handles wake ups */ + + omap3_wake_init(); + + omap3_acc_irq_init(omap3h1_i2c2_board_info[0].irq, (void *) &omap3h1_devices); } MACHINE_START(OMAP3_H1, "Olio OMAP3 H1 Board") |