diff options
| -rw-r--r-- | arch/arm/plat-spear/include/plat/keyboard.h | 2 | ||||
| -rw-r--r-- | drivers/input/keyboard/spear-keyboard.c | 46 |
2 files changed, 46 insertions, 2 deletions
diff --git a/arch/arm/plat-spear/include/plat/keyboard.h b/arch/arm/plat-spear/include/plat/keyboard.h index 0562f134621d..9248e3a7e333 100644 --- a/arch/arm/plat-spear/include/plat/keyboard.h +++ b/arch/arm/plat-spear/include/plat/keyboard.h | |||
| @@ -149,6 +149,7 @@ int _name[] = { \ | |||
| 149 | * keymap: pointer to keymap data (table and size) | 149 | * keymap: pointer to keymap data (table and size) |
| 150 | * rep: enables key autorepeat | 150 | * rep: enables key autorepeat |
| 151 | * mode: choose keyboard support(9x9, 6x6, 2x2) | 151 | * mode: choose keyboard support(9x9, 6x6, 2x2) |
| 152 | * suspended_rate: rate at which keyboard would operate in suspended mode | ||
| 152 | * | 153 | * |
| 153 | * This structure is supposed to be used by platform code to supply | 154 | * This structure is supposed to be used by platform code to supply |
| 154 | * keymaps to drivers that implement keyboards. | 155 | * keymaps to drivers that implement keyboards. |
| @@ -157,6 +158,7 @@ struct kbd_platform_data { | |||
| 157 | const struct matrix_keymap_data *keymap; | 158 | const struct matrix_keymap_data *keymap; |
| 158 | bool rep; | 159 | bool rep; |
| 159 | unsigned int mode; | 160 | unsigned int mode; |
| 161 | unsigned int suspended_rate; | ||
| 160 | }; | 162 | }; |
| 161 | 163 | ||
| 162 | #endif /* __PLAT_KEYBOARD_H */ | 164 | #endif /* __PLAT_KEYBOARD_H */ |
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index 617a33dc2ef3..72ef01be3360 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c | |||
| @@ -63,6 +63,8 @@ struct spear_kbd { | |||
| 63 | unsigned short last_key; | 63 | unsigned short last_key; |
| 64 | unsigned short keycodes[NUM_ROWS * NUM_COLS]; | 64 | unsigned short keycodes[NUM_ROWS * NUM_COLS]; |
| 65 | bool rep; | 65 | bool rep; |
| 66 | unsigned int suspended_rate; | ||
| 67 | u32 mode_ctl_reg; | ||
| 66 | }; | 68 | }; |
| 67 | 69 | ||
| 68 | static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) | 70 | static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) |
| @@ -149,7 +151,7 @@ static int __devinit spear_kbd_parse_dt(struct platform_device *pdev, | |||
| 149 | { | 151 | { |
| 150 | struct device_node *np = pdev->dev.of_node; | 152 | struct device_node *np = pdev->dev.of_node; |
| 151 | int error; | 153 | int error; |
| 152 | u32 val; | 154 | u32 val, suspended_rate; |
| 153 | 155 | ||
| 154 | if (!np) { | 156 | if (!np) { |
| 155 | dev_err(&pdev->dev, "Missing DT data\n"); | 157 | dev_err(&pdev->dev, "Missing DT data\n"); |
| @@ -159,6 +161,9 @@ static int __devinit spear_kbd_parse_dt(struct platform_device *pdev, | |||
| 159 | if (of_property_read_bool(np, "autorepeat")) | 161 | if (of_property_read_bool(np, "autorepeat")) |
| 160 | kbd->rep = true; | 162 | kbd->rep = true; |
| 161 | 163 | ||
| 164 | if (of_property_read_u32(np, "suspended_rate", &suspended_rate)) | ||
| 165 | kbd->suspended_rate = suspended_rate; | ||
| 166 | |||
| 162 | error = of_property_read_u32(np, "st,mode", &val); | 167 | error = of_property_read_u32(np, "st,mode", &val); |
| 163 | if (error) { | 168 | if (error) { |
| 164 | dev_err(&pdev->dev, "DT: Invalid or missing mode\n"); | 169 | dev_err(&pdev->dev, "DT: Invalid or missing mode\n"); |
| @@ -216,6 +221,7 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev) | |||
| 216 | } else { | 221 | } else { |
| 217 | kbd->mode = pdata->mode; | 222 | kbd->mode = pdata->mode; |
| 218 | kbd->rep = pdata->rep; | 223 | kbd->rep = pdata->rep; |
| 224 | kbd->suspended_rate = pdata->suspended_rate; | ||
| 219 | } | 225 | } |
| 220 | 226 | ||
| 221 | kbd->res = request_mem_region(res->start, resource_size(res), | 227 | kbd->res = request_mem_region(res->start, resource_size(res), |
| @@ -317,16 +323,48 @@ static int spear_kbd_suspend(struct device *dev) | |||
| 317 | struct platform_device *pdev = to_platform_device(dev); | 323 | struct platform_device *pdev = to_platform_device(dev); |
| 318 | struct spear_kbd *kbd = platform_get_drvdata(pdev); | 324 | struct spear_kbd *kbd = platform_get_drvdata(pdev); |
| 319 | struct input_dev *input_dev = kbd->input; | 325 | struct input_dev *input_dev = kbd->input; |
| 326 | unsigned int rate = 0, mode_ctl_reg, val; | ||
| 320 | 327 | ||
| 321 | mutex_lock(&input_dev->mutex); | 328 | mutex_lock(&input_dev->mutex); |
| 322 | 329 | ||
| 330 | /* explicitly enable clock as we may program device */ | ||
| 331 | clk_enable(kbd->clk); | ||
| 332 | |||
| 333 | mode_ctl_reg = readl_relaxed(kbd->io_base + MODE_CTL_REG); | ||
| 334 | |||
| 323 | if (device_may_wakeup(&pdev->dev)) { | 335 | if (device_may_wakeup(&pdev->dev)) { |
| 324 | enable_irq_wake(kbd->irq); | 336 | enable_irq_wake(kbd->irq); |
| 337 | |||
| 338 | /* | ||
| 339 | * reprogram the keyboard operating frequency as on some | ||
| 340 | * platform it may change during system suspended | ||
| 341 | */ | ||
| 342 | if (kbd->suspended_rate) | ||
| 343 | rate = kbd->suspended_rate / 1000000 - 1; | ||
| 344 | else | ||
| 345 | rate = clk_get_rate(kbd->clk) / 1000000 - 1; | ||
| 346 | |||
| 347 | val = mode_ctl_reg & | ||
| 348 | ~(MODE_CTL_PCLK_FREQ_MSK << MODE_CTL_PCLK_FREQ_SHIFT); | ||
| 349 | val |= (rate & MODE_CTL_PCLK_FREQ_MSK) | ||
| 350 | << MODE_CTL_PCLK_FREQ_SHIFT; | ||
| 351 | writel_relaxed(val, kbd->io_base + MODE_CTL_REG); | ||
| 352 | |||
| 325 | } else { | 353 | } else { |
| 326 | if (input_dev->users) | 354 | if (input_dev->users) { |
| 355 | writel_relaxed(mode_ctl_reg & ~MODE_CTL_START_SCAN, | ||
| 356 | kbd->io_base + MODE_CTL_REG); | ||
| 327 | clk_disable(kbd->clk); | 357 | clk_disable(kbd->clk); |
| 358 | } | ||
| 328 | } | 359 | } |
| 329 | 360 | ||
| 361 | /* store current configuration */ | ||
| 362 | if (input_dev->users) | ||
| 363 | kbd->mode_ctl_reg = mode_ctl_reg; | ||
| 364 | |||
| 365 | /* restore previous clk state */ | ||
| 366 | clk_disable(kbd->clk); | ||
| 367 | |||
| 330 | mutex_unlock(&input_dev->mutex); | 368 | mutex_unlock(&input_dev->mutex); |
| 331 | 369 | ||
| 332 | return 0; | 370 | return 0; |
| @@ -347,6 +385,10 @@ static int spear_kbd_resume(struct device *dev) | |||
| 347 | clk_enable(kbd->clk); | 385 | clk_enable(kbd->clk); |
| 348 | } | 386 | } |
| 349 | 387 | ||
| 388 | /* restore current configuration */ | ||
| 389 | if (input_dev->users) | ||
| 390 | writel_relaxed(kbd->mode_ctl_reg, kbd->io_base + MODE_CTL_REG); | ||
| 391 | |||
| 350 | mutex_unlock(&input_dev->mutex); | 392 | mutex_unlock(&input_dev->mutex); |
| 351 | 393 | ||
| 352 | return 0; | 394 | return 0; |
