summaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorShiraz Hashim <shiraz.hashim@st.com>2012-07-13 00:11:10 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-07-13 00:14:01 -0700
commit8314f532ebd55f1d6dc23b143cda3c1714ffe201 (patch)
treef9845473fd28cbcc33c3ac4de1427c1f58b82a28 /drivers/input
parent53fe628558bab9a11050ba067a09442c92dca6bb (diff)
downloadlinux-8314f532ebd55f1d6dc23b143cda3c1714ffe201.tar.bz2
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>
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 {
unsigned short last_key;
unsigned short keycodes[NUM_ROWS * NUM_COLS];
bool rep;
+ unsigned int suspended_rate;
+ u32 mode_ctl_reg;
};
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,
{
struct device_node *np = pdev->dev.of_node;
int error;
- u32 val;
+ u32 val, suspended_rate;
if (!np) {
dev_err(&pdev->dev, "Missing DT data\n");
@@ -159,6 +161,9 @@ static int __devinit spear_kbd_parse_dt(struct platform_device *pdev,
if (of_property_read_bool(np, "autorepeat"))
kbd->rep = true;
+ if (of_property_read_u32(np, "suspended_rate", &suspended_rate))
+ kbd->suspended_rate = suspended_rate;
+
error = of_property_read_u32(np, "st,mode", &val);
if (error) {
dev_err(&pdev->dev, "DT: Invalid or missing mode\n");
@@ -216,6 +221,7 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
} else {
kbd->mode = pdata->mode;
kbd->rep = pdata->rep;
+ kbd->suspended_rate = pdata->suspended_rate;
}
kbd->res = request_mem_region(res->start, resource_size(res),
@@ -317,16 +323,48 @@ static int spear_kbd_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct spear_kbd *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input;
+ unsigned int rate = 0, mode_ctl_reg, val;
mutex_lock(&input_dev->mutex);
+ /* explicitly enable clock as we may program device */
+ clk_enable(kbd->clk);
+
+ mode_ctl_reg = readl_relaxed(kbd->io_base + MODE_CTL_REG);
+
if (device_may_wakeup(&pdev->dev)) {
enable_irq_wake(kbd->irq);
+
+ /*
+ * reprogram the keyboard operating frequency as on some
+ * platform it may change during system suspended
+ */
+ if (kbd->suspended_rate)
+ rate = kbd->suspended_rate / 1000000 - 1;
+ else
+ rate = clk_get_rate(kbd->clk) / 1000000 - 1;
+
+ val = mode_ctl_reg &
+ ~(MODE_CTL_PCLK_FREQ_MSK << MODE_CTL_PCLK_FREQ_SHIFT);
+ val |= (rate & MODE_CTL_PCLK_FREQ_MSK)
+ << MODE_CTL_PCLK_FREQ_SHIFT;
+ writel_relaxed(val, kbd->io_base + MODE_CTL_REG);
+
} else {
- if (input_dev->users)
+ if (input_dev->users) {
+ writel_relaxed(mode_ctl_reg & ~MODE_CTL_START_SCAN,
+ kbd->io_base + MODE_CTL_REG);
clk_disable(kbd->clk);
+ }
}
+ /* store current configuration */
+ if (input_dev->users)
+ kbd->mode_ctl_reg = mode_ctl_reg;
+
+ /* restore previous clk state */
+ clk_disable(kbd->clk);
+
mutex_unlock(&input_dev->mutex);
return 0;
@@ -347,6 +385,10 @@ static int spear_kbd_resume(struct device *dev)
clk_enable(kbd->clk);
}
+ /* restore current configuration */
+ if (input_dev->users)
+ writel_relaxed(kbd->mode_ctl_reg, kbd->io_base + MODE_CTL_REG);
+
mutex_unlock(&input_dev->mutex);
return 0;