aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorVic Yang <victoryang@google.com>2016-08-10 13:05:25 -0400
committerLee Jones <lee.jones@linaro.org>2016-08-31 05:51:09 -0400
commit44051a6825d58c02820c07ded54a010479460308 (patch)
tree5711ae86443d3cec76f1343c8827d309384b4a82 /drivers/input
parent6f1d912b687d3d17c1731f5bda3b5d6703bce4a0 (diff)
Input: cros_ec_keyb: Stop handling interrupts directly
Because events other that keyboard ones will be handled by now on by other drivers, stop directly handling interrupts and instead listen to the new notifier in the MFD driver. Signed-off-by: Vic Yang <victoryang@google.com> Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com> Tested-by: Enric Balletbo i Serra <enric.balletbo@collabora.com> Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c135
1 files changed, 31 insertions, 104 deletions
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index 4b0878f35471..25943e9bc8bf 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -27,6 +27,7 @@
27#include <linux/input.h> 27#include <linux/input.h>
28#include <linux/interrupt.h> 28#include <linux/interrupt.h>
29#include <linux/kernel.h> 29#include <linux/kernel.h>
30#include <linux/notifier.h>
30#include <linux/platform_device.h> 31#include <linux/platform_device.h>
31#include <linux/slab.h> 32#include <linux/slab.h>
32#include <linux/input/matrix_keypad.h> 33#include <linux/input/matrix_keypad.h>
@@ -44,6 +45,7 @@
44 * @dev: Device pointer 45 * @dev: Device pointer
45 * @idev: Input device 46 * @idev: Input device
46 * @ec: Top level ChromeOS device to use to talk to EC 47 * @ec: Top level ChromeOS device to use to talk to EC
48 * @notifier: interrupt event notifier for transport devices
47 */ 49 */
48struct cros_ec_keyb { 50struct cros_ec_keyb {
49 unsigned int rows; 51 unsigned int rows;
@@ -57,6 +59,7 @@ struct cros_ec_keyb {
57 struct device *dev; 59 struct device *dev;
58 struct input_dev *idev; 60 struct input_dev *idev;
59 struct cros_ec_device *ec; 61 struct cros_ec_device *ec;
62 struct notifier_block notifier;
60}; 63};
61 64
62 65
@@ -146,67 +149,44 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,
146 input_sync(ckdev->idev); 149 input_sync(ckdev->idev);
147} 150}
148 151
149static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) 152static int cros_ec_keyb_open(struct input_dev *dev)
150{
151 int ret = 0;
152 struct cros_ec_command *msg;
153
154 msg = kmalloc(sizeof(*msg) + ckdev->cols, GFP_KERNEL);
155 if (!msg)
156 return -ENOMEM;
157
158 msg->version = 0;
159 msg->command = EC_CMD_MKBP_STATE;
160 msg->insize = ckdev->cols;
161 msg->outsize = 0;
162
163 ret = cros_ec_cmd_xfer(ckdev->ec, msg);
164 if (ret < 0) {
165 dev_err(ckdev->dev, "Error transferring EC message %d\n", ret);
166 goto exit;
167 }
168
169 memcpy(kb_state, msg->data, ckdev->cols);
170exit:
171 kfree(msg);
172 return ret;
173}
174
175static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
176{ 153{
177 struct cros_ec_keyb *ckdev = data; 154 struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
178 struct cros_ec_device *ec = ckdev->ec;
179 int ret;
180 uint8_t kb_state[ckdev->cols];
181
182 if (device_may_wakeup(ec->dev))
183 pm_wakeup_event(ec->dev, 0);
184
185 ret = cros_ec_keyb_get_state(ckdev, kb_state);
186 if (ret >= 0)
187 cros_ec_keyb_process(ckdev, kb_state, ret);
188 else
189 dev_err(ckdev->dev, "failed to get keyboard state: %d\n", ret);
190 155
191 return IRQ_HANDLED; 156 return blocking_notifier_chain_register(&ckdev->ec->event_notifier,
157 &ckdev->notifier);
192} 158}
193 159
194static int cros_ec_keyb_open(struct input_dev *dev) 160static void cros_ec_keyb_close(struct input_dev *dev)
195{ 161{
196 struct cros_ec_keyb *ckdev = input_get_drvdata(dev); 162 struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
197 struct cros_ec_device *ec = ckdev->ec;
198 163
199 return request_threaded_irq(ec->irq, NULL, cros_ec_keyb_irq, 164 blocking_notifier_chain_unregister(&ckdev->ec->event_notifier,
200 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 165 &ckdev->notifier);
201 "cros_ec_keyb", ckdev);
202} 166}
203 167
204static void cros_ec_keyb_close(struct input_dev *dev) 168static int cros_ec_keyb_work(struct notifier_block *nb,
169 unsigned long queued_during_suspend, void *_notify)
205{ 170{
206 struct cros_ec_keyb *ckdev = input_get_drvdata(dev); 171 struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
207 struct cros_ec_device *ec = ckdev->ec; 172 notifier);
208 173
209 free_irq(ec->irq, ckdev); 174 if (ckdev->ec->event_data.event_type != EC_MKBP_EVENT_KEY_MATRIX)
175 return NOTIFY_DONE;
176 /*
177 * If EC is not the wake source, discard key state changes during
178 * suspend.
179 */
180 if (queued_during_suspend)
181 return NOTIFY_OK;
182 if (ckdev->ec->event_size != ckdev->cols) {
183 dev_err(ckdev->dev,
184 "Discarded incomplete key matrix event.\n");
185 return NOTIFY_OK;
186 }
187 cros_ec_keyb_process(ckdev, ckdev->ec->event_data.data.key_matrix,
188 ckdev->ec->event_size);
189 return NOTIFY_OK;
210} 190}
211 191
212/* 192/*
@@ -265,12 +245,8 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
265 if (!idev) 245 if (!idev)
266 return -ENOMEM; 246 return -ENOMEM;
267 247
268 if (!ec->irq) {
269 dev_err(dev, "no EC IRQ specified\n");
270 return -EINVAL;
271 }
272
273 ckdev->ec = ec; 248 ckdev->ec = ec;
249 ckdev->notifier.notifier_call = cros_ec_keyb_work;
274 ckdev->dev = dev; 250 ckdev->dev = dev;
275 dev_set_drvdata(dev, ckdev); 251 dev_set_drvdata(dev, ckdev);
276 252
@@ -311,54 +287,6 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
311 return 0; 287 return 0;
312} 288}
313 289
314#ifdef CONFIG_PM_SLEEP
315/* Clear any keys in the buffer */
316static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev)
317{
318 uint8_t old_state[ckdev->cols];
319 uint8_t new_state[ckdev->cols];
320 unsigned long duration;
321 int i, ret;
322
323 /*
324 * Keep reading until we see that the scan state does not change.
325 * That indicates that we are done.
326 *
327 * Assume that the EC keyscan buffer is at most 32 deep.
328 */
329 duration = jiffies;
330 ret = cros_ec_keyb_get_state(ckdev, new_state);
331 for (i = 1; !ret && i < 32; i++) {
332 memcpy(old_state, new_state, sizeof(old_state));
333 ret = cros_ec_keyb_get_state(ckdev, new_state);
334 if (0 == memcmp(old_state, new_state, sizeof(old_state)))
335 break;
336 }
337 duration = jiffies - duration;
338 dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i,
339 jiffies_to_usecs(duration));
340}
341
342static int cros_ec_keyb_resume(struct device *dev)
343{
344 struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
345
346 /*
347 * When the EC is not a wake source, then it could not have caused the
348 * resume, so we clear the EC's key scan buffer. If the EC was a
349 * wake source (e.g. the lid is open and the user might press a key to
350 * wake) then the key scan buffer should be preserved.
351 */
352 if (!ckdev->ec->was_wake_device)
353 cros_ec_keyb_clear_keyboard(ckdev);
354
355 return 0;
356}
357
358#endif
359
360static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume);
361
362#ifdef CONFIG_OF 290#ifdef CONFIG_OF
363static const struct of_device_id cros_ec_keyb_of_match[] = { 291static const struct of_device_id cros_ec_keyb_of_match[] = {
364 { .compatible = "google,cros-ec-keyb" }, 292 { .compatible = "google,cros-ec-keyb" },
@@ -372,7 +300,6 @@ static struct platform_driver cros_ec_keyb_driver = {
372 .driver = { 300 .driver = {
373 .name = "cros-ec-keyb", 301 .name = "cros-ec-keyb",
374 .of_match_table = of_match_ptr(cros_ec_keyb_of_match), 302 .of_match_table = of_match_ptr(cros_ec_keyb_of_match),
375 .pm = &cros_ec_keyb_pm_ops,
376 }, 303 },
377}; 304};
378 305