[PATCH 1/6] input/spear-keyboard: fix disable device_init_wakeup in remove

Subsystems: input (keyboard, mouse, joystick, touchscreen) drivers, the rest

STALE5206d

10 messages, 2 authors, 2012-07-09 · open the first message on its own page

[PATCH 1/6] input/spear-keyboard: fix disable device_init_wakeup in remove

From: Shiraz Hashim <hidden>
Date: 2012-07-02 06:50:30

From: Vipul Kumar Samar <redacted>

This patch is to disable device wakeup while removing keyboard.

Signed-off-by: Vipul Kumar Samar <redacted>
---
 drivers/input/keyboard/spear-keyboard.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 605d3d2..67d9afb 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -303,7 +303,7 @@ static int __devexit spear_kbd_remove(struct platform_device *pdev)
 	release_mem_region(kbd->res->start, resource_size(kbd->res));
 	kfree(kbd);
 
-	device_init_wakeup(&pdev->dev, 1);
+	device_init_wakeup(&pdev->dev, 0);
 	platform_set_drvdata(pdev, NULL);
 
 	return 0;
-- 
1.7.10

[PATCH 2/6] input/spear_keyboard: fix clock handling during suspend/resume

From: Shiraz Hashim <hidden>
Date: 2012-07-02 06:50:34

SPEAr keyboard should normally disable clock during suspend and enable it
during resume.

For cases where it is expected to act as a wakeup source the clock can
remain in the same state i.e. kept enabled if it is being used.

Signed-off-by: Shiraz Hashim <redacted>
---
 drivers/input/keyboard/spear-keyboard.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 67d9afb..ef147f3 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -318,12 +318,12 @@ static int spear_kbd_suspend(struct device *dev)
 
 	mutex_lock(&input_dev->mutex);
 
-	if (input_dev->users)
-		clk_enable(kbd->clk);
-
 	if (device_may_wakeup(&pdev->dev)) {
 		if (!enable_irq_wake(kbd->irq))
 			kbd->irq_wake = 1;
+	} else {
+		if (input_dev->users)
+			clk_disable(kbd->clk);
 	}
 
 	mutex_unlock(&input_dev->mutex);
@@ -344,11 +344,11 @@ static int spear_kbd_resume(struct device *dev)
 			kbd->irq_wake = 0;
 			disable_irq_wake(kbd->irq);
 		}
+	} else {
+		if (input_dev->users)
+			clk_enable(kbd->clk);
 	}
 
-	if (input_dev->users)
-		clk_enable(kbd->clk);
-
 	mutex_unlock(&input_dev->mutex);
 
 	return 0;
-- 
1.7.10

[PATCH 3/6] input/spear_keyboard: use correct io accessors

From: Shiraz Hashim <hidden>
Date: 2012-07-02 06:50:37

All SPEAr keyboard registers are 32 bit wide and are word aligned. This
patch aligns all io access to be word size using relaxed version of
readl/writel.

Signed-off-by: Shiraz Hashim <redacted>
---
 drivers/input/keyboard/spear-keyboard.c |   30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index ef147f3..36c145a 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -27,9 +27,9 @@
 #include <plat/keyboard.h>
 
 /* Keyboard Registers */
-#define MODE_REG	0x00	/* 16 bit reg */
-#define STATUS_REG	0x0C	/* 2 bit reg */
-#define DATA_REG	0x10	/* 8 bit reg */
+#define MODE_REG	0x00
+#define STATUS_REG	0x0C
+#define DATA_REG	0x10
 #define INTR_MASK	0x54
 
 /* Register Values */
@@ -73,9 +73,9 @@ static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
 	struct spear_kbd *kbd = dev_id;
 	struct input_dev *input = kbd->input;
 	unsigned int key;
-	u8 sts, val;
+	u32 sts, val;
 
-	sts = readb(kbd->io_base + STATUS_REG);
+	sts = readl_relaxed(kbd->io_base + STATUS_REG);
 	if (!(sts & DATA_AVAIL))
 		return IRQ_NONE;
 
@@ -85,7 +85,7 @@ static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
 	}
 
 	/* following reads active (row, col) pair */
-	val = readb(kbd->io_base + DATA_REG);
+	val = readl_relaxed(kbd->io_base + DATA_REG);
 	key = kbd->keycodes[val];
 
 	input_event(input, EV_MSC, MSC_SCAN, val);
