aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShiraz Hashim <shiraz.hashim@st.com>2012-07-13 03:11:10 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-07-13 03:14:01 -0400
commit8314f532ebd55f1d6dc23b143cda3c1714ffe201 (patch)
treef9845473fd28cbcc33c3ac4de1427c1f58b82a28
parent53fe628558bab9a11050ba067a09442c92dca6bb (diff)
Input: spear_keyboard - reconfigure operating frequency on suspend
On some platform it may happen that the input clock to keyboard may change during suspend, thus impacting its wakeup capability. There is no means for keyboard driver to know this frequency before hand. Hence introduce a platform data 'suspended_rate' which indicates the frequency during suspend at which keyboard operates. Accordingly reprogram keyboard while going into suspend and restore original configuration at the time of resume. Signed-off-by: Shiraz Hashim <shiraz.hashim@st.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--arch/arm/plat-spear/include/plat/keyboard.h2
-rw-r--r--drivers/input/keyboard/spear-keyboard.c46
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
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;