From: David-John Willis Date: Tue, 17 Nov 2009 12:11:41 +0000 (+0000) Subject: omap3-pandora-kernel: Add AUFS2 shim and keypad 'WIP' code. X-Git-Tag: Release-2010-05/1~172 X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=674f9cd7e2ed0cf3821abd9b534d03384c4df385;p=openpandora.oe.git omap3-pandora-kernel: Add AUFS2 shim and keypad 'WIP' code. --- diff --git a/recipes/linux/omap3-pandora-kernel/aufs2/aufs2-base.patch b/recipes/linux/omap3-pandora-kernel/aufs2/aufs2-base.patch new file mode 100644 index 0000000..b97a4ca --- /dev/null +++ b/recipes/linux/omap3-pandora-kernel/aufs2/aufs2-base.patch @@ -0,0 +1,81 @@ +aufs2 base patch for linux-2.6.27 + +diff --git a/fs/namei.c b/fs/namei.c +index 4ea63ed..2759ad4 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -1241,7 +1241,7 @@ out: + * needs parent already locked. Doesn't follow mounts. + * SMP-safe. + */ +-static struct dentry *lookup_hash(struct nameidata *nd) ++struct dentry *lookup_hash(struct nameidata *nd) + { + int err; + +@@ -1251,7 +1251,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) + return __lookup_hash(&nd->last, nd->path.dentry, nd); + } + +-static int __lookup_one_len(const char *name, struct qstr *this, ++int __lookup_one_len(const char *name, struct qstr *this, + struct dentry *base, int len) + { + unsigned long hash; +diff --git a/fs/splice.c b/fs/splice.c +index a1e701c..409245a 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -887,8 +887,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); + /* + * Attempt to initiate a splice from pipe to file. + */ +-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) ++long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) + { + int ret; + +@@ -911,9 +911,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + /* + * Attempt to initiate a splice from a file to a pipe. + */ +-static long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) ++long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) + { + int ret; + +diff --git a/include/linux/namei.h b/include/linux/namei.h +index 68f8c32..5522432 100644 +--- a/include/linux/namei.h ++++ b/include/linux/namei.h +@@ -71,6 +71,9 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry + extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); + extern void release_open_intent(struct nameidata *); + ++extern struct dentry *lookup_hash(struct nameidata *nd); ++extern int __lookup_one_len(const char *name, struct qstr *this, ++ struct dentry *base, int len); + extern struct dentry *lookup_one_len(const char *, struct dentry *, int); + extern struct dentry *lookup_one_noperm(const char *, struct dentry *); + +diff --git a/include/linux/splice.h b/include/linux/splice.h +index 528dcb9..5123bc6 100644 +--- a/include/linux/splice.h ++++ b/include/linux/splice.h +@@ -71,4 +71,10 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *, + extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, + splice_direct_actor *); + ++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++extern long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++ + #endif diff --git a/recipes/linux/omap3-pandora-kernel/aufs2/aufs2-standalone.patch b/recipes/linux/omap3-pandora-kernel/aufs2/aufs2-standalone.patch new file mode 100644 index 0000000..c40db9e --- /dev/null +++ b/recipes/linux/omap3-pandora-kernel/aufs2/aufs2-standalone.patch @@ -0,0 +1,138 @@ +aufs2 standalone patch for linux-2.6.27 + +diff --git a/fs/namei.c b/fs/namei.c +index 2759ad4..b207821 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -354,6 +354,7 @@ int deny_write_access(struct file * file) + + return 0; + } ++EXPORT_SYMBOL(deny_write_access); + + /** + * path_get - get a reference to a path +@@ -1250,6 +1251,7 @@ struct dentry *lookup_hash(struct nameidata *nd) + return ERR_PTR(err); + return __lookup_hash(&nd->last, nd->path.dentry, nd); + } ++EXPORT_SYMBOL(lookup_hash); + + int __lookup_one_len(const char *name, struct qstr *this, + struct dentry *base, int len) +@@ -1272,6 +1274,7 @@ int __lookup_one_len(const char *name, struct qstr *this, + this->hash = end_name_hash(hash); + return 0; + } ++EXPORT_SYMBOL(__lookup_one_len); + + /** + * lookup_one_len - filesystem helper to lookup single pathname component +diff --git a/fs/namespace.c b/fs/namespace.c +index 6e283c9..36030e8 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -37,6 +37,7 @@ + + /* spinlock for vfsmount related operations, inplace of dcache_lock */ + __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); ++EXPORT_SYMBOL(vfsmount_lock); + + static int event; + static DEFINE_IDA(mnt_id_ida); +diff --git a/fs/open.c b/fs/open.c +index 07da935..b8e9726 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -222,6 +222,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, + mutex_unlock(&dentry->d_inode->i_mutex); + return err; + } ++EXPORT_SYMBOL(do_truncate); + + static long do_sys_truncate(const char __user *pathname, loff_t length) + { +diff --git a/fs/splice.c b/fs/splice.c +index 409245a..48d7e72 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -907,6 +907,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + + return out->f_op->splice_write(pipe, out, ppos, len, flags); + } ++EXPORT_SYMBOL(do_splice_from); + + /* + * Attempt to initiate a splice from a file to a pipe. +@@ -929,6 +930,7 @@ long do_splice_to(struct file *in, loff_t *ppos, + + return in->f_op->splice_read(in, ppos, pipe, len, flags); + } ++EXPORT_SYMBOL(do_splice_to); + + /** + * splice_direct_to_actor - splices data directly between two non-pipes +diff --git a/fs/super.c b/fs/super.c +index e931ae9..141853c 100644 +--- a/fs/super.c ++++ b/fs/super.c +@@ -270,6 +270,7 @@ int fsync_super(struct super_block *sb) + __fsync_super(sb); + return sync_blockdev(sb->s_bdev); + } ++EXPORT_SYMBOL(fsync_super); + + /** + * generic_shutdown_super - common helper for ->kill_sb() +diff --git a/fs/sync.c b/fs/sync.c +index 2967562..34040d6 100644 +--- a/fs/sync.c ++++ b/fs/sync.c +@@ -104,6 +104,7 @@ long do_fsync(struct file *file, int datasync) + out: + return ret; + } ++EXPORT_SYMBOL(do_fsync); + + static long __do_fsync(unsigned int fd, int datasync) + { +diff --git a/security/device_cgroup.c b/security/device_cgroup.c +index 46f2397..00ec611 100644 +--- a/security/device_cgroup.c ++++ b/security/device_cgroup.c +@@ -537,6 +537,7 @@ acc_check: + + return -EPERM; + } ++EXPORT_SYMBOL(devcgroup_inode_permission); + + int devcgroup_inode_mknod(int mode, dev_t dev) + { +diff --git a/security/security.c b/security/security.c +index 3a4b4f5..79be80b 100644 +--- a/security/security.c ++++ b/security/security.c +@@ -425,6 +425,7 @@ int security_inode_readlink(struct dentry *dentry) + return 0; + return security_ops->inode_readlink(dentry); + } ++EXPORT_SYMBOL(security_inode_readlink); + + int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd) + { +@@ -439,6 +440,7 @@ int security_inode_permission(struct inode *inode, int mask) + return 0; + return security_ops->inode_permission(inode, mask); + } ++EXPORT_SYMBOL(security_inode_permission); + + int security_inode_setattr(struct dentry *dentry, struct iattr *attr) + { +@@ -539,6 +541,7 @@ int security_file_permission(struct file *file, int mask) + { + return security_ops->file_permission(file, mask); + } ++EXPORT_SYMBOL(security_file_permission); + + int security_file_alloc(struct file *file) + { diff --git a/recipes/linux/omap3-pandora-kernel/defconfig b/recipes/linux/omap3-pandora-kernel/defconfig index 3c5f95e..937a8ab 100755 --- a/recipes/linux/omap3-pandora-kernel/defconfig +++ b/recipes/linux/omap3-pandora-kernel/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.27-omap1 -# Sun Aug 30 18:56:27 2009 +# Fri Nov 13 10:18:13 2009 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -277,7 +277,7 @@ CONFIG_GENERIC_CLOCKEVENTS_BUILD=y # CONFIG_PREEMPT is not set CONFIG_HZ=128 CONFIG_AEABI=y -# CONFIG_OABI_COMPAT is not set +CONFIG_OABI_COMPAT=y CONFIG_ARCH_FLATMEM_HAS_HOLES=y # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set CONFIG_SELECT_MEMORY_MODEL=y @@ -310,21 +310,7 @@ CONFIG_ATAGS_PROC=y # # CPU Frequency scaling # -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_TABLE=y -# CONFIG_CPU_FREQ_DEBUG is not set -CONFIG_CPU_FREQ_STAT=y -# CONFIG_CPU_FREQ_STAT_DETAILS is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +# CONFIG_CPU_FREQ is not set # # Floating point emulation @@ -333,6 +319,8 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m # # At least one emulation must be selected # +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set CONFIG_VFP=y CONFIG_VFPv3=y CONFIG_NEON=y @@ -385,7 +373,7 @@ CONFIG_IP_PNP_RARP=y # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_INET_XFRM_TUNNEL is not set -# CONFIG_INET_TUNNEL is not set +CONFIG_INET_TUNNEL=m CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_INET_XFRM_MODE_BEET=y @@ -396,7 +384,25 @@ CONFIG_INET_TCP_DIAG=y CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_TCP_MD5SIG is not set -# CONFIG_IPV6 is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set # CONFIG_IP_DCCP is not set @@ -455,7 +461,7 @@ CONFIG_NET_SCH_FIFO=y # CONFIG_IRDA is not set CONFIG_BT=y CONFIG_BT_L2CAP=y -# CONFIG_BT_SCO is not set +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=y @@ -466,10 +472,12 @@ CONFIG_BT_HIDP=y # # Bluetooth device drivers # -# CONFIG_BT_HCIUSB is not set -# CONFIG_BT_HCIBTUSB is not set +CONFIG_BT_HCIBTUSB=m # CONFIG_BT_HCIBTSDIO is not set -# CONFIG_BT_HCIUART is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +CONFIG_BT_HCIUART_LL=y # CONFIG_BT_HCIBCM203X is not set # CONFIG_BT_HCIBPA10X is not set # CONFIG_BT_HCIBFUSB is not set @@ -507,7 +515,9 @@ CONFIG_MAC80211_VERBOSE_DEBUG=y # CONFIG_MAC80211_LOWTX_FRAME_DUMP is not set # CONFIG_MAC80211_VERBOSE_SPECT_MGMT_DEBUG is not set # CONFIG_IEEE80211 is not set -# CONFIG_RFKILL is not set +CONFIG_RFKILL=m +# CONFIG_RFKILL_INPUT is not set +CONFIG_RFKILL_LEDS=y # CONFIG_NET_9P is not set # @@ -735,6 +745,7 @@ CONFIG_USB_ARMLINUX=y CONFIG_USB_EPSON2888=y CONFIG_USB_KC2190=y CONFIG_USB_NET_ZAURUS=m +# CONFIG_USB_HSO is not set # CONFIG_WAN is not set CONFIG_PPP=m CONFIG_PPP_MULTILINK=y @@ -814,7 +825,7 @@ CONFIG_INPUT_MISC=y # CONFIG_INPUT_ATI_REMOTE is not set # CONFIG_INPUT_ATI_REMOTE2 is not set # CONFIG_INPUT_KEYSPAN_REMOTE is not set -# CONFIG_INPUT_POWERMATE is not set +CONFIG_INPUT_POWERMATE=m # CONFIG_INPUT_YEALINK is not set CONFIG_INPUT_UINPUT=y CONFIG_INPUT_VSENSE=y @@ -914,6 +925,7 @@ CONFIG_TWL4030_PWRBUTTON=y CONFIG_TWL4030_POWEROFF=y # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_TSL2563 is not set # CONFIG_LP5521 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set @@ -968,7 +980,61 @@ CONFIG_POWER_SUPPLY=y # CONFIG_BATTERY_DS2760 is not set # CONFIG_BATTERY_BQ27x00 is not set CONFIG_TWL4030_BCI_BATTERY=y -# CONFIG_HWMON is not set +CONFIG_HWMON=m +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7473 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_TSC210X is not set +# CONFIG_SENSORS_OMAP34XX is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # CONFIG_WATCHDOG is not set # @@ -1077,7 +1143,7 @@ CONFIG_USB_ZR364XX=m # CONFIG_VIDEO_SH_MOBILE_CEU is not set CONFIG_RADIO_ADAPTERS=y # CONFIG_RADIO_TEA5761 is not set -# CONFIG_USB_DSBR is not set +CONFIG_USB_DSBR=m # CONFIG_USB_SI470X is not set CONFIG_DVB_CAPTURE_DRIVERS=y # CONFIG_TTPCI_EEPROM is not set @@ -1196,7 +1262,7 @@ CONFIG_DVB_LNBP21=m # CONFIG_DVB_ISL6405 is not set CONFIG_DVB_ISL6421=m CONFIG_DAB=y -# CONFIG_USB_DABUSB is not set +CONFIG_USB_DABUSB=m # # Graphics support @@ -1546,7 +1612,7 @@ CONFIG_MMC_EMBEDDED_SDIO=y # CONFIG_MMC_BLOCK=y CONFIG_MMC_BLOCK_BOUNCE=y -# CONFIG_SDIO_UART is not set +CONFIG_SDIO_UART=m # CONFIG_MMC_TEST is not set # @@ -1662,7 +1728,7 @@ CONFIG_JBD=y CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set +CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set # CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set @@ -1744,9 +1810,13 @@ CONFIG_NFS_V3=y # CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -# CONFIG_NFSD is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y diff --git a/recipes/linux/omap3-pandora-kernel/keypad/0001-input-remove-old-twl4030keypad-to-replace-it-with-ma.patch b/recipes/linux/omap3-pandora-kernel/keypad/0001-input-remove-old-twl4030keypad-to-replace-it-with-ma.patch new file mode 100644 index 0000000..610dbe3 --- /dev/null +++ b/recipes/linux/omap3-pandora-kernel/keypad/0001-input-remove-old-twl4030keypad-to-replace-it-with-ma.patch @@ -0,0 +1,566 @@ +From 917491ccf4546bbd34d999cd4878c3b10b621c1c Mon Sep 17 00:00:00 2001 +From: Grazvydas Ignotas +Date: Tue, 3 Nov 2009 15:15:00 +0200 +Subject: [PATCH 1/7] input: remove old twl4030keypad to replace it with mainline version + +--- + drivers/input/keyboard/Kconfig | 10 - + drivers/input/keyboard/Makefile | 1 - + drivers/input/keyboard/omap-twl4030keypad.c | 422 --------------------------- + drivers/input/keyboard/twl4030-keypad.h | 82 ------ + 4 files changed, 0 insertions(+), 515 deletions(-) + delete mode 100644 drivers/input/keyboard/omap-twl4030keypad.c + delete mode 100644 drivers/input/keyboard/twl4030-keypad.h + +diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig +index 616ce41..59ad05a 100644 +--- a/drivers/input/keyboard/Kconfig ++++ b/drivers/input/keyboard/Kconfig +@@ -259,16 +259,6 @@ config KEYBOARD_OMAP + To compile this driver as a module, choose M here: the + module will be called omap-keypad. + +-config KEYBOARD_TWL4030 +- tristate "TI TWL4030 keypad support" +- depends on TWL4030_CORE && (MACH_OMAP_2430SDP || MACH_OMAP2EVM || MACH_OMAP_3430SDP || MACH_OMAP3EVM || MACH_OMAP3_PANDORA) +- help +- Say Y here if you want to use the OMAP TWL4030 keypad. +- +- To compile this driver as a module, choose M here: the +- module will be called omap-twl4030keypad. This driver depends on +- TWL4030 Core and TWL4030 GPIO I2C client driver +- + config OMAP_PS2 + tristate "TI OMAP Innovator 1510 PS/2 keyboard & mouse support" + depends on ARCH_OMAP15XX && MACH_OMAP_INNOVATOR +diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile +index ae47fff..81e59f7 100644 +--- a/drivers/input/keyboard/Makefile ++++ b/drivers/input/keyboard/Makefile +@@ -22,7 +22,6 @@ obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o + obj-$(CONFIG_OMAP_PS2) += innovator_ps2.o + obj-$(CONFIG_KEYBOARD_TSC2301) += tsc2301_kp.o + obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o +-obj-$(CONFIG_KEYBOARD_TWL4030) += omap-twl4030keypad.o + obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o + obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o + obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o +diff --git a/drivers/input/keyboard/omap-twl4030keypad.c b/drivers/input/keyboard/omap-twl4030keypad.c +deleted file mode 100644 +index f6f1ad8..0000000 +--- a/drivers/input/keyboard/omap-twl4030keypad.c ++++ /dev/null +@@ -1,422 +0,0 @@ +-/* +- * drivers/input/keyboard/omap-twl4030keypad.c +- * +- * Copyright (C) 2007 Texas Instruments, Inc. +- * Copyright (C) 2008 Nokia Corporation +- * +- * Code re-written for 2430SDP by: +- * Syed Mohammed Khasim +- * +- * Initial Code: +- * Manjunatha G K +- * +- * 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 "twl4030-keypad.h" +- +-#define PTV_PRESCALER 4 +- +-#define MAX_ROWS 8 /* TWL4030 hardlimit */ +-#define ROWCOL_MASK 0xFF000000 +-#define KEYNUM_MASK 0x00FFFFFF +-#define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val)) +- +-/* Global variables */ +- +-struct omap_keypad { +- int *keymap; +- unsigned int keymapsize; +- u16 kp_state[MAX_ROWS]; +- int n_rows; +- int n_cols; +- int irq; +- +- struct device *dbg_dev; +- struct input_dev *omap_twl4030kp; +- +- /* sync read/write */ +- struct mutex mutex; +-}; +- +-static int twl4030_kpread(struct omap_keypad *kp, +- u32 module, u8 *data, u32 reg, u8 num_bytes) +-{ +- int ret; +- +- ret = twl4030_i2c_read(module, data, reg, num_bytes); +- if (ret < 0) { +- dev_warn(kp->dbg_dev, +- "Couldn't read TWL4030: %X - ret %d[%x]\n", +- reg, ret, ret); +- return ret; +- } +- return ret; +-} +- +-static int twl4030_kpwrite_u8(struct omap_keypad *kp, +- u32 module, u8 data, u32 reg) +-{ +- int ret; +- +- ret = twl4030_i2c_write_u8(module, data, reg); +- if (ret < 0) { +- dev_warn(kp->dbg_dev, +- "Could not write TWL4030: %X - ret %d[%x]\n", +- reg, ret, ret); +- return ret; +- } +- return ret; +-} +- +-static int omap_kp_find_key(struct omap_keypad *kp, int col, int row) +-{ +- int i, rc; +- +- rc = KEY(col, row, 0); +- for (i = 0; i < kp->keymapsize; i++) +- if ((kp->keymap[i] & ROWCOL_MASK) == rc) +- return kp->keymap[i] & KEYNUM_MASK; +- +- return -EINVAL; +-} +- +-static inline u16 omap_kp_col_xlate(struct omap_keypad *kp, u8 col) +-{ +- /* If all bits in a row are active for all coloumns then +- * we have that row line connected to gnd. Mark this +- * key on as if it was on matrix position n_cols (ie +- * one higher than the size of the matrix). +- */ +- if (col == 0xFF) +- return 1 << kp->n_cols; +- else +- return col & ((1 << kp->n_cols) - 1); +-} +- +-static int omap_kp_read_kp_matrix_state(struct omap_keypad *kp, u16 *state) +-{ +- u8 new_state[MAX_ROWS]; +- int row; +- int ret = twl4030_kpread(kp, TWL4030_MODULE_KEYPAD, +- new_state, KEYP_FULL_CODE_7_0, kp->n_rows); +- if (ret >= 0) { +- for (row = 0; row < kp->n_rows; row++) +- state[row] = omap_kp_col_xlate(kp, new_state[row]); +- } +- return ret; +-} +- +-static int omap_kp_is_in_ghost_state(struct omap_keypad *kp, u16 *key_state) +-{ +- int i; +- u16 check = 0; +- +- for (i = 0; i < kp->n_rows; i++) { +- u16 col = key_state[i]; +- +- if ((col & check) && hweight16(col) > 1) +- return 1; +- check |= col; +- } +- +- return 0; +-} +- +-static void twl4030_kp_scan(struct omap_keypad *kp, int release_all) +-{ +- u16 new_state[MAX_ROWS]; +- int col, row; +- +- if (release_all) +- memset(new_state, 0, sizeof(new_state)); +- else { +- /* check for any changes */ +- int ret = omap_kp_read_kp_matrix_state(kp, new_state); +- if (ret < 0) /* panic ... */ +- return; +- +- if (omap_kp_is_in_ghost_state(kp, new_state)) +- return; +- } +- +- mutex_lock(&kp->mutex); +- +- /* check for changes and print those */ +- for (row = 0; row < kp->n_rows; row++) { +- int changed = new_state[row] ^ kp->kp_state[row]; +- +- if (!changed) +- continue; +- +- for (col = 0; col < kp->n_cols; col++) { +- int key; +- +- if (!(changed & (1 << col))) +- continue; +- +- dev_dbg(kp->dbg_dev, "key [%d:%d] %s\n", row, col, +- (new_state[row] & (1 << col)) ? +- "press" : "release"); +- +- key = omap_kp_find_key(kp, col, row); +- if (key < 0) +- dev_warn(kp->dbg_dev, +- "Spurious key event %d-%d\n", +- col, row); +- else +- input_report_key(kp->omap_twl4030kp, key, +- new_state[row] & (1 << col)); +- } +- kp->kp_state[row] = new_state[row]; +- } +- +- mutex_unlock(&kp->mutex); +-} +- +-/* +- * Keypad interrupt handler +- */ +-static irqreturn_t do_kp_irq(int irq, void *_kp) +-{ +- struct omap_keypad *kp = _kp; +- u8 reg; +- int ret; +- +-#ifdef CONFIG_LOCKDEP +- /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which +- * we don't want and can't tolerate. Although it might be +- * friendlier not to borrow this thread context... +- */ +- local_irq_enable(); +-#endif +- +- /* Read & Clear TWL4030 pending interrupt */ +- ret = twl4030_kpread(kp, TWL4030_MODULE_KEYPAD, ®, KEYP_ISR1, 1); +- +- /* Release all keys if I2C has gone bad or +- * the KEYP has gone to idle state */ +- if ((ret >= 0) && (reg & KEYP_IMR1_KP)) +- twl4030_kp_scan(kp, 0); +- else +- twl4030_kp_scan(kp, 1); +- +- return IRQ_HANDLED; +-} +- +-/* +- * Registers keypad device with input sub system +- * and configures TWL4030 keypad registers +- */ +-static int __init omap_kp_probe(struct platform_device *pdev) +-{ +- u8 reg; +- int i; +- int ret = 0; +- struct omap_keypad *kp; +- struct twl4030_keypad_data *pdata = pdev->dev.platform_data; +- +- kp = kzalloc(sizeof(*kp), GFP_KERNEL); +- if (!kp) +- return -ENOMEM; +- +- if (!pdata->rows || !pdata->cols || !pdata->keymap) { +- dev_err(&pdev->dev, "No rows, cols or keymap from pdata\n"); +- kfree(kp); +- return -EINVAL; +- } +- +- dev_set_drvdata(&pdev->dev, kp); +- +- /* Get the debug Device */ +- kp->dbg_dev = &pdev->dev; +- +- kp->omap_twl4030kp = input_allocate_device(); +- if (!kp->omap_twl4030kp) { +- kfree(kp); +- return -ENOMEM; +- } +- +- mutex_init(&kp->mutex); +- +- kp->keymap = pdata->keymap; +- kp->keymapsize = pdata->keymapsize; +- kp->n_rows = pdata->rows; +- kp->n_cols = pdata->cols; +- kp->irq = pdata->irq; +- +- /* setup input device */ +- set_bit(EV_KEY, kp->omap_twl4030kp->evbit); +- +- /* Enable auto repeat feature of Linux input subsystem */ +- if (pdata->rep) +- set_bit(EV_REP, kp->omap_twl4030kp->evbit); +- +- for (i = 0; i < kp->keymapsize; i++) +- set_bit(kp->keymap[i] & KEYNUM_MASK, +- kp->omap_twl4030kp->keybit); +- +- kp->omap_twl4030kp->name = "omap_twl4030keypad"; +- kp->omap_twl4030kp->phys = "omap_twl4030keypad/input0"; +- kp->omap_twl4030kp->dev.parent = &pdev->dev; +- +- kp->omap_twl4030kp->id.bustype = BUS_HOST; +- kp->omap_twl4030kp->id.vendor = 0x0001; +- kp->omap_twl4030kp->id.product = 0x0001; +- kp->omap_twl4030kp->id.version = 0x0003; +- +- kp->omap_twl4030kp->keycode = kp->keymap; +- kp->omap_twl4030kp->keycodesize = sizeof(unsigned int); +- kp->omap_twl4030kp->keycodemax = kp->keymapsize; +- +- ret = input_register_device(kp->omap_twl4030kp); +- if (ret < 0) { +- dev_err(kp->dbg_dev, +- "Unable to register twl4030 keypad device\n"); +- goto err2; +- } +- +- /* Disable auto-repeat */ +- reg = KEYP_CTRL_NOAUTORPT; +- ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, reg, KEYP_CTRL); +- if (ret < 0) +- goto err3; +- +- /* Enable TO rising and KP rising and falling edge detection */ +- reg = KEYP_EDR_KP_BOTH | KEYP_EDR_TO_RISING; +- ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, reg, KEYP_EDR); +- if (ret < 0) +- goto err3; +- +- /* Set PTV prescaler Field */ +- reg = (PTV_PRESCALER << KEYP_LK_PTV_PTV_SHIFT); +- ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, reg, KEYP_LK_PTV); +- if (ret < 0) +- goto err3; +- +- /* Set key debounce time to 20 ms */ +- i = KEYP_PERIOD_US(20000, PTV_PRESCALER); +- ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, i, KEYP_DEB); +- if (ret < 0) +- goto err3; +- +- /* Set timeout period to 100 ms */ +- i = KEYP_PERIOD_US(200000, PTV_PRESCALER); +- ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, +- (i & 0xFF), KEYP_TIMEOUT_L); +- if (ret < 0) +- goto err3; +- +- ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, +- (i >> 8), KEYP_TIMEOUT_H); +- if (ret < 0) +- goto err3; +- +- /* Enable Clear-on-Read */ +- reg = KEYP_SIH_CTRL_COR | KEYP_SIH_CTRL_PEND_DIS; +- ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, +- reg, KEYP_SIH_CTRL); +- if (ret < 0) +- goto err3; +- +- /* +- * This ISR will always execute in kernel thread context because of +- * the need to access the TWL4030 over the I2C bus. +- */ +- ret = request_irq(kp->irq, do_kp_irq, 0, pdev->name, kp); +- if (ret < 0) { +- dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n", +- kp->irq); +- goto err3; +- } else { +- /* Enable KP and TO interrupts now. */ +- reg = ~(KEYP_IMR1_KP | KEYP_IMR1_TO); +- ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, +- reg, KEYP_IMR1); +- if (ret < 0) +- goto err5; +- } +- +- ret = omap_kp_read_kp_matrix_state(kp, kp->kp_state); +- if (ret < 0) +- goto err4; +- +- return ret; +-err5: +- /* mask all events - we don't care about the result */ +- (void) twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, 0xff, KEYP_IMR1); +-err4: +- free_irq(kp->irq, NULL); +-err3: +- input_unregister_device(kp->omap_twl4030kp); +-err2: +- input_free_device(kp->omap_twl4030kp); +- +- return -ENODEV; +-} +- +-static int omap_kp_remove(struct platform_device *pdev) +-{ +- struct omap_keypad *kp = dev_get_drvdata(&pdev->dev); +- +- free_irq(kp->irq, kp); +- input_unregister_device(kp->omap_twl4030kp); +- kfree(kp); +- +- return 0; +-} +- +- +-static struct platform_driver omap_kp_driver = { +- .probe = omap_kp_probe, +- .remove = __devexit_p(omap_kp_remove), +- .driver = { +- .name = "twl4030_keypad", +- .owner = THIS_MODULE, +- }, +-}; +- +-/* +- * OMAP TWL4030 Keypad init +- */ +-static int __devinit omap_kp_init(void) +-{ +- return platform_driver_register(&omap_kp_driver); +-} +- +-static void __exit omap_kp_exit(void) +-{ +- platform_driver_unregister(&omap_kp_driver); +-} +- +-module_init(omap_kp_init); +-module_exit(omap_kp_exit); +-MODULE_ALIAS("platform:twl4030_keypad"); +-MODULE_AUTHOR("Texas Instruments"); +-MODULE_DESCRIPTION("OMAP TWL4030 Keypad Driver"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/input/keyboard/twl4030-keypad.h b/drivers/input/keyboard/twl4030-keypad.h +deleted file mode 100644 +index b903a77..0000000 +--- a/drivers/input/keyboard/twl4030-keypad.h ++++ /dev/null +@@ -1,82 +0,0 @@ +-/* +- * drivers/input/keyboard/twl4030-keypad.h +- * +- * Copyright (C) 2006-2007 Texas Instruments, Inc. +- * +- * Intial Code: +- * Syed Mohammed Khasim +- * +- * 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 __TWL4030_KEYPAD_H__ +-#define __TWL4030_KEYPAD_H__ +- +-/* Register Definitions */ +-#define KEYP_CTRL 0x00 +-#define KEYP_DEB 0x01 +-#define KEYP_LONG_KEY 0x02 +-#define KEYP_LK_PTV 0x03 +-#define KEYP_TIMEOUT_L 0x04 +-#define KEYP_TIMEOUT_H 0x05 +-#define KEYP_FULL_CODE_7_0 0x09 +-#define KEYP_ISR1 0x11 +-#define KEYP_IMR1 0x12 +-#define KEYP_EDR 0x16 +-#define KEYP_SIH_CTRL 0x17 +- +-/* KEYP_CTRL_REG Fields */ +-#define KEYP_CTRL_SOFT_NRST 0x01 +-#define KEYP_CTRL_SOFTMODEN 0x02 +-#define KEYP_CTRL_LK_EN 0x04 +-#define KEYP_CTRL_TOE_EN 0x08 +-#define KEYP_CTRL_TOLE_EN 0x10 +-#define KEYP_CTRL_RP_EN 0x20 +-#define KEYP_CTRL_KBD_ON 0x40 +- +- +-#define KEYP_CTRL_NOAUTORPT (KEYP_CTRL_SOFT_NRST | \ +- KEYP_CTRL_SOFTMODEN | \ +- KEYP_CTRL_TOE_EN | \ +- KEYP_CTRL_KBD_ON) +- +-/* KEYP_DEB, KEYP_LONG_KEY, KEYP_TIMEOUT_x*/ +-#define KEYP_PERIOD_US(T, prescale) (T / (31 << (prescale + 1)) - 1) +- +-/* KEYP_LK_PTV_REG Fields */ +-#define KEYP_LK_PTV_PTV_SHIFT 5 +- +-/* KEYP_IMR1 Fields */ +-#define KEYP_IMR1_MIS 0x08 +-#define KEYP_IMR1_TO 0x04 +-#define KEYP_IMR1_LK 0x02 +-#define KEYP_IMR1_KP 0x01 +- +-/* KEYP_EDR Fields */ +-#define KEYP_EDR_KP_FALLING 0x01 +-#define KEYP_EDR_KP_RISING 0x02 +-#define KEYP_EDR_KP_BOTH 0x03 +-#define KEYP_EDR_LK_FALLING 0x04 +-#define KEYP_EDR_LK_RISING 0x08 +-#define KEYP_EDR_TO_FALLING 0x10 +-#define KEYP_EDR_TO_RISING 0x20 +-#define KEYP_EDR_MIS_FALLING 0x40 +-#define KEYP_EDR_MIS_RISING 0x80 +- +-/* KEYP_SIH_CTRL Fields */ +-#define KEYP_SIH_CTRL_COR 0x04 +-#define KEYP_SIH_CTRL_PEND_DIS 0x02 +-#define KEYP_SIH_CTRL_EXCL_EN 0x01 +- +-#endif /* End of __TWL4030-KEYPAD_H__ */ +-- +1.6.3.1 + diff --git a/recipes/linux/omap3-pandora-kernel/keypad/0002-Input-add-support-for-generic-GPIO-based-matrix-keyp.patch b/recipes/linux/omap3-pandora-kernel/keypad/0002-Input-add-support-for-generic-GPIO-based-matrix-keyp.patch new file mode 100644 index 0000000..814a561 --- /dev/null +++ b/recipes/linux/omap3-pandora-kernel/keypad/0002-Input-add-support-for-generic-GPIO-based-matrix-keyp.patch @@ -0,0 +1,612 @@ +From a38e5cd354ef968dc6dc0decf579243c8d473698 Mon Sep 17 00:00:00 2001 +From: Eric Miao +Date: Tue, 3 Nov 2009 15:43:49 +0200 +Subject: [PATCH 2/7] Input: add support for generic GPIO-based matrix keypad + +Original patch by Marek Vasut, modified by Eric in: + +1. use delayed work to simplify the debouncing +2. combine col_polarity/row_polarity into a single active_low field +3. use a generic bit array based XOR algorithm to detect key + press/release, which should make the column assertion time + shorter and code a bit cleaner +4. remove the ALT_FN handling, which is no way generic, the ALT_FN + key should be treated as no different from other keys, and + translation will be done by user space by commands like 'loadkeys'. +5. explicitly disable row IRQs and flush potential pending work, + and schedule an immediate scan after resuming as suggested + by Uli Luckas +6. incorporate review comments from many others + +Patch tested on Littleton/PXA310 (though PXA310 has a dedicate keypad +controller, I have to configure those pins as generic GPIO to use this +driver, works quite well, though), and Sharp Zaurus model SL-C7x0 +and SL-C1000. + +[dtor@mail.ru: fix error unwinding path, support changing keymap + from userspace] +Signed-off-by: Marek Vasut +Reviewed-by: Trilok Soni +Reviewed-by: Uli Luckas +Reviewed-by: Russell King +Reviewed-by: Robert Jarzmik +Signed-off-by: Eric Miao +Signed-off-by: Dmitry Torokhov + +Conflicts: + + drivers/input/keyboard/Kconfig + drivers/input/keyboard/Makefile +--- + drivers/input/keyboard/Kconfig | 9 + + drivers/input/keyboard/Makefile | 1 + + drivers/input/keyboard/matrix_keypad.c | 453 ++++++++++++++++++++++++++++++++ + include/linux/input/matrix_keypad.h | 65 +++++ + 4 files changed, 528 insertions(+), 0 deletions(-) + create mode 100644 drivers/input/keyboard/matrix_keypad.c + create mode 100644 include/linux/input/matrix_keypad.h + +diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig +index 59ad05a..b0a3c78 100644 +--- a/drivers/input/keyboard/Kconfig ++++ b/drivers/input/keyboard/Kconfig +@@ -199,6 +199,15 @@ config KEYBOARD_ATARI + To compile this driver as a module, choose M here: the + module will be called atakbd. + ++config KEYBOARD_MATRIX ++ tristate "GPIO driven matrix keypad support" ++ depends on GENERIC_GPIO ++ help ++ Enable support for GPIO driven matrix keypad. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called matrix_keypad. ++ + config KEYBOARD_HIL_OLD + tristate "HP HIL keyboard support (simple driver)" + depends on GSC || HP300 +diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile +index 81e59f7..7b8bc44 100644 +--- a/drivers/input/keyboard/Makefile ++++ b/drivers/input/keyboard/Makefile +@@ -28,5 +28,6 @@ obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o + obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o + obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o + obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o ++obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o + obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o + obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o +diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c +new file mode 100644 +index 0000000..e9b2e7c +--- /dev/null ++++ b/drivers/input/keyboard/matrix_keypad.c +@@ -0,0 +1,453 @@ ++/* ++ * GPIO driven matrix keyboard driver ++ * ++ * Copyright (c) 2008 Marek Vasut ++ * ++ * Based on corgikbd.c ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct matrix_keypad { ++ const struct matrix_keypad_platform_data *pdata; ++ struct input_dev *input_dev; ++ unsigned short *keycodes; ++ ++ uint32_t last_key_state[MATRIX_MAX_COLS]; ++ struct delayed_work work; ++ bool scan_pending; ++ bool stopped; ++ spinlock_t lock; ++}; ++ ++/* ++ * NOTE: normally the GPIO has to be put into HiZ when de-activated to cause ++ * minmal side effect when scanning other columns, here it is configured to ++ * be input, and it should work on most platforms. ++ */ ++static void __activate_col(const struct matrix_keypad_platform_data *pdata, ++ int col, bool on) ++{ ++ bool level_on = !pdata->active_low; ++ ++ if (on) { ++ gpio_direction_output(pdata->col_gpios[col], level_on); ++ } else { ++ gpio_set_value_cansleep(pdata->col_gpios[col], !level_on); ++ gpio_direction_input(pdata->col_gpios[col]); ++ } ++} ++ ++static void activate_col(const struct matrix_keypad_platform_data *pdata, ++ int col, bool on) ++{ ++ __activate_col(pdata, col, on); ++ ++ if (on && pdata->col_scan_delay_us) ++ udelay(pdata->col_scan_delay_us); ++} ++ ++static void activate_all_cols(const struct matrix_keypad_platform_data *pdata, ++ bool on) ++{ ++ int col; ++ ++ for (col = 0; col < pdata->num_col_gpios; col++) ++ __activate_col(pdata, col, on); ++} ++ ++static bool row_asserted(const struct matrix_keypad_platform_data *pdata, ++ int row) ++{ ++ return gpio_get_value_cansleep(pdata->row_gpios[row]) ? ++ !pdata->active_low : pdata->active_low; ++} ++ ++static void enable_row_irqs(struct matrix_keypad *keypad) ++{ ++ const struct matrix_keypad_platform_data *pdata = keypad->pdata; ++ int i; ++ ++ for (i = 0; i < pdata->num_row_gpios; i++) ++ enable_irq(gpio_to_irq(pdata->row_gpios[i])); ++} ++ ++static void disable_row_irqs(struct matrix_keypad *keypad) ++{ ++ const struct matrix_keypad_platform_data *pdata = keypad->pdata; ++ int i; ++ ++ for (i = 0; i < pdata->num_row_gpios; i++) ++ disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i])); ++} ++ ++/* ++ * This gets the keys from keyboard and reports it to input subsystem ++ */ ++static void matrix_keypad_scan(struct work_struct *work) ++{ ++ struct matrix_keypad *keypad = ++ container_of(work, struct matrix_keypad, work.work); ++ struct input_dev *input_dev = keypad->input_dev; ++ const struct matrix_keypad_platform_data *pdata = keypad->pdata; ++ uint32_t new_state[MATRIX_MAX_COLS]; ++ int row, col, code; ++ ++ /* de-activate all columns for scanning */ ++ activate_all_cols(pdata, false); ++ ++ memset(new_state, 0, sizeof(new_state)); ++ ++ /* assert each column and read the row status out */ ++ for (col = 0; col < pdata->num_col_gpios; col++) { ++ ++ activate_col(pdata, col, true); ++ ++ for (row = 0; row < pdata->num_row_gpios; row++) ++ new_state[col] |= ++ row_asserted(pdata, row) ? (1 << row) : 0; ++ ++ activate_col(pdata, col, false); ++ } ++ ++ for (col = 0; col < pdata->num_col_gpios; col++) { ++ uint32_t bits_changed; ++ ++ bits_changed = keypad->last_key_state[col] ^ new_state[col]; ++ if (bits_changed == 0) ++ continue; ++ ++ for (row = 0; row < pdata->num_row_gpios; row++) { ++ if ((bits_changed & (1 << row)) == 0) ++ continue; ++ ++ code = (row << 4) + col; ++ input_event(input_dev, EV_MSC, MSC_SCAN, code); ++ input_report_key(input_dev, ++ keypad->keycodes[code], ++ new_state[col] & (1 << row)); ++ } ++ } ++ input_sync(input_dev); ++ ++ memcpy(keypad->last_key_state, new_state, sizeof(new_state)); ++ ++ activate_all_cols(pdata, true); ++ ++ /* Enable IRQs again */ ++ spin_lock_irq(&keypad->lock); ++ keypad->scan_pending = false; ++ enable_row_irqs(keypad); ++ spin_unlock_irq(&keypad->lock); ++} ++ ++static irqreturn_t matrix_keypad_interrupt(int irq, void *id) ++{ ++ struct matrix_keypad *keypad = id; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&keypad->lock, flags); ++ ++ /* ++ * See if another IRQ beaten us to it and scheduled the ++ * scan already. In that case we should not try to ++ * disable IRQs again. ++ */ ++ if (unlikely(keypad->scan_pending || keypad->stopped)) ++ goto out; ++ ++ disable_row_irqs(keypad); ++ keypad->scan_pending = true; ++ schedule_delayed_work(&keypad->work, ++ msecs_to_jiffies(keypad->pdata->debounce_ms)); ++ ++out: ++ spin_unlock_irqrestore(&keypad->lock, flags); ++ return IRQ_HANDLED; ++} ++ ++static int matrix_keypad_start(struct input_dev *dev) ++{ ++ struct matrix_keypad *keypad = input_get_drvdata(dev); ++ ++ keypad->stopped = false; ++ mb(); ++ ++ /* ++ * Schedule an immediate key scan to capture current key state; ++ * columns will be activated and IRQs be enabled after the scan. ++ */ ++ schedule_delayed_work(&keypad->work, 0); ++ ++ return 0; ++} ++ ++static void matrix_keypad_stop(struct input_dev *dev) ++{ ++ struct matrix_keypad *keypad = input_get_drvdata(dev); ++ ++ keypad->stopped = true; ++ mb(); ++ flush_work(&keypad->work.work); ++ /* ++ * matrix_keypad_scan() will leave IRQs enabled; ++ * we should disable them now. ++ */ ++ disable_row_irqs(keypad); ++} ++ ++#ifdef CONFIG_PM ++static int matrix_keypad_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct matrix_keypad *keypad = platform_get_drvdata(pdev); ++ const struct matrix_keypad_platform_data *pdata = keypad->pdata; ++ int i; ++ ++ matrix_keypad_stop(keypad->input_dev); ++ ++ if (device_may_wakeup(&pdev->dev)) ++ for (i = 0; i < pdata->num_row_gpios; i++) ++ enable_irq_wake(gpio_to_irq(pdata->row_gpios[i])); ++ ++ return 0; ++} ++ ++static int matrix_keypad_resume(struct platform_device *pdev) ++{ ++ struct matrix_keypad *keypad = platform_get_drvdata(pdev); ++ const struct matrix_keypad_platform_data *pdata = keypad->pdata; ++ int i; ++ ++ if (device_may_wakeup(&pdev->dev)) ++ for (i = 0; i < pdata->num_row_gpios; i++) ++ disable_irq_wake(gpio_to_irq(pdata->row_gpios[i])); ++ ++ matrix_keypad_start(keypad->input_dev); ++ ++ return 0; ++} ++#else ++#define matrix_keypad_suspend NULL ++#define matrix_keypad_resume NULL ++#endif ++ ++static int __devinit init_matrix_gpio(struct platform_device *pdev, ++ struct matrix_keypad *keypad) ++{ ++ const struct matrix_keypad_platform_data *pdata = keypad->pdata; ++ int i, err = -EINVAL; ++ ++ /* initialized strobe lines as outputs, activated */ ++ for (i = 0; i < pdata->num_col_gpios; i++) { ++ err = gpio_request(pdata->col_gpios[i], "matrix_kbd_col"); ++ if (err) { ++ dev_err(&pdev->dev, ++ "failed to request GPIO%d for COL%d\n", ++ pdata->col_gpios[i], i); ++ goto err_free_cols; ++ } ++ ++ gpio_direction_output(pdata->col_gpios[i], !pdata->active_low); ++ } ++ ++ for (i = 0; i < pdata->num_row_gpios; i++) { ++ err = gpio_request(pdata->row_gpios[i], "matrix_kbd_row"); ++ if (err) { ++ dev_err(&pdev->dev, ++ "failed to request GPIO%d for ROW%d\n", ++ pdata->row_gpios[i], i); ++ goto err_free_rows; ++ } ++ ++ gpio_direction_input(pdata->row_gpios[i]); ++ } ++ ++ for (i = 0; i < pdata->num_row_gpios; i++) { ++ err = request_irq(gpio_to_irq(pdata->row_gpios[i]), ++ matrix_keypad_interrupt, ++ IRQF_DISABLED | ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, ++ "matrix-keypad", keypad); ++ if (err) { ++ dev_err(&pdev->dev, ++ "Unable to acquire interrupt for GPIO line %i\n", ++ pdata->row_gpios[i]); ++ goto err_free_irqs; ++ } ++ } ++ ++ /* initialized as disabled - enabled by input->open */ ++ disable_row_irqs(keypad); ++ return 0; ++ ++err_free_irqs: ++ while (--i >= 0) ++ free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); ++ i = pdata->num_row_gpios; ++err_free_rows: ++ while (--i >= 0) ++ gpio_free(pdata->row_gpios[i]); ++ i = pdata->num_col_gpios; ++err_free_cols: ++ while (--i >= 0) ++ gpio_free(pdata->col_gpios[i]); ++ ++ return err; ++} ++ ++static int __devinit matrix_keypad_probe(struct platform_device *pdev) ++{ ++ const struct matrix_keypad_platform_data *pdata; ++ const struct matrix_keymap_data *keymap_data; ++ struct matrix_keypad *keypad; ++ struct input_dev *input_dev; ++ unsigned short *keycodes; ++ int i; ++ int err; ++ ++ pdata = pdev->dev.platform_data; ++ if (!pdata) { ++ dev_err(&pdev->dev, "no platform data defined\n"); ++ return -EINVAL; ++ } ++ ++ keymap_data = pdata->keymap_data; ++ if (!keymap_data) { ++ dev_err(&pdev->dev, "no keymap data defined\n"); ++ return -EINVAL; ++ } ++ ++ if (!keymap_data->max_keymap_size) { ++ dev_err(&pdev->dev, "invalid keymap data supplied\n"); ++ return -EINVAL; ++ } ++ ++ keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL); ++ keycodes = kzalloc(keymap_data->max_keymap_size * ++ sizeof(keypad->keycodes), ++ GFP_KERNEL); ++ input_dev = input_allocate_device(); ++ if (!keypad || !keycodes || !input_dev) { ++ err = -ENOMEM; ++ goto err_free_mem; ++ } ++ ++ keypad->input_dev = input_dev; ++ keypad->pdata = pdata; ++ keypad->keycodes = keycodes; ++ keypad->stopped = true; ++ INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan); ++ spin_lock_init(&keypad->lock); ++ ++ input_dev->name = pdev->name; ++ input_dev->id.bustype = BUS_HOST; ++ input_dev->dev.parent = &pdev->dev; ++ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); ++ input_dev->open = matrix_keypad_start; ++ input_dev->close = matrix_keypad_stop; ++ ++ input_dev->keycode = keycodes; ++ input_dev->keycodesize = sizeof(*keycodes); ++ input_dev->keycodemax = keymap_data->max_keymap_size; ++ ++ for (i = 0; i < keymap_data->keymap_size; i++) { ++ unsigned int key = keymap_data->keymap[i]; ++ unsigned int row = KEY_ROW(key); ++ unsigned int col = KEY_COL(key); ++ unsigned short code = KEY_VAL(key); ++ ++ keycodes[(row << 4) + col] = code; ++ __set_bit(code, input_dev->keybit); ++ } ++ __clear_bit(KEY_RESERVED, input_dev->keybit); ++ ++ input_set_capability(input_dev, EV_MSC, MSC_SCAN); ++ input_set_drvdata(input_dev, keypad); ++ ++ err = init_matrix_gpio(pdev, keypad); ++ if (err) ++ goto err_free_mem; ++ ++ err = input_register_device(keypad->input_dev); ++ if (err) ++ goto err_free_mem; ++ ++ device_init_wakeup(&pdev->dev, pdata->wakeup); ++ platform_set_drvdata(pdev, keypad); ++ ++ return 0; ++ ++err_free_mem: ++ input_free_device(input_dev); ++ kfree(keycodes); ++ kfree(keypad); ++ return err; ++} ++ ++static int __devexit matrix_keypad_remove(struct platform_device *pdev) ++{ ++ struct matrix_keypad *keypad = platform_get_drvdata(pdev); ++ const struct matrix_keypad_platform_data *pdata = keypad->pdata; ++ int i; ++ ++ device_init_wakeup(&pdev->dev, 0); ++ ++ for (i = 0; i < pdata->num_row_gpios; i++) { ++ free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); ++ gpio_free(pdata->row_gpios[i]); ++ } ++ ++ for (i = 0; i < pdata->num_col_gpios; i++) ++ gpio_free(pdata->col_gpios[i]); ++ ++ input_unregister_device(keypad->input_dev); ++ platform_set_drvdata(pdev, NULL); ++ kfree(keypad->keycodes); ++ kfree(keypad); ++ ++ return 0; ++} ++ ++static struct platform_driver matrix_keypad_driver = { ++ .probe = matrix_keypad_probe, ++ .remove = __devexit_p(matrix_keypad_remove), ++ .suspend = matrix_keypad_suspend, ++ .resume = matrix_keypad_resume, ++ .driver = { ++ .name = "matrix-keypad", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init matrix_keypad_init(void) ++{ ++ return platform_driver_register(&matrix_keypad_driver); ++} ++ ++static void __exit matrix_keypad_exit(void) ++{ ++ platform_driver_unregister(&matrix_keypad_driver); ++} ++ ++module_init(matrix_keypad_init); ++module_exit(matrix_keypad_exit); ++ ++MODULE_AUTHOR("Marek Vasut "); ++MODULE_DESCRIPTION("GPIO Driven Matrix Keypad Driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:matrix-keypad"); +diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h +new file mode 100644 +index 0000000..7964516 +--- /dev/null ++++ b/include/linux/input/matrix_keypad.h +@@ -0,0 +1,65 @@ ++#ifndef _MATRIX_KEYPAD_H ++#define _MATRIX_KEYPAD_H ++ ++#include ++#include ++ ++#define MATRIX_MAX_ROWS 16 ++#define MATRIX_MAX_COLS 16 ++ ++#define KEY(row, col, val) ((((row) & (MATRIX_MAX_ROWS - 1)) << 24) |\ ++ (((col) & (MATRIX_MAX_COLS - 1)) << 16) |\ ++ (val & 0xffff)) ++ ++#define KEY_ROW(k) (((k) >> 24) & 0xff) ++#define KEY_COL(k) (((k) >> 16) & 0xff) ++#define KEY_VAL(k) ((k) & 0xffff) ++ ++/** ++ * struct matrix_keymap_data - keymap for matrix keyboards ++ * @keymap: pointer to array of uint32 values encoded with KEY() macro ++ * representing keymap ++ * @keymap_size: number of entries (initialized) in this keymap ++ * @max_keymap_size: maximum size of keymap supported by the device ++ * ++ * This structure is supposed to be used by platform code to supply ++ * keymaps to drivers that implement matrix-like keypads/keyboards. ++ */ ++struct matrix_keymap_data { ++ const uint32_t *keymap; ++ unsigned int keymap_size; ++ unsigned int max_keymap_size; ++}; ++ ++/** ++ * struct matrix_keypad_platform_data - platform-dependent keypad data ++ * @keymap_data: pointer to &matrix_keymap_data ++ * @row_gpios: array of gpio numbers reporesenting rows ++ * @col_gpios: array of gpio numbers reporesenting colums ++ * @num_row_gpios: actual number of row gpios used by device ++ * @num_col_gpios: actual number of col gpios used by device ++ * @col_scan_delay_us: delay, measured in microseconds, that is ++ * needed before we can keypad after activating column gpio ++ * @debounce_ms: debounce interval in milliseconds ++ * ++ * This structure represents platform-specific data that use used by ++ * matrix_keypad driver to perform proper initialization. ++ */ ++struct matrix_keypad_platform_data { ++ const struct matrix_keymap_data *keymap_data; ++ ++ unsigned int row_gpios[MATRIX_MAX_ROWS]; ++ unsigned int col_gpios[MATRIX_MAX_COLS]; ++ unsigned int num_row_gpios; ++ unsigned int num_col_gpios; ++ ++ unsigned int col_scan_delay_us; ++ ++ /* key debounce interval in milli-second */ ++ unsigned int debounce_ms; ++ ++ bool active_low; ++ bool wakeup; ++}; ++ ++#endif /* _MATRIX_KEYPAD_H */ +-- +1.6.3.1 + diff --git a/recipes/linux/omap3-pandora-kernel/keypad/0003-Input-matrix_keypad-make-matrix-keymap-size-dynamic.patch b/recipes/linux/omap3-pandora-kernel/keypad/0003-Input-matrix_keypad-make-matrix-keymap-size-dynamic.patch new file mode 100644 index 0000000..8b8ee6f --- /dev/null +++ b/recipes/linux/omap3-pandora-kernel/keypad/0003-Input-matrix_keypad-make-matrix-keymap-size-dynamic.patch @@ -0,0 +1,140 @@ +From 99250cbbae885e9535553e095c63c762d32b4325 Mon Sep 17 00:00:00 2001 +From: Eric Miao +Date: Wed, 5 Aug 2009 01:24:41 -0700 +Subject: [PATCH 3/7] Input: matrix_keypad - make matrix keymap size dynamic + +Remove assumption on the shift and size of rows/columns form +matrix_keypad driver. + +Signed-off-by: Eric Miao +Signed-off-by: Dmitry Torokhov +(cherry picked from commit d82f1c35348cebe2fb2d4a4d31ce0ab0769e3d93) +--- + drivers/input/keyboard/matrix_keypad.c | 18 +++++++++--------- + include/linux/input/matrix_keypad.h | 13 +++++++------ + 2 files changed, 16 insertions(+), 15 deletions(-) + +diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c +index e9b2e7c..541b981 100644 +--- a/drivers/input/keyboard/matrix_keypad.c ++++ b/drivers/input/keyboard/matrix_keypad.c +@@ -27,6 +27,7 @@ struct matrix_keypad { + const struct matrix_keypad_platform_data *pdata; + struct input_dev *input_dev; + unsigned short *keycodes; ++ unsigned int row_shift; + + uint32_t last_key_state[MATRIX_MAX_COLS]; + struct delayed_work work; +@@ -136,7 +137,7 @@ static void matrix_keypad_scan(struct work_struct *work) + if ((bits_changed & (1 << row)) == 0) + continue; + +- code = (row << 4) + col; ++ code = MATRIX_SCAN_CODE(row, col, keypad->row_shift); + input_event(input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(input_dev, + keypad->keycodes[code], +@@ -317,6 +318,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) + struct matrix_keypad *keypad; + struct input_dev *input_dev; + unsigned short *keycodes; ++ unsigned int row_shift; + int i; + int err; + +@@ -332,14 +334,11 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) + return -EINVAL; + } + +- if (!keymap_data->max_keymap_size) { +- dev_err(&pdev->dev, "invalid keymap data supplied\n"); +- return -EINVAL; +- } ++ row_shift = get_count_order(pdata->num_col_gpios); + + keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL); +- keycodes = kzalloc(keymap_data->max_keymap_size * +- sizeof(keypad->keycodes), ++ keycodes = kzalloc((pdata->num_row_gpios << row_shift) * ++ sizeof(*keycodes), + GFP_KERNEL); + input_dev = input_allocate_device(); + if (!keypad || !keycodes || !input_dev) { +@@ -350,6 +349,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) + keypad->input_dev = input_dev; + keypad->pdata = pdata; + keypad->keycodes = keycodes; ++ keypad->row_shift = row_shift; + keypad->stopped = true; + INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan); + spin_lock_init(&keypad->lock); +@@ -363,7 +363,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) + + input_dev->keycode = keycodes; + input_dev->keycodesize = sizeof(*keycodes); +- input_dev->keycodemax = keymap_data->max_keymap_size; ++ input_dev->keycodemax = pdata->num_row_gpios << keypad->row_shift; + + for (i = 0; i < keymap_data->keymap_size; i++) { + unsigned int key = keymap_data->keymap[i]; +@@ -371,7 +371,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) + unsigned int col = KEY_COL(key); + unsigned short code = KEY_VAL(key); + +- keycodes[(row << 4) + col] = code; ++ keycodes[MATRIX_SCAN_CODE(row, col, row_shift)] = code; + __set_bit(code, input_dev->keybit); + } + __clear_bit(KEY_RESERVED, input_dev->keybit); +diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h +index 7964516..15d5903 100644 +--- a/include/linux/input/matrix_keypad.h ++++ b/include/linux/input/matrix_keypad.h +@@ -15,12 +15,13 @@ + #define KEY_COL(k) (((k) >> 16) & 0xff) + #define KEY_VAL(k) ((k) & 0xffff) + ++#define MATRIX_SCAN_CODE(row, col, row_shift) (((row) << (row_shift)) + (col)) ++ + /** + * struct matrix_keymap_data - keymap for matrix keyboards + * @keymap: pointer to array of uint32 values encoded with KEY() macro + * representing keymap + * @keymap_size: number of entries (initialized) in this keymap +- * @max_keymap_size: maximum size of keymap supported by the device + * + * This structure is supposed to be used by platform code to supply + * keymaps to drivers that implement matrix-like keypads/keyboards. +@@ -28,14 +29,13 @@ + struct matrix_keymap_data { + const uint32_t *keymap; + unsigned int keymap_size; +- unsigned int max_keymap_size; + }; + + /** + * struct matrix_keypad_platform_data - platform-dependent keypad data + * @keymap_data: pointer to &matrix_keymap_data +- * @row_gpios: array of gpio numbers reporesenting rows +- * @col_gpios: array of gpio numbers reporesenting colums ++ * @row_gpios: pointer to array of gpio numbers representing rows ++ * @col_gpios: pointer to array of gpio numbers reporesenting colums + * @num_row_gpios: actual number of row gpios used by device + * @num_col_gpios: actual number of col gpios used by device + * @col_scan_delay_us: delay, measured in microseconds, that is +@@ -48,8 +48,9 @@ struct matrix_keymap_data { + struct matrix_keypad_platform_data { + const struct matrix_keymap_data *keymap_data; + +- unsigned int row_gpios[MATRIX_MAX_ROWS]; +- unsigned int col_gpios[MATRIX_MAX_COLS]; ++ const unsigned int *row_gpios; ++ const unsigned int *col_gpios; ++ + unsigned int num_row_gpios; + unsigned int num_col_gpios; + +-- +1.6.3.1 + diff --git a/recipes/linux/omap3-pandora-kernel/keypad/0004-Input-matrix-keypad-add-function-to-build-device-key.patch b/recipes/linux/omap3-pandora-kernel/keypad/0004-Input-matrix-keypad-add-function-to-build-device-key.patch new file mode 100644 index 0000000..0ac80a6 --- /dev/null +++ b/recipes/linux/omap3-pandora-kernel/keypad/0004-Input-matrix-keypad-add-function-to-build-device-key.patch @@ -0,0 +1,94 @@ +From 81d264643825f8318c2e0ca39a8b5ce6a4ce3a5a Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Tue, 3 Nov 2009 15:49:37 +0200 +Subject: [PATCH 4/7] Input: matrix-keypad - add function to build device keymap + +Signed-off-by: Dmitry Torokhov +(cherry picked from commit 77a53fd21870c726b670c0d8179294ac1ea33468) + +Conflicts: + + drivers/input/keyboard/w90p910_keypad.c +--- + drivers/input/keyboard/matrix_keypad.c | 15 +++------------ + include/linux/input/matrix_keypad.h | 32 ++++++++++++++++++++++++++++++++ + 2 files changed, 35 insertions(+), 12 deletions(-) + +diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c +index 541b981..91cfe51 100644 +--- a/drivers/input/keyboard/matrix_keypad.c ++++ b/drivers/input/keyboard/matrix_keypad.c +@@ -319,7 +319,6 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) + struct input_dev *input_dev; + unsigned short *keycodes; + unsigned int row_shift; +- int i; + int err; + + pdata = pdev->dev.platform_data; +@@ -363,18 +362,10 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) + + input_dev->keycode = keycodes; + input_dev->keycodesize = sizeof(*keycodes); +- input_dev->keycodemax = pdata->num_row_gpios << keypad->row_shift; +- +- for (i = 0; i < keymap_data->keymap_size; i++) { +- unsigned int key = keymap_data->keymap[i]; +- unsigned int row = KEY_ROW(key); +- unsigned int col = KEY_COL(key); +- unsigned short code = KEY_VAL(key); ++ input_dev->keycodemax = pdata->num_row_gpios << row_shift; + +- keycodes[MATRIX_SCAN_CODE(row, col, row_shift)] = code; +- __set_bit(code, input_dev->keybit); +- } +- __clear_bit(KEY_RESERVED, input_dev->keybit); ++ matrix_keypad_build_keymap(keymap_data, row_shift, ++ input_dev->keycode, input_dev->keybit); + + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + input_set_drvdata(input_dev, keypad); +diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h +index 15d5903..b3cd42d 100644 +--- a/include/linux/input/matrix_keypad.h ++++ b/include/linux/input/matrix_keypad.h +@@ -63,4 +63,36 @@ struct matrix_keypad_platform_data { + bool wakeup; + }; + ++/** ++ * matrix_keypad_build_keymap - convert platform keymap into matrix keymap ++ * @keymap_data: keymap supplied by the platform code ++ * @row_shift: number of bits to shift row value by to advance to the next ++ * line in the keymap ++ * @keymap: expanded version of keymap that is suitable for use by ++ * matrix keyboad driver ++ * @keybit: pointer to bitmap of keys supported by input device ++ * ++ * This function converts platform keymap (encoded with KEY() macro) into ++ * an array of keycodes that is suitable for using in a standard matrix ++ * keyboard driver that uses row and col as indices. ++ */ ++static inline void ++matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, ++ unsigned int row_shift, ++ unsigned short *keymap, unsigned long *keybit) ++{ ++ int i; ++ ++ for (i = 0; i < keymap_data->keymap_size; i++) { ++ unsigned int key = keymap_data->keymap[i]; ++ unsigned int row = KEY_ROW(key); ++ unsigned int col = KEY_COL(key); ++ unsigned short code = KEY_VAL(key); ++ ++ keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code; ++ __set_bit(code, keybit); ++ } ++ __clear_bit(KEY_RESERVED, keybit); ++} ++ + #endif /* _MATRIX_KEYPAD_H */ +-- +1.6.3.1 + diff --git a/recipes/linux/omap3-pandora-kernel/keypad/0005-Input-add-twl4030_keypad-driver.patch b/recipes/linux/omap3-pandora-kernel/keypad/0005-Input-add-twl4030_keypad-driver.patch new file mode 100644 index 0000000..c47b00e --- /dev/null +++ b/recipes/linux/omap3-pandora-kernel/keypad/0005-Input-add-twl4030_keypad-driver.patch @@ -0,0 +1,583 @@ +From 0958f20b0237ef414371c3ff967a5e26649c30fe Mon Sep 17 00:00:00 2001 +From: David Brownell +Date: Tue, 3 Nov 2009 15:53:51 +0200 +Subject: [PATCH 5/7] Input: add twl4030_keypad driver + +Add a driver for the keypad controller on TWL4030 family chips. +These support up to an 8x8 key matrix. The TWL4030 multifunction +chips are mostly used on OMAP3 (or OMAP 2430) based boards. + +[dtor@mail.ru: switch to matrix-keypad framework, fix changing +keymap from userspace] +Reviewed-by: Trilok Soni +Signed-off-by: David Brownell +Signed-off-by: Dmitry Torokhov + +Conflicts: + + drivers/input/keyboard/Kconfig + drivers/input/keyboard/Makefile +--- + drivers/input/keyboard/Kconfig | 11 + + drivers/input/keyboard/Makefile | 1 + + drivers/input/keyboard/twl4030_keypad.c | 480 +++++++++++++++++++++++++++++++ + include/linux/i2c/twl4030.h | 19 +- + 4 files changed, 505 insertions(+), 6 deletions(-) + create mode 100644 drivers/input/keyboard/twl4030_keypad.c + +diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig +index b0a3c78..e6a0584 100644 +--- a/drivers/input/keyboard/Kconfig ++++ b/drivers/input/keyboard/Kconfig +@@ -355,4 +355,15 @@ config KEYBOARD_SH_KEYSC + + To compile this driver as a module, choose M here: the + module will be called sh_keysc. ++ ++config KEYBOARD_TWL4030 ++ tristate "TI TWL4030/TWL5030/TPS659x0 keypad support" ++ depends on TWL4030_CORE ++ help ++ Say Y here if your board use the keypad controller on ++ TWL4030 family chips. It's safe to say enable this ++ even on boards that don't use the keypad controller. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called twl4030_keypad. + endif +diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile +index 7b8bc44..2085127 100644 +--- a/drivers/input/keyboard/Makefile ++++ b/drivers/input/keyboard/Makefile +@@ -31,3 +31,4 @@ obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o + obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o + obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o + obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o ++obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o +diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c +new file mode 100644 +index 0000000..9a2977c +--- /dev/null ++++ b/drivers/input/keyboard/twl4030_keypad.c +@@ -0,0 +1,480 @@ ++/* ++ * twl4030_keypad.c - driver for 8x8 keypad controller in twl4030 chips ++ * ++ * Copyright (C) 2007 Texas Instruments, Inc. ++ * Copyright (C) 2008 Nokia Corporation ++ * ++ * Code re-written for 2430SDP by: ++ * Syed Mohammed Khasim ++ * ++ * Initial Code: ++ * Manjunatha G K ++ * ++ * 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 ++ ++ ++/* ++ * The TWL4030 family chips include a keypad controller that supports ++ * up to an 8x8 switch matrix. The controller can issue system wakeup ++ * events, since it uses only the always-on 32KiHz oscillator, and has ++ * an internal state machine that decodes pressed keys, including ++ * multi-key combinations. ++ * ++ * This driver lets boards define what keycodes they wish to report for ++ * which scancodes, as part of the "struct twl4030_keypad_data" used in ++ * the probe() routine. ++ * ++ * See the TPS65950 documentation; that's the general availability ++ * version of the TWL5030 second generation part. ++ */ ++#define TWL4030_MAX_ROWS 8 /* TWL4030 hard limit */ ++#define TWL4030_MAX_COLS 8 ++#define TWL4030_ROW_SHIFT 3 ++#define TWL4030_KEYMAP_SIZE (TWL4030_MAX_ROWS * TWL4030_MAX_COLS) ++ ++struct twl4030_keypad { ++ unsigned short keymap[TWL4030_KEYMAP_SIZE]; ++ u16 kp_state[TWL4030_MAX_ROWS]; ++ unsigned n_rows; ++ unsigned n_cols; ++ unsigned irq; ++ ++ struct device *dbg_dev; ++ struct input_dev *input; ++}; ++ ++/*----------------------------------------------------------------------*/ ++ ++/* arbitrary prescaler value 0..7 */ ++#define PTV_PRESCALER 4 ++ ++/* Register Offsets */ ++#define KEYP_CTRL 0x00 ++#define KEYP_DEB 0x01 ++#define KEYP_LONG_KEY 0x02 ++#define KEYP_LK_PTV 0x03 ++#define KEYP_TIMEOUT_L 0x04 ++#define KEYP_TIMEOUT_H 0x05 ++#define KEYP_KBC 0x06 ++#define KEYP_KBR 0x07 ++#define KEYP_SMS 0x08 ++#define KEYP_FULL_CODE_7_0 0x09 /* row 0 column status */ ++#define KEYP_FULL_CODE_15_8 0x0a /* ... row 1 ... */ ++#define KEYP_FULL_CODE_23_16 0x0b ++#define KEYP_FULL_CODE_31_24 0x0c ++#define KEYP_FULL_CODE_39_32 0x0d ++#define KEYP_FULL_CODE_47_40 0x0e ++#define KEYP_FULL_CODE_55_48 0x0f ++#define KEYP_FULL_CODE_63_56 0x10 ++#define KEYP_ISR1 0x11 ++#define KEYP_IMR1 0x12 ++#define KEYP_ISR2 0x13 ++#define KEYP_IMR2 0x14 ++#define KEYP_SIR 0x15 ++#define KEYP_EDR 0x16 /* edge triggers */ ++#define KEYP_SIH_CTRL 0x17 ++ ++/* KEYP_CTRL_REG Fields */ ++#define KEYP_CTRL_SOFT_NRST BIT(0) ++#define KEYP_CTRL_SOFTMODEN BIT(1) ++#define KEYP_CTRL_LK_EN BIT(2) ++#define KEYP_CTRL_TOE_EN BIT(3) ++#define KEYP_CTRL_TOLE_EN BIT(4) ++#define KEYP_CTRL_RP_EN BIT(5) ++#define KEYP_CTRL_KBD_ON BIT(6) ++ ++/* KEYP_DEB, KEYP_LONG_KEY, KEYP_TIMEOUT_x*/ ++#define KEYP_PERIOD_US(t, prescale) ((t) / (31 << (prescale + 1)) - 1) ++ ++/* KEYP_LK_PTV_REG Fields */ ++#define KEYP_LK_PTV_PTV_SHIFT 5 ++ ++/* KEYP_{IMR,ISR,SIR} Fields */ ++#define KEYP_IMR1_MIS BIT(3) ++#define KEYP_IMR1_TO BIT(2) ++#define KEYP_IMR1_LK BIT(1) ++#define KEYP_IMR1_KP BIT(0) ++ ++/* KEYP_EDR Fields */ ++#define KEYP_EDR_KP_FALLING 0x01 ++#define KEYP_EDR_KP_RISING 0x02 ++#define KEYP_EDR_KP_BOTH 0x03 ++#define KEYP_EDR_LK_FALLING 0x04 ++#define KEYP_EDR_LK_RISING 0x08 ++#define KEYP_EDR_TO_FALLING 0x10 ++#define KEYP_EDR_TO_RISING 0x20 ++#define KEYP_EDR_MIS_FALLING 0x40 ++#define KEYP_EDR_MIS_RISING 0x80 ++ ++ ++/*----------------------------------------------------------------------*/ ++ ++static int twl4030_kpread(struct twl4030_keypad *kp, ++ u8 *data, u32 reg, u8 num_bytes) ++{ ++ int ret = twl4030_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes); ++ ++ if (ret < 0) ++ dev_warn(kp->dbg_dev, ++ "Couldn't read TWL4030: %X - ret %d[%x]\n", ++ reg, ret, ret); ++ ++ return ret; ++} ++ ++static int twl4030_kpwrite_u8(struct twl4030_keypad *kp, u8 data, u32 reg) ++{ ++ int ret = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg); ++ ++ if (ret < 0) ++ dev_warn(kp->dbg_dev, ++ "Could not write TWL4030: %X - ret %d[%x]\n", ++ reg, ret, ret); ++ ++ return ret; ++} ++ ++static inline u16 twl4030_col_xlate(struct twl4030_keypad *kp, u8 col) ++{ ++ /* If all bits in a row are active for all coloumns then ++ * we have that row line connected to gnd. Mark this ++ * key on as if it was on matrix position n_cols (ie ++ * one higher than the size of the matrix). ++ */ ++ if (col == 0xFF) ++ return 1 << kp->n_cols; ++ else ++ return col & ((1 << kp->n_cols) - 1); ++} ++ ++static int twl4030_read_kp_matrix_state(struct twl4030_keypad *kp, u16 *state) ++{ ++ u8 new_state[TWL4030_MAX_ROWS]; ++ int row; ++ int ret = twl4030_kpread(kp, new_state, ++ KEYP_FULL_CODE_7_0, kp->n_rows); ++ if (ret >= 0) ++ for (row = 0; row < kp->n_rows; row++) ++ state[row] = twl4030_col_xlate(kp, new_state[row]); ++ ++ return ret; ++} ++ ++static int twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state) ++{ ++ int i; ++ u16 check = 0; ++ ++ for (i = 0; i < kp->n_rows; i++) { ++ u16 col = key_state[i]; ++ ++ if ((col & check) && hweight16(col) > 1) ++ return 1; ++ ++ check |= col; ++ } ++ ++ return 0; ++} ++ ++static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all) ++{ ++ struct input_dev *input = kp->input; ++ u16 new_state[TWL4030_MAX_ROWS]; ++ int col, row; ++ ++ if (release_all) ++ memset(new_state, 0, sizeof(new_state)); ++ else { ++ /* check for any changes */ ++ int ret = twl4030_read_kp_matrix_state(kp, new_state); ++ ++ if (ret < 0) /* panic ... */ ++ return; ++ ++ if (twl4030_is_in_ghost_state(kp, new_state)) ++ return; ++ } ++ ++ /* check for changes and print those */ ++ for (row = 0; row < kp->n_rows; row++) { ++ int changed = new_state[row] ^ kp->kp_state[row]; ++ ++ if (!changed) ++ continue; ++ ++ for (col = 0; col < kp->n_cols; col++) { ++ int code; ++ ++ if (!(changed & (1 << col))) ++ continue; ++ ++ dev_dbg(kp->dbg_dev, "key [%d:%d] %s\n", row, col, ++ (new_state[row] & (1 << col)) ? ++ "press" : "release"); ++ ++ code = MATRIX_SCAN_CODE(row, col, TWL4030_ROW_SHIFT); ++ input_event(input, EV_MSC, MSC_SCAN, code); ++ input_report_key(input, kp->keymap[code], ++ new_state[row] & (1 << col)); ++ } ++ kp->kp_state[row] = new_state[row]; ++ } ++ input_sync(input); ++} ++ ++/* ++ * Keypad interrupt handler ++ */ ++static irqreturn_t do_kp_irq(int irq, void *_kp) ++{ ++ struct twl4030_keypad *kp = _kp; ++ u8 reg; ++ int ret; ++ ++#ifdef CONFIG_LOCKDEP ++ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which ++ * we don't want and can't tolerate. Although it might be ++ * friendlier not to borrow this thread context... ++ */ ++ local_irq_enable(); ++#endif ++ ++ /* Read & Clear TWL4030 pending interrupt */ ++ ret = twl4030_kpread(kp, ®, KEYP_ISR1, 1); ++ ++ /* Release all keys if I2C has gone bad or ++ * the KEYP has gone to idle state */ ++ if (ret >= 0 && (reg & KEYP_IMR1_KP)) ++ twl4030_kp_scan(kp, false); ++ else ++ twl4030_kp_scan(kp, true); ++ ++ return IRQ_HANDLED; ++} ++ ++static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) ++{ ++ u8 reg; ++ int i; ++ ++ /* Enable controller, with hardware decoding but not autorepeat */ ++ reg = KEYP_CTRL_SOFT_NRST | KEYP_CTRL_SOFTMODEN ++ | KEYP_CTRL_TOE_EN | KEYP_CTRL_KBD_ON; ++ if (twl4030_kpwrite_u8(kp, reg, KEYP_CTRL) < 0) ++ return -EIO; ++ ++ /* NOTE: we could use sih_setup() here to package keypad ++ * event sources as four different IRQs ... but we don't. ++ */ ++ ++ /* Enable TO rising and KP rising and falling edge detection */ ++ reg = KEYP_EDR_KP_BOTH | KEYP_EDR_TO_RISING; ++ if (twl4030_kpwrite_u8(kp, reg, KEYP_EDR) < 0) ++ return -EIO; ++ ++ /* Set PTV prescaler Field */ ++ reg = (PTV_PRESCALER << KEYP_LK_PTV_PTV_SHIFT); ++ if (twl4030_kpwrite_u8(kp, reg, KEYP_LK_PTV) < 0) ++ return -EIO; ++ ++ /* Set key debounce time to 20 ms */ ++ i = KEYP_PERIOD_US(20000, PTV_PRESCALER); ++ if (twl4030_kpwrite_u8(kp, i, KEYP_DEB) < 0) ++ return -EIO; ++ ++ /* Set timeout period to 100 ms */ ++ i = KEYP_PERIOD_US(200000, PTV_PRESCALER); ++ if (twl4030_kpwrite_u8(kp, (i & 0xFF), KEYP_TIMEOUT_L) < 0) ++ return -EIO; ++ ++ if (twl4030_kpwrite_u8(kp, (i >> 8), KEYP_TIMEOUT_H) < 0) ++ return -EIO; ++ ++ /* ++ * Enable Clear-on-Read; disable remembering events that fire ++ * after the IRQ but before our handler acks (reads) them, ++ */ ++ reg = TWL4030_SIH_CTRL_COR_MASK | TWL4030_SIH_CTRL_PENDDIS_MASK; ++ if (twl4030_kpwrite_u8(kp, reg, KEYP_SIH_CTRL) < 0) ++ return -EIO; ++ ++ /* initialize key state; irqs update it from here on */ ++ if (twl4030_read_kp_matrix_state(kp, kp->kp_state) < 0) ++ return -EIO; ++ ++ return 0; ++} ++ ++/* ++ * Registers keypad device with input subsystem ++ * and configures TWL4030 keypad registers ++ */ ++static int __devinit twl4030_kp_probe(struct platform_device *pdev) ++{ ++ struct twl4030_keypad_data *pdata = pdev->dev.platform_data; ++ const struct matrix_keymap_data *keymap_data = pdata->keymap_data; ++ struct twl4030_keypad *kp; ++ struct input_dev *input; ++ u8 reg; ++ int error; ++ ++ if (!pdata || !pdata->rows || !pdata->cols || ++ pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) { ++ dev_err(&pdev->dev, "Invalid platform_data\n"); ++ return -EINVAL; ++ } ++ ++ kp = kzalloc(sizeof(*kp), GFP_KERNEL); ++ input = input_allocate_device(); ++ if (!kp || !input) { ++ error = -ENOMEM; ++ goto err1; ++ } ++ ++ /* Get the debug Device */ ++ kp->dbg_dev = &pdev->dev; ++ kp->input = input; ++ ++ kp->n_rows = pdata->rows; ++ kp->n_cols = pdata->cols; ++ kp->irq = platform_get_irq(pdev, 0); ++ ++ /* setup input device */ ++ __set_bit(EV_KEY, input->evbit); ++ ++ /* Enable auto repeat feature of Linux input subsystem */ ++ if (pdata->rep) ++ __set_bit(EV_REP, input->evbit); ++ ++ input_set_capability(input, EV_MSC, MSC_SCAN); ++ ++ input->name = "TWL4030 Keypad"; ++ input->phys = "twl4030_keypad/input0"; ++ input->dev.parent = &pdev->dev; ++ ++ input->id.bustype = BUS_HOST; ++ input->id.vendor = 0x0001; ++ input->id.product = 0x0001; ++ input->id.version = 0x0003; ++ ++ input->keycode = kp->keymap; ++ input->keycodesize = sizeof(kp->keymap[0]); ++ input->keycodemax = ARRAY_SIZE(kp->keymap); ++ ++ matrix_keypad_build_keymap(keymap_data, TWL4030_ROW_SHIFT, ++ input->keycode, input->keybit); ++ ++ error = input_register_device(input); ++ if (error) { ++ dev_err(kp->dbg_dev, ++ "Unable to register twl4030 keypad device\n"); ++ goto err1; ++ } ++ ++ error = twl4030_kp_program(kp); ++ if (error) ++ goto err2; ++ ++ /* ++ * This ISR will always execute in kernel thread context because of ++ * the need to access the TWL4030 over the I2C bus. ++ * ++ * NOTE: we assume this host is wired to TWL4040 INT1, not INT2 ... ++ */ ++ error = request_irq(kp->irq, do_kp_irq, 0, pdev->name, kp); ++ if (error) { ++ dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n", ++ kp->irq); ++ goto err3; ++ } ++ ++ /* Enable KP and TO interrupts now. */ ++ reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO); ++ if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) { ++ error = -EIO; ++ goto err4; ++ } ++ ++ platform_set_drvdata(pdev, kp); ++ return 0; ++ ++err4: ++ /* mask all events - we don't care about the result */ ++ (void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1); ++err3: ++ free_irq(kp->irq, NULL); ++err2: ++ input_unregister_device(input); ++ input = NULL; ++err1: ++ input_free_device(input); ++ kfree(kp); ++ return error; ++} ++ ++static int __devexit twl4030_kp_remove(struct platform_device *pdev) ++{ ++ struct twl4030_keypad *kp = platform_get_drvdata(pdev); ++ ++ free_irq(kp->irq, kp); ++ input_unregister_device(kp->input); ++ platform_set_drvdata(pdev, NULL); ++ kfree(kp); ++ ++ return 0; ++} ++ ++/* ++ * NOTE: twl4030 are multi-function devices connected via I2C. ++ * So this device is a child of an I2C parent, thus it needs to ++ * support unplug/replug (which most platform devices don't). ++ */ ++ ++static struct platform_driver twl4030_kp_driver = { ++ .probe = twl4030_kp_probe, ++ .remove = __devexit_p(twl4030_kp_remove), ++ .driver = { ++ .name = "twl4030_keypad", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init twl4030_kp_init(void) ++{ ++ return platform_driver_register(&twl4030_kp_driver); ++} ++module_init(twl4030_kp_init); ++ ++static void __exit twl4030_kp_exit(void) ++{ ++ platform_driver_unregister(&twl4030_kp_driver); ++} ++module_exit(twl4030_kp_exit); ++ ++MODULE_AUTHOR("Texas Instruments"); ++MODULE_DESCRIPTION("TWL4030 Keypad Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:twl4030_keypad"); ++ +diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h +index dc40f95..3d6321e 100644 +--- a/include/linux/i2c/twl4030.h ++++ b/include/linux/i2c/twl4030.h +@@ -25,6 +25,9 @@ + #ifndef __TWL4030_H_ + #define __TWL4030_H_ + ++#include ++#include ++ + /* + * Using the twl4030 core we address registers using a pair + * { module id, relative register offset } +@@ -254,13 +257,17 @@ struct twl4030_madc_platform_data { + int irq_line; + }; + ++/* Boards have uniqe mappings of {col, row} --> keycode. ++ * Column and row are 4 bits, but range only from 0..7. ++ * a PERSISTENT_KEY is "always on" and never reported. ++ */ ++#define PERSISTENT_KEY(c, r) KEY((c), (r), KEY_RESERVED) ++ + struct twl4030_keypad_data { +- int rows; +- int cols; +- int *keymap; +- int irq; +- unsigned int keymapsize; +- unsigned int rep:1; ++ const struct matrix_keymap_data *keymap_data; ++ unsigned rows; ++ unsigned cols; ++ bool rep; + }; + + enum twl4030_usb_mode { +-- +1.6.3.1 + diff --git a/recipes/linux/omap3-pandora-kernel/keypad/0006-input-hacks-updates-for-mainline-twl4030-driver.patch b/recipes/linux/omap3-pandora-kernel/keypad/0006-input-hacks-updates-for-mainline-twl4030-driver.patch new file mode 100644 index 0000000..753404f --- /dev/null +++ b/recipes/linux/omap3-pandora-kernel/keypad/0006-input-hacks-updates-for-mainline-twl4030-driver.patch @@ -0,0 +1,182 @@ +From 9416a510c6939bc6da62cf12de665fd11b89a9f6 Mon Sep 17 00:00:00 2001 +From: Grazvydas Ignotas +Date: Thu, 5 Nov 2009 12:44:01 +0200 +Subject: [PATCH 6/7] input: hacks+updates for mainline twl4030 driver + +This includes some differing #includes and col/row swap +in the KEY() macro. +--- + arch/arm/mach-omap2/board-omap3pandora-input.c | 89 ++++++++++++----------- + drivers/input/keyboard/twl4030_keypad.c | 1 + + drivers/mfd/twl4030-core.c | 8 ++ + include/linux/i2c/twl4030.h | 3 - + 4 files changed, 55 insertions(+), 46 deletions(-) + +diff --git a/arch/arm/mach-omap2/board-omap3pandora-input.c b/arch/arm/mach-omap2/board-omap3pandora-input.c +index 6ca69ce..ce9df0e 100644 +--- a/arch/arm/mach-omap2/board-omap3pandora-input.c ++++ b/arch/arm/mach-omap2/board-omap3pandora-input.c +@@ -23,68 +23,71 @@ + #include + #include + #include ++#include + + #include +-#include + #include + + /* hardware debounce, (value + 1) * 31us */ + #define GPIO_DEBOUNCE_TIME 0x7f + + static int omap3pandora_keymap[] = { +- /* col, row, code */ ++ /* row, col, code */ + KEY(0, 0, KEY_9), +- KEY(0, 1, KEY_0), +- KEY(0, 2, KEY_BACKSPACE), +- KEY(0, 3, KEY_O), +- KEY(0, 4, KEY_P), +- KEY(0, 5, KEY_K), +- KEY(0, 6, KEY_L), +- KEY(0, 7, KEY_ENTER), +- KEY(1, 0, KEY_8), ++ KEY(0, 1, KEY_8), ++ KEY(0, 2, KEY_I), ++ KEY(0, 3, KEY_J), ++ KEY(0, 4, KEY_N), ++ KEY(0, 5, KEY_M), ++ KEY(1, 0, KEY_0), + KEY(1, 1, KEY_7), +- KEY(1, 2, KEY_6), +- KEY(1, 3, KEY_5), +- KEY(1, 4, KEY_4), +- KEY(1, 5, KEY_3), +- KEY(1, 6, KEY_2), +- KEY(1, 7, KEY_1), +- KEY(2, 0, KEY_I), +- KEY(2, 1, KEY_U), ++ KEY(1, 2, KEY_U), ++ KEY(1, 3, KEY_H), ++ KEY(1, 4, KEY_B), ++ KEY(1, 5, KEY_SPACE), ++ KEY(2, 0, KEY_BACKSPACE), ++ KEY(2, 1, KEY_6), + KEY(2, 2, KEY_Y), +- KEY(2, 3, KEY_T), +- KEY(2, 4, KEY_R), +- KEY(2, 5, KEY_E), +- KEY(2, 6, KEY_W), +- KEY(2, 7, KEY_Q), +- KEY(3, 0, KEY_J), +- KEY(3, 1, KEY_H), +- KEY(3, 2, KEY_G), ++ KEY(2, 3, KEY_G), ++ KEY(2, 4, KEY_V), ++ KEY(2, 5, KEY_FN), ++ KEY(3, 0, KEY_O), ++ KEY(3, 1, KEY_5), ++ KEY(3, 2, KEY_T), + KEY(3, 3, KEY_F), +- KEY(3, 4, KEY_D), +- KEY(3, 5, KEY_S), +- KEY(3, 6, KEY_A), +- KEY(3, 7, KEY_LEFTSHIFT), +- KEY(4, 0, KEY_N), +- KEY(4, 1, KEY_B), +- KEY(4, 2, KEY_V), +- KEY(4, 3, KEY_C), ++ KEY(3, 4, KEY_C), ++ KEY(4, 0, KEY_P), ++ KEY(4, 1, KEY_4), ++ KEY(4, 2, KEY_R), ++ KEY(4, 3, KEY_D), + KEY(4, 4, KEY_X), +- KEY(4, 5, KEY_Z), +- KEY(4, 6, KEY_DOT), +- KEY(4, 7, KEY_COMMA), +- KEY(5, 0, KEY_M), +- KEY(5, 1, KEY_SPACE), +- KEY(5, 2, KEY_FN), ++ KEY(5, 0, KEY_K), ++ KEY(5, 1, KEY_3), ++ KEY(5, 2, KEY_E), ++ KEY(5, 3, KEY_S), ++ KEY(5, 4, KEY_Z), ++ KEY(6, 0, KEY_L), ++ KEY(6, 1, KEY_2), ++ KEY(6, 2, KEY_W), ++ KEY(6, 3, KEY_A), ++ KEY(6, 4, KEY_DOT), ++ KEY(7, 0, KEY_ENTER), ++ KEY(7, 1, KEY_1), ++ KEY(7, 2, KEY_Q), ++ KEY(7, 3, KEY_LEFTSHIFT), ++ KEY(7, 4, KEY_COMMA), ++}; ++ ++static struct matrix_keymap_data board_map_data = { ++ .keymap = omap3pandora_keymap, ++ .keymap_size = ARRAY_SIZE(omap3pandora_keymap), + }; + + struct twl4030_keypad_data omap3pandora_kp_data = { ++ .keymap_data = &board_map_data, + .rows = 8, + .cols = 6, +- .keymap = omap3pandora_keymap, +- .keymapsize = ARRAY_SIZE(omap3pandora_keymap), + .rep = 1, +- .irq = TWL4030_MODIRQ_KEYPAD, + }; + + static struct gpio_keys_button gpio_buttons[] = { +diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c +index 9a2977c..99bb58d 100644 +--- a/drivers/input/keyboard/twl4030_keypad.c ++++ b/drivers/input/keyboard/twl4030_keypad.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + + /* +diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c +index dd843c4..4c502d7 100644 +--- a/drivers/mfd/twl4030-core.c ++++ b/drivers/mfd/twl4030-core.c +@@ -468,7 +468,15 @@ static int add_children(struct twl4030_platform_data *pdata) + status); + platform_device_put(pdev); + goto err; ++ } else { ++ struct resource r = { ++ .start = pdata->irq_base + 1, ++ .flags = IORESOURCE_IRQ, ++ }; ++ ++ status = platform_device_add_resources(pdev, &r, 1); + } ++ + status = platform_device_add(pdev); + if (status < 0) { + platform_device_put(pdev); +diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h +index 3d6321e..4a31016 100644 +--- a/include/linux/i2c/twl4030.h ++++ b/include/linux/i2c/twl4030.h +@@ -25,9 +25,6 @@ + #ifndef __TWL4030_H_ + #define __TWL4030_H_ + +-#include +-#include +- + /* + * Using the twl4030 core we address registers using a pair + * { module id, relative register offset } +-- +1.6.3.1 + diff --git a/recipes/linux/omap3-pandora-kernel/keypad/0007-some-hackish-Fn-handling-for-testing.patch b/recipes/linux/omap3-pandora-kernel/keypad/0007-some-hackish-Fn-handling-for-testing.patch new file mode 100644 index 0000000..be0a2a4 --- /dev/null +++ b/recipes/linux/omap3-pandora-kernel/keypad/0007-some-hackish-Fn-handling-for-testing.patch @@ -0,0 +1,157 @@ +From fc359f9dd7efd346c070950320dda62ae671519f Mon Sep 17 00:00:00 2001 +From: Grazvydas Ignotas +Date: Thu, 5 Nov 2009 12:52:23 +0200 +Subject: [PATCH 7/7] some hackish Fn handling for testing + +--- + arch/arm/mach-omap2/board-omap3pandora-input.c | 47 ++++++++++++++++++++++++ + drivers/input/keyboard/twl4030_keypad.c | 39 +++++++++++++++++--- + 2 files changed, 81 insertions(+), 5 deletions(-) + +diff --git a/arch/arm/mach-omap2/board-omap3pandora-input.c b/arch/arm/mach-omap2/board-omap3pandora-input.c +index ce9df0e..3d530cf 100644 +--- a/arch/arm/mach-omap2/board-omap3pandora-input.c ++++ b/arch/arm/mach-omap2/board-omap3pandora-input.c +@@ -31,6 +31,9 @@ + /* hardware debounce, (value + 1) * 31us */ + #define GPIO_DEBOUNCE_TIME 0x7f + ++/* HACK: this requires patched twl4030_keypad driver */ ++#define FNKEY(row, col, code) KEY((row + 8), col, code) ++ + static int omap3pandora_keymap[] = { + /* row, col, code */ + KEY(0, 0, KEY_9), +@@ -76,6 +79,50 @@ static int omap3pandora_keymap[] = { + KEY(7, 2, KEY_Q), + KEY(7, 3, KEY_LEFTSHIFT), + KEY(7, 4, KEY_COMMA), ++ /* Fn keys */ ++ FNKEY(0, 0, KEY_F9), ++ FNKEY(0, 1, KEY_F8), ++ FNKEY(0, 2, KEY_BRIGHTNESSUP), ++ FNKEY(0, 3, KEY_F13), /* apostrophe, differs from Fn-A? */ ++ FNKEY(0, 4, KEY_DOLLAR), ++ FNKEY(0, 5, KEY_EURO), ++ FNKEY(1, 0, KEY_F10), ++ FNKEY(1, 1, KEY_F7), ++ FNKEY(1, 2, KEY_BRIGHTNESSDOWN), ++ FNKEY(1, 3, KEY_GRAVE), ++ FNKEY(1, 4, KEY_F14), /* pipe/bar */ ++ FNKEY(1, 5, KEY_TAB), ++ FNKEY(2, 0, KEY_INSERT), ++ FNKEY(2, 1, KEY_F6), ++ FNKEY(2, 2, KEY_F15), /* dash */ ++ FNKEY(2, 3, KEY_EQUAL), ++ FNKEY(2, 4, KEY_F16), /* # (pound/hash) */ ++ FNKEY(2, 5, KEY_FN), ++ FNKEY(3, 0, KEY_F11), ++ FNKEY(3, 1, KEY_F5), ++ FNKEY(3, 2, KEY_F17), /* ! */ ++ FNKEY(3, 3, KEY_KPPLUS), ++ FNKEY(3, 4, KEY_BACKSLASH), ++ FNKEY(4, 0, KEY_F12), ++ FNKEY(4, 1, KEY_F4), ++ FNKEY(4, 2, KEY_RIGHTBRACE), ++ FNKEY(4, 3, KEY_KPMINUS), ++ FNKEY(4, 4, KEY_QUESTION), ++ FNKEY(5, 0, KEY_F18), /* £ (pound) */ ++ FNKEY(5, 1, KEY_F3), ++ FNKEY(5, 2, KEY_LEFTBRACE), ++ FNKEY(5, 3, KEY_F19), /* " */ ++ FNKEY(5, 4, KEY_SLASH), ++ FNKEY(6, 0, KEY_YEN), ++ FNKEY(6, 1, KEY_F2), ++ FNKEY(6, 2, KEY_F20), /* @ */ ++ FNKEY(6, 3, KEY_APOSTROPHE), ++ FNKEY(6, 4, KEY_F21), /* : */ ++ FNKEY(7, 0, KEY_ENTER), ++ FNKEY(7, 1, KEY_F1), ++ FNKEY(7, 2, KEY_ESC), ++ FNKEY(7, 3, KEY_CAPSLOCK), ++ FNKEY(7, 4, KEY_SEMICOLON), + }; + + static struct matrix_keymap_data board_map_data = { +diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c +index 99bb58d..74485d6 100644 +--- a/drivers/input/keyboard/twl4030_keypad.c ++++ b/drivers/input/keyboard/twl4030_keypad.c +@@ -52,7 +52,7 @@ + #define TWL4030_MAX_ROWS 8 /* TWL4030 hard limit */ + #define TWL4030_MAX_COLS 8 + #define TWL4030_ROW_SHIFT 3 +-#define TWL4030_KEYMAP_SIZE (TWL4030_MAX_ROWS * TWL4030_MAX_COLS) ++#define TWL4030_KEYMAP_SIZE (TWL4030_MAX_ROWS * 2 * TWL4030_MAX_COLS) + + struct twl4030_keypad { + unsigned short keymap[TWL4030_KEYMAP_SIZE]; +@@ -61,6 +61,9 @@ struct twl4030_keypad { + unsigned n_cols; + unsigned irq; + ++ unsigned fn_down:1; ++ unsigned fn_sticked:1; ++ + struct device *dbg_dev; + struct input_dev *input; + }; +@@ -226,7 +229,8 @@ static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all) + continue; + + for (col = 0; col < kp->n_cols; col++) { +- int code; ++ int code, kcode, is_down; ++ int code2; + + if (!(changed & (1 << col))) + continue; +@@ -236,9 +240,34 @@ static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all) + "press" : "release"); + + code = MATRIX_SCAN_CODE(row, col, TWL4030_ROW_SHIFT); ++ kcode = kp->keymap[code]; ++ is_down = (new_state[row] & (1 << col)) ? 1 : 0; ++ ++ dev_dbg(kp->dbg_dev, "code: %d %d\n", code, kcode); ++ /* Fn handling */ ++ if (kcode == KEY_FN) { ++ kp->fn_down = is_down; ++ kp->fn_sticked |= is_down; ++ } else if (kp->fn_down || kp->fn_sticked) { ++ /* make sure other function is up */ ++ input_event(input, EV_MSC, MSC_SCAN, code); ++ input_report_key(input, kcode, 0); ++ ++ code = MATRIX_SCAN_CODE(row + TWL4030_MAX_ROWS, ++ col, TWL4030_ROW_SHIFT); ++ kcode = kp->keymap[code]; ++ ++ kp->fn_sticked = 0; ++ } else { ++ code2 = MATRIX_SCAN_CODE(row + TWL4030_MAX_ROWS, ++ col, TWL4030_ROW_SHIFT); ++ input_event(input, EV_MSC, MSC_SCAN, code2); ++ input_report_key(input, kp->keymap[code2], 0); ++ } ++ ++ dev_dbg(kp->dbg_dev, "code(fn): %d %d\n", code, kcode); + input_event(input, EV_MSC, MSC_SCAN, code); +- input_report_key(input, kp->keymap[code], +- new_state[row] & (1 << col)); ++ input_report_key(input, kcode, is_down); + } + kp->kp_state[row] = new_state[row]; + } +@@ -371,7 +400,7 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev) + + input_set_capability(input, EV_MSC, MSC_SCAN); + +- input->name = "TWL4030 Keypad"; ++ input->name = "omap_twl4030keypad"; + input->phys = "twl4030_keypad/input0"; + input->dev.parent = &pdev->dev; + +-- +1.6.3.1 + diff --git a/recipes/linux/omap3-pandora-kernel_2.6.27-pandora.bb b/recipes/linux/omap3-pandora-kernel_2.6.27-pandora.bb index 3079525..6a6a824 100755 --- a/recipes/linux/omap3-pandora-kernel_2.6.27-pandora.bb +++ b/recipes/linux/omap3-pandora-kernel_2.6.27-pandora.bb @@ -5,23 +5,6 @@ KERNEL_IMAGETYPE = "uImage" COMPATIBLE_MACHINE = "omap3-pandora" -# ----- Revision 2 Boards ----- - -#GIT HEAD for Rev2 - Same as Rev3 without Batt Fuel Guage and Nub/Button changes. - -#SRCREV = "45dce3afbd5c2d2af899ae7e7a107d01a5c15558" - -#SRC_URI = " \ -# git://git.openpandora.org/pandora-kernel.git;protocol=git;branch=rev2 \ -#" - -# ----------------------------- - - -# ----- Revision 3 > Boards ----- - -#GIT HEAD for Rev3 > (i.e. Shipping units) - Will run on Rev2 boards without Nubs and an incorrect Start button. - SRCREV = "b7075725f109114e144c5534cd519ffa2b9780d9" SRC_URI = " \ @@ -61,5 +44,24 @@ SRC_URI_append = " \ file://0002-Add-a-very-basic-platform-driver-module-to-bring-up-.patch;patch=1 \ file://0003-Remove-old-msm_wifi-hack-as-the-temp-platform-driver.patch;patch=1 \ " + +# AUFS2 Patches - Used by ausf2-27 recipe to build as a module. + +SRC_URI_append = " \ + file://aufs2/aufs2-base.patch;patch=1 \ + file://aufs2/aufs2-standalone.patch;patch=1 \ +" + +# Temp Keypad Patches for FN. + +SRC_URI_append = " \ + file://keypad/0001-input-remove-old-twl4030keypad-to-replace-it-with-ma.patch;patch=1 \ + file://keypad/0002-Input-add-support-for-generic-GPIO-based-matrix-keyp.patch;patch=1 \ + file://keypad/0003-Input-matrix_keypad-make-matrix-keymap-size-dynamic.patch;patch=1 \ + file://keypad/0004-Input-matrix-keypad-add-function-to-build-device-key.patch;patch=1 \ + file://keypad/0005-Input-add-twl4030_keypad-driver.patch;patch=1 \ + file://keypad/0006-input-hacks-updates-for-mainline-twl4030-driver.patch;patch=1 \ + file://keypad/0007-some-hackish-Fn-handling-for-testing.patch;patch=1 \ +" S = "${WORKDIR}/git"