Re: [RESEND PATCH v3 1/6] mfd: cros_ec: Add MKBP event support

2016-03-02 Thread One Thousand Gnomes

> +static int cros_ec_get_host_command_version_mask(struct cros_ec_device 
> *ec_dev,
> + u16 cmd, u32 *mask)
> +{
> + struct ec_params_get_cmd_versions *pver;
> + struct ec_response_get_cmd_versions *rver;
> + struct cros_ec_command *msg;
> + int ret;
> +
> + msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)),
> +   GFP_KERNEL);
> + if (!msg)
> + return -ENOMEM;
> +
> + msg->version = 0;
> + msg->command = EC_CMD_GET_CMD_VERSIONS;
> + msg->insize = sizeof(rver);
> + msg->outsize = sizeof(pver);

*rver and *pver surely ?




Re: [RESEND PATCH v3 1/6] mfd: cros_ec: Add MKBP event support

2016-03-02 Thread One Thousand Gnomes

> +static int cros_ec_get_host_command_version_mask(struct cros_ec_device 
> *ec_dev,
> + u16 cmd, u32 *mask)
> +{
> + struct ec_params_get_cmd_versions *pver;
> + struct ec_response_get_cmd_versions *rver;
> + struct cros_ec_command *msg;
> + int ret;
> +
> + msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)),
> +   GFP_KERNEL);
> + if (!msg)
> + return -ENOMEM;
> +
> + msg->version = 0;
> + msg->command = EC_CMD_GET_CMD_VERSIONS;
> + msg->insize = sizeof(rver);
> + msg->outsize = sizeof(pver);

*rver and *pver surely ?




[RESEND PATCH v3 1/6] mfd: cros_ec: Add MKBP event support

2016-03-02 Thread Tomeu Vizoso
From: Vic Yang 

Newer revisions of the ChromeOS EC add more events besides the keyboard
ones. So handle interrupts in the MFD driver and let consumers register
for notifications for the events they might care.

To keep backward compatibility, if the EC doesn't support MKBP event, we
fall back to the old MKBP key matrix host command.

Signed-off-by: Vic Yang 
[bleung: fixup some context changes going from v3.14 to v3.18]
Signed-off-by: Benson Leung 
[tomeu: adapted to changes in mainline (in power-supply and platform/chrome)]
Signed-off-by: Tomeu Vizoso 
Cc: Randall Spangler 
Cc: Vincent Palatin 
---

Changes in v3:
- Remove duplicated prototype of cros_ec_get_host_event.

Changes in v2:
- Allocate enough for the structs in cros_ec_get_host_command_version_mask,
  not their pointers.
- Allocate msg in the stack in get_next_event and
  get_keyboard_state_event, as suggested by Gwendal.

 drivers/input/keyboard/cros_ec_keyb.c   | 135 
 drivers/mfd/cros_ec.c   |  57 +-
 drivers/platform/chrome/cros_ec_proto.c |  92 ++
 include/linux/mfd/cros_ec.h |  34 
 include/linux/mfd/cros_ec_commands.h|  34 
 5 files changed, 245 insertions(+), 107 deletions(-)

diff --git a/drivers/input/keyboard/cros_ec_keyb.c 
b/drivers/input/keyboard/cros_ec_keyb.c
index b01966dc7eb3..b891503143dc 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -27,6 +27,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -44,6 +45,7 @@
  * @dev: Device pointer
  * @idev: Input device
  * @ec: Top level ChromeOS device to use to talk to EC