@@ -95,7 +95,7 @@ static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
 	kbd->last_key = key;
 
 	/* clear interrupt */
-	writeb(0, kbd->io_base + STATUS_REG);
+	writel_relaxed(0, kbd->io_base + STATUS_REG);
 
 	return IRQ_HANDLED;
 }
@@ -104,7 +104,7 @@ static int spear_kbd_open(struct input_dev *dev)
 {
 	struct spear_kbd *kbd = input_get_drvdata(dev);
 	int error;
-	u16 val;
+	u32 val;
 
 	kbd->last_key = KEY_RESERVED;
 
@@ -115,13 +115,13 @@ static int spear_kbd_open(struct input_dev *dev)
 	/* program keyboard */
 	val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK |
 		(kbd->mode << KEY_MATRIX_SHIFT);
-	writew(val, kbd->io_base + MODE_REG);
-	writeb(1, kbd->io_base + STATUS_REG);
+	writel_relaxed(val, kbd->io_base + MODE_REG);
+	writel_relaxed(1, kbd->io_base + STATUS_REG);
 
 	/* start key scan */
-	val = readw(kbd->io_base + MODE_REG);
+	val = readl_relaxed(kbd->io_base + MODE_REG);
 	val |= START_SCAN;
-	writew(val, kbd->io_base + MODE_REG);
+	writel_relaxed(val, kbd->io_base + MODE_REG);
 
 	return 0;
 }
