diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/keyboard/spear-keyboard.c | 46 |
1 files changed, 44 insertions, 2 deletions
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; |