+ * @notifier: interrupt event notifier for transport devices
  */
 struct cros_ec_keyb {
unsigned int rows;
@@ -57,6 +59,7 @@ struct cros_ec_keyb {
struct device *dev;
struct input_dev *idev;
struct cros_ec_device *ec;
+   struct notifier_block notifier;
 };
 
 
@@ -146,67 +149,44 @@ static void cros_ec_keyb_process(struct cros_ec_keyb 
*ckdev,
input_sync(ckdev->idev);
 }
 
-static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t 
*kb_state)
-{
-   int ret = 0;
-   struct cros_ec_command *msg;
-
-   msg = kmalloc(sizeof(*msg) + ckdev->cols, GFP_KERNEL);
-   if (!msg)
-   return -ENOMEM;
-
-   msg->version = 0;
-   msg->command = EC_CMD_MKBP_STATE;
-   msg->insize = ckdev->cols;
-   msg->outsize = 0;
-
-   ret = cros_ec_cmd_xfer(ckdev->ec, msg);
-   if (ret < 0) {
-   dev_err(ckdev->dev, "Error transferring EC message %d\n", ret);
-   goto exit;
-   }
-
-   memcpy(kb_state, msg->data, ckdev->cols);
-exit:
-   kfree(msg);
-   return ret;
-}
-
-static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
+static int cros_ec_keyb_open(struct input_dev *dev)
 {
-   struct cros_ec_keyb *ckdev = data;
-   struct cros_ec_device *ec = ckdev->ec;
-   int ret;
-   uint8_t kb_state[ckdev->cols];
-
-   if (device_may_wakeup(ec->dev))
-   pm_wakeup_event(ec->dev, 0);
-
-   ret = cros_ec_keyb_get_state(ckdev, kb_state);
-   if (ret >= 0)
-   cros_ec_keyb_process(ckdev, kb_state, ret);
-   else
-   dev_err(ec->dev, "failed to get keyboard state: %d\n", ret);
+   struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
 
-   return IRQ_HANDLED;
+   return blocking_notifier_chain_register(>ec->event_notifier,
+   >notifier);
 }
 
-static int cros_ec_keyb_open(struct input_dev *dev)
+static void cros_ec_keyb_close(struct input_dev *dev)
 {
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
-   struct cros_ec_device *ec = ckdev->ec;
 
-   return request_threaded_irq(ec->irq, NULL, cros_ec_keyb_irq,
-   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-   "cros_ec_keyb", ckdev);
+   blocking_notifier_chain_unregister(>ec->event_notifier,
+  >notifier);
 }
 
-static void cros_ec_keyb_close(struct input_dev *dev)
+static int cros_ec_keyb_work(struct notifier_block *nb,
+unsigned long queued_during_suspend, void *_notify)
 {
-   struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
-   struct cros_ec_device *ec = ckdev->ec;
+   struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
+ notifier);
 
-   free_irq(ec->irq, ckdev);
+   if (ckdev->ec->event_data.event_type != EC_MKBP_EVENT_KEY_MATRIX)
+   return NOTIFY_DONE;
+   /*
+* If EC is not the wake source, discard key state changes during
+

[RESEND PATCH v3 1/6] mfd: cros_ec: Add MKBP event support

2016-03-02 Thread Tomeu Vizoso
From: Vic Yang 

Newer revisions of the ChromeOS EC add more events besides the keyboard
ones. So handle interrupts in the MFD driver and let consumers register
for notifications for the events they might care.

To keep backward compatibility, if the EC doesn't support MKBP event, we
fall back to the old MKBP key matrix host command.

Signed-off-by: Vic Yang 
[bleung: fixup some context changes going from v3.14 to v3.18]
Signed-off-by: Benson Leung 
[tomeu: adapted to changes in mainline (in power-supply and platform/chrome)]
Signed-off-by: Tomeu Vizoso 
Cc: Randall Spangler 
Cc: Vincent Palatin 
---

Changes in v3:
- Remove duplicated prototype of cros_ec_get_host_event.

Changes in v2:
- Allocate enough for the structs in cros_ec_get_host_command_version_mask,
  not their pointers.
- Allocate msg in the stack in get_next_event and
  get_keyboard_state_event, as suggested by Gwendal.

 drivers/input/keyboard/cros_ec_keyb.c   | 135 
 drivers/mfd/cros_ec.c   |  57 +-
 drivers/platform/chrome/cros_ec_proto.c |  92 ++
 include/linux/mfd/cros_ec.h |  34 
 include/linux/mfd/cros_ec_commands.h|  34 
 5 files changed, 245 insertions(+), 107 deletions(-)

diff --git a/drivers/input/keyboard/cros_ec_keyb.c 
b/drivers/input/keyboard/cros_ec_keyb.c
index b01966dc7eb3..b891503143dc 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -27,6 +27,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -44,6 +45,7 @@
  * @dev: Device pointer
  * @idev: Input device
  * @ec: Top level ChromeOS device to use to talk to EC
+ * @notifier: interrupt event notifier for transport devices
  */
 struct cros_ec_keyb {
unsigned int rows;
@@ -57,6 +59,7 @@ struct cros_ec_keyb {
struct device *dev;
struct input_dev *idev;
struct cros_ec_device *ec;
+   struct notifier_block notifier;
 };
 
 
@@ -146,67 +149,44 @@ static void cros_ec_keyb_process(struct cros_ec_keyb 
*ckdev,
input_sync(ckdev->idev);
 }
 
-static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t 
*kb_state)
-{
-   int ret = 0;
-   struct cros_ec_command *msg;
-
-   msg = kmalloc(sizeof(*msg) + ckdev->cols, GFP_KERNEL);
-   if (!msg)
-   return -ENOMEM;
-
-   msg->version = 0;
-   msg->command = EC_CMD_MKBP_STATE;
-   msg->insize = ckdev->cols;
-   msg->outsize = 0;
-
-   ret = cros_ec_cmd_xfer(ckdev->ec, msg);
-   if (ret < 0) {
-   dev_err(ckdev->dev, "Error transferring EC message %d\n", ret);
-   goto exit;
-   }
-
-   memcpy(kb_state, msg->data, ckdev->cols);
-exit:
-   kfree(msg);
-   return ret;
-}
-
-static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
+static int cros_ec_keyb_open(struct input_dev *dev)
 {
-   struct cros_ec_keyb *ckdev = data;
-   struct cros_ec_device *ec = ckdev->ec;
-   int ret;
-   uint8_t kb_state[ckdev->cols];
-
-   if (device_may_wakeup(ec->dev))
-   pm_wakeup_event(ec->dev, 0);
-
-   ret = cros_ec_keyb_get_state(ckdev, kb_state);
-   if (ret >= 0)
-   cros_ec_keyb_process(ckdev, kb_state, ret);
-   else
-   dev_err(ec->dev, "failed to get keyboard state: %d\n", ret);
+   struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
 
-   return IRQ_HANDLED;
+   return blocking_notifier_chain_register(>ec->event_notifier,
+   >notifier);
 }
 
