diff options
| author | Magnus Damm <damm@opensource.se> | 2010-02-11 01:13:21 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-02-11 02:04:13 -0500 |
| commit | 324e5ade1569111a40c349726d8a2694b28d7943 (patch) | |
| tree | 27bf7ba3d3a3634ab9266ac0a160e6d16e349a28 | |
| parent | 2b14a808fbbb042d0de323260d939bdf95e9efdf (diff) | |
Input: sh_keysc - switch to using bitmaps
Use bitmaps instead of using 32-bit integers to keep track of the key
states. With this change in place the driver supports key pads with
more than 32 keys.
Signed-off-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
| -rw-r--r-- | drivers/input/keyboard/sh_keysc.c | 69 |
1 files changed, 44 insertions, 25 deletions
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 6218b2f02495..c2fc97732f0c 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 20 | #include <linux/input.h> | 20 | #include <linux/input.h> |
| 21 | #include <linux/input/sh_keysc.h> | 21 | #include <linux/input/sh_keysc.h> |
| 22 | #include <linux/bitmap.h> | ||
| 22 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
| 23 | #include <linux/io.h> | 24 | #include <linux/io.h> |
| 24 | 25 | ||
| @@ -35,7 +36,7 @@ static const struct { | |||
| 35 | struct sh_keysc_priv { | 36 | struct sh_keysc_priv { |
| 36 | void __iomem *iomem_base; | 37 | void __iomem *iomem_base; |
| 37 | struct clk *clk; | 38 | struct clk *clk; |
| 38 | unsigned long last_keys; | 39 | DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS); |
| 39 | struct input_dev *input; | 40 | struct input_dev *input; |
| 40 | struct sh_keysc_info pdata; | 41 | struct sh_keysc_info pdata; |
| 41 | }; | 42 | }; |
| @@ -71,69 +72,87 @@ static void sh_keysc_level_mode(struct sh_keysc_priv *p, | |||
| 71 | udelay(pdata->kycr2_delay); | 72 | udelay(pdata->kycr2_delay); |
| 72 | } | 73 | } |
| 73 | 74 | ||
| 75 | static void sh_keysc_map_dbg(struct device *dev, unsigned long *map, | ||
| 76 | const char *str) | ||
| 77 | { | ||
| 78 | int k; | ||
| 79 | |||
| 80 | for (k = 0; k < BITS_TO_LONGS(SH_KEYSC_MAXKEYS); k++) | ||
| 81 | dev_dbg(dev, "%s[%d] 0x%lx\n", str, k, map[k]); | ||
| 82 | } | ||
| 83 | |||
| 74 | static irqreturn_t sh_keysc_isr(int irq, void *dev_id) | 84 | static irqreturn_t sh_keysc_isr(int irq, void *dev_id) |
| 75 | { | 85 | { |
| 76 | struct platform_device *pdev = dev_id; | 86 | struct platform_device *pdev = dev_id; |
| 77 | struct sh_keysc_priv *priv = platform_get_drvdata(pdev); | 87 | struct sh_keysc_priv *priv = platform_get_drvdata(pdev); |
| 78 | struct sh_keysc_info *pdata = &priv->pdata; | 88 | struct sh_keysc_info *pdata = &priv->pdata; |
| 79 | unsigned long keys, keys1, keys0, mask; | 89 | int keyout_nr = sh_keysc_mode[pdata->mode].keyout; |
| 90 | int keyin_nr = sh_keysc_mode[pdata->mode].keyin; | ||
| 91 | DECLARE_BITMAP(keys, SH_KEYSC_MAXKEYS); | ||
| 92 | DECLARE_BITMAP(keys0, SH_KEYSC_MAXKEYS); | ||
| 93 | DECLARE_BITMAP(keys1, SH_KEYSC_MAXKEYS); | ||
| 80 | unsigned char keyin_set, tmp; | 94 | unsigned char keyin_set, tmp; |
| 81 | int i, k; | 95 | int i, k, n; |
| 82 | 96 | ||
| 83 | dev_dbg(&pdev->dev, "isr!\n"); | 97 | dev_dbg(&pdev->dev, "isr!\n"); |
| 84 | 98 | ||
| 85 | keys1 = ~0; | 99 | bitmap_fill(keys1, SH_KEYSC_MAXKEYS); |
| 86 | keys0 = 0; | 100 | bitmap_zero(keys0, SH_KEYSC_MAXKEYS); |
| 87 | 101 | ||
| 88 | do { | 102 | do { |
| 89 | keys = 0; | 103 | bitmap_zero(keys, SH_KEYSC_MAXKEYS); |
| 90 | keyin_set = 0; | 104 | keyin_set = 0; |
| 91 | 105 | ||
| 92 | sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED); | 106 | sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED); |
| 93 | 107 | ||
| 94 | for (i = 0; i < sh_keysc_mode[pdata->mode].keyout; i++) { | 108 | for (i = 0; i < keyout_nr; i++) { |
| 109 | n = keyin_nr * i; | ||
| 110 | |||
| 111 | /* drive one KEYOUT pin low, read KEYIN pins */ | ||
| 95 | sh_keysc_write(priv, KYOUTDR, 0xfff ^ (3 << (i * 2))); | 112 | sh_keysc_write(priv, KYOUTDR, 0xfff ^ (3 << (i * 2))); |
| 96 | udelay(pdata->delay); | 113 | udelay(pdata->delay); |
| 97 | tmp = sh_keysc_read(priv, KYINDR); | 114 | tmp = sh_keysc_read(priv, KYINDR); |
| 98 | 115 | ||
| 99 | keys |= tmp << (sh_keysc_mode[pdata->mode].keyin * i); | 116 | /* set bit if key press has been detected */ |
| 100 | tmp ^= (1 << sh_keysc_mode[pdata->mode].keyin) - 1; | 117 | for (k = 0; k < keyin_nr; k++) { |
| 101 | keyin_set |= tmp; | 118 | if (tmp & (1 << k)) |
| 119 | __set_bit(n + k, keys); | ||
| 120 | } | ||
| 121 | |||
| 122 | /* keep track of which KEYIN bits that have been set */ | ||
| 123 | keyin_set |= tmp ^ ((1 << keyin_nr) - 1); | ||
| 102 | } | 124 | } |
| 103 | 125 | ||
| 104 | sh_keysc_level_mode(priv, keyin_set); | 126 | sh_keysc_level_mode(priv, keyin_set); |
| 105 | 127 | ||
| 106 | keys ^= ~0; | 128 | bitmap_complement(keys, keys, SH_KEYSC_MAXKEYS); |
| 107 | keys &= (1 << (sh_keysc_mode[pdata->mode].keyin * | 129 | bitmap_and(keys1, keys1, keys, SH_KEYSC_MAXKEYS); |
| 108 | sh_keysc_mode[pdata->mode].keyout)) - 1; | 130 | bitmap_or(keys0, keys0, keys, SH_KEYSC_MAXKEYS); |
| 109 | keys1 &= keys; | ||
| 110 | keys0 |= keys; | ||
| 111 | 131 | ||
| 112 | dev_dbg(&pdev->dev, "keys 0x%08lx\n", keys); | 132 | sh_keysc_map_dbg(&pdev->dev, keys, "keys"); |
| 113 | 133 | ||
| 114 | } while (sh_keysc_read(priv, KYCR2) & 0x01); | 134 | } while (sh_keysc_read(priv, KYCR2) & 0x01); |
| 115 | 135 | ||
| 116 | dev_dbg(&pdev->dev, "last_keys 0x%08lx keys0 0x%08lx keys1 0x%08lx\n", | 136 | sh_keysc_map_dbg(&pdev->dev, priv->last_keys, "last_keys"); |
| 117 | priv->last_keys, keys0, keys1); | 137 | sh_keysc_map_dbg(&pdev->dev, keys0, "keys0"); |
| 138 | sh_keysc_map_dbg(&pdev->dev, keys1, "keys1"); | ||
| 118 | 139 | ||
| 119 | for (i = 0; i < SH_KEYSC_MAXKEYS; i++) { | 140 | for (i = 0; i < SH_KEYSC_MAXKEYS; i++) { |
| 120 | k = pdata->keycodes[i]; | 141 | k = pdata->keycodes[i]; |
| 121 | if (!k) | 142 | if (!k) |
| 122 | continue; | 143 | continue; |
| 123 | 144 | ||
| 124 | mask = 1 << i; | 145 | if (test_bit(i, keys0) == test_bit(i, priv->last_keys)) |
| 125 | |||
| 126 | if (!((priv->last_keys ^ keys0) & mask)) | ||
| 127 | continue; | 146 | continue; |
| 128 | 147 | ||
| 129 | if ((keys1 | keys0) & mask) { | 148 | if (test_bit(i, keys1) || test_bit(i, keys0)) { |
| 130 | input_event(priv->input, EV_KEY, k, 1); | 149 | input_event(priv->input, EV_KEY, k, 1); |
| 131 | priv->last_keys |= mask; | 150 | __set_bit(i, priv->last_keys); |
| 132 | } | 151 | } |
| 133 | 152 | ||
| 134 | if (!(keys1 & mask)) { | 153 | if (!test_bit(i, keys1)) { |
| 135 | input_event(priv->input, EV_KEY, k, 0); | 154 | input_event(priv->input, EV_KEY, k, 0); |
| 136 | priv->last_keys &= ~mask; | 155 | __clear_bit(i, priv->last_keys); |
| 137 | } | 156 | } |
| 138 | 157 | ||
| 139 | } | 158 | } |
