From patchwork Fri Sep 4 16:24:22 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: miguel.aguilar@ridgerun.com X-Patchwork-Id: 45702 Received: from devils.ext.ti.com (devils.ext.ti.com [198.47.26.153]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n84GOpWN029648 for ; Fri, 4 Sep 2009 16:24:52 GMT Received: from dlep33.itg.ti.com ([157.170.170.112]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id n84GOkSG017811 for ; Fri, 4 Sep 2009 11:24:51 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep33.itg.ti.com (8.13.7/8.13.7) with ESMTP id n84GOjDY016958 for ; Fri, 4 Sep 2009 11:24:45 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 2D9288062A for ; Fri, 4 Sep 2009 11:24:44 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp52.itg.ti.com (dflp52.itg.ti.com [128.247.22.96]) by linux.omap.com (Postfix) with ESMTP id 3CC1880626 for ; Fri, 4 Sep 2009 11:24:39 -0500 (CDT) Received: from medina.ext.ti.com (localhost [127.0.0.1]) by dflp52.itg.ti.com (8.13.7/8.13.7) with ESMTP id n84GOdap025624 for ; Fri, 4 Sep 2009 11:24:39 -0500 (CDT) Received: from mail92-tx2-R.bigfish.com (mail-tx2.bigfish.com [65.55.88.112]) by medina.ext.ti.com (8.13.7/8.13.7) with ESMTP id n84GOXct028880 for ; Fri, 4 Sep 2009 11:24:38 -0500 Received: from mail92-tx2 (localhost.localdomain [127.0.0.1]) by mail92-tx2-R.bigfish.com (Postfix) with ESMTP id CD5254080BB for ; Fri, 4 Sep 2009 16:24:33 +0000 (UTC) X-SpamScore: 2 X-BigFish: vps2(zz18c1J655Na4b1oc8kzz1202hzzz2fh66h) X-Spam-TCS-SCL: 5:0 X-FB-SS: 5, X-MS-Exchange-Organization-Antispam-Report: OrigIP: 74.208.67.6; Service: EHS Received: by mail92-tx2 (MessageSwitch) id 1252081469561187_11884; Fri, 4 Sep 2009 16:24:29 +0000 (UCT) Received: from mail.navvo.net (mail.navvo.net [74.208.67.6]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail92-tx2.bigfish.com (Postfix) with ESMTP id 66DFBA98056; Fri, 4 Sep 2009 16:24:29 +0000 (UTC) Received: from [201.198.127.70] (helo=localhost.localdomain) by mail.navvo.net with esmtpa (Exim 4.63) (envelope-from ) id 1MjbaI-0001GX-GW; Fri, 04 Sep 2009 11:24:28 -0500 From: miguel.aguilar@ridgerun.com To: davinci-linux-open-source@linux.davincidsp.com, nsnehaprabha@ti.com Date: Fri, 4 Sep 2009 10:24:22 -0600 Message-Id: <1252081462-31551-1-git-send-email-miguel.aguilar@ridgerun.com> X-Mailer: git-send-email 1.6.0.4 X-SA-Exim-Connect-IP: 201.198.127.70 X-SA-Exim-Mail-From: miguel.aguilar@ridgerun.com X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on mail.navvo.net X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_00, NO_REAL_NAME autolearn=ham version=3.1.7-deb X-SA-Exim-Version: 4.2.1 (built Tue, 09 Jan 2007 17:23:22 +0000) X-SA-Exim-Scanned: Yes (on mail.navvo.net) Cc: santiago.nunez@ridgerun.com, todd.fischer@ridgerun.com, clark.becker@ridgerun.com, Miguel Aguilar Subject: [PATCH 1/2] Input: Add DaVinci DM365 Keypad support X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.4 Precedence: list List-Id: davinci-linux-open-source.linux.davincidsp.com List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: davinci-linux-open-source-bounces+patchwork-davinci=patchwork.kernel.org@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces+patchwork-davinci=patchwork.kernel.org@linux.davincidsp.com From: Miguel Aguilar Adds the driver for enabling keypad support on DM365 platform. This driver was tested on DM365 EVM rev c. Signed-off-by: Miguel Aguilar --- arch/arm/mach-davinci/include/mach/keypad.h | 44 ++++ drivers/input/keyboard/Kconfig | 6 + drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/davinci_dm365_keypad.c | 315 +++++++++++++++++++++++++ 4 files changed, 366 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-davinci/include/mach/keypad.h create mode 100644 drivers/input/keyboard/davinci_dm365_keypad.c diff --git a/arch/arm/mach-davinci/include/mach/keypad.h b/arch/arm/mach-davinci/include/mach/keypad.h new file mode 100644 index 0000000..16f4419 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/keypad.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Texas Instruments, Inc + * + * Author: Miguel Aguilar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DAVINCI_KEYPAD_H +#define DAVINCI_KEYPAD_H + +#include + +struct davinci_kp_platform_data { + int *keymap; + u32 keymapsize; + u32 rep:1; + u32 strobe; + u32 interval; +}; + +struct davinci_kp { + struct input_dev *input; + struct davinci_kp_platform_data *pdata; + int irq; + void __iomem *base; + resource_size_t pbase; + size_t base_size; +}; + +#endif + diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a6b989a..08ed7d4 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -361,4 +361,10 @@ config KEYBOARD_XTKBD To compile this driver as a module, choose M here: the module will be called xtkbd. +config KEYBOARD_DAVINCI_DM365 + tristate "TI DaVinci DM365 Keypad" + depends on ARCH_DAVINCI_DM365 + help + Supports the keypad module on the DM365 + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index b5b5eae..1921bac 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o +obj-$(CONFIG_KEYBOARD_DAVINCI_DM365) += davinci_dm365_keypad.o diff --git a/drivers/input/keyboard/davinci_dm365_keypad.c b/drivers/input/keyboard/davinci_dm365_keypad.c new file mode 100644 index 0000000..be52fae --- /dev/null +++ b/drivers/input/keyboard/davinci_dm365_keypad.c @@ -0,0 +1,315 @@ +/* + * DaVinci DM365 Keypad Driver + * + * Copyright (C) 2009 Texas Instruments, Inc + * + * Author: Miguel Aguilar + * + * Intial Code: Sandeep Paulraj + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Keypad registers */ +#define KEYPAD_BASE DM365_KEYSCAN_BASE +#define DM365_KEYPAD_KEYCTRL (0x0000) +#define DM365_KEYPAD_INTENA (0x0004) +#define DM365_KEYPAD_INTFLAG (0x0008) +#define DM365_KEYPAD_INTCLR (0x000c) +#define DM365_KEYPAD_STRBWIDTH (0x0010) +#define DM365_KEYPAD_INTERVAL (0x0014) +#define DM365_KEYPAD_CONTTIME (0x0018) +#define DM365_KEYPAD_CURRENTST (0x001c) +#define DM365_KEYPAD_PREVSTATE (0x0020) +#define DM365_KEYPAD_EMUCTRL (0x0024) +#define DM365_KEYPAD_IODFTCTRL (0x002c) + +/* Key Control Register (KEYCTRL) */ +#define DM365_KEYPAD_KEYEN 0x00000001 +#define DM365_KEYPAD_PREVMODE 0x00000002 +#define DM365_KEYPAD_CHATOFF 0x00000004 +#define DM365_KEYPAD_AUTODET 0x00000008 +#define DM365_KEYPAD_SCANMODE 0x00000010 +#define DM365_KEYPAD_OUTTYPE 0x00000020 +#define DM365_KEYPAD_4X4 0x00000040 + +/* Masks for the interrupts */ +#define DM365_KEYPAD_INT_CONT 0x00000008 +#define DM365_KEYPAD_INT_OFF 0x00000004 +#define DM365_KEYPAD_INT_ON 0x00000002 +#define DM365_KEYPAD_INT_CHANGE 0x00000001 +#define DM365_KEYPAD_INT_ALL 0x0000000f + +/* Debug flag */ +#undef DEBUG + +void dm365_kp_write(struct davinci_kp *dm365_kp, u32 val, u32 addr) +{ + u32 base = (u32)dm365_kp->base; + + __raw_writel(val,(u32 *)(base + addr)); +} + +u32 dm365_kp_read(struct davinci_kp *dm365_kp, u32 addr) +{ + u32 base = (u32)dm365_kp->base; + + return __raw_readl((u32 *)(base + addr)); +} + +/* Initializing the kp Module */ +void dm365_kp_initialize(struct davinci_kp *dm365_kp) +{ + u32 strobe = dm365_kp->pdata->strobe; + u32 interval = dm365_kp->pdata->interval; + + /* Enable all interrupts */ + dm365_kp_write(dm365_kp, DM365_KEYPAD_INT_ALL, DM365_KEYPAD_INTENA); + + /* Clear interrupts if any */ + dm365_kp_write(dm365_kp, DM365_KEYPAD_INT_ALL, DM365_KEYPAD_INTCLR); + + /* Setup the scan period = strobe + interval */ + dm365_kp_write(dm365_kp, strobe, DM365_KEYPAD_STRBWIDTH); + dm365_kp_write(dm365_kp, interval, DM365_KEYPAD_INTERVAL); + dm365_kp_write(dm365_kp, 0x01, DM365_KEYPAD_CONTTIME); + + /* Enable Keyscan module and enable */ + dm365_kp_write(dm365_kp, DM365_KEYPAD_AUTODET | DM365_KEYPAD_KEYEN, + DM365_KEYPAD_KEYCTRL); +} + +static irqreturn_t dm365_kp_interrupt(int irq, void *dev_id) +{ + int i; + u32 prev_status, new_status, changed; + int keycode = KEY_UNKNOWN; + struct davinci_kp *dm365_kp = dev_id; + int *keymap = dm365_kp->pdata->keymap; + u32 keymapsize = dm365_kp->pdata->keymapsize; + + /* Disable interrupt */ + dm365_kp_write(dm365_kp, 0x0, DM365_KEYPAD_INTENA); + + /* Reading previous and new status of the keypad */ + prev_status = dm365_kp_read(dm365_kp, DM365_KEYPAD_PREVSTATE); + new_status = dm365_kp_read(dm365_kp, DM365_KEYPAD_CURRENTST); + + changed = prev_status ^ new_status; + + for (i = 0; i < keymapsize; i++) { + if ((changed >> i) & 0x1) { + keycode = keymap[i]; + if((new_status >> i) & 0x1) { + /* Report release */ + input_report_key(dm365_kp->input, keycode, 0); + input_sync(dm365_kp->input); +#ifdef DEBUG + printk(KERN_INFO "dm365_keypad: key %d released\n", + keycode); +#endif + } else { + /* Report press */ + input_report_key(dm365_kp->input, keycode, 1); + input_sync(dm365_kp->input); +#ifdef DEBUG + printk(KERN_INFO "dm365_keypad: key %d pressed\n", + keycode); +#endif + } + } + } + + /* Clearing interrupt */ + dm365_kp_write(dm365_kp, DM365_KEYPAD_INT_ALL, DM365_KEYPAD_INTCLR); + + /* Enable interrupts */ + dm365_kp_write(dm365_kp, 0x1, DM365_KEYPAD_INTENA); + + return IRQ_HANDLED; +} + +/* + * Registers keypad device with input sub system and configures + * DM365 keypad registers + */ +static int dm365_kp_probe(struct platform_device *pdev) +{ + struct davinci_kp *dm365_kp; + struct input_dev *key_dev; + struct resource *res, *mem; + int ret, i; + struct davinci_kp_platform_data *pdata = pdev->dev.platform_data; + + if (!pdata->keymap) { + printk(KERN_ERR "No keymap from pdata\n"); + return -EINVAL; + } + + dm365_kp = kzalloc(sizeof *dm365_kp, GFP_KERNEL); + key_dev = input_allocate_device(); + + if (!dm365_kp || !key_dev) { + printk(KERN_ERR "Could not allocate input device\n"); + return -EINVAL; + } + + platform_set_drvdata(pdev, dm365_kp); + + dm365_kp->input = key_dev; + + dm365_kp->irq = platform_get_irq(pdev, 0); + if (dm365_kp->irq <= 0) { + pr_debug("%s: No DM365 Keypad irq\n", pdev->name); + goto fail1; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + dm365_kp->pbase = res->start; + dm365_kp->base_size = res->end - res->start + 1; + + if (res) + mem = request_mem_region(res->start, + dm365_kp->base_size, pdev->name); + else + mem = NULL; + + if (!mem) { + pr_debug("%s: KEYSCAN registers at %08x are not free\n", + pdev->name, dm365_kp->pbase); + goto fail1; + } + + dm365_kp->base = ioremap(res->start, dm365_kp->base_size); + if (dm365_kp->base == NULL) { + pr_debug("%s: Can't ioremap MEM resource.\n", pdev->name); + goto fail2; + } + + /* Enable auto repeat feature of Linux input subsystem */ + if (pdata->rep) + __set_bit(EV_REP, key_dev->evbit); + + /* Setup input device */ + __set_bit(EV_KEY, key_dev->evbit); + + /* Setup the keymap */ + dm365_kp->pdata = pdata; + + for (i = 0; i < dm365_kp->pdata->keymapsize; i++) + __set_bit(dm365_kp->pdata->keymap[i], key_dev->keybit); + + key_dev->name = "dm365_keypad"; + key_dev->phys = "dm365_keypad/input0"; + key_dev->dev.parent = &pdev->dev; + key_dev->id.bustype = BUS_HOST; + key_dev->id.vendor = 0x0001; + key_dev->id.product = 0x0365; + key_dev->id.version = 0x0001; + key_dev->keycode = dm365_kp->pdata->keymap; + key_dev->keycodesize = sizeof(unsigned int); + key_dev->keycodemax = dm365_kp->pdata->keymapsize; + + ret = input_register_device(dm365_kp->input); + if (ret < 0) { + printk(KERN_ERR + "Unable to register DaVinci DM365 keypad device\n"); + goto fail3; + } + + ret = request_irq(dm365_kp->irq, dm365_kp_interrupt, IRQF_DISABLED, + "dm365_keypad", dm365_kp); + if (ret < 0) { + printk(KERN_ERR + "Unable to register DaVinci DM365 keypad Interrupt\n"); + goto fail4; + } + + dm365_kp_initialize(dm365_kp); + + return 0; +fail4: + input_unregister_device(dm365_kp->input); + key_dev = NULL; +fail3: + iounmap(dm365_kp->base); +fail2: + release_mem_region(dm365_kp->pbase, dm365_kp->base_size); +fail1: + kfree(dm365_kp); + input_free_device(key_dev); + + return -EINVAL; +} + +static int __devexit dm365_kp_remove(struct platform_device *pdev) +{ + struct davinci_kp *dm365_kp = platform_get_drvdata(pdev); + + input_unregister_device(dm365_kp->input); + free_irq(dm365_kp->irq, dm365_kp); + kfree(dm365_kp); + + iounmap(dm365_kp->base); + release_mem_region(dm365_kp->pbase, dm365_kp->base_size); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver dm365_kp_driver = { + .probe = dm365_kp_probe, + .remove = __devexit_p(dm365_kp_remove), + .driver = { + .name = "dm365_keypad", + .owner = THIS_MODULE, + }, +}; + +static int __init dm365_kp_init(void) +{ + printk(KERN_INFO "DaVinci DM365 Keypad Driver\n"); + + return platform_driver_register(&dm365_kp_driver); +} + +static void __exit dm365_kp_exit(void) +{ + platform_driver_unregister(&dm365_kp_driver); +} + +module_init(dm365_kp_init); +module_exit(dm365_kp_exit); + +MODULE_AUTHOR("Miguel Aguilar"); +MODULE_DESCRIPTION("Texas Instruments DaVinci DM365 EVM Keypad Driver"); +MODULE_LICENSE("GPL");