-static int cros_ec_keyb_open(struct input_dev *dev)
+static void cros_ec_keyb_close(struct input_dev *dev)
 {
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
-   struct cros_ec_device *ec = ckdev->ec;
 
-   return request_threaded_irq(ec->irq, NULL, cros_ec_keyb_irq,
-   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-   "cros_ec_keyb", ckdev);
+   blocking_notifier_chain_unregister(>ec->event_notifier,
+  >notifier);
 }
 
-static void cros_ec_keyb_close(struct input_dev *dev)
+static int cros_ec_keyb_work(struct notifier_block *nb,
+unsigned long queued_during_suspend, void *_notify)
 {
-   struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
-   struct cros_ec_device *ec = ckdev->ec;
+   struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
+ notifier);
 
-   free_irq(ec->irq, ckdev);
+   if (ckdev->ec->event_data.event_type != EC_MKBP_EVENT_KEY_MATRIX)
+   return NOTIFY_DONE;
+   /*
+* If EC is not the wake source, discard key state changes during
+* suspend.
+*/
+   if (queued_during_suspend)
+   return NOTIFY_OK;
+   if (ckdev->ec->event_size != ckdev->cols) {

[PATCH v3 1/6] mfd: cros_ec: Add MKBP event support

2016-02-17 Thread Tomeu Vizoso
From: Vic Yang 

Newer revisions of the ChromeOS EC add more events besides the keyboard
ones. So handle interrupts in the MFD driver and let consumers register
for notifications for the events they might care.

To keep backward compatibility, if the EC doesn't support MKBP event, we
fall back to the old MKBP key matrix host command.

Signed-off-by: Vic Yang 
[bleung: fixup some context changes going from v3.14 to v3.18]
Signed-off-by: Benson Leung 
[tomeu: adapted to changes in mainline (in power-supply and platform/chrome)]
Signed-off-by: Tomeu Vizoso 
Cc: Randall Spangler 
Cc: Vincent Palatin 
---

Changes in v3:
- Remove duplicated prototype of cros_ec_get_host_event.

Changes in v2:
- Allocate enough for the structs in cros_ec_get_host_command_version_mask,
  not their pointers.
- Allocate msg in the stack in get_next_event and
  get_keyboard_state_event, as suggested by Gwendal.

 drivers/input/keyboard/cros_ec_keyb.c   | 135 
 drivers/mfd/cros_ec.c   |  57 +-
 drivers/platform/chrome/cros_ec_proto.c |  92 ++
 include/linux/mfd/cros_ec.h |  34 
 include/linux/mfd/cros_ec_commands.h|  34 
 5 files changed, 245 insertions(+), 107 deletions(-)

diff --git a/drivers/input/keyboard/cros_ec_keyb.c 
b/drivers/input/keyboard/cros_ec_keyb.c
index b01966dc7eb3..b891503143dc 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -27,6 +27,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -44,6 +45,7 @@
  * @dev: Device pointer
  * @idev: Input device
  * @ec: Top level ChromeOS device to use to talk to EC
+ * @notifier: interrupt event notifier for transport devices
  */
 struct cros_ec_keyb {
unsigned int rows;
@@ -57,6 +59,7 @@ struct cros_ec_keyb {
struct device *dev;
struct input_dev *idev;
struct cros_ec_device *ec;
+   struct notifier_block notifier;
 };
 
 
@@ -146,67 +149,44 @@ static void cros_ec_keyb_process(struct cros_ec_keyb 
*ckdev,
input_sync(ckdev->idev);
 }
 
-static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t 
*kb_state)
-{
-   int ret = 0;
-   struct cros_ec_command *msg;
-
-   msg = kmalloc(sizeof(*msg) + ckdev->cols, GFP_KERNEL);
-   if (!msg)
-   return -ENOMEM;
-
-   msg->version = 0;
-   msg->command = EC_CMD_MKBP_STATE;
-   msg->insize = ckdev->cols;
-   msg->outsize = 0;
-
-   ret = cros_ec_cmd_xfer(ckdev->ec, msg);
-   if (ret < 0) {
-   dev_err(ckdev->dev, "Error transferring EC message %d\n", ret);
-   goto exit;
-   }
-
-   memcpy(kb_state, msg->data, ckdev->cols);
-exit:
-   kfree(msg);
-   return ret;
-}
-
-static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
+static int cros_ec_keyb_open(struct input_dev *dev)
 {
-   struct cros_ec_keyb *ckdev = data;
-   struct cros_ec_device *ec = ckdev->ec;
-   int ret;
-   uint8_t kb_state[ckdev->cols];
-
-   if (device_may_wakeup(ec->dev))
-   pm_wakeup_event(ec->dev, 0);
-
-   ret = cros_ec_keyb_get_state(ckdev, kb_state);
-   if (ret >= 0)
-   cros_ec_keyb_process(ckdev, kb_state, ret);
-   else
-   dev_err(ec->dev, "failed to get keyboard state: %d\n", ret);
+   struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
 
-   return IRQ_HANDLED;
+   return blocking_notifier_chain_register(>ec->event_notifier,
+   >notifier);
 }
 
-static int cros_ec_keyb_open(struct input_dev *dev)
+static void cros_ec_keyb_close(struct input_dev *dev)
 {
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
-   struct cros_ec_device *ec = ckdev->ec;
 
-   return request_threaded_irq(ec->irq, NULL, cros_ec_keyb_irq,
-   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-   "cros_ec_keyb", ckdev);
+   blocking_notifier_chain_unregister(>ec->event_notifier,
+  >notifier);
 }
 
-static void cros_ec_keyb_close(struct input_dev *dev)
+static int cros_ec_keyb_work(struct notifier_block *nb,
+unsigned long queued_during_suspend, void *_notify)
 {
-   struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
-   struct cros_ec_device *ec = ckdev->ec;
+   struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
+ notifier);
 
-   free_irq(ec->irq, ckdev);
+   if (ckdev->ec->event_data.event_type != EC_MKBP_EVENT_KEY_MATRIX)
+   return NOTIFY_DONE;
+   /*
+* If EC is not the wake source, discard key state changes during
+

[PATCH v3 1/6] mfd: cros_ec: Add MKBP event support

2016-02-17 Thread Tomeu Vizoso
From: Vic Yang 

Newer revisions of the ChromeOS EC add more events besides the keyboard
ones. So handle interrupts in the MFD driver and let consumers register
for notifications for the events they might care.

To keep backward compatibility, if the EC doesn't support MKBP event, we
fall back to the old MKBP key matrix host command.

Signed-off-by: Vic Yang 
[bleung: fixup some context changes going from v3.14 to v3.18]
Signed-off-by: Benson Leung 
[tomeu: adapted to changes in mainline (in power-supply and platform/chrome)]
Signed-off-by: Tomeu Vizoso 
Cc: Randall Spangler 
Cc: Vincent Palatin 
---

Changes in v3:
- Remove duplicated prototype of cros_ec_get_host_event.

Changes in v2:
- Allocate enough for the structs in cros_ec_get_host_command_version_mask,
  not their pointers.
- Allocate msg in the stack in get_next_event and
  get_keyboard_state_event, as suggested by Gwendal.

 drivers/input/keyboard/cros_ec_keyb.c   | 135 
 drivers/mfd/cros_ec.c   |  57 +-
 drivers/platform/chrome/cros_ec_proto.c |  92 ++
 include/linux/mfd/cros_ec.h |  34 
 include/linux/mfd/cros_ec_commands.h|  34 
 5 files changed, 245 insertions(+), 107 deletions(-)

diff --git a/drivers/input/keyboard/cros_ec_keyb.c 
b/drivers/input/keyboard/cros_ec_keyb.c
index b01966dc7eb3..b891503143dc 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -27,6 +27,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -44,6 +45,7 @@
  * @dev: Device pointer
  * @idev: Input device
  * @ec: Top level ChromeOS device to use to talk to EC
+ * @notifier: interrupt event notifier for transport devices
  */
 struct cros_ec_keyb {
unsigned int rows;
@@ -57,6 +59,7 @@ struct cros_ec_keyb {
struct device *dev;
struct input_dev *idev;
struct cros_ec_device *ec;
+   struct notifier_block notifier;
 };
 
 
@@ -146,67 +149,44 @@ static void cros_ec_keyb_process(struct cros_ec_keyb 
*ckdev,
input_sync(ckdev->idev);
 }
 
-static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t 
*kb_state)
-{
-   int ret = 0;
-   struct cros_ec_command *msg;
-
-   msg = kmalloc(sizeof(*msg) + ckdev->cols, GFP_KERNEL);
-   if (!msg)
-   return -ENOMEM;
-
-   msg->version = 0;
-   msg->command = EC_CMD_MKBP_STATE;
-   msg->insize = ckdev->cols;
-   msg->outsize = 0;
-
-   ret = cros_ec_cmd_xfer(ckdev->ec, msg);
-   if (ret < 0) {
-   dev_err(ckdev->dev, "Error transferring EC message %d\n", ret);
-   goto exit;
-   }
-
-   memcpy(kb_state, msg->data, ckdev->cols);
-exit:
-   kfree(msg);
-   return ret;
-}
-
-static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
+static int cros_ec_keyb_open(struct input_dev *dev)
 {
-   struct cros_ec_keyb *ckdev = data;
-   struct cros_ec_device *ec = ckdev->ec;
-   int ret;
-   uint8_t kb_state[ckdev->cols];
-
-   if (device_may_wakeup(ec->dev))
-   pm_wakeup_event(ec->dev, 0);
-
-   ret = cros_ec_keyb_get_state(ckdev, kb_state);
-   if (ret >= 0)
-   cros_ec_keyb_process(ckdev, kb_state, ret);
-   else
-   dev_err(ec->dev, "failed to get keyboard state: %d\n", ret);
+   struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
 
-   return IRQ_HANDLED;
+   return blocking_notifier_chain_register(>ec->event_notifier,
+   >notifier);
 }
 
-static int cros_ec_keyb_open(struct input_dev *dev)
+static void cros_ec_keyb_close(struct input_dev *dev)
 {
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
-   struct cros_ec_device *ec = ckdev->ec;
 
-   return request_threaded_irq(ec->irq, NULL, cros_ec_keyb_irq,
-   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-   "cros_ec_keyb", ckdev);
+   blocking_notifier_chain_unregister(>ec->event_notifier,
+  >notifier);
 }
 
-static void cros_ec_keyb_close(struct input_dev *dev)
+static int cros_ec_keyb_work(struct notifier_block *nb,
+unsigned long queued_during_suspend, void *_notify)
 {
-   struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
-   struct cros_ec_device *ec = ckdev->ec;
+   struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
+ notifier);
 
-   free_irq(ec->irq, ckdev);
+   if (ckdev->ec->event_data.event_type != EC_MKBP_EVENT_KEY_MATRIX)
+   return NOTIFY_DONE;
+   /*
+* If EC is not the wake source, discard key state changes during
+* suspend.
+*/
+   if (queued_during_suspend)
+   return NOTIFY_OK;
+   if (ckdev->ec->event_size != ckdev->cols) {