From: <hap...@us...> - 2007-09-17 15:42:09
|
Revision: 1328 http://hackndev.svn.sourceforge.net/hackndev/?rev=1328&view=rev Author: happy-slapin Date: 2007-09-17 08:37:25 -0700 (Mon, 17 Sep 2007) Log Message: ----------- cleanup: update from hh.org Added Paths: ----------- linux4palm/linux/branches/cleanup-branch-never-commit/drivers/input/keyboard/gpiodev_keys2.c linux4palm/linux/branches/cleanup-branch-never-commit/include/linux/gpiodev_keys2.h linux4palm/linux/branches/cleanup-branch-never-commit/include/linux/mfd/htc-bbkeys.h Removed Paths: ------------- linux4palm/linux/branches/cleanup-branch-never-commit/include/asm-arm/arch-pxa/i2c-pxa.h Added: linux4palm/linux/branches/cleanup-branch-never-commit/drivers/input/keyboard/gpiodev_keys2.c =================================================================== --- linux4palm/linux/branches/cleanup-branch-never-commit/drivers/input/keyboard/gpiodev_keys2.c (rev 0) +++ linux4palm/linux/branches/cleanup-branch-never-commit/drivers/input/keyboard/gpiodev_keys2.c 2007-09-17 15:37:25 UTC (rev 1328) @@ -0,0 +1,336 @@ +/* + * Driver for diagonal joypads on GPIO lines capable of generating interrupts. + * + * Copyright 2007 Milan Plzik, based on gpio-keys.c (c) Phil Blundell 2005 + * + * 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. + */ + +#include <linux/module.h> +#include <linux/version.h> + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/pm.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/irq.h> +#include <linux/sort.h> +#include <linux/gpiodev.h> +#include <linux/gpiodev_keys2.h> + +struct gpiodev_keys2_drvdata { + struct input_dev *input; + struct timer_list debounce_timer; + struct gpiodev_keys2_gpio ***button_gpios; + int *gpio_delays; + struct gpiodev_keys2_button **buttons_by_prio; + int *gpio_used_prio; +}; + + +static struct gpiodev_keys2_gpio *lookup_gpio (struct gpiodev_keys2_platform_data *pdata, + const char *name) +{ + int i; + + for (i = 0; i < pdata->ngpios; i++) { + if (!strcmp (name, pdata->gpios[i].name)) + return &pdata->gpios[i]; + } + + return NULL; +} + +static int count_gpios (struct gpiodev_keys2_button *btn) +{ + int i = 0; + const char **gpio = btn->gpio_names; + + while (gpio[i]) i++; + + return i; +} + + +static irqreturn_t gpiodev_keys2_isr(int irq, void *data) +{ + int i; + struct platform_device *pdev = data; + struct gpiodev_keys2_platform_data *pdata = pdev->dev.platform_data; + struct gpiodev_keys2_drvdata *drvdata = platform_get_drvdata(pdev); + + /* Find out which GPIO has been asserted and the corresponding delay for + * debouncing. */ + for (i = 0; i < pdata->ngpios; i++) + if (irq == gpiodev_to_irq(&pdata->gpios[i].gpio)) { + break; + }; + + /* Prepare delayed call of debounce handler */ + if (time_before(drvdata->debounce_timer.expires, jiffies + + msecs_to_jiffies(drvdata->gpio_delays[i])) || + !timer_pending(&drvdata->debounce_timer)) + mod_timer(&drvdata->debounce_timer, + jiffies + msecs_to_jiffies(drvdata->gpio_delays[i])); + + return IRQ_HANDLED; +} + +static void debounce_handler(unsigned long data) +{ + struct platform_device *pdev = (void*)data; + struct gpiodev_keys2_platform_data *pdata = pdev->dev.platform_data; + struct gpiodev_keys2_drvdata *drvdata = platform_get_drvdata(pdev); + struct gpiodev_keys2_button *button; + struct gpiodev_keys2_gpio **gpio; + int i; + + memset(drvdata->gpio_used_prio, 0, sizeof(drvdata->gpio_used_prio[0])*pdata->ngpios); + + /* Clear reported buttons */ + for (i = 0; i < pdata->nbuttons; i++) + input_report_key(drvdata->input, pdata->buttons[i].keycode, 0); + + for (i = 0; i < pdata->nbuttons; i++) { + int button_idx = drvdata->buttons_by_prio[i] - &pdata->buttons[0]; + button = drvdata->buttons_by_prio[i]; + gpio = drvdata->button_gpios[button_idx]; + + /* are all required GPIOs asserted? */ + do { + int gpio_idx = gpio[0] - pdata->gpios; /* index in pdata->gpios */ + if (((gpiodev_get_value(&gpio[0]->gpio) ? 1 : 0) ^ (gpio[0]->active_low)) && + /* this is only true when gpio prio is 0, + * because the buttons are ordered descending by + * priority */ + drvdata->gpio_used_prio[gpio_idx]<=button->priority) + continue; + else + break; + } while ((++gpio)[0] != NULL); + + if (gpio[0] == NULL) { + /* all gpios are asserted and unused otherwise, so key + * can be pressed and GPIOs will be marked as used. */ + gpio = drvdata->button_gpios[button_idx]; + do { + int gpio_idx = gpio[0] - pdata->gpios; + drvdata->gpio_used_prio[gpio_idx] = button->priority; + } while (((++gpio)[0]) != NULL); + if (button->keycode != -1) + input_report_key(drvdata->input, button->keycode, 1); + } + }; + input_sync(drvdata->input); +} + + +static int btnprio_cmp (const void *a, const void *b) +{ + const struct gpiodev_keys2_button *b1, *b2; + + b1 = *((const struct gpiodev_keys2_button**)a); + b2 = *((const struct gpiodev_keys2_button**)b); + + return b2->priority - b1->priority; +} + +/* Builds array, which on i-th position contains pointers to all GPIOs used by + * i-th button in pdata->buttons, and also finds maximal debounce time for each + * gpio. + */ + +static int gpiodev_keys2_init_drvdata(struct platform_device *pdev) +{ + struct gpiodev_keys2_platform_data *pdata = pdev->dev.platform_data; + struct gpiodev_keys2_drvdata *drvdata = platform_get_drvdata(pdev); + struct gpiodev_keys2_gpio *gpio; + int i, j; + int button_gpios; + + if (drvdata->button_gpios) { + printk (KERN_ERR "gpiodev-keys2: Attempting to re-create drvdata\n"); + return -EBUSY; + }; + + drvdata->button_gpios = kzalloc( + pdata->nbuttons*sizeof(*drvdata->button_gpios), + GFP_KERNEL); + drvdata->gpio_delays = kzalloc(pdata->ngpios*sizeof(*drvdata->gpio_delays), GFP_KERNEL); + drvdata->buttons_by_prio = kzalloc(pdata->nbuttons*sizeof(*drvdata->buttons_by_prio), GFP_KERNEL); + drvdata->gpio_used_prio = kzalloc(pdata->ngpios*sizeof(*drvdata->gpio_used_prio), GFP_KERNEL); + + for (i = 0; i < pdata->nbuttons; i++) { + button_gpios = count_gpios(&pdata->buttons[i]); + drvdata->button_gpios[i] = kzalloc((button_gpios+1)*sizeof(drvdata->button_gpios[i]), GFP_KERNEL); + + /* Put all GPIOs used by i-th button into button_gpios[i] */ + for (j = 0; j < button_gpios; j++) { + gpio = lookup_gpio(pdata, pdata->buttons[i].gpio_names[j]); + if (!gpio) { + printk(KERN_WARNING "gpiodev-keys2: Unknown gpio '%s'\n", pdata->buttons[i].gpio_names[j]); + continue; + }; + + /* See whether actual button has delay, which is bigger + * than delay GPIO. If so, update GPIOs delay. + */ + drvdata->gpio_delays[gpio - pdata->gpios] = max( + drvdata->gpio_delays[gpio - pdata->gpios], + pdata->buttons[i].debounce_ms); + + drvdata->button_gpios[i][j] = gpio; + }; + + + }; + + /* Create list of buttons sorted descending by priority */ + for (i = 0; i < pdata->nbuttons; i++) + drvdata->buttons_by_prio[i] = &pdata->buttons[i]; + + sort(drvdata->buttons_by_prio, pdata->nbuttons, sizeof(drvdata->buttons_by_prio[0]), btnprio_cmp, NULL); + for (i = 0; i <pdata->nbuttons; i++) + printk (KERN_INFO "- button '%s', prio %d\n", drvdata->buttons_by_prio[i]->gpio_names[0], drvdata->buttons_by_prio[i]->priority); + + return 0; +} + +static void gpiodev_keys2_free_mapping(struct platform_device *pdev) +{ + struct gpiodev_keys2_platform_data *pdata = pdev->dev.platform_data; + struct gpiodev_keys2_drvdata *drvdata = platform_get_drvdata(pdev); + int i; + + if (!drvdata) + return; + + for (i = 0; i < pdata->nbuttons; i++) + kfree(drvdata->button_gpios[i]); + + kfree(drvdata->button_gpios); + kfree(drvdata->gpio_delays); + kfree(drvdata->buttons_by_prio); + kfree(drvdata->gpio_used_prio); +} + + +static int __devinit gpiodev_keys2_probe(struct platform_device *pdev) +{ + struct gpiodev_keys2_drvdata *drvdata; + struct gpiodev_keys2_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input; + int i, error; + + input = input_allocate_device(); + if (!input) + return -ENOMEM; + + input->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input->name = pdev->name; + input->phys = "gpiodev-keys2/input0"; + input->cdev.dev = &pdev->dev; + // input->private // do we need this? + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + drvdata = kzalloc(sizeof(struct gpiodev_keys2_drvdata), GFP_KERNEL); + drvdata->input = input; + platform_set_drvdata(pdev, drvdata); + + setup_timer(&drvdata->debounce_timer, debounce_handler, (unsigned long) pdev); + + for (i = 0; i < pdata->nbuttons; i++) + set_bit(pdata->buttons[i].keycode, input->keybit); + + error = input_register_device(input); + if (error) { + printk(KERN_ERR "Unable to register gpiodev-keys2 input device\n"); + goto fail; + } + + gpiodev_keys2_init_drvdata(pdev); + + + for (i = 0; i < pdata->ngpios; i++) { + int irq = gpiodev_to_irq(&(pdata->gpios[i].gpio)); + + set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); + error = request_irq(irq, gpiodev_keys2_isr, + IRQF_SAMPLE_RANDOM | IRQF_SHARED, + pdata->gpios[i].name ? + pdata->gpios[i].name : "gpiodev_keys2", pdev); + + if (error) { + printk(KERN_ERR "gpiodev-keys: unable to claim irq %d; error %d\n", irq, error); + goto fail; + } + } + + + return 0; + +fail: + for (i = i - 1; i >= 0; i--) + free_irq(gpiodev_to_irq(&pdata->gpios[i].gpio),pdev); + + input_free_device(input); + + del_timer_sync(&drvdata->debounce_timer); + + return error; +} + +static int __devexit gpiodev_keys2_remove(struct platform_device *pdev) +{ + struct gpiodev_keys2_drvdata *drvdata = platform_get_drvdata(pdev); + struct gpiodev_keys2_platform_data *pdata = pdev->dev.platform_data; + int i; + + del_timer_sync(&drvdata->debounce_timer); + + for (i = 0; i < pdata->ngpios; i++) + free_irq(gpiodev_to_irq(&pdata->gpios[i].gpio), pdev); + + input_unregister_device(drvdata->input); + input_free_device(drvdata->input); + gpiodev_keys2_free_mapping(pdev); + kfree(drvdata); + + return 0; +} + + +struct platform_driver gpiodev_keys2_device_driver = { + .probe = gpiodev_keys2_probe, + .remove = __devexit_p(gpiodev_keys2_remove), + .driver = { + .name = "gpiodev-keys2", + } +}; + +static int __init gpiodev_keys2_init(void) +{ + return platform_driver_register(&gpiodev_keys2_device_driver); +} + +static void __exit gpiodev_keys2_exit(void) +{ + platform_driver_unregister(&gpiodev_keys2_device_driver); +} + +module_init(gpiodev_keys2_init); +module_exit(gpiodev_keys2_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Milan Plzik <mil...@gm...>"); +MODULE_DESCRIPTION("Keyboard driver for GPIO"); Deleted: linux4palm/linux/branches/cleanup-branch-never-commit/include/asm-arm/arch-pxa/i2c-pxa.h =================================================================== --- linux4palm/linux/branches/cleanup-branch-never-commit/include/asm-arm/arch-pxa/i2c-pxa.h 2007-09-17 15:12:45 UTC (rev 1327) +++ linux4palm/linux/branches/cleanup-branch-never-commit/include/asm-arm/arch-pxa/i2c-pxa.h 2007-09-17 15:37:25 UTC (rev 1328) @@ -1,76 +0,0 @@ -/* - * i2c_pxa.h - * - * Copyright (C) 2002 Intrinsyc Software Inc. - * - * 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. - * - */ -#ifndef _I2C_PXA_H_ -#define _I2C_PXA_H_ - -struct i2c_algo_pxa_data -{ - void (*write_byte) (u8 value); - u8 (*read_byte) (void); - void (*start) (void); - void (*repeat_start) (void); - void (*stop) (void); - void (*abort) (void); - int (*wait_bus_not_busy) (void); - int (*wait_for_interrupt) (int wait_type); - void (*transfer) (int lastbyte, int receive, int midbyte); - void (*reset) (void); - - int udelay; - int timeout; -}; - -#define DEF_TIMEOUT 3 -#define BUS_ERROR (-EREMOTEIO) -#define ACK_DELAY 0 /* time to delay before checking bus error */ -#define MAX_MESSAGES 65536 /* maximum number of messages to send */ - -#define I2C_SLEEP_TIMEOUT 2 /* time to sleep for on i2c transactions */ -#define I2C_RETRY (-2000) /* an error has occurred retry transmit */ -#define I2C_TRANSMIT 1 -#define I2C_RECEIVE 0 -#define I2C_PXA_SLAVE_ADDR 0x1 /* slave pxa unit address */ -#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) /* ICR initialization value */ -/* ICR initialize bit values -* -* 15. FM 0 (100 Khz operation) -* 14. UR 0 (No unit reset) -* 13. SADIE 0 (Disables the unit from interrupting on slave addresses -* matching its slave address) -* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration -* in master mode) -* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode) -* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent) -* 9. IRFIE 1 (Enable interrupts from full buffer received) -* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty) -* 7. GCD 1 (Disables i2c unit response to general call messages as a slave) -* 6. IUE 0 (Disable unit until we change settings) -* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL) -* 4. MA 0 (Only send stop with the ICR stop bit) -* 3. TB 0 (We are not transmitting a byte initially) -* 2. ACKNAK 0 (Send an ACK after the unit receives a byte) -* 1. STOP 0 (Do not send a STOP) -* 0. START 0 (Do not send a START) -* -*/ - -#define I2C_ISR_INIT 0x7FF /* status register init */ -/* I2C status register init values - * - * 10. BED 1 (Clear bus error detected) - * 9. SAD 1 (Clear slave address detected) - * 7. IRF 1 (Clear IDBR Receive Full) - * 6. ITE 1 (Clear IDBR Transmit Empty) - * 5. ALD 1 (Clear Arbitration Loss Detected) - * 4. SSD 1 (Clear Slave Stop Detected) - */ - -#endif Added: linux4palm/linux/branches/cleanup-branch-never-commit/include/linux/gpiodev_keys2.h =================================================================== --- linux4palm/linux/branches/cleanup-branch-never-commit/include/linux/gpiodev_keys2.h (rev 0) +++ linux4palm/linux/branches/cleanup-branch-never-commit/include/linux/gpiodev_keys2.h 2007-09-17 15:37:25 UTC (rev 1328) @@ -0,0 +1,37 @@ +#ifndef __GPIODEV_KEYS2_H +#define __GPIODEV_KEYS2_H + +#include <linux/gpiodev.h> + +#define MAX_GPIOS_PER_BUTTON 5 + +struct gpiodev_keys2_gpio { + const char *name; /* GPIO identifier */ + struct gpio gpio; /* gpiodev descriptor */ + int active_low; +}; + +struct gpiodev_keys2_button { + int keycode; /* key code for the button */ + + const char *gpio_names[MAX_GPIOS_PER_BUTTON]; + /* which GPIOs have to be asserted in order + * to emit keypress. This is NULL-terminated + * array of string GPIO identifiers */ + + int debounce_ms; /* Value for this button's debounce will be at + * least this number of milliseconds. */ + + int priority; /* If more buttons are likely to be pressed, + * only those with highest priority will + * generate keypress, others will be released */ +}; + +struct gpiodev_keys2_platform_data { + struct gpiodev_keys2_gpio *gpios; + int ngpios; + struct gpiodev_keys2_button *buttons; + int nbuttons; +}; + +#endif Added: linux4palm/linux/branches/cleanup-branch-never-commit/include/linux/mfd/htc-bbkeys.h =================================================================== --- linux4palm/linux/branches/cleanup-branch-never-commit/include/linux/mfd/htc-bbkeys.h (rev 0) +++ linux4palm/linux/branches/cleanup-branch-never-commit/include/linux/mfd/htc-bbkeys.h 2007-09-17 15:37:25 UTC (rev 1328) @@ -0,0 +1,20 @@ +#ifndef _HTC_BBKEYS_H +#define _HTC_BBKEYS_H + +/* Maximum number of keys available */ +enum { BBKEYS_MAXKEY = 16 }; + +struct htc_bbkeys_platform_data { + /* Beginning of available gpios (eg, GPIO_BASE_INCREMENT) */ + int gpio_base; + + /* Main interface gpios */ + int sda_gpio, scl_gpio; + + /* Registers for working with keypad */ + int ackreg, key1reg, key2reg; + /* Keycodes for buttons */ + int buttons[BBKEYS_MAXKEY]; +}; + +#endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |