From patchwork Mon Sep 17 18:15:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 10603283 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8301314DA for ; Mon, 17 Sep 2018 18:16:42 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6518128CB7 for ; Mon, 17 Sep 2018 18:16:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5915F28FB8; Mon, 17 Sep 2018 18:16:42 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B393928CB7 for ; Mon, 17 Sep 2018 18:16:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728370AbeIQXok (ORCPT ); Mon, 17 Sep 2018 19:44:40 -0400 Received: from mail-pg1-f193.google.com ([209.85.215.193]:35992 "EHLO mail-pg1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727375AbeIQXok (ORCPT ); Mon, 17 Sep 2018 19:44:40 -0400 Received: by mail-pg1-f193.google.com with SMTP id d1-v6so8058982pgo.3; Mon, 17 Sep 2018 11:16:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=d3fIP0OMtgTjhkPYLUxyTxunfUZOBZasBX82KtlY6aY=; b=Xpzyg0q5COUrFAz3refnOhFQG3PSsxhDQvq5VYGY1sw8L36O3kSW8diK+aVnBFurha 0euYR05HvKlZuAyY0Vo6Wt0Saidl6fND9WNQWrmzT7U94cy7iv4+Mlx7ELwQq1pi1iyy uZmnykj+HtSUTzi6vVvlCHrc18Z/aHGAZ7aEHc9DezmntCV9aYYasDkWiDx0tR6DV5vR g1XDWMnrxsM0IZ56HlCSl9mysQSBEMyo6GTjHujdYogcYvI7sfxBn5qobr6oTs/VmYPM EIae5Q8w2S0FtH8tVUrRGkhcj3RsrAlPZKbkBcoyEVco4xnRd8JuCEKUUkwXsAx+nXC+ hqvg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=d3fIP0OMtgTjhkPYLUxyTxunfUZOBZasBX82KtlY6aY=; b=hLnAuwInpPOx41glnO0ViB3DIh5Ikh3olEDAYKAA0ntAP2ugpRnH9wPnfT2ddP4HxA /tV3e3wpjKg9/LH75gaMunt4ISXUEjl1wLhJk6D2IWrp+0PJPB9jZN5xRqAQ1EykpZHZ it3+1LNeBc0tj2pQYNsqKqrM0OMCKOPPGa9KTIy65aRJ6iiVU6RoZqche1HexOOQqGHS Oa/J+eRUW3hcqbvyNEIVm63iIRM5QRCIc9hsIuDdTpgjkFNdDvqZfFqrW/1kiOjTVR9D zgjLYlipED+k+CkhS4Wmyscxdaq4hxJG+7g4F/LuJffUewQ50BtG+of1ol4PW3oSoCr+ O4Qg== X-Gm-Message-State: APzg51CkSCglgA4/GOBgCYNg+/E2H6iUyoexjs6/j9S2weC0g1qaFDYU slrVQ3xzv/CcWHNMjTII6Bc= X-Google-Smtp-Source: ANB0VdYHh/i3AlkXhPshV2gFml2RGL8TK6UGyIB/FFfx4F4FPsIT9bFFmvvxUGzEWRx2PBcN/S1+Qg== X-Received: by 2002:a62:4898:: with SMTP id q24-v6mr27357439pfi.22.1537208168904; Mon, 17 Sep 2018 11:16:08 -0700 (PDT) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:3adc:b08c:7acc:b325]) by smtp.gmail.com with ESMTPSA id 74-v6sm24076366pfv.33.2018.09.17.11.16.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 17 Sep 2018 11:16:07 -0700 (PDT) From: Dmitry Torokhov To: Linus Walleij , "Rafael J . Wysocki" Cc: linux-input@vger.kernel.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Shevchenko Subject: [RFC/PATCH 1/5] device property: split generic properties and property sets Date: Mon, 17 Sep 2018 11:15:59 -0700 Message-Id: <20180917181603.125492-2-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.19.0.397.gdd90340f6a-goog In-Reply-To: <20180917181603.125492-1-dmitry.torokhov@gmail.com> References: <20180917181603.125492-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP drivers/base/property.c became a bit of a kitchen sink, with code handling generic device/fwnode properties intermingled with code handling static properties (pset). Let's split them apart to not pollute each other. Signed-off-by: Dmitry Torokhov --- drivers/base/Makefile | 4 +- drivers/base/property.c | 525 ---------------------------------- drivers/base/pset_property.c | 540 +++++++++++++++++++++++++++++++++++ 3 files changed, 542 insertions(+), 527 deletions(-) create mode 100644 drivers/base/pset_property.c diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 704f44295810..5f72cd5ab8ba 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -5,8 +5,8 @@ obj-y := component.o core.o bus.o dd.o syscore.o \ driver.o class.o platform.o \ cpu.o firmware.o init.o map.o devres.o \ attribute_container.o transport_class.o \ - topology.o container.o property.o cacheinfo.o \ - devcon.o + topology.o container.o cacheinfo.o \ + property.o pset_property.o devcon.o obj-$(CONFIG_DEVTMPFS) += devtmpfs.o obj-y += power/ obj-$(CONFIG_ISA_BUS_API) += isa.o diff --git a/drivers/base/property.c b/drivers/base/property.c index 240ab5230ff6..d57df94e396c 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -18,236 +18,6 @@ #include #include -struct property_set { - struct device *dev; - struct fwnode_handle fwnode; - const struct property_entry *properties; -}; - -static const struct fwnode_operations pset_fwnode_ops; - -static inline bool is_pset_node(const struct fwnode_handle *fwnode) -{ - return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &pset_fwnode_ops; -} - -#define to_pset_node(__fwnode) \ - ({ \ - typeof(__fwnode) __to_pset_node_fwnode = __fwnode; \ - \ - is_pset_node(__to_pset_node_fwnode) ? \ - container_of(__to_pset_node_fwnode, \ - struct property_set, fwnode) : \ - NULL; \ - }) - -static const struct property_entry * -pset_prop_get(const struct property_set *pset, const char *name) -{ - const struct property_entry *prop; - - if (!pset || !pset->properties) - return NULL; - - for (prop = pset->properties; prop->name; prop++) - if (!strcmp(name, prop->name)) - return prop; - - return NULL; -} - -static const void *property_get_pointer(const struct property_entry *prop) -{ - switch (prop->type) { - case DEV_PROP_U8: - if (prop->is_array) - return prop->pointer.u8_data; - return &prop->value.u8_data; - case DEV_PROP_U16: - if (prop->is_array) - return prop->pointer.u16_data; - return &prop->value.u16_data; - case DEV_PROP_U32: - if (prop->is_array) - return prop->pointer.u32_data; - return &prop->value.u32_data; - case DEV_PROP_U64: - if (prop->is_array) - return prop->pointer.u64_data; - return &prop->value.u64_data; - case DEV_PROP_STRING: - if (prop->is_array) - return prop->pointer.str; - return &prop->value.str; - default: - return NULL; - } -} - -static void property_set_pointer(struct property_entry *prop, const void *pointer) -{ - switch (prop->type) { - case DEV_PROP_U8: - if (prop->is_array) - prop->pointer.u8_data = pointer; - else - prop->value.u8_data = *((u8 *)pointer); - break; - case DEV_PROP_U16: - if (prop->is_array) - prop->pointer.u16_data = pointer; - else - prop->value.u16_data = *((u16 *)pointer); - break; - case DEV_PROP_U32: - if (prop->is_array) - prop->pointer.u32_data = pointer; - else - prop->value.u32_data = *((u32 *)pointer); - break; - case DEV_PROP_U64: - if (prop->is_array) - prop->pointer.u64_data = pointer; - else - prop->value.u64_data = *((u64 *)pointer); - break; - case DEV_PROP_STRING: - if (prop->is_array) - prop->pointer.str = pointer; - else - prop->value.str = pointer; - break; - default: - break; - } -} - -static const void *pset_prop_find(const struct property_set *pset, - const char *propname, size_t length) -{ - const struct property_entry *prop; - const void *pointer; - - prop = pset_prop_get(pset, propname); - if (!prop) - return ERR_PTR(-EINVAL); - pointer = property_get_pointer(prop); - if (!pointer) - return ERR_PTR(-ENODATA); - if (length > prop->length) - return ERR_PTR(-EOVERFLOW); - return pointer; -} - -static int pset_prop_read_u8_array(const struct property_set *pset, - const char *propname, - u8 *values, size_t nval) -{ - const void *pointer; - size_t length = nval * sizeof(*values); - - pointer = pset_prop_find(pset, propname, length); - if (IS_ERR(pointer)) - return PTR_ERR(pointer); - - memcpy(values, pointer, length); - return 0; -} - -static int pset_prop_read_u16_array(const struct property_set *pset, - const char *propname, - u16 *values, size_t nval) -{ - const void *pointer; - size_t length = nval * sizeof(*values); - - pointer = pset_prop_find(pset, propname, length); - if (IS_ERR(pointer)) - return PTR_ERR(pointer); - - memcpy(values, pointer, length); - return 0; -} - -static int pset_prop_read_u32_array(const struct property_set *pset, - const char *propname, - u32 *values, size_t nval) -{ - const void *pointer; - size_t length = nval * sizeof(*values); - - pointer = pset_prop_find(pset, propname, length); - if (IS_ERR(pointer)) - return PTR_ERR(pointer); - - memcpy(values, pointer, length); - return 0; -} - -static int pset_prop_read_u64_array(const struct property_set *pset, - const char *propname, - u64 *values, size_t nval) -{ - const void *pointer; - size_t length = nval * sizeof(*values); - - pointer = pset_prop_find(pset, propname, length); - if (IS_ERR(pointer)) - return PTR_ERR(pointer); - - memcpy(values, pointer, length); - return 0; -} - -static int pset_prop_count_elems_of_size(const struct property_set *pset, - const char *propname, size_t length) -{ - const struct property_entry *prop; - - prop = pset_prop_get(pset, propname); - if (!prop) - return -EINVAL; - - return prop->length / length; -} - -static int pset_prop_read_string_array(const struct property_set *pset, - const char *propname, - const char **strings, size_t nval) -{ - const struct property_entry *prop; - const void *pointer; - size_t array_len, length; - - /* Find out the array length. */ - prop = pset_prop_get(pset, propname); - if (!prop) - return -EINVAL; - - if (!prop->is_array) - /* The array length for a non-array string property is 1. */ - array_len = 1; - else - /* Find the length of an array. */ - array_len = pset_prop_count_elems_of_size(pset, propname, - sizeof(const char *)); - - /* Return how many there are if strings is NULL. */ - if (!strings) - return array_len; - - array_len = min(nval, array_len); - length = array_len * sizeof(*strings); - - pointer = pset_prop_find(pset, propname, length); - if (IS_ERR(pointer)) - return PTR_ERR(pointer); - - memcpy(strings, pointer, length); - - return array_len; -} - struct fwnode_handle *dev_fwnode(struct device *dev) { return IS_ENABLED(CONFIG_OF) && dev->of_node ? @@ -255,51 +25,6 @@ struct fwnode_handle *dev_fwnode(struct device *dev) } EXPORT_SYMBOL_GPL(dev_fwnode); -static bool pset_fwnode_property_present(const struct fwnode_handle *fwnode, - const char *propname) -{ - return !!pset_prop_get(to_pset_node(fwnode), propname); -} - -static int pset_fwnode_read_int_array(const struct fwnode_handle *fwnode, - const char *propname, - unsigned int elem_size, void *val, - size_t nval) -{ - const struct property_set *node = to_pset_node(fwnode); - - if (!val) - return pset_prop_count_elems_of_size(node, propname, elem_size); - - switch (elem_size) { - case sizeof(u8): - return pset_prop_read_u8_array(node, propname, val, nval); - case sizeof(u16): - return pset_prop_read_u16_array(node, propname, val, nval); - case sizeof(u32): - return pset_prop_read_u32_array(node, propname, val, nval); - case sizeof(u64): - return pset_prop_read_u64_array(node, propname, val, nval); - } - - return -ENXIO; -} - -static int -pset_fwnode_property_read_string_array(const struct fwnode_handle *fwnode, - const char *propname, - const char **val, size_t nval) -{ - return pset_prop_read_string_array(to_pset_node(fwnode), propname, - val, nval); -} - -static const struct fwnode_operations pset_fwnode_ops = { - .property_present = pset_fwnode_property_present, - .property_read_int_array = pset_fwnode_read_int_array, - .property_read_string_array = pset_fwnode_property_read_string_array, -}; - /** * device_property_present - check if a property of a device is present * @dev: Device whose property is being checked @@ -759,256 +484,6 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode, } EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); -static void property_entry_free_data(const struct property_entry *p) -{ - const void *pointer = property_get_pointer(p); - size_t i, nval; - - if (p->is_array) { - if (p->type == DEV_PROP_STRING && p->pointer.str) { - nval = p->length / sizeof(const char *); - for (i = 0; i < nval; i++) - kfree(p->pointer.str[i]); - } - kfree(pointer); - } else if (p->type == DEV_PROP_STRING) { - kfree(p->value.str); - } - kfree(p->name); -} - -static int property_copy_string_array(struct property_entry *dst, - const struct property_entry *src) -{ - const char **d; - size_t nval = src->length / sizeof(*d); - int i; - - d = kcalloc(nval, sizeof(*d), GFP_KERNEL); - if (!d) - return -ENOMEM; - - for (i = 0; i < nval; i++) { - d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL); - if (!d[i] && src->pointer.str[i]) { - while (--i >= 0) - kfree(d[i]); - kfree(d); - return -ENOMEM; - } - } - - dst->pointer.str = d; - return 0; -} - -static int property_entry_copy_data(struct property_entry *dst, - const struct property_entry *src) -{ - const void *pointer = property_get_pointer(src); - const void *new; - int error; - - if (src->is_array) { - if (!src->length) - return -ENODATA; - - if (src->type == DEV_PROP_STRING) { - error = property_copy_string_array(dst, src); - if (error) - return error; - new = dst->pointer.str; - } else { - new = kmemdup(pointer, src->length, GFP_KERNEL); - if (!new) - return -ENOMEM; - } - } else if (src->type == DEV_PROP_STRING) { - new = kstrdup(src->value.str, GFP_KERNEL); - if (!new && src->value.str) - return -ENOMEM; - } else { - new = pointer; - } - - dst->length = src->length; - dst->is_array = src->is_array; - dst->type = src->type; - - property_set_pointer(dst, new); - - dst->name = kstrdup(src->name, GFP_KERNEL); - if (!dst->name) - goto out_free_data; - - return 0; - -out_free_data: - property_entry_free_data(dst); - return -ENOMEM; -} - -/** - * property_entries_dup - duplicate array of properties - * @properties: array of properties to copy - * - * This function creates a deep copy of the given NULL-terminated array - * of property entries. - */ -struct property_entry * -property_entries_dup(const struct property_entry *properties) -{ - struct property_entry *p; - int i, n = 0; - - while (properties[n].name) - n++; - - p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL); - if (!p) - return ERR_PTR(-ENOMEM); - - for (i = 0; i < n; i++) { - int ret = property_entry_copy_data(&p[i], &properties[i]); - if (ret) { - while (--i >= 0) - property_entry_free_data(&p[i]); - kfree(p); - return ERR_PTR(ret); - } - } - - return p; -} -EXPORT_SYMBOL_GPL(property_entries_dup); - -/** - * property_entries_free - free previously allocated array of properties - * @properties: array of properties to destroy - * - * This function frees given NULL-terminated array of property entries, - * along with their data. - */ -void property_entries_free(const struct property_entry *properties) -{ - const struct property_entry *p; - - for (p = properties; p->name; p++) - property_entry_free_data(p); - - kfree(properties); -} -EXPORT_SYMBOL_GPL(property_entries_free); - -/** - * pset_free_set - releases memory allocated for copied property set - * @pset: Property set to release - * - * Function takes previously copied property set and releases all the - * memory allocated to it. - */ -static void pset_free_set(struct property_set *pset) -{ - if (!pset) - return; - - property_entries_free(pset->properties); - kfree(pset); -} - -/** - * pset_copy_set - copies property set - * @pset: Property set to copy - * - * This function takes a deep copy of the given property set and returns - * pointer to the copy. Call device_free_property_set() to free resources - * allocated in this function. - * - * Return: Pointer to the new property set or error pointer. - */ -static struct property_set *pset_copy_set(const struct property_set *pset) -{ - struct property_entry *properties; - struct property_set *p; - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return ERR_PTR(-ENOMEM); - - properties = property_entries_dup(pset->properties); - if (IS_ERR(properties)) { - kfree(p); - return ERR_CAST(properties); - } - - p->properties = properties; - return p; -} - -/** - * device_remove_properties - Remove properties from a device object. - * @dev: Device whose properties to remove. - * - * The function removes properties previously associated to the device - * secondary firmware node with device_add_properties(). Memory allocated - * to the properties will also be released. - */ -void device_remove_properties(struct device *dev) -{ - struct fwnode_handle *fwnode; - struct property_set *pset; - - fwnode = dev_fwnode(dev); - if (!fwnode) - return; - /* - * Pick either primary or secondary node depending which one holds - * the pset. If there is no real firmware node (ACPI/DT) primary - * will hold the pset. - */ - pset = to_pset_node(fwnode); - if (pset) { - set_primary_fwnode(dev, NULL); - } else { - pset = to_pset_node(fwnode->secondary); - if (pset && dev == pset->dev) - set_secondary_fwnode(dev, NULL); - } - if (pset && dev == pset->dev) - pset_free_set(pset); -} -EXPORT_SYMBOL_GPL(device_remove_properties); - -/** - * device_add_properties - Add a collection of properties to a device object. - * @dev: Device to add properties to. - * @properties: Collection of properties to add. - * - * Associate a collection of device properties represented by @properties with - * @dev as its secondary firmware node. The function takes a copy of - * @properties. - */ -int device_add_properties(struct device *dev, - const struct property_entry *properties) -{ - struct property_set *p, pset; - - if (!properties) - return -EINVAL; - - pset.properties = properties; - - p = pset_copy_set(&pset); - if (IS_ERR(p)) - return PTR_ERR(p); - - p->fwnode.ops = &pset_fwnode_ops; - set_secondary_fwnode(dev, &p->fwnode); - p->dev = dev; - return 0; -} -EXPORT_SYMBOL_GPL(device_add_properties); - /** * fwnode_get_next_parent - Iterate to the node's parent * @fwnode: Firmware whose parent is retrieved diff --git a/drivers/base/pset_property.c b/drivers/base/pset_property.c new file mode 100644 index 000000000000..08ecc13080ae --- /dev/null +++ b/drivers/base/pset_property.c @@ -0,0 +1,540 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Handling of device properties defined in legacy board files. + * + * Copyright (C) 2014, Intel Corporation + * Authors: Rafael J. Wysocki + * Mika Westerberg + */ + +#include +#include +#include +#include +#include +#include + +struct property_set { + struct device *dev; + struct fwnode_handle fwnode; + const struct property_entry *properties; +}; + +static const struct fwnode_operations pset_fwnode_ops; + +static inline bool is_pset_node(const struct fwnode_handle *fwnode) +{ + return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &pset_fwnode_ops; +} + +#define to_pset_node(__fwnode) \ + ({ \ + typeof(__fwnode) __to_pset_node_fwnode = __fwnode; \ + \ + is_pset_node(__to_pset_node_fwnode) ? \ + container_of(__to_pset_node_fwnode, \ + struct property_set, fwnode) : \ + NULL; \ + }) + +static const struct property_entry * +pset_prop_get(const struct property_set *pset, const char *name) +{ + const struct property_entry *prop; + + if (!pset || !pset->properties) + return NULL; + + for (prop = pset->properties; prop->name; prop++) + if (!strcmp(name, prop->name)) + return prop; + + return NULL; +} + +static const void *property_get_pointer(const struct property_entry *prop) +{ + switch (prop->type) { + case DEV_PROP_U8: + if (prop->is_array) + return prop->pointer.u8_data; + return &prop->value.u8_data; + case DEV_PROP_U16: + if (prop->is_array) + return prop->pointer.u16_data; + return &prop->value.u16_data; + case DEV_PROP_U32: + if (prop->is_array) + return prop->pointer.u32_data; + return &prop->value.u32_data; + case DEV_PROP_U64: + if (prop->is_array) + return prop->pointer.u64_data; + return &prop->value.u64_data; + case DEV_PROP_STRING: + if (prop->is_array) + return prop->pointer.str; + return &prop->value.str; + default: + return NULL; + } +} + +static void property_set_pointer(struct property_entry *prop, const void *pointer) +{ + switch (prop->type) { + case DEV_PROP_U8: + if (prop->is_array) + prop->pointer.u8_data = pointer; + else + prop->value.u8_data = *((u8 *)pointer); + break; + case DEV_PROP_U16: + if (prop->is_array) + prop->pointer.u16_data = pointer; + else + prop->value.u16_data = *((u16 *)pointer); + break; + case DEV_PROP_U32: + if (prop->is_array) + prop->pointer.u32_data = pointer; + else + prop->value.u32_data = *((u32 *)pointer); + break; + case DEV_PROP_U64: + if (prop->is_array) + prop->pointer.u64_data = pointer; + else + prop->value.u64_data = *((u64 *)pointer); + break; + case DEV_PROP_STRING: + if (prop->is_array) + prop->pointer.str = pointer; + else + prop->value.str = pointer; + break; + default: + break; + } +} + +static const void *pset_prop_find(const struct property_set *pset, + const char *propname, size_t length) +{ + const struct property_entry *prop; + const void *pointer; + + prop = pset_prop_get(pset, propname); + if (!prop) + return ERR_PTR(-EINVAL); + pointer = property_get_pointer(prop); + if (!pointer) + return ERR_PTR(-ENODATA); + if (length > prop->length) + return ERR_PTR(-EOVERFLOW); + return pointer; +} + +static int pset_prop_read_u8_array(const struct property_set *pset, + const char *propname, + u8 *values, size_t nval) +{ + const void *pointer; + size_t length = nval * sizeof(*values); + + pointer = pset_prop_find(pset, propname, length); + if (IS_ERR(pointer)) + return PTR_ERR(pointer); + + memcpy(values, pointer, length); + return 0; +} + +static int pset_prop_read_u16_array(const struct property_set *pset, + const char *propname, + u16 *values, size_t nval) +{ + const void *pointer; + size_t length = nval * sizeof(*values); + + pointer = pset_prop_find(pset, propname, length); + if (IS_ERR(pointer)) + return PTR_ERR(pointer); + + memcpy(values, pointer, length); + return 0; +} + +static int pset_prop_read_u32_array(const struct property_set *pset, + const char *propname, + u32 *values, size_t nval) +{ + const void *pointer; + size_t length = nval * sizeof(*values); + + pointer = pset_prop_find(pset, propname, length); + if (IS_ERR(pointer)) + return PTR_ERR(pointer); + + memcpy(values, pointer, length); + return 0; +} + +static int pset_prop_read_u64_array(const struct property_set *pset, + const char *propname, + u64 *values, size_t nval) +{ + const void *pointer; + size_t length = nval * sizeof(*values); + + pointer = pset_prop_find(pset, propname, length); + if (IS_ERR(pointer)) + return PTR_ERR(pointer); + + memcpy(values, pointer, length); + return 0; +} + +static int pset_prop_count_elems_of_size(const struct property_set *pset, + const char *propname, size_t length) +{ + const struct property_entry *prop; + + prop = pset_prop_get(pset, propname); + if (!prop) + return -EINVAL; + + return prop->length / length; +} + +static int pset_prop_read_string_array(const struct property_set *pset, + const char *propname, + const char **strings, size_t nval) +{ + const struct property_entry *prop; + const void *pointer; + size_t array_len, length; + + /* Find out the array length. */ + prop = pset_prop_get(pset, propname); + if (!prop) + return -EINVAL; + + if (!prop->is_array) + /* The array length for a non-array string property is 1. */ + array_len = 1; + else + /* Find the length of an array. */ + array_len = pset_prop_count_elems_of_size(pset, propname, + sizeof(const char *)); + + /* Return how many there are if strings is NULL. */ + if (!strings) + return array_len; + + array_len = min(nval, array_len); + length = array_len * sizeof(*strings); + + pointer = pset_prop_find(pset, propname, length); + if (IS_ERR(pointer)) + return PTR_ERR(pointer); + + memcpy(strings, pointer, length); + + return array_len; +} + +static bool pset_fwnode_property_present(const struct fwnode_handle *fwnode, + const char *propname) +{ + return !!pset_prop_get(to_pset_node(fwnode), propname); +} + +static int pset_fwnode_read_int_array(const struct fwnode_handle *fwnode, + const char *propname, + unsigned int elem_size, void *val, + size_t nval) +{ + const struct property_set *node = to_pset_node(fwnode); + + if (!val) + return pset_prop_count_elems_of_size(node, propname, elem_size); + + switch (elem_size) { + case sizeof(u8): + return pset_prop_read_u8_array(node, propname, val, nval); + case sizeof(u16): + return pset_prop_read_u16_array(node, propname, val, nval); + case sizeof(u32): + return pset_prop_read_u32_array(node, propname, val, nval); + case sizeof(u64): + return pset_prop_read_u64_array(node, propname, val, nval); + } + + return -ENXIO; +} + +static int +pset_fwnode_property_read_string_array(const struct fwnode_handle *fwnode, + const char *propname, + const char **val, size_t nval) +{ + return pset_prop_read_string_array(to_pset_node(fwnode), propname, + val, nval); +} + +static const struct fwnode_operations pset_fwnode_ops = { + .property_present = pset_fwnode_property_present, + .property_read_int_array = pset_fwnode_read_int_array, + .property_read_string_array = pset_fwnode_property_read_string_array, +}; + +static void property_entry_free_data(const struct property_entry *p) +{ + const void *pointer = property_get_pointer(p); + size_t i, nval; + + if (p->is_array) { + if (p->type == DEV_PROP_STRING && p->pointer.str) { + nval = p->length / sizeof(const char *); + for (i = 0; i < nval; i++) + kfree(p->pointer.str[i]); + } + kfree(pointer); + } else if (p->type == DEV_PROP_STRING) { + kfree(p->value.str); + } + kfree(p->name); +} + +static int property_copy_string_array(struct property_entry *dst, + const struct property_entry *src) +{ + const char **d; + size_t nval = src->length / sizeof(*d); + int i; + + d = kcalloc(nval, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + for (i = 0; i < nval; i++) { + d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL); + if (!d[i] && src->pointer.str[i]) { + while (--i >= 0) + kfree(d[i]); + kfree(d); + return -ENOMEM; + } + } + + dst->pointer.str = d; + return 0; +} + +static int property_entry_copy_data(struct property_entry *dst, + const struct property_entry *src) +{ + const void *pointer = property_get_pointer(src); + const void *new; + int error; + + if (src->is_array) { + if (!src->length) + return -ENODATA; + + if (src->type == DEV_PROP_STRING) { + error = property_copy_string_array(dst, src); + if (error) + return error; + new = dst->pointer.str; + } else { + new = kmemdup(pointer, src->length, GFP_KERNEL); + if (!new) + return -ENOMEM; + } + } else if (src->type == DEV_PROP_STRING) { + new = kstrdup(src->value.str, GFP_KERNEL); + if (!new && src->value.str) + return -ENOMEM; + } else { + new = pointer; + } + + dst->length = src->length; + dst->is_array = src->is_array; + dst->type = src->type; + + property_set_pointer(dst, new); + + dst->name = kstrdup(src->name, GFP_KERNEL); + if (!dst->name) + goto out_free_data; + + return 0; + +out_free_data: + property_entry_free_data(dst); + return -ENOMEM; +} + +/** + * property_entries_dup - duplicate array of properties + * @properties: array of properties to copy + * + * This function creates a deep copy of the given NULL-terminated array + * of property entries. + */ +struct property_entry * +property_entries_dup(const struct property_entry *properties) +{ + struct property_entry *p; + int i, n = 0; + + while (properties[n].name) + n++; + + p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL); + if (!p) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < n; i++) { + int ret = property_entry_copy_data(&p[i], &properties[i]); + if (ret) { + while (--i >= 0) + property_entry_free_data(&p[i]); + kfree(p); + return ERR_PTR(ret); + } + } + + return p; +} +EXPORT_SYMBOL_GPL(property_entries_dup); + +/** + * property_entries_free - free previously allocated array of properties + * @properties: array of properties to destroy + * + * This function frees given NULL-terminated array of property entries, + * along with their data. + */ +void property_entries_free(const struct property_entry *properties) +{ + const struct property_entry *p; + + for (p = properties; p->name; p++) + property_entry_free_data(p); + + kfree(properties); +} +EXPORT_SYMBOL_GPL(property_entries_free); + +/** + * pset_free_set - releases memory allocated for copied property set + * @pset: Property set to release + * + * Function takes previously copied property set and releases all the + * memory allocated to it. + */ +static void pset_free_set(struct property_set *pset) +{ + if (!pset) + return; + + property_entries_free(pset->properties); + kfree(pset); +} + +/** + * pset_copy_set - copies property set + * @pset: Property set to copy + * + * This function takes a deep copy of the given property set and returns + * pointer to the copy. Call device_free_property_set() to free resources + * allocated in this function. + * + * Return: Pointer to the new property set or error pointer. + */ +static struct property_set *pset_copy_set(const struct property_set *pset) +{ + struct property_entry *properties; + struct property_set *p; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return ERR_PTR(-ENOMEM); + + properties = property_entries_dup(pset->properties); + if (IS_ERR(properties)) { + kfree(p); + return ERR_CAST(properties); + } + + p->properties = properties; + return p; +} + +/** + * device_remove_properties - Remove properties from a device object. + * @dev: Device whose properties to remove. + * + * The function removes properties previously associated to the device + * secondary firmware node with device_add_properties(). Memory allocated + * to the properties will also be released. + */ +void device_remove_properties(struct device *dev) +{ + struct fwnode_handle *fwnode; + struct property_set *pset; + + fwnode = dev_fwnode(dev); + if (!fwnode) + return; + /* + * Pick either primary or secondary node depending which one holds + * the pset. If there is no real firmware node (ACPI/DT) primary + * will hold the pset. + */ + pset = to_pset_node(fwnode); + if (pset) { + set_primary_fwnode(dev, NULL); + } else { + pset = to_pset_node(fwnode->secondary); + if (pset && dev == pset->dev) + set_secondary_fwnode(dev, NULL); + } + if (pset && dev == pset->dev) + pset_free_set(pset); +} +EXPORT_SYMBOL_GPL(device_remove_properties); + +/** + * device_add_properties - Add a collection of properties to a device object. + * @dev: Device to add properties to. + * @properties: Collection of properties to add. + * + * Associate a collection of device properties represented by @properties with + * @dev as its secondary firmware node. The function takes a copy of + * @properties. + */ +int device_add_properties(struct device *dev, + const struct property_entry *properties) +{ + struct property_set *p, pset; + + if (!properties) + return -EINVAL; + + pset.properties = properties; + + p = pset_copy_set(&pset); + if (IS_ERR(p)) + return PTR_ERR(p); + + p->fwnode.ops = &pset_fwnode_ops; + set_secondary_fwnode(dev, &p->fwnode); + p->dev = dev; + return 0; +} +EXPORT_SYMBOL_GPL(device_add_properties); From patchwork Mon Sep 17 18:16:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 10603281 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A700E14DA for ; Mon, 17 Sep 2018 18:16:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8B74028CB7 for ; Mon, 17 Sep 2018 18:16:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7FCD328FB8; Mon, 17 Sep 2018 18:16:35 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E475E28CB7 for ; Mon, 17 Sep 2018 18:16:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727375AbeIQXol (ORCPT ); Mon, 17 Sep 2018 19:44:41 -0400 Received: from mail-pl1-f195.google.com ([209.85.214.195]:32793 "EHLO mail-pl1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727832AbeIQXol (ORCPT ); Mon, 17 Sep 2018 19:44:41 -0400 Received: by mail-pl1-f195.google.com with SMTP id b97-v6so2598251plb.0; Mon, 17 Sep 2018 11:16:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=cR2ZY5S1Yja/f9VPMz3/lblLM7a2jgt5NnCXrQBwTLk=; b=c4xskV4sIjAyCBbVTJ0Vt+mRWJYOz75PIRumQMq0iHkphvsdPTjIYEVtJ4a3wbXyXX tfJO+aMm7vsU0Azc6J4Gd0U67PNrRvl+toeIOAeYt8qFcJOtmrqhYBNCUhDB8T4ALsJS sZEjw/jC0bruDToOUA22z2RCUL5QHYGqxcM8Ha1kBalx2h3vZbp8ePOI+dUSWYoScsh1 ejHkn1Yn2/TGJonxDJnUr5oPFJj1qG6G/pcbZXQJyCxTq6Xr7RJV6GtvnnkUOfcNBNOH pt1SLd3WQsOXhRmQVPAVNva9awHL32vrRaxSZl7pS1sN3i+/o2nRA0jQJu3IocjTE+H+ eJrg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=cR2ZY5S1Yja/f9VPMz3/lblLM7a2jgt5NnCXrQBwTLk=; b=OoGTQMVK+phwpM5/qEDrNesdYYReJljfCh6DYTjDKYbOboflllCfUDlyXZ6kS3XDPq 3obChRfndzf1lFQTTWqspXYsWG+1WN9vZaq7h6bjuTjTyWQP/bdMZb6XsymNjeIyK8hX kb3nkDgP1w+AH6/OmrLPAZZwxgsF8e19ojSXdtcRWgQK88N41kI0JjQTcGNc5uP20YCe GwPrQUSbS3/frSTt2Ja7hql1DIo8AFIQZumh/58+Kr/ml3k2PBE/zhNV1BDWOlME8qsX OclGw938VBNg9F+fopIg3sRVewuN11DMFhBpHRf3toMUd1v4BZDTMjrXcjlwAKjaTbMj VnSg== X-Gm-Message-State: APzg51Be5co7rYjcsvfRSOd4XCdTLpPsJSw58RDH1HW5P4JW6Q+kqi9E Jna16cvzYc0HfmqqRtwDBPM= X-Google-Smtp-Source: ANB0VdaYkGooPjhs86OMmjctxm1O4CRss1h7MZmiu8Oogo1OczAK60zjhJjI4o/QT766065kQspwgw== X-Received: by 2002:a17:902:d694:: with SMTP id v20-v6mr25517217ply.328.1537208170392; Mon, 17 Sep 2018 11:16:10 -0700 (PDT) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:3adc:b08c:7acc:b325]) by smtp.gmail.com with ESMTPSA id 74-v6sm24076366pfv.33.2018.09.17.11.16.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 17 Sep 2018 11:16:09 -0700 (PDT) From: Dmitry Torokhov To: Linus Walleij , "Rafael J . Wysocki" Cc: linux-input@vger.kernel.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Shevchenko Subject: [RFC/PATCH 2/5] device property: introduce notion of subnodes for legacy boards Date: Mon, 17 Sep 2018 11:16:00 -0700 Message-Id: <20180917181603.125492-3-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.19.0.397.gdd90340f6a-goog In-Reply-To: <20180917181603.125492-1-dmitry.torokhov@gmail.com> References: <20180917181603.125492-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Several drivers rely on having notion of sub-nodes when describing hardware, let's allow static board-defined properties also have it. The board files will then attach properties to devices in the following fashion: device_add_properties(&board_platform_device.dev, main_device_props); device_add_child_properties(&board_platform_device.dev, dev_fwnode(&board_platform_device.dev), child1_device_props); device_add_child_properties(&board_platform_device.dev, dev_fwnode(&board_platform_device.dev), child2_device_props); ... platform_device_register(&board_platform_device.dev); Signed-off-by: Dmitry Torokhov --- drivers/base/pset_property.c | 110 +++++++++++++++++++++++++++++++---- include/linux/property.h | 4 ++ 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/drivers/base/pset_property.c b/drivers/base/pset_property.c index 08ecc13080ae..63f2377aefe8 100644 --- a/drivers/base/pset_property.c +++ b/drivers/base/pset_property.c @@ -18,6 +18,11 @@ struct property_set { struct device *dev; struct fwnode_handle fwnode; const struct property_entry *properties; + + struct property_set *parent; + /* Entry in parent->children list */ + struct list_head child_node; + struct list_head children; }; static const struct fwnode_operations pset_fwnode_ops; @@ -283,10 +288,47 @@ pset_fwnode_property_read_string_array(const struct fwnode_handle *fwnode, val, nval); } +struct fwnode_handle *pset_fwnode_get_parent(const struct fwnode_handle *fwnode) +{ + struct property_set *pset = to_pset_node(fwnode); + + return pset ? &pset->parent->fwnode : NULL; +} + +struct fwnode_handle * +pset_fwnode_get_next_subnode(const struct fwnode_handle *fwnode, + struct fwnode_handle *child) +{ + const struct property_set *pset = to_pset_node(fwnode); + struct property_set *first_child; + struct property_set *next; + + if (!pset) + return NULL; + + if (list_empty(&pset->children)) + return NULL; + + first_child = list_first_entry(&pset->children, struct property_set, + child_node); + + if (child) { + next = list_next_entry(to_pset_node(child), child_node); + if (next == first_child) + return NULL; + } else { + next = first_child; + } + + return &next->fwnode; +} + static const struct fwnode_operations pset_fwnode_ops = { .property_present = pset_fwnode_property_present, .property_read_int_array = pset_fwnode_read_int_array, .property_read_string_array = pset_fwnode_property_read_string_array, + .get_parent = pset_fwnode_get_parent, + .get_next_child_node = pset_fwnode_get_next_subnode, }; static void property_entry_free_data(const struct property_entry *p) @@ -439,24 +481,31 @@ EXPORT_SYMBOL_GPL(property_entries_free); */ static void pset_free_set(struct property_set *pset) { + struct property_set *child, *next; + if (!pset) return; + list_for_each_entry_safe(child, next, &pset->children, child_node) { + list_del(&child->child_node); + pset_free_set(child); + } + property_entries_free(pset->properties); kfree(pset); } /** - * pset_copy_set - copies property set - * @pset: Property set to copy + * pset_create_set - creates property set. + * @src: property entries for the set. * - * This function takes a deep copy of the given property set and returns - * pointer to the copy. Call device_free_property_set() to free resources - * allocated in this function. + * This function takes a deep copy of the given property entries and creates + * property set. Call pset_free_set() to free resources allocated in this + * function. * * Return: Pointer to the new property set or error pointer. */ -static struct property_set *pset_copy_set(const struct property_set *pset) +static struct property_set *pset_create_set(const struct property_entry *src) { struct property_entry *properties; struct property_set *p; @@ -465,7 +514,11 @@ static struct property_set *pset_copy_set(const struct property_set *pset) if (!p) return ERR_PTR(-ENOMEM); - properties = property_entries_dup(pset->properties); + INIT_LIST_HEAD(&p->child_node); + INIT_LIST_HEAD(&p->children); + p->fwnode.ops = &pset_fwnode_ops; + + properties = property_entries_dup(src); if (IS_ERR(properties)) { kfree(p); return ERR_CAST(properties); @@ -521,20 +574,53 @@ EXPORT_SYMBOL_GPL(device_remove_properties); int device_add_properties(struct device *dev, const struct property_entry *properties) { - struct property_set *p, pset; + struct property_set *p; if (!properties) return -EINVAL; - pset.properties = properties; - - p = pset_copy_set(&pset); + p = pset_create_set(properties); if (IS_ERR(p)) return PTR_ERR(p); - p->fwnode.ops = &pset_fwnode_ops; set_secondary_fwnode(dev, &p->fwnode); p->dev = dev; return 0; } EXPORT_SYMBOL_GPL(device_add_properties); + +/** + * device_add_child_properties - Add a collection of properties to a device object. + * @dev: Device to add properties to. + * @properties: Collection of properties to add. + * + * Associate a collection of device properties represented by @properties as a + * child of given @parent firmware node. The function takes a copy of + * @properties. + */ +struct fwnode_handle * +device_add_child_properties(struct device *dev, + struct fwnode_handle *parent, + const struct property_entry *properties) +{ + struct property_set *p; + struct property_set *parent_pset; + + if (!properties) + return ERR_PTR(-EINVAL); + + parent_pset = to_pset_node(parent); + if (!parent_pset) + return ERR_PTR(-EINVAL); + + p = pset_create_set(properties); + if (IS_ERR(p)) + return ERR_CAST(p); + + p->dev = dev; + p->parent = parent_pset; + list_add_tail(&p->child_node, &parent_pset->children); + + return &p->fwnode; +} +EXPORT_SYMBOL_GPL(device_add_child_properties); diff --git a/include/linux/property.h b/include/linux/property.h index ac8a1ebc4c1b..bb1cf4f30770 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -275,6 +275,10 @@ void property_entries_free(const struct property_entry *properties); int device_add_properties(struct device *dev, const struct property_entry *properties); +struct fwnode_handle * +device_add_child_properties(struct device *dev, + struct fwnode_handle *parent, + const struct property_entry *properties); void device_remove_properties(struct device *dev); bool device_dma_supported(struct device *dev); From patchwork Mon Sep 17 18:16:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 10603279 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B9AA0112B for ; Mon, 17 Sep 2018 18:16:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9F35628CB7 for ; Mon, 17 Sep 2018 18:16:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9125F28FCF; Mon, 17 Sep 2018 18:16:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2DC5128CB7 for ; Mon, 17 Sep 2018 18:16:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728458AbeIQXon (ORCPT ); Mon, 17 Sep 2018 19:44:43 -0400 Received: from mail-pl1-f196.google.com ([209.85.214.196]:38473 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727832AbeIQXom (ORCPT ); Mon, 17 Sep 2018 19:44:42 -0400 Received: by mail-pl1-f196.google.com with SMTP id u11-v6so7804279plq.5; Mon, 17 Sep 2018 11:16:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=r8mNCJS03Mr9/67bWJUwh5jkftsqLb++Nk1K1auq53Y=; b=I3jtGw4fD0wpL80B4RZaxWxWhB5Wy9PjM5O0FPyBPWUbaXkrEHwrvss0c6BUN7FTEi /7H2MulVUabnqIX6Db9ZG6UAEv/1uxiHuA+9K7zkDDGjFPOrZUxdRk6ZCrTY0/2BgChR L1FKYI4FdrI56p5wKDbTMn5sZr6QpJJdxR/ykFQ4MRNPL0DiEFK0cQdHAnAJiW7s5NkJ 2WIMsqO7jp5AWjOxh6uyJg95GG8hihp2fZxbmIcNxyMD5jsCVUofy0JAk1VirgLaHXPu LV/+rYzOJ2Bk1siJLxAKR4T+WBoTTHcwAIw/3k1MAhYKhiAXPNcrjl9F0IdokYV1rK9P TE5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=r8mNCJS03Mr9/67bWJUwh5jkftsqLb++Nk1K1auq53Y=; b=dUsRRfBaQ8bVbxFg4JpYUcunY07Zhh6CywXywvs4Kxprk74xydOqIY6bPjMesxBMkY bSua0urZ7j9WbABEVT+vWohhM23SMqsEE+9zc7N5kNB72l16kY1Gzbtib0LCUWtY9Tfl wzkM63WCaL130bM1FtXcUl2qGDMmapBbPCKx2a0MH4xnYxEEaGEC3+B/CZ2igxwVA0Ui aH5nEoHhgTqeZeUFZF6S9eyra4VXlzNkPidIjhMFXeN7dqzoE15FtaAOHVbuJQP0b5VB YskRLiu1G/kbZkxAgSWazFfjU58/0MW8H0LIalOc8SFP1txrypF5VB88xOUhB2oehzHb GaiA== X-Gm-Message-State: APzg51A0vboBTmTGQGCpeI+7jQaPlVCKMc44EO6EOxYLCCdDDTPNzDFL 50mYLl1mff3b+l7z4EKESFA= X-Google-Smtp-Source: ANB0VdYJh0/BnClHmiPjbt4L1btxq+Ee0x+g73dY8RrCJO1u+NIHJ73Laat6r1hRRQxzT0TVOCVk3g== X-Received: by 2002:a17:902:561:: with SMTP id 88-v6mr25788070plf.320.1537208172276; Mon, 17 Sep 2018 11:16:12 -0700 (PDT) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:3adc:b08c:7acc:b325]) by smtp.gmail.com with ESMTPSA id 74-v6sm24076366pfv.33.2018.09.17.11.16.10 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 17 Sep 2018 11:16:10 -0700 (PDT) From: Dmitry Torokhov To: Linus Walleij , "Rafael J . Wysocki" Cc: linux-input@vger.kernel.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Shevchenko Subject: [RFC/PATCH 3/5] device property: export property_set structure Date: Mon, 17 Sep 2018 11:16:01 -0700 Message-Id: <20180917181603.125492-4-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.19.0.397.gdd90340f6a-goog In-Reply-To: <20180917181603.125492-1-dmitry.torokhov@gmail.com> References: <20180917181603.125492-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Future gpiolib will need to handle property sets properly, and this we need to export property_set, is_pset_node() and to_pset_node(). Signed-off-by: Dmitry Torokhov --- drivers/base/pset_property.c | 31 ++----------------------------- include/linux/property.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/drivers/base/pset_property.c b/drivers/base/pset_property.c index 63f2377aefe8..7118528816a4 100644 --- a/drivers/base/pset_property.c +++ b/drivers/base/pset_property.c @@ -14,34 +14,6 @@ #include #include -struct property_set { - struct device *dev; - struct fwnode_handle fwnode; - const struct property_entry *properties; - - struct property_set *parent; - /* Entry in parent->children list */ - struct list_head child_node; - struct list_head children; -}; - -static const struct fwnode_operations pset_fwnode_ops; - -static inline bool is_pset_node(const struct fwnode_handle *fwnode) -{ - return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &pset_fwnode_ops; -} - -#define to_pset_node(__fwnode) \ - ({ \ - typeof(__fwnode) __to_pset_node_fwnode = __fwnode; \ - \ - is_pset_node(__to_pset_node_fwnode) ? \ - container_of(__to_pset_node_fwnode, \ - struct property_set, fwnode) : \ - NULL; \ - }) - static const struct property_entry * pset_prop_get(const struct property_set *pset, const char *name) { @@ -323,13 +295,14 @@ pset_fwnode_get_next_subnode(const struct fwnode_handle *fwnode, return &next->fwnode; } -static const struct fwnode_operations pset_fwnode_ops = { +const struct fwnode_operations pset_fwnode_ops = { .property_present = pset_fwnode_property_present, .property_read_int_array = pset_fwnode_read_int_array, .property_read_string_array = pset_fwnode_property_read_string_array, .get_parent = pset_fwnode_get_parent, .get_next_child_node = pset_fwnode_get_next_subnode, }; +EXPORT_SYMBOL_GPL(pset_fwnode_ops); static void property_entry_free_data(const struct property_entry *p) { diff --git a/include/linux/property.h b/include/linux/property.h index bb1cf4f30770..957f75d10cf9 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -13,6 +13,7 @@ #ifndef _LINUX_PROPERTY_H_ #define _LINUX_PROPERTY_H_ +#include #include #include @@ -281,6 +282,34 @@ device_add_child_properties(struct device *dev, const struct property_entry *properties); void device_remove_properties(struct device *dev); +struct property_set { + struct device *dev; + struct fwnode_handle fwnode; + const struct property_entry *properties; + + struct property_set *parent; + /* Entry in parent->children list */ + struct list_head child_node; + struct list_head children; +}; + +extern const struct fwnode_operations pset_fwnode_ops; + +static inline bool is_pset_node(const struct fwnode_handle *fwnode) +{ + return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &pset_fwnode_ops; +} + +#define to_pset_node(__fwnode) \ + ({ \ + typeof(__fwnode) __to_pset_node_fwnode = __fwnode; \ + \ + is_pset_node(__to_pset_node_fwnode) ? \ + container_of(__to_pset_node_fwnode, \ + struct property_set, fwnode) : \ + NULL; \ + }) + bool device_dma_supported(struct device *dev); enum dev_dma_attr device_get_dma_attr(struct device *dev); From patchwork Mon Sep 17 18:16:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 10603277 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BD26F112B for ; Mon, 17 Sep 2018 18:16:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 953B528FB8 for ; Mon, 17 Sep 2018 18:16:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 892B92904A; Mon, 17 Sep 2018 18:16:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0046E28FB8 for ; Mon, 17 Sep 2018 18:16:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728497AbeIQXoq (ORCPT ); Mon, 17 Sep 2018 19:44:46 -0400 Received: from mail-pg1-f194.google.com ([209.85.215.194]:34066 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727832AbeIQXoo (ORCPT ); Mon, 17 Sep 2018 19:44:44 -0400 Received: by mail-pg1-f194.google.com with SMTP id d19-v6so8066330pgv.1; Mon, 17 Sep 2018 11:16:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=T1Quryx9grl41Nd+ls3UYvD3BSFyx3VEwFoALI86xJw=; b=tVQsuPOjqGVRle8ylIE8s1cW+1fpxJ9/yHljnmT+lGQ+WFaGI18TFmWHmHGxQ1vijA Siw/VBrlM1/sHRXaMFsISnFyf2xsfD6/IXQXkufrLENfvDjgFUpPebE8LkDIHDfT9Ltz DAxc54XiWOimBafflzb5pZa8jDp/sWznKk+oTLkRiiUKPFtqGnJjkM8eRPSuE7XRIYGG D9W4yrjVMN80MH+ntUNCZbzaC5S+rcsaxpBG+sPzLvN89UQYCSa2c0+BUMteYoSZG/9A dEeHwMAjVd3n2Hkm9wUQP+eDZnT2r8l5yDNjOCXjq4NPoEcTFiH23WJTzu+J0pYfVWRo a3Bw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=T1Quryx9grl41Nd+ls3UYvD3BSFyx3VEwFoALI86xJw=; b=NfdJH7nWoH3404jbXRTHvDFfDK8VhYJHvxwSvWSQP9bQTuN31tBqK6TRB+5iD/lpr0 OQA8mZAMy3iTftpIyvovDvHSLW3I/Yy8M7iVPjCBqYbcSmQwBSoI/UM3jVa+Ww4txTW4 xG65VCqLhRs0SXraE1dMuBxRFT78sXjM99xSvNleEtL49UzpOwVzJtnarAgd2Q/okuEO p22IIeygSsWhr7mDeGFq8iXXCjTOh4Wq+kGwB/SeZZDGyyP10qIC/ZcnjZWRl7YjmPgA 0DjKMwBNinyLTELrFn9e1Qkfm94ZZaBD1Eomj5nGY5ek4kDX6r+/cQKIpN+owQIsDwof DIhw== X-Gm-Message-State: APzg51BiXPiFwaQZ8FR71B6cDrpk+jpnBIWG3RmMOZg1f7xf3BmfOGX7 z3pfs+1SbSgKHUGxRKYYiszQD821 X-Google-Smtp-Source: ANB0VdaMekFx/e50wCirIkIu6OgBfIqYV/NronOKMUdRGpwLgnphfbw/GNC1xywDpyW/IBilrb2Hdg== X-Received: by 2002:a62:e08b:: with SMTP id d11-v6mr27049617pfm.214.1537208174006; Mon, 17 Sep 2018 11:16:14 -0700 (PDT) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:3adc:b08c:7acc:b325]) by smtp.gmail.com with ESMTPSA id 74-v6sm24076366pfv.33.2018.09.17.11.16.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 17 Sep 2018 11:16:12 -0700 (PDT) From: Dmitry Torokhov To: Linus Walleij , "Rafael J . Wysocki" Cc: linux-input@vger.kernel.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Shevchenko Subject: [RFC/PATCH 4/5] gpiolib: add support for fetching descriptors from static properties Date: Mon, 17 Sep 2018 11:16:02 -0700 Message-Id: <20180917181603.125492-5-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.19.0.397.gdd90340f6a-goog In-Reply-To: <20180917181603.125492-1-dmitry.torokhov@gmail.com> References: <20180917181603.125492-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Now that static device properties understand notion of child nodes, let's teach gpiolib to tie such children and machine GPIO descriptor tables. We will continue using a single table for entire device, but instead of using connection ID as a lookup key in the GPIO descriptor table directly, we will perform additional translation: fwnode_get_named_gpiod() when dealing with property_set-backed fwnodes will try parsing string property with name matching connection ID and use result of the lookup as the key in the table: static const struct property_entry dev_child1_props[] __initconst = { ... PROPERTY_ENTRY_STRING("gpios", "child-1-gpios"), { } }; static struct gpiod_lookup_table dev_gpiod_table = { .dev_id = "some-device", .table = { ... GPIO_LOOKUP_IDX("B", 1, "child-1-gpios", 1, GPIO_ACTIVE_LOW), ... }, }; Signed-off-by: Dmitry Torokhov --- drivers/gpio/gpiolib.c | 109 +++++++++++++++++++++++++++++------------ 1 file changed, 79 insertions(+), 30 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e11a3bb03820..f0e51d34a1c1 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3959,39 +3959,44 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, } EXPORT_SYMBOL(gpiod_get_from_of_node); -/** - * fwnode_get_named_gpiod - obtain a GPIO from firmware node - * @fwnode: handle of the firmware node - * @propname: name of the firmware property representing the GPIO - * @index: index of the GPIO to obtain for the consumer - * @dflags: GPIO initialization flags - * @label: label to attach to the requested GPIO - * - * This function can be used for drivers that get their configuration - * from opaque firmware. - * - * The function properly finds the corresponding GPIO using whatever is the - * underlying firmware interface and then makes sure that the GPIO - * descriptor is requested before it is returned to the caller. - * - * Returns: - * On successful request the GPIO pin is configured in accordance with - * provided @dflags. - * - * In case of error an ERR_PTR() is returned. - */ -struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, - const char *propname, int index, - enum gpiod_flags dflags, - const char *label) +static struct gpio_desc *pset_node_get_gpiod(struct fwnode_handle *fwnode, + const char *propname, int index, + enum gpio_lookup_flags *flags) { - struct gpio_desc *desc = ERR_PTR(-ENODEV); - unsigned long lflags = 0; - int ret; + struct property_set *pset; + const char *con_id; - if (!fwnode) + pset = to_pset_node(fwnode); + if (!pset) return ERR_PTR(-EINVAL); + if (fwnode_property_read_string(fwnode, propname, &con_id)) { + /* + * We could not find string mapping property name to + * entry in gpio lookup table. Let's see if we are + * dealing with firmware node corresponding to the + * device (and not a child node): for such nodes we can + * try doing lookup directly with property name. + */ + if (pset->parent) + return ERR_PTR(-ENOENT); + + con_id = propname; + } + + return gpiod_find(pset->dev, con_id, index, flags); +} + +static struct gpio_desc *__fwnode_get_named_gpiod(struct fwnode_handle *fwnode, + const char *propname, + int index, + enum gpiod_flags dflags, + const char *label) +{ + struct gpio_desc *desc = ERR_PTR(-ENODEV); + enum gpio_lookup_flags lflags = 0; + int ret; + if (is_of_node(fwnode)) { desc = gpiod_get_from_of_node(to_of_node(fwnode), propname, index, @@ -4009,9 +4014,12 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, if (info.polarity == GPIO_ACTIVE_LOW) lflags |= GPIO_ACTIVE_LOW; + } else if (is_pset_node(fwnode)) { + desc = pset_node_get_gpiod(fwnode, propname, index, &lflags); + if (IS_ERR(desc)) + return desc; } - /* Currently only ACPI takes this path */ ret = gpiod_request(desc, label); if (ret) return ERR_PTR(ret); @@ -4024,6 +4032,47 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, return desc; } + +/** + * fwnode_get_named_gpiod - obtain a GPIO from firmware node + * @fwnode: handle of the firmware node + * @propname: name of the firmware property representing the GPIO + * @index: index of the GPIO to obtain for the consumer + * @dflags: GPIO initialization flags + * @label: label to attach to the requested GPIO + * + * This function can be used for drivers that get their configuration + * from opaque firmware. + * + * The function properly finds the corresponding GPIO using whatever is the + * underlying firmware interface and then makes sure that the GPIO + * descriptor is requested before it is returned to the caller. + * + * Returns: + * On successful request the GPIO pin is configured in accordance with + * provided @dflags. + * + * In case of error an ERR_PTR() is returned. + */ +struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label) +{ + struct gpio_desc *desc; + + if (!fwnode) + return ERR_PTR(-EINVAL); + + desc = __fwnode_get_named_gpiod(fwnode, propname, index, dflags, label); + if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT && + !IS_ERR_OR_NULL(fwnode->secondary)) { + desc = __fwnode_get_named_gpiod(fwnode->secondary, + propname, index, dflags, label); + } + + return desc; +} EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod); /** From patchwork Mon Sep 17 18:16:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 10603275 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3926614DA for ; Mon, 17 Sep 2018 18:16:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1CD7328F76 for ; Mon, 17 Sep 2018 18:16:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0F2A028FCF; Mon, 17 Sep 2018 18:16:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 94E9F28F76 for ; Mon, 17 Sep 2018 18:16:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727832AbeIQXor (ORCPT ); Mon, 17 Sep 2018 19:44:47 -0400 Received: from mail-pf1-f196.google.com ([209.85.210.196]:45388 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728486AbeIQXoq (ORCPT ); Mon, 17 Sep 2018 19:44:46 -0400 Received: by mail-pf1-f196.google.com with SMTP id i26-v6so7921986pfo.12; Mon, 17 Sep 2018 11:16:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HazVNGD9t6FfNvcp88ZRO3a2sLfWT0t9gqSYYowwjIc=; b=fHRCST8y8fiCjUuF8LMaFMwcxAnNCySikGe+6L1wyBsEQHsa0tjYmI0h789VRHGw7y 5/8aFQW9KRuX1L06zWZiFuNHqRMz9slhFuRqedmTQHcDNajrqxe7h9OQkubn6by/UVvo hp3FCZpmAZyCEqcHMx8q7gGoFcmygEFrigh1MAWZC+f5d+k6rrM9iLq/Cxd0QzJfg5ta zrRvZhwgXsBCRyhMRlYClEt/Rg79vrfa7SqP08OLQryA8RoGL1uEIObr0SicZ3jCURJe 0q5RVEkStEskHrxpRp50ShWnUywFw2OTnc+Ewr2ZCKTw1Zi8Dj1hzqJnF9yuey2xMpCt PzeA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=HazVNGD9t6FfNvcp88ZRO3a2sLfWT0t9gqSYYowwjIc=; b=njSBjWdlq1s+hAzQkM7OYeat4KUnKY4oi5EPspoHQxTffDQ/6Z5kriWYvS5qQ44t91 XucbgjXIrw1VbuTxEFw2Ag/5T4IKP/Auf1weMZkRAuDrl1e9UuEQsHPozo4PiSQ9MW9Q K6WB3ZQaXy3f/fYo3nn4cW3K6w2lpPx8Two/wN/5dlIRcR6bf2SF7sbAUpe34PxttEDv nUenC1xMtAd0Lnn2vaj53cuXbFlaazfuCIOFd1FI7pFsPopp5feUicBnsohOW+wG+0Yc cVzfUD1JxjJEfHlo+3aS53zfYXwnELrcmRn3IDOPEGA0GGeTId3cMAbKgwkfPIjyQxld vrQA== X-Gm-Message-State: APzg51B5MtbVrbyONOjyu8QEDdV7mHKjpNyuF2hBdWpSxZVnIUI54pAL qig0aPO8yU3nUzsV+/7sR1U= X-Google-Smtp-Source: ANB0VdaTmM5ZIMl0DBUv9NjUnOD4oXlKnFz8JTWC14Tijnm2wF4kc2rBUIw+nkUzHqrC2qVRu+4bzw== X-Received: by 2002:a63:d70e:: with SMTP id d14-v6mr24867555pgg.110.1537208176009; Mon, 17 Sep 2018 11:16:16 -0700 (PDT) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:3adc:b08c:7acc:b325]) by smtp.gmail.com with ESMTPSA id 74-v6sm24076366pfv.33.2018.09.17.11.16.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 17 Sep 2018 11:16:14 -0700 (PDT) From: Dmitry Torokhov To: Linus Walleij , "Rafael J . Wysocki" Cc: linux-input@vger.kernel.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Shevchenko Subject: [RFC/PATCH 5/5] RFC: ARM: simone: Hacked in keys Date: Mon, 17 Sep 2018 11:16:03 -0700 Message-Id: <20180917181603.125492-6-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.19.0.397.gdd90340f6a-goog In-Reply-To: <20180917181603.125492-1-dmitry.torokhov@gmail.com> References: <20180917181603.125492-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Linus Walleij This serves as an illustration of how to use the gpio-keys in board files using static device properties and machine GPIO descriptor tables. It is a hack for the joystick connector on the entirely boardfile-based SIM.ONE. It will probably not be applied. Signed-off-by: Linus Walleij Signed-off-by: Dmitry Torokhov --- arch/arm/mach-ep93xx/simone.c | 60 +++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c index 41aa57581356..b998d6772158 100644 --- a/arch/arm/mach-ep93xx/simone.c +++ b/arch/arm/mach-ep93xx/simone.c @@ -24,7 +24,11 @@ #include #include #include +#include #include +#include +#include +#include #include #include @@ -34,6 +38,47 @@ #include "soc.h" +static const struct property_entry simone_key_enter_props[] __initconst = { + PROPERTY_ENTRY_U32("linux,code", KEY_ENTER), + PROPERTY_ENTRY_STRING("label", "enter"), + PROPERTY_ENTRY_STRING("gpios", "enter-gpios"), + { } +}; + +static const struct property_entry simone_key_up_props[] __initconst = { + PROPERTY_ENTRY_U32("linux,code", KEY_UP), + PROPERTY_ENTRY_STRING("label", "up"), + PROPERTY_ENTRY_STRING("gpios", "up-gpios"), + { } +}; + +static const struct property_entry simone_key_up_props[] __initconst = { + PROPERTY_ENTRY_U32("linux,code", KEY_LEFT), + PROPERTY_ENTRY_STRING("label", "left"), + PROPERTY_ENTRY_STRING("gpios", "left-gpios"), + { } +}; + +static const struct property_entry simone_key_props[] __initconst = { + /* There are no properties at device level on this device */ + { } +}; + +static struct gpiod_lookup_table simone_keys_gpiod_table = { + .dev_id = "gpio-keys", + .table = { + /* Use local offsets on gpiochip/port "B" */ + GPIO_LOOKUP_IDX("B", 0, "enter-gpios", 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("B", 1, "up-gpios", 1, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("B", 2, "left-gpios", 2, GPIO_ACTIVE_LOW), + }, +}; + +static struct platform_device simone_keys_device = { + .name = "gpio-keys", + .id = -1, +}; + static struct ep93xx_eth_data __initdata simone_eth_data = { .phy_id = 1, }; @@ -107,6 +152,21 @@ static void __init simone_init_machine(void) ARRAY_SIZE(simone_i2c_board_info)); ep93xx_register_spi(&simone_spi_info, simone_spi_devices, ARRAY_SIZE(simone_spi_devices)); + + gpiod_add_lookup_table(&simone_keys_gpiod_table); + device_add_properties(&simone_keys_device.dev, + simone_keys_device_props); + device_add_child_properties(&simone_keys_device.dev, + dev_fwnode(&simone_keys_device.dev), + simone_key_enter_props); + device_add_child_properties(&simone_keys_device.dev, + dev_fwnode(&simone_keys_device.dev), + simone_key_up_props); + device_add_child_properties(&simone_keys_device.dev, + dev_fwnode(&simone_keys_device.dev), + simone_key_left_props); + platform_device_register(&simone_keys_device); + simone_register_audio(); }