From patchwork Wed Jun 18 18:14:07 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 4378711 Return-Path: X-Original-To: patchwork-linux-samsung-soc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id EAE7E9F433 for ; Wed, 18 Jun 2014 18:17:01 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E28E020377 for ; Wed, 18 Jun 2014 18:17:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C74B820304 for ; Wed, 18 Jun 2014 18:16:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754428AbaFRSPv (ORCPT ); Wed, 18 Jun 2014 14:15:51 -0400 Received: from mail-pa0-f73.google.com ([209.85.220.73]:57955 "EHLO mail-pa0-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754089AbaFRSOP (ORCPT ); Wed, 18 Jun 2014 14:14:15 -0400 Received: by mail-pa0-f73.google.com with SMTP id kq14so139303pab.0 for ; Wed, 18 Jun 2014 11:14:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=z8YXRsN622Y5M8gscKh0TpXaSh58TNOSLvXkpGVAIoY=; b=WJtlKmloKlzScxLInY84hB0N0yhSFnmjXe3FmSP059+8ZBP8F2VYED0zY5zODUv/yY 0U+QzhItHVf4emvQ7hobWJGUICgvFoR6l9YnoYG2GlEFQK89i4QfpnWJ+CVRuKblpXhH GeP75DyWUWwA2xishwhIhN3S6dFGeYEutbfUkVYxC+DPtVpN0MEPmSrPK/oMt/kfTTN7 LnH+KKbX0aq3wt+GWwGv4nXvjpZ5fbzo48JndccamADZjnOkqCLFpmtBcSEzUhTF0jDI wRm89lDA8CrBsTqlsNWn/De6K5f3TFkc1a5+/YjTlcunCI+vVyglncePlV1HK2aiOCuT 4Shg== X-Gm-Message-State: ALoCoQnm9nUIcxkjDA7JSzC0bbjsqLXcb0CUcug1SpqW/5EfCF1h2kh7G5gv/rFq/4/wCq0PQOqV X-Received: by 10.66.120.143 with SMTP id lc15mr1537041pab.28.1403115254375; Wed, 18 Jun 2014 11:14:14 -0700 (PDT) Received: from corp2gmr1-2.hot.corp.google.com (corp2gmr1-2.hot.corp.google.com [172.24.189.93]) by gmr-mx.google.com with ESMTPS id j5si186684yhi.1.2014.06.18.11.14.14 for (version=TLSv1.1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 18 Jun 2014 11:14:14 -0700 (PDT) Received: from tictac.mtv.corp.google.com (tictac.mtv.corp.google.com [172.22.72.141]) by corp2gmr1-2.hot.corp.google.com (Postfix) with ESMTP id 23EED5A48F9; Wed, 18 Jun 2014 11:14:14 -0700 (PDT) Received: by tictac.mtv.corp.google.com (Postfix, from userid 121310) id 03ABA80921; Wed, 18 Jun 2014 11:14:13 -0700 (PDT) From: Doug Anderson To: Lee Jones Cc: Andrew Bresticker , swarren@wwwdotorg.org, olof@lixom.net, Sonny Rao , linux-samsung-soc@vger.kernel.org, Javier Martinez Canillas , Bill Richardson , sjg@chromium.org, Wolfram Sang , broonie@kernel.org, Doug Anderson , dmitry.torokhov@gmail.com, sameo@linux.intel.com, geert@linux-m68k.org, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 10/10] mfd: cros_ec: move EC interrupt to cros_ec_keyb Date: Wed, 18 Jun 2014 11:14:07 -0700 Message-Id: <1403115247-8853-11-git-send-email-dianders@chromium.org> X-Mailer: git-send-email 2.0.0.526.g5318336 In-Reply-To: <1403115247-8853-1-git-send-email-dianders@chromium.org> References: <1403115247-8853-1-git-send-email-dianders@chromium.org> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Andrew Bresticker If we receive EC interrupts after the cros_ec driver has probed, but before the cros_ec_keyb driver has probed, the cros_ec IRQ handler will not run the cros_ec_keyb notifier and the EC will leave the IRQ line asserted. The cros_ec IRQ handler then returns IRQ_HANDLED and the resulting flood of interrupts causes the machine to hang. Since the EC interrupt is currently only used for the keyboard, move the setup and handling of the EC interrupt to the cros_ec_keyb driver. Signed-off-by: Andrew Bresticker Signed-off-by: Doug Anderson Reviewed-by: Simon Glass --- Changes in v2: - IRQs should be optional => move EC interrupt to keyboard. drivers/input/keyboard/cros_ec_keyb.c | 58 ++++++++++++++++++++--------------- drivers/mfd/cros_ec.c | 35 +-------------------- include/linux/mfd/cros_ec.h | 2 -- 3 files changed, 34 insertions(+), 61 deletions(-) diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index b8341ab..791781a 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -24,8 +24,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -42,7 +42,6 @@ * @dev: Device pointer * @idev: Input device * @ec: Top level ChromeOS device to use to talk to EC - * @event_notifier: interrupt event notifier for transport devices */ struct cros_ec_keyb { unsigned int rows; @@ -55,7 +54,6 @@ struct cros_ec_keyb { struct device *dev; struct input_dev *idev; struct cros_ec_device *ec; - struct notifier_block notifier; }; @@ -173,22 +171,6 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, input_sync(ckdev->idev); } -static int cros_ec_keyb_open(struct input_dev *dev) -{ - struct cros_ec_keyb *ckdev = input_get_drvdata(dev); - - return blocking_notifier_chain_register(&ckdev->ec->event_notifier, - &ckdev->notifier); -} - -static void cros_ec_keyb_close(struct input_dev *dev) -{ - struct cros_ec_keyb *ckdev = input_get_drvdata(dev); - - blocking_notifier_chain_unregister(&ckdev->ec->event_notifier, - &ckdev->notifier); -} - static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) { struct cros_ec_command msg = { @@ -203,19 +185,41 @@ static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) return ckdev->ec->cmd_xfer(ckdev->ec, &msg); } -static int cros_ec_keyb_work(struct notifier_block *nb, - unsigned long state, void *_notify) +static irqreturn_t cros_ec_keyb_irq(int irq, void *data) { + struct cros_ec_keyb *ckdev = data; + struct cros_ec_device *ec = ckdev->ec; int ret; - struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb, - notifier); 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); - return NOTIFY_DONE; + return IRQ_HANDLED; +} + +static int cros_ec_keyb_open(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); +} + +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; + + free_irq(ec->irq, ckdev); } static int cros_ec_keyb_probe(struct platform_device *pdev) @@ -246,8 +250,12 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) if (!idev) return -ENOMEM; + if (!ec->irq) { + dev_err(dev, "no EC IRQ specified\n"); + return -EINVAL; + } + ckdev->ec = ec; - ckdev->notifier.notifier_call = cros_ec_keyb_work; ckdev->dev = dev; dev_set_drvdata(&pdev->dev, ckdev); diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 83e30c6..4873f9c 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -62,18 +62,6 @@ int cros_ec_check_result(struct cros_ec_device *ec_dev, } EXPORT_SYMBOL(cros_ec_check_result); -static irqreturn_t ec_irq_thread(int irq, void *data) -{ - struct cros_ec_device *ec_dev = data; - - if (device_may_wakeup(ec_dev->dev)) - pm_wakeup_event(ec_dev->dev, 0); - - blocking_notifier_call_chain(&ec_dev->event_notifier, 1, ec_dev); - - return IRQ_HANDLED; -} - static const struct mfd_cell cros_devs[] = { { .name = "cros-ec-keyb", @@ -92,8 +80,6 @@ int cros_ec_register(struct cros_ec_device *ec_dev) struct device *dev = ec_dev->dev; int err = 0; - BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier); - if (ec_dev->din_size) { ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL); if (!ec_dev->din) @@ -105,42 +91,23 @@ int cros_ec_register(struct cros_ec_device *ec_dev) return -ENOMEM; } - if (!ec_dev->irq) { - dev_dbg(dev, "no valid IRQ: %d\n", ec_dev->irq); - return err; - } - - err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "chromeos-ec", ec_dev); - if (err) { - dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err); - return err; - } - err = mfd_add_devices(dev, 0, cros_devs, ARRAY_SIZE(cros_devs), NULL, ec_dev->irq, NULL); if (err) { dev_err(dev, "failed to add mfd devices\n"); - goto fail_mfd; + return err; } dev_info(dev, "Chrome EC device registered\n"); return 0; - -fail_mfd: - free_irq(ec_dev->irq, ec_dev); - - return err; } EXPORT_SYMBOL(cros_ec_register); int cros_ec_remove(struct cros_ec_device *ec_dev) { mfd_remove_devices(ec_dev->dev); - free_irq(ec_dev->irq, ec_dev); return 0; } diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h index 0ebf26f..fcbe9d1 100644 --- a/include/linux/mfd/cros_ec.h +++ b/include/linux/mfd/cros_ec.h @@ -62,7 +62,6 @@ struct cros_ec_command { * @dev: Device pointer * @was_wake_device: true if this device was set to wake the system from * sleep at the last suspend - * @event_notifier: interrupt event notifier for transport devices * @cmd_xfer: send command to EC and get response * Returns the number of bytes received if the communication succeeded, but * that doesn't mean the EC was happy with the command. The caller @@ -93,7 +92,6 @@ struct cros_ec_device { struct device *dev; bool was_wake_device; struct class *cros_class; - struct blocking_notifier_head event_notifier; int (*cmd_xfer)(struct cros_ec_device *ec, struct cros_ec_command *msg);