aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/keyboard/spear-keyboard.c46
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
68static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) 70static 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;