From patchwork Sun Aug 17 06:04:14 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Westerberg X-Patchwork-Id: 4730661 Return-Path: X-Original-To: patchwork-linux-acpi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 55A0EC0338 for ; Sun, 17 Aug 2014 06:06:05 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 29FA6201C8 for ; Sun, 17 Aug 2014 06:06:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0022C2015D for ; Sun, 17 Aug 2014 06:06:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751811AbaHQGFM (ORCPT ); Sun, 17 Aug 2014 02:05:12 -0400 Received: from mga02.intel.com ([134.134.136.20]:54331 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751768AbaHQGFL (ORCPT ); Sun, 17 Aug 2014 02:05:11 -0400 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 16 Aug 2014 23:05:10 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.01,878,1400050800"; d="scan'208";a="589195664" Received: from blue.fi.intel.com ([10.237.72.156]) by orsmga002.jf.intel.com with ESMTP; 16 Aug 2014 23:04:50 -0700 Received: by blue.fi.intel.com (Postfix, from userid 1004) id 64231E00A6; Sun, 17 Aug 2014 09:04:19 +0300 (EEST) From: Mika Westerberg To: Darren Hart , "Rafael J. Wysocki" Cc: Aaron Lu , Max Eliaser , Mika Westerberg , linux-acpi@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 4/9] of: Add property_ops callback for devices with of_node Date: Sun, 17 Aug 2014 09:04:14 +0300 Message-Id: <1408255459-17625-5-git-send-email-mika.westerberg@linux.intel.com> X-Mailer: git-send-email 2.1.0.rc1 In-Reply-To: <1408255459-17625-1-git-send-email-mika.westerberg@linux.intel.com> References: <1408255459-17625-1-git-send-email-mika.westerberg@linux.intel.com> Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Spam-Status: No, score=-7.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, 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: Aaron Lu With the unified device properties interface in place, add device tree support. By adding the dev_prop_ops for of_node devices, drivers can access properties from ACPI or Device Tree in a generic way. Signed-off-by: Aaron Lu Reviewed-by: Darren Hart Signed-off-by: Mika Westerberg --- drivers/of/base.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++- drivers/of/platform.c | 4 +- include/linux/property.h | 4 + 3 files changed, 200 insertions(+), 2 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index b9864806e9b8..527004d01423 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -1343,6 +1343,39 @@ int of_property_read_u64(const struct device_node *np, const char *propname, EXPORT_SYMBOL_GPL(of_property_read_u64); /** + * of_property_read_u64_array - Find and read an array of 64 bit integers + * from a property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_values: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read + * + * Search for a property in a device node and read 64-bit value(s) from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * The out_values is modified only if a valid u64 value can be decoded. + */ +int of_property_read_u64_array(const struct device_node *np, + const char *propname, u64 *out_values, + size_t sz) +{ + const __be32 *val = of_find_property_value_of_size(np, propname, + (sz * sizeof(*out_values))); + + if (IS_ERR(val)) + return PTR_ERR(val); + + while (sz--) { + *out_values++ = of_read_number(val, 2); + val += 2; + }; + return 0; +} + +/** * of_property_read_string - Find and read a string from a property * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. @@ -1490,6 +1523,47 @@ int of_property_count_strings(struct device_node *np, const char *propname) } EXPORT_SYMBOL_GPL(of_property_count_strings); +/** + * of_property_read_string_array - Find and read an array of strings + * from a multiple strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_string: pointer to null terminated return string, modified only if + * return value is 0. + * @sz: number of array elements to read + * + * Search for a property in a device tree node and retrieve a list of + * terminated string value (pointer to data, not a copy) in that property. + * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if + * property does not have a value, and -EILSEQ if the string is not + * null-terminated within the length of the property data. + * + * The out_string pointer is modified only if a valid string can be decoded. + */ +int of_property_read_string_array(struct device_node *np, const char *propname, + char **output, size_t sz) +{ + struct property *prop = of_find_property(np, propname, NULL); + int i = 0; + size_t l = 0, total = 0; + char *p; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if (strnlen(prop->value, prop->length) >= prop->length) + return -EILSEQ; + + p = prop->value; + + for (i = 0; total < prop->length; total += l, p += l) { + output[i++] = p; + l = strlen(p) + 1; + } + return 0; +} + void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) { int i; @@ -2376,3 +2450,121 @@ struct device_node *of_graph_get_remote_port(const struct device_node *node) return of_get_next_parent(np); } EXPORT_SYMBOL(of_graph_get_remote_port); + +static int of_dev_prop_get(struct device *dev, const char *propname, + void **valptr) +{ + struct property *pp = of_find_property(dev->of_node, propname, NULL); + + if (!pp) + return -ENODATA; + + if (valptr) + *valptr = pp->value; + return 0; +} + +static int of_dev_prop_read(struct device *dev, const char *propname, + enum dev_prop_type proptype, void *val) +{ + void *value; + int ret = of_dev_prop_get(dev, propname, &value); + + if (ret) + return ret; + + if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) { + switch (proptype) { + case DEV_PROP_U8: + *(u8 *)val = *(u8 *)value; + break; + case DEV_PROP_U16: + *(u16 *)val = *(u16 *)value; + break; + case DEV_PROP_U32: + *(u32 *)val = *(u32 *)value; + break; + default: + *(u64 *)val = *(u64 *)value; + break; + } + } else if (proptype == DEV_PROP_STRING) { + *(char **)val = value; + } + return ret; + +} + +static int of_dev_prop_read_array(struct device *dev, const char *propname, + enum dev_prop_type proptype, void *val, + size_t nval) +{ + int ret, elem_size; + + if (!val) { + switch (proptype) { + case DEV_PROP_U8: + elem_size = sizeof(u8); + break; + case DEV_PROP_U16: + elem_size = sizeof(u16); + break; + case DEV_PROP_U32: + elem_size = sizeof(u32); + break; + case DEV_PROP_U64: + elem_size = sizeof(u64); + break; + case DEV_PROP_STRING: + return of_property_count_strings(dev->of_node, + propname); + default: + return -EINVAL; + } + return of_property_count_elems_of_size(dev->of_node, propname, + elem_size); + } + + switch (proptype) { + case DEV_PROP_U8: + ret = of_property_read_u8_array(dev->of_node, propname, + (u8 *)val, nval); + break; + case DEV_PROP_U16: + ret = of_property_read_u16_array(dev->of_node, propname, + (u16 *)val, nval); + break; + case DEV_PROP_U32: + ret = of_property_read_u32_array(dev->of_node, propname, + (u32 *)val, nval); + break; + case DEV_PROP_U64: + ret = of_property_read_u64_array(dev->of_node, propname, + (u64 *)val, nval); + break; + case DEV_PROP_STRING: + ret = of_property_read_string_array(dev->of_node, propname, + (char **)val, nval); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int of_dev_get_child_count(struct device *dev) +{ + struct device_node *node = dev->of_node; + + if (!node) + return -EINVAL; + return of_get_child_count(node); +} + +struct dev_prop_ops of_property_ops = { + .get = of_dev_prop_get, + .read = of_dev_prop_read, + .read_array = of_dev_prop_read_array, + .child_count = of_dev_get_child_count, +}; diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 500436f9be7f..3113d3704eff 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -138,6 +138,7 @@ struct platform_device *of_device_alloc(struct device_node *np, } dev->dev.of_node = of_node_get(np); + dev->dev.property_ops = &of_property_ops; dev->dev.parent = parent; if (bus_id) @@ -293,6 +294,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node, /* setup generic device info */ dev->dev.coherent_dma_mask = ~0; dev->dev.of_node = of_node_get(node); + dev->dev.property_ops = &of_property_ops; dev->dev.parent = parent; dev->dev.platform_data = platform_data; if (bus_id) diff --git a/include/linux/property.h b/include/linux/property.h index 52ea7fe7fe09..a840c1784c82 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -38,6 +38,10 @@ struct dev_prop_ops { extern struct dev_prop_ops acpi_property_ops; #endif +#ifdef CONFIG_OF +extern struct dev_prop_ops of_property_ops; +#endif + int device_property_get(struct device *dev, const char *propname, void **valptr); int device_property_read(struct device *dev, const char *propname,