@@ -129,12 +129,12 @@ static int spear_kbd_open(struct input_dev *dev)
 static void spear_kbd_close(struct input_dev *dev)
 {
 	struct spear_kbd *kbd = input_get_drvdata(dev);
-	u16 val;
+	u32 val;
 
 	/* stop key scan */
-	val = readw(kbd->io_base + MODE_REG);
+	val = readl_relaxed(kbd->io_base + MODE_REG);
 	val &= ~START_SCAN;
-	writew(val, kbd->io_base + MODE_REG);
+	writel_relaxed(val, kbd->io_base + MODE_REG);
 
 	clk_disable(kbd->clk);
 
-- 
1.7.10

[PATCH 4/6] input/spear_keyboard: rename bit definitions to reflect register

From: Shiraz Hashim <hidden>
Date: 2012-07-02 06:50:40

Rename bit definition macros to reflect keyboard registers clearly thus
being more readable.

Signed-off-by: Shiraz Hashim <redacted>
---
 drivers/input/keyboard/spear-keyboard.c |   52 ++++++++++++++++---------------
 1 file changed, 27 insertions(+), 25 deletions(-)
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 36c145a..70f43c2 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -27,7 +27,7 @@
 #include <plat/keyboard.h>
 
 /* Keyboard Registers */
-#define MODE_REG	0x00
+#define MODE_CTL_REG	0x00
 #define STATUS_REG	0x0C
 #define DATA_REG	0x10
 #define INTR_MASK	0x54
@@ -38,22 +38,23 @@
  * control register as 1010010(82MHZ)
  */
 #define PCLK_FREQ_MSK	0xA400	/* 82 MHz */
-#define START_SCAN	0x0100
-#define SCAN_RATE_10	0x0000
-#define SCAN_RATE_20	0x0004
-#define SCAN_RATE_40	0x0008
-#define SCAN_RATE_80	0x000C
-#define MODE_KEYBOARD	0x0002
-#define DATA_AVAIL	0x2
-
-#define KEY_MASK	0xFF000000
-#define KEY_VALUE	0x00FFFFFF
-#define ROW_MASK	0xF0
-#define COLUMN_MASK	0x0F
 #define NUM_ROWS	16
 #define NUM_COLS	16
 
-#define KEY_MATRIX_SHIFT	6
+#define MODE_CTL_KEYBOARD	(0x2 << 0)
+#define MODE_CTL_SCAN_RATE_10	(0x0 << 2)
+#define MODE_CTL_SCAN_RATE_20	(0x1 << 2)
+#define MODE_CTL_SCAN_RATE_40	(0x2 << 2)
+#define MODE_CTL_SCAN_RATE_80	(0x3 << 2)
+#define MODE_CTL_KEYNUM_SHIFT	6
+#define MODE_CTL_START_SCAN	(0x1 << 8)
+
+#define STATUS_DATA_AVAIL	(0x1 << 1)
+
+#define DATA_ROW_MASK		0xF0
+#define DATA_COLUMN_MASK	0x0F
+
+#define ROW_SHIFT		4
 
 struct spear_kbd {
 	struct input_dev *input;
@@ -76,7 +77,7 @@ static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
 	u32 sts, val;
 
 	sts = readl_relaxed(kbd->io_base + STATUS_REG);
-	if (!(sts & DATA_AVAIL))
+	if (!(sts & STATUS_DATA_AVAIL))
 		return IRQ_NONE;
 
 	if (kbd->last_key != KEY_RESERVED) {
@@ -85,7 +86,8 @@ static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
 	}
 
 	/* following reads active (row, col) pair */
-	val = readl_relaxed(kbd->io_base + DATA_REG);
+	val = readl_relaxed(kbd->io_base + DATA_REG) &
+		(DATA_ROW_MASK | DATA_COLUMN_MASK);
 	key = kbd->keycodes[val];
 
 	input_event(input, EV_MSC, MSC_SCAN, val);
@@ -113,15 +115,15 @@ static int spear_kbd_open(struct input_dev *dev)
 		return error;
 
 	/* program keyboard */
-	val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK |
-		(kbd->mode << KEY_MATRIX_SHIFT);
-	writel_relaxed(val, kbd->io_base + MODE_REG);
+	val = MODE_CTL_SCAN_RATE_80 | MODE_CTL_KEYBOARD | PCLK_FREQ_MSK |
+		(kbd->mode << MODE_CTL_KEYNUM_SHIFT);
+	writel_relaxed(val, kbd->io_base + MODE_CTL_REG);
 	writel_relaxed(1, kbd->io_base + STATUS_REG);
 
 	/* start key scan */
-	val = readl_relaxed(kbd->io_base + MODE_REG);
-	val |= START_SCAN;
-	writel_relaxed(val, kbd->io_base + MODE_REG);
+	val = readl_relaxed(kbd->io_base + MODE_CTL_REG);
+	val |= MODE_CTL_START_SCAN;
+	writel_relaxed(val, kbd->io_base + MODE_CTL_REG);
 
 	return 0;
 }
@@ -132,9 +134,9 @@ static void spear_kbd_close(struct input_dev *dev)
 	u32 val;
 
 	/* stop key scan */
-	val = readl_relaxed(kbd->io_base + MODE_REG);
-	val &= ~START_SCAN;
-	writel_relaxed(val, kbd->io_base + MODE_REG);
+	val = readl_relaxed(kbd->io_base + MODE_CTL_REG);
+	val &= ~MODE_CTL_START_SCAN;
+	writel_relaxed(val, kbd->io_base + MODE_CTL_REG);
 
 	clk_disable(kbd->clk);
 
-- 
1.7.10

[PATCH 5/6] input/spear_keyboard: generalize keyboard frequency configuration

From: Shiraz Hashim <hidden>
Date: 2012-07-02 06:50:44

Current implementation hard coded keyboard frequency configuration
assuming input clock as fixed APB (83 MHz). Generalize the configuration
using clock framework APIs.

Signed-off-by: Shiraz Hashim <redacted>
---
 drivers/input/keyboard/spear-keyboard.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 70f43c2..ae1132e 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -33,13 +33,10 @@
 #define INTR_MASK	0x54
 
 /* Register Values */
-/*
- * pclk freq mask = (APB FEQ -1)= 82 MHZ.Programme bit 15-9 in mode
- * control register as 1010010(82MHZ)
- */
-#define PCLK_FREQ_MSK	0xA400	/* 82 MHz */
 #define NUM_ROWS	16
 #define NUM_COLS	16
+#define MODE_CTL_PCLK_FREQ_SHIFT	9
+#define MODE_CTL_PCLK_FREQ_MSK		0x7F
 
 #define MODE_CTL_KEYBOARD	(0x2 << 0)
 #define MODE_CTL_SCAN_RATE_10	(0x0 << 2)
@@ -114,8 +111,12 @@ static int spear_kbd_open(struct input_dev *dev)
 	if (error)
 		return error;
 
+	/* keyboard rate to be programmed is input clock (in MHz) - 1 */
+	val = clk_get_rate(kbd->clk) / 1000000 - 1;
+	val = (val & MODE_CTL_PCLK_FREQ_MSK) << MODE_CTL_PCLK_FREQ_SHIFT;
+
 	/* program keyboard */
-	val = MODE_CTL_SCAN_RATE_80 | MODE_CTL_KEYBOARD | PCLK_FREQ_MSK |
+	val = MODE_CTL_SCAN_RATE_80 | MODE_CTL_KEYBOARD | val |
 		(kbd->mode << MODE_CTL_KEYNUM_SHIFT);
 	writel_relaxed(val, kbd->io_base + MODE_CTL_REG);
 	writel_relaxed(1, kbd->io_base + STATUS_REG);
-- 
1.7.10

[PATCH 6/6] input/spear_keyboard: reconfigure operating frequency on suspend

From: Shiraz Hashim <hidden>
Date: 2012-07-02 06:50:49

On some platform it may happen that the input clock to keyboard may
change 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 <redacted>
---
 arch/arm/plat-spear/include/plat/keyboard.h |    2 ++
 drivers/input/keyboard/spear-keyboard.c     |   44 +++++++++++++++++++++++++--
 2 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/arch/arm/plat-spear/include/plat/keyboard.h b/arch/arm/plat-spear/include/plat/keyboard.h
index 0562f13..9248e3a 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[] = { \
  * keymap: pointer to keymap data (table and size)
  * rep: enables key autorepeat
  * mode: choose keyboard support(9x9, 6x6, 2x2)
+ * suspended_rate: rate at which keyboard would operate in suspended mode
  *
  * This structure is supposed to be used by platform code to supply
  * keymaps to drivers that implement keyboards.
@@ -157,6 +158,7 @@ struct kbd_platform_data {
 	const struct matrix_keymap_data *keymap;
 	bool rep;
 	unsigned int mode;
+	unsigned int suspended_rate;
 };
 
 #endif /* __PLAT_KEYBOARD_H */
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index ae1132e..9333a35 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -64,6 +64,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)
@@ -150,7 +152,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");
@@ -160,6 +162,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");
@@ -217,6 +222,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),
@@ -318,17 +324,47 @@ 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)) {
 		if (!enable_irq_wake(kbd->irq))
 			kbd->irq_wake = 1;
+
+		/*
+		 * 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;
+
+		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;
@@ -352,6 +388,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;
-- 
1.7.10

Re: [PATCH 2/6] input/spear_keyboard: fix clock handling during suspend/resume

From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Date: 2012-07-08 01:12:00

Hi Shiraz,

On Mon, Jul 02, 2012 at 12:20:10PM +0530, Shiraz Hashim wrote:
quoted hunk
SPEAr keyboard should normally disable clock during suspend and enable it
during resume.

For cases where it is expected to act as a wakeup source the clock can
remain in the same state i.e. kept enabled if it is being used.

Signed-off-by: Shiraz Hashim <redacted>
---
 drivers/input/keyboard/spear-keyboard.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 67d9afb..ef147f3 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -318,12 +318,12 @@ static int spear_kbd_suspend(struct device *dev)
 
 	mutex_lock(&input_dev->mutex);
 
-	if (input_dev->users)
-		clk_enable(kbd->clk);
-
 	if (device_may_wakeup(&pdev->dev)) {
 		if (!enable_irq_wake(kbd->irq))
 			kbd->irq_wake = 1;
+	} else {
+		if (input_dev->users)
+			clk_disable(kbd->clk);
 	}
This patch does not apply to mainline version of the driver because the
change introducing handling for enable_irq_wake() failures was rejected
from mainline. I also have not appplied the 6th patch in the series
because it depends on this one.

Also, don't you need to enable clock if device is marked as wakeup
source but happens to have no active users?

Thanks.

-- 
Dmitry

Re: [PATCH 2/6] input/spear_keyboard: fix clock handling during suspend/resume

From: Shiraz Hashim <hidden>
Date: 2012-07-09 04:03:20

Hi Dmitry,

On Sat, Jul 07, 2012 at 06:11:55PM -0700, Dmitry Torokhov wrote:
Hi Shiraz,

On Mon, Jul 02, 2012 at 12:20:10PM +0530, Shiraz Hashim wrote:
quoted
SPEAr keyboard should normally disable clock during suspend and enable it
during resume.

For cases where it is expected to act as a wakeup source the clock can
remain in the same state i.e. kept enabled if it is being used.

Signed-off-by: Shiraz Hashim <redacted>
---
 drivers/input/keyboard/spear-keyboard.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 67d9afb..ef147f3 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -318,12 +318,12 @@ static int spear_kbd_suspend(struct device *dev)
 
 	mutex_lock(&input_dev->mutex);
 
-	if (input_dev->users)
-		clk_enable(kbd->clk);
-
 	if (device_may_wakeup(&pdev->dev)) {
 		if (!enable_irq_wake(kbd->irq))
 			kbd->irq_wake = 1;
+	} else {
+		if (input_dev->users)
+			clk_disable(kbd->clk);
 	}
This patch does not apply to mainline version of the driver because the
change introducing handling for enable_irq_wake() failures was rejected
from mainline. I also have not appplied the 6th patch in the series
because it depends on this one.
Oh. Sorry, I should have been careful. I would clean up and send V2
for this.
Also, don't you need to enable clock if device is marked as wakeup
source but happens to have no active users?
The keyboard is initialized and programmed in open and disabled in
close, so I thought even if I just enable the clock in suspend
(without open being called) it would not be able to generate the
wakeup interrupt.

--
regards
Shiraz

[PATCH V2 2/6] input/spear_keyboard: fix clock handling during suspend/resume

From: Shiraz Hashim <hidden>
Date: 2012-07-09 06:36:12

SPEAr keyboard should normally disable clock during suspend and enable it
during resume.

For cases where it is expected to act as a wakeup source the clock can
remain in the same state i.e. kept enabled if it is being used.

Signed-off-by: Shiraz Hashim <redacted>
---
Changes since V1:
 * remove discarded irq balancing patch dependency

 drivers/input/keyboard/spear-keyboard.c |   18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 45dd02c..aa1259a 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -317,11 +317,12 @@ static int spear_kbd_suspend(struct device *dev)
 
 	mutex_lock(&input_dev->mutex);
 
-	if (input_dev->users)
-		clk_enable(kbd->clk);
-
-	if (device_may_wakeup(&pdev->dev))
+	if (device_may_wakeup(&pdev->dev)) {
 		enable_irq_wake(kbd->irq);
+	} else {
+		if (input_dev->users)
+			clk_disable(kbd->clk);
+	}
 
 	mutex_unlock(&input_dev->mutex);
 
@@ -336,11 +337,12 @@ static int spear_kbd_resume(struct device *dev)
 
 	mutex_lock(&input_dev->mutex);
 
-	if (device_may_wakeup(&pdev->dev))
+	if (device_may_wakeup(&pdev->dev)) {
 		disable_irq_wake(kbd->irq);
-
-	if (input_dev->users)
-		clk_enable(kbd->clk);
+	} else {
+		if (input_dev->users)
+			clk_enable(kbd->clk);
+	}
 
 	mutex_unlock(&input_dev->mutex);
 
-- 
1.7.10

[PATCH V2 6/6] input/spear_keyboard: reconfigure operating frequency on suspend

From: Shiraz Hashim <hidden>
Date: 2012-07-09 06:37:04

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 <redacted>
---
Changes since V1:
 * remove discarded irq balancing patch dependency
 * consifer kbd rate from clock APIs, if suspended_rate is not available

 arch/arm/plat-spear/include/plat/keyboard.h |    2 ++
 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 0562f13..9248e3a 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[] = { \
  * keymap: pointer to keymap data (table and size)
  * rep: enables key autorepeat
  * mode: choose keyboard support(9x9, 6x6, 2x2)
+ * suspended_rate: rate at which keyboard would operate in suspended mode
  *
  * This structure is supposed to be used by platform code to supply
  * keymaps to drivers that implement keyboards.
@@ -157,6 +158,7 @@ struct kbd_platform_data {
 	const struct matrix_keymap_data *keymap;
 	bool rep;
 	unsigned int mode;
+	unsigned int suspended_rate;
 };
 
 #endif /* __PLAT_KEYBOARD_H */
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 617a33d..72ef01b 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;
-- 
1.7.10
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help