diff options
| -rw-r--r-- | drivers/input/keyboard/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/input/keyboard/omap4-keypad.c | 118 |
2 files changed, 94 insertions, 28 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 7eaf93fe5128..ea4bbaae9e02 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -522,9 +522,9 @@ config KEYBOARD_OMAP | |||
| 522 | module will be called omap-keypad. | 522 | module will be called omap-keypad. |
| 523 | 523 | ||
| 524 | config KEYBOARD_OMAP4 | 524 | config KEYBOARD_OMAP4 |
| 525 | tristate "TI OMAP4 keypad support" | 525 | tristate "TI OMAP4+ keypad support" |
| 526 | help | 526 | help |
| 527 | Say Y here if you want to use the OMAP4 keypad. | 527 | Say Y here if you want to use the OMAP4+ keypad. |
| 528 | 528 | ||
| 529 | To compile this driver as a module, choose M here: the | 529 | To compile this driver as a module, choose M here: the |
| 530 | module will be called omap4-keypad. | 530 | module will be called omap4-keypad. |
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index e809ac095a38..28da0e469689 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c | |||
| @@ -68,19 +68,52 @@ | |||
| 68 | 68 | ||
| 69 | #define OMAP4_MASK_IRQSTATUSDISABLE 0xFFFF | 69 | #define OMAP4_MASK_IRQSTATUSDISABLE 0xFFFF |
| 70 | 70 | ||
| 71 | enum { | ||
| 72 | KBD_REVISION_OMAP4 = 0, | ||
| 73 | KBD_REVISION_OMAP5, | ||
| 74 | }; | ||
| 75 | |||
| 71 | struct omap4_keypad { | 76 | struct omap4_keypad { |
| 72 | struct input_dev *input; | 77 | struct input_dev *input; |
| 73 | 78 | ||
| 74 | void __iomem *base; | 79 | void __iomem *base; |
| 75 | int irq; | 80 | unsigned int irq; |
| 76 | 81 | ||
| 77 | unsigned int rows; | 82 | unsigned int rows; |
| 78 | unsigned int cols; | 83 | unsigned int cols; |
| 84 | u32 reg_offset; | ||
| 85 | u32 irqreg_offset; | ||
| 79 | unsigned int row_shift; | 86 | unsigned int row_shift; |
| 80 | unsigned char key_state[8]; | 87 | unsigned char key_state[8]; |
| 81 | unsigned short keymap[]; | 88 | unsigned short keymap[]; |
| 82 | }; | 89 | }; |
| 83 | 90 | ||
| 91 | static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset) | ||
| 92 | { | ||
| 93 | return __raw_readl(keypad_data->base + | ||
| 94 | keypad_data->reg_offset + offset); | ||
| 95 | } | ||
| 96 | |||
| 97 | static void kbd_writel(struct omap4_keypad *keypad_data, u32 offset, u32 value) | ||
| 98 | { | ||
| 99 | __raw_writel(value, | ||
| 100 | keypad_data->base + keypad_data->reg_offset + offset); | ||
| 101 | } | ||
| 102 | |||
| 103 | static int kbd_read_irqreg(struct omap4_keypad *keypad_data, u32 offset) | ||
| 104 | { | ||
| 105 | return __raw_readl(keypad_data->base + | ||
| 106 | keypad_data->irqreg_offset + offset); | ||
| 107 | } | ||
| 108 | |||
| 109 | static void kbd_write_irqreg(struct omap4_keypad *keypad_data, | ||
| 110 | u32 offset, u32 value) | ||
| 111 | { | ||
| 112 | __raw_writel(value, | ||
| 113 | keypad_data->base + keypad_data->irqreg_offset + offset); | ||
| 114 | } | ||
| 115 | |||
| 116 | |||
| 84 | /* Interrupt handler */ | 117 | /* Interrupt handler */ |
| 85 | static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) | 118 | static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) |
| 86 | { | 119 | { |
| @@ -91,12 +124,11 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) | |||
| 91 | u32 *new_state = (u32 *) key_state; | 124 | u32 *new_state = (u32 *) key_state; |
| 92 | 125 | ||
| 93 | /* Disable interrupts */ | 126 | /* Disable interrupts */ |
| 94 | __raw_writel(OMAP4_VAL_IRQDISABLE, | 127 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, |
| 95 | keypad_data->base + OMAP4_KBD_IRQENABLE); | 128 | OMAP4_VAL_IRQDISABLE); |
| 96 | 129 | ||
| 97 | *new_state = __raw_readl(keypad_data->base + OMAP4_KBD_FULLCODE31_0); | 130 | *new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0); |
| 98 | *(new_state + 1) = __raw_readl(keypad_data->base | 131 | *(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32); |
| 99 | + OMAP4_KBD_FULLCODE63_32); | ||
| 100 | 132 | ||
| 101 | for (row = 0; row < keypad_data->rows; row++) { | 133 | for (row = 0; row < keypad_data->rows; row++) { |
| 102 | changed = key_state[row] ^ keypad_data->key_state[row]; | 134 | changed = key_state[row] ^ keypad_data->key_state[row]; |
| @@ -121,12 +153,13 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) | |||
| 121 | sizeof(keypad_data->key_state)); | 153 | sizeof(keypad_data->key_state)); |
| 122 | 154 | ||
| 123 | /* clear pending interrupts */ | 155 | /* clear pending interrupts */ |
| 124 | __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS), | 156 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, |
| 125 | keypad_data->base + OMAP4_KBD_IRQSTATUS); | 157 | kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); |
| 126 | 158 | ||
| 127 | /* enable interrupts */ | 159 | /* enable interrupts */ |
| 128 | __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY, | 160 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, |
| 129 | keypad_data->base + OMAP4_KBD_IRQENABLE); | 161 | OMAP4_DEF_IRQENABLE_EVENTEN | |
| 162 | OMAP4_DEF_IRQENABLE_LONGKEY); | ||
| 130 | 163 | ||
| 131 | return IRQ_HANDLED; | 164 | return IRQ_HANDLED; |
| 132 | } | 165 | } |
| @@ -139,16 +172,17 @@ static int omap4_keypad_open(struct input_dev *input) | |||
| 139 | 172 | ||
| 140 | disable_irq(keypad_data->irq); | 173 | disable_irq(keypad_data->irq); |
| 141 | 174 | ||
| 142 | __raw_writel(OMAP4_VAL_FUNCTIONALCFG, | 175 | kbd_writel(keypad_data, OMAP4_KBD_CTRL, |
| 143 | keypad_data->base + OMAP4_KBD_CTRL); | 176 | OMAP4_VAL_FUNCTIONALCFG); |
| 144 | __raw_writel(OMAP4_VAL_DEBOUNCINGTIME, | 177 | kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME, |
| 145 | keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME); | 178 | OMAP4_VAL_DEBOUNCINGTIME); |
| 146 | __raw_writel(OMAP4_VAL_IRQDISABLE, | 179 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, |
| 147 | keypad_data->base + OMAP4_KBD_IRQSTATUS); | 180 | OMAP4_VAL_IRQDISABLE); |
| 148 | __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY, | 181 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, |
| 149 | keypad_data->base + OMAP4_KBD_IRQENABLE); | 182 | OMAP4_DEF_IRQENABLE_EVENTEN | |
| 150 | __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA, | 183 | OMAP4_DEF_IRQENABLE_LONGKEY); |
| 151 | keypad_data->base + OMAP4_KBD_WAKEUPENABLE); | 184 | kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE, |
| 185 | OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA); | ||
| 152 | 186 | ||
| 153 | enable_irq(keypad_data->irq); | 187 | enable_irq(keypad_data->irq); |
| 154 | 188 | ||
| @@ -162,12 +196,12 @@ static void omap4_keypad_close(struct input_dev *input) | |||
| 162 | disable_irq(keypad_data->irq); | 196 | disable_irq(keypad_data->irq); |
| 163 | 197 | ||
| 164 | /* Disable interrupts */ | 198 | /* Disable interrupts */ |
| 165 | __raw_writel(OMAP4_VAL_IRQDISABLE, | 199 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, |
| 166 | keypad_data->base + OMAP4_KBD_IRQENABLE); | 200 | OMAP4_VAL_IRQDISABLE); |
| 167 | 201 | ||
| 168 | /* clear pending interrupts */ | 202 | /* clear pending interrupts */ |
| 169 | __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS), | 203 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, |
| 170 | keypad_data->base + OMAP4_KBD_IRQSTATUS); | 204 | kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); |
| 171 | 205 | ||
| 172 | enable_irq(keypad_data->irq); | 206 | enable_irq(keypad_data->irq); |
| 173 | 207 | ||
| @@ -182,6 +216,7 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) | |||
| 182 | struct resource *res; | 216 | struct resource *res; |
| 183 | resource_size_t size; | 217 | resource_size_t size; |
| 184 | unsigned int row_shift, max_keys; | 218 | unsigned int row_shift, max_keys; |
| 219 | int rev; | ||
| 185 | int irq; | 220 | int irq; |
| 186 | int error; | 221 | int error; |
| 187 | 222 | ||
| @@ -241,11 +276,40 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) | |||
| 241 | keypad_data->rows = pdata->rows; | 276 | keypad_data->rows = pdata->rows; |
| 242 | keypad_data->cols = pdata->cols; | 277 | keypad_data->cols = pdata->cols; |
| 243 | 278 | ||
| 279 | /* | ||
| 280 | * Enable clocks for the keypad module so that we can read | ||
| 281 | * revision register. | ||
| 282 | */ | ||
| 283 | pm_runtime_enable(&pdev->dev); | ||
| 284 | error = pm_runtime_get_sync(&pdev->dev); | ||
| 285 | if (error) { | ||
| 286 | dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); | ||
| 287 | goto err_unmap; | ||
| 288 | } | ||
| 289 | rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION); | ||
| 290 | rev &= 0x03 << 30; | ||
| 291 | rev >>= 30; | ||
| 292 | switch (rev) { | ||
| 293 | case KBD_REVISION_OMAP4: | ||
| 294 | keypad_data->reg_offset = 0x00; | ||
| 295 | keypad_data->irqreg_offset = 0x00; | ||
| 296 | break; | ||
| 297 | case KBD_REVISION_OMAP5: | ||
| 298 | keypad_data->reg_offset = 0x10; | ||
| 299 | keypad_data->irqreg_offset = 0x0c; | ||
| 300 | break; | ||
| 301 | default: | ||
| 302 | dev_err(&pdev->dev, | ||
| 303 | "Keypad reports unsupported revision %d", rev); | ||
| 304 | error = -EINVAL; | ||
| 305 | goto err_pm_put_sync; | ||
| 306 | } | ||
| 307 | |||
| 244 | /* input device allocation */ | 308 | /* input device allocation */ |
| 245 | keypad_data->input = input_dev = input_allocate_device(); | 309 | keypad_data->input = input_dev = input_allocate_device(); |
| 246 | if (!input_dev) { | 310 | if (!input_dev) { |
| 247 | error = -ENOMEM; | 311 | error = -ENOMEM; |
| 248 | goto err_unmap; | 312 | goto err_pm_put_sync; |
| 249 | } | 313 | } |
| 250 | 314 | ||
| 251 | input_dev->name = pdev->name; | 315 | input_dev->name = pdev->name; |
| @@ -280,7 +344,7 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) | |||
| 280 | goto err_free_input; | 344 | goto err_free_input; |
| 281 | } | 345 | } |
| 282 | 346 | ||
| 283 | pm_runtime_enable(&pdev->dev); | 347 | pm_runtime_put_sync(&pdev->dev); |
| 284 | 348 | ||
| 285 | error = input_register_device(keypad_data->input); | 349 | error = input_register_device(keypad_data->input); |
| 286 | if (error < 0) { | 350 | if (error < 0) { |
| @@ -296,6 +360,8 @@ err_pm_disable: | |||
| 296 | free_irq(keypad_data->irq, keypad_data); | 360 | free_irq(keypad_data->irq, keypad_data); |
| 297 | err_free_input: | 361 | err_free_input: |
| 298 | input_free_device(input_dev); | 362 | input_free_device(input_dev); |
| 363 | err_pm_put_sync: | ||
| 364 | pm_runtime_put_sync(&pdev->dev); | ||
| 299 | err_unmap: | 365 | err_unmap: |
| 300 | iounmap(keypad_data->base); | 366 | iounmap(keypad_data->base); |
| 301 | err_release_mem: | 367 | err_release_mem: |
