From patchwork Thu Jul 24 15:51:16 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Nowicki X-Patchwork-Id: 34230 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vc0-f200.google.com (mail-vc0-f200.google.com [209.85.220.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id ADE1820C7F for ; Thu, 24 Jul 2014 15:51:29 +0000 (UTC) Received: by mail-vc0-f200.google.com with SMTP id hq11sf8815227vcb.11 for ; Thu, 24 Jul 2014 08:51:29 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:sender:precedence:list-id:x-original-sender :x-original-authentication-results:mailing-list:list-post:list-help :list-archive:list-unsubscribe; bh=GA7RLgD0H6qVeQfBz/qikzuIJMYi1QwwXc0S6+kqBvU=; b=FJwE+RvCHFszXNlakgU1ezvIeUq1Bbz3xxTMU0BtX9pmIqTkkvtQL0IIMHxKgMAnqS qCTX8DZf4/YhOTUTzW7o3A7d1xYhyby0x370oVonWbKfG2S40Q0e58dg6dZmTxCMJ0HC Up6PIIPXXM0MYPcKQwQUJpUkxUPuzdmPLh+etO0zhTGjwY8JQhKeCH1Pv6s58VvWM5E/ q32tHcOmbYtjgcAhbXirjWby2x1xPY117TJPm21tPDz2/Uz/vhq5sjJxG4NlcJcggCyh lCBUcReSSnuo9yzdVH/p6BrwAMxaEYoJtWtEZkQYPfH+fTMmOOx+/509bifl8Uqsv2V+ TQjA== X-Gm-Message-State: ALoCoQlvgs/RIqhLdE2xU3ZDyw0iFbgiN8P3Z+HOJttlXylRFp6Ydq0lWLme9lNNpYQAg6DsimPo X-Received: by 10.52.231.97 with SMTP id tf1mr4072435vdc.3.1406217087197; Thu, 24 Jul 2014 08:51:27 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.102.246 with SMTP id w109ls850339qge.4.gmail; Thu, 24 Jul 2014 08:51:27 -0700 (PDT) X-Received: by 10.52.185.72 with SMTP id fa8mr11555168vdc.4.1406217087077; Thu, 24 Jul 2014 08:51:27 -0700 (PDT) Received: from mail-vc0-f170.google.com (mail-vc0-f170.google.com [209.85.220.170]) by mx.google.com with ESMTPS id sf9si5455690vcb.80.2014.07.24.08.51.27 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 24 Jul 2014 08:51:27 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.170 as permitted sender) client-ip=209.85.220.170; Received: by mail-vc0-f170.google.com with SMTP id lf12so5348124vcb.1 for ; Thu, 24 Jul 2014 08:51:27 -0700 (PDT) X-Received: by 10.220.50.8 with SMTP id x8mr13257284vcf.18.1406217086909; Thu, 24 Jul 2014 08:51:26 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.37.5 with SMTP id tc5csp376224vcb; Thu, 24 Jul 2014 08:51:26 -0700 (PDT) X-Received: by 10.70.103.74 with SMTP id fu10mr11367572pdb.119.1406217086040; Thu, 24 Jul 2014 08:51:26 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id ou8si3203523pdb.247.2014.07.24.08.51.25 for ; Thu, 24 Jul 2014 08:51:26 -0700 (PDT) Received-SPF: none (google.com: linux-kernel-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933298AbaGXPvX (ORCPT + 13 others); Thu, 24 Jul 2014 11:51:23 -0400 Received: from mail-wi0-f174.google.com ([209.85.212.174]:58204 "EHLO mail-wi0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932207AbaGXPvW (ORCPT ); Thu, 24 Jul 2014 11:51:22 -0400 Received: by mail-wi0-f174.google.com with SMTP id d1so9959211wiv.7 for ; Thu, 24 Jul 2014 08:51:21 -0700 (PDT) X-Received: by 10.194.142.148 with SMTP id rw20mr13119541wjb.69.1406217080939; Thu, 24 Jul 2014 08:51:20 -0700 (PDT) Received: from tn-HP-4.semihalf.com ([80.82.22.190]) by mx.google.com with ESMTPSA id 20sm16880896wjt.42.2014.07.24.08.51.19 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 24 Jul 2014 08:51:20 -0700 (PDT) From: Tomasz Nowicki To: rjw@rjwysocki.net, linus.walleij@linaro.org, gnurou@gmail.com Cc: linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, linaro-acpi@lists.linaro.org, Tomasz Nowicki Subject: [RFC] ACPI: Add GPIO-signaled event simulator. Date: Thu, 24 Jul 2014 17:51:16 +0200 Message-Id: <1406217076-17150-1-git-send-email-tomasz.nowicki@linaro.org> X-Mailer: git-send-email 1.9.1 Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: tomasz.nowicki@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.170 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , GPIO signaled events is quite new thing in Linux kernel. AFAIK, there are not many board which can take advantage of it. However, GPIO events are very useful feature during work on ACPI subsystems. This commit emulates GPIO h/w behaviour and consists on read/write operation to debugfs file. GPIO device instance is still required in DSDT table along with _AEI resources and event methods. Reading from file provides pin to GPIO device map e.g. : $ cat /sys/kernel/debug/acpi/gpio_event GPIO device name: /__SB.GPI0 Available GPIO pin map: /__SB.GPI0 <-> pin 0x100 Based on that, user can trigger method corresponding to device pin number: $ echo "/__SB.GPI0 0x100" > /sys/kernel/debug/acpi/gpio_event Please, see Kconfig help and driver head section for more details regarding tool usage. Signed-off-by: Tomasz Nowicki --- drivers/acpi/Kconfig | 11 +++ drivers/acpi/Makefile | 1 + drivers/acpi/gpio_evt_emu.c | 207 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 drivers/acpi/gpio_evt_emu.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index fd54a74..59e4c67 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -122,6 +122,17 @@ config ACPI_BUTTON To compile this driver as a module, choose M here: the module will be called button. +config ACPI_GPIO_EVT_EMULATE + bool "ACPI GPIO-signaled Events Emulation Support" + depends on DEBUG_FS + default n + help + This will enable your system to emulate GPIO-signaled event through + proc file system /sys/kernel/debug/acpi/gpio_event. User needs to print + available GPIO devices and pin map (cat path_to_proc_file) so that he + knows how to trigger given event by echo "XXX YYY" > path_to_proc_file + (where, XXX is a path to GPIO device and YYY is a pin number). + config ACPI_VIDEO tristate "Video" depends on X86 && BACKLIGHT_CLASS_DEVICE diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 9fa20ff..fb3c335 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -55,6 +55,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o ifdef CONFIG_ACPI_VIDEO acpi-y += video_detect.o endif +acpi-$(CONFIG_ACPI_GPIO_EVT_EMULATE) += gpio_evt_emu.o # These are (potentially) separate modules diff --git a/drivers/acpi/gpio_evt_emu.c b/drivers/acpi/gpio_evt_emu.c new file mode 100644 index 0000000..a2f762c --- /dev/null +++ b/drivers/acpi/gpio_evt_emu.c @@ -0,0 +1,207 @@ +/* + * Code to emulate GPIO-signaled events. + * + * The sole purpose of this module is to help with GPIO event triggering. + * Suggested way of using: + * 1. Perform walk of the namespac device tree looking for GPIO devices + * with associated _AEI resources e.g.: + * $ cat /sys/kernel/debug/acpi/gpio_event + * GPIO device name: /__SB.GPI0 + * Available GPIO pin map: + * /__SB.GPI0 <-> pin 0x100 + * + * 2. Trigger method corresponding to device pin number: + * $ echo "/__SB.GPI0 0x100" > /sys/kernel/debug/acpi/gpio_event + */ + +/* + * Copyright (C) 2014, Linaro Ltd. + * Author: Tomasz Nowicki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "acpica/accommon.h" +#include "acpica/acnamesp.h" + +#include "internal.h" + +static struct dentry *gpio_evt_dentry; + +static void gpio_trigger_event(char *gpio_path, u32 pin) +{ + acpi_handle gpio_handle, evt_handle; + char ev_name[5]; + + if (ACPI_FAILURE(acpi_get_handle(NULL, gpio_path, &gpio_handle))) { + pr_err(PREFIX "getting handle to <%s> failed\n", gpio_path); + return; + } + + if (pin <= 255) + sprintf(ev_name, "_L%02X", pin); + else + sprintf(ev_name, "_EVT"); + + + if (ACPI_FAILURE(acpi_get_handle(gpio_handle, ev_name, &evt_handle))) { + pr_err(PREFIX "getting handle to <%s.%s> failed, there is no method related to 0x%02X pin\n", + gpio_path, ev_name, pin); + return; + } + + if (ACPI_FAILURE(acpi_execute_simple_method(evt_handle, NULL, + pin <= 255 ? 0 : pin))) + pr_err(PREFIX "evaluating <%s._EVT for pin %d> failed\n", + gpio_path, pin); + + return; +} + +static ssize_t gpio_evt_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + u32 pin_number; + char *gpio_path = NULL; + char *pin_str = NULL; + const char *delim = " "; + char *temp_buf = NULL; + char *temp_buf_addr = NULL; + + temp_buf = kmalloc(count+1, GFP_ATOMIC); + if (!temp_buf) { + pr_warn(PREFIX "%s: Memory allocation failed\n", __func__); + return count; + } + temp_buf[count] = '\0'; + temp_buf_addr = temp_buf; + if (copy_from_user(temp_buf, user_buf, count)) + goto out; + + gpio_path = strsep(&temp_buf, delim); + pin_str = strsep(&temp_buf, delim); + + if (gpio_path && pin_str) { + ssize_t ret; + unsigned long val; + + ret = kstrtoul(pin_str, 10, &val); + if (ret) { + pr_warn(PREFIX "unknown event\n"); + goto out; + } + + pin_number = (u32)val; + } else { + pr_warn(PREFIX "unknown device\n"); + goto out; + } + + pr_info(PREFIX "ACPI device name is <%s>, pin number is <%d>\n", + gpio_path, pin_number); + + gpio_trigger_event(gpio_path, pin_number); + +out: + kfree(temp_buf_addr); + return count; +} + +static acpi_status gpio_list_resource(struct acpi_resource *ares, + void *context) +{ + struct acpi_resource_gpio *agpio; + struct seq_file *m = context; + int pin; + + if (!m) + return AE_OK; + + if (ares->type != ACPI_RESOURCE_TYPE_GPIO) + return AE_OK; + + agpio = &ares->data.gpio; + if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) + return AE_OK; + + pin = agpio->pin_table[0]; + seq_printf(m, "%s <-> pin %d\n", agpio->resource_source.string_ptr, + pin); + + return AE_OK; +} + +static acpi_status gpio_find_resource(acpi_handle handle, u32 lvl, + void *context, void **rv) +{ + struct acpi_namespace_node *node; + struct seq_file *m = context; + + if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__AEI, + gpio_list_resource, NULL))) + return AE_OK; + + node = acpi_ns_validate_handle(handle); + if (!node) { + pr_err(PREFIX "Mapping GPIO handle to node failed\n"); + return AE_OK; + } + + seq_printf(m, "GPIO device name: %4.4s\nAvailable GPIO pin map:\n", + ACPI_CAST_PTR(char, &node->name)); + acpi_walk_resources(handle, METHOD_NAME__AEI, gpio_list_resource, + context); + return AE_OK; +} + +static int gpio_evt_show(struct seq_file *m, void *v) +{ + acpi_get_devices(NULL, gpio_find_resource, m, NULL); + return 0; +} + +static int gpio_evt_open(struct inode *inode, struct file *file) +{ + return single_open(file, gpio_evt_show, NULL); +} + +static const struct file_operations gpio_evt_emu_fops = { + .open = gpio_evt_open, + .write = gpio_evt_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init gpio_evt_emu_init(void) +{ + if (acpi_debugfs_dir == NULL) + return -ENOENT; + + gpio_evt_dentry = debugfs_create_file("gpio_event", S_IWUSR, + acpi_debugfs_dir, NULL, &gpio_evt_emu_fops); + if (gpio_evt_dentry == NULL) + return -ENODEV; + + return 0; +} + +device_initcall(gpio_evt_emu_init); +ACPI_MODULE_NAME("acpi_evt_emu"); +MODULE_LICENSE("GPL");