From patchwork Fri May 9 02:04:33 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiubo Li X-Patchwork-Id: 4140051 Return-Path: X-Original-To: patchwork-linux-arm@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 21130BFF02 for ; Fri, 9 May 2014 02:54:06 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 113F8202EA for ; Fri, 9 May 2014 02:54:05 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id F1197202DD for ; Fri, 9 May 2014 02:54:03 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wiaty-0007d3-7j; Fri, 09 May 2014 02:51:10 +0000 Received: from mail-bn1blp0184.outbound.protection.outlook.com ([207.46.163.184] helo=na01-bn1-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wiato-0007Vk-Nl for linux-arm-kernel@lists.infradead.org; Fri, 09 May 2014 02:51:02 +0000 Received: from BY2PR03CA047.namprd03.prod.outlook.com (10.141.249.20) by BY2PR03MB507.namprd03.prod.outlook.com (10.141.143.21) with Microsoft SMTP Server (TLS) id 15.0.934.12; Fri, 9 May 2014 02:50:36 +0000 Received: from BN1AFFO11FD012.protection.gbl (2a01:111:f400:7c10::159) by BY2PR03CA047.outlook.office365.com (2a01:111:e400:2c5d::20) with Microsoft SMTP Server (TLS) id 15.0.939.12 via Frontend Transport; Fri, 9 May 2014 02:50:35 +0000 Received: from az84smr01.freescale.net (192.88.158.2) by BN1AFFO11FD012.mail.protection.outlook.com (10.58.52.72) with Microsoft SMTP Server (TLS) id 15.0.939.9 via Frontend Transport; Fri, 9 May 2014 02:50:35 +0000 Received: from rock.ap.freescale.net (rock.ap.freescale.net [10.193.20.106]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id s492oGqS004875; Thu, 8 May 2014 19:50:31 -0700 From: Xiubo Li To: , , , , , , , , Subject: [PATCHv4 2/2] regmap: add DT endianness binding support. Date: Fri, 9 May 2014 10:04:33 +0800 Message-ID: <1399601073-19278-3-git-send-email-Li.Xiubo@freescale.com> X-Mailer: git-send-email 1.8.0 In-Reply-To: <1399601073-19278-1-git-send-email-Li.Xiubo@freescale.com> References: <1399601073-19278-1-git-send-email-Li.Xiubo@freescale.com> X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:192.88.158.2; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10009001)(6009001)(189002)(199002)(64706001)(77982001)(76176999)(50226001)(47776003)(20776003)(36756003)(50986999)(88136002)(87936001)(81542001)(81342001)(62966002)(80022001)(21056001)(77096999)(87286001)(76482001)(19580395003)(31966008)(2009001)(93916002)(85852003)(575784001)(86362001)(50466002)(74662001)(74502001)(92566001)(83072002)(2201001)(4396001)(92726001)(48376002)(46102001)(19580405001)(44976005)(83322001)(99396002)(6806004)(77156001)(89996001)(68736004)(69596002)(79102001); DIR:OUT; SFP:1101; SCL:1; SRVR:BY2PR03MB507; H:az84smr01.freescale.net; FPR:; MLV:sfv; PTR:InfoDomainNonexistent; MX:1; A:1; LANG:en; MIME-Version: 1.0 X-Forefront-PRVS: 02065A9E77 Received-SPF: Fail (: domain of freescale.com does not designate 192.88.158.2 as permitted sender) receiver=; client-ip=192.88.158.2; helo=az84smr01.freescale.net; Authentication-Results: spf=fail (sender IP is 192.88.158.2) smtp.mailfrom=Li.Xiubo@freescale.com; X-OriginatorOrg: freescale.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140508_195101_462124_DBBEB280 X-CRM114-Status: GOOD ( 14.49 ) X-Spam-Score: -0.0 (/) Cc: devicetree@vger.kernel.org, Xiubo Li , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00,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 For many drivers which will support rich endianness of CPU<-->Dev need define DT properties by itself without the binding support. The endianness using regmap: Index CPU Device Endianess flag for DT bool property ------------------------------------------------------------ 1 LE LE - 2 LE BE 'big-endian-{val,reg}' 3 BE BE - 4 BE LE 'little-endian-{val,reg}' Please see the following documetation for detail: Documentation/devicetree/bindings/endianness/endianness.txt Signed-off-by: Xiubo Li --- drivers/base/regmap/regmap-i2c.c | 2 + drivers/base/regmap/regmap-spi.c | 2 + drivers/base/regmap/regmap.c | 148 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 141 insertions(+), 11 deletions(-) diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index ebd1895..9b0fbf9 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -95,6 +95,8 @@ static struct regmap_bus regmap_i2c = { .write = regmap_i2c_write, .gather_write = regmap_i2c_gather_write, .read = regmap_i2c_read, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, }; /** diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index 0eb3097..53d1148 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c @@ -109,6 +109,8 @@ static struct regmap_bus regmap_spi = { .async_alloc = regmap_spi_async_alloc, .read = regmap_spi_read, .read_flag_mask = 0x80, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, }; /** diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 63e30ef..4805246 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -402,6 +403,133 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, } EXPORT_SYMBOL_GPL(regmap_attach_dev); +enum regmap_endian_type { + REGMAP_ENDIAN_REG, + REGMAP_ENDIAN_VAL, +}; + +/** + * of_regmap_endian_by_type() - Parses and lookups the endianness referenced + * by a device node + * @np: pointer to the consumer device node + * @type: endianness type for values or registers + * + * This function parses the device endianness properties, and uses them to + * determine the endianness of the device's registers and values. + */ +static int of_regmap_endian_by_type(struct device_node *np, + enum regmap_endian_type type, + enum regmap_endian *endian) +{ + if (!endian) + return -EINVAL; + + switch (type) { + case REGMAP_ENDIAN_REG: + if (of_property_read_bool(np, "big-endian-reg")) + *endian = REGMAP_ENDIAN_BIG; + else if (of_property_read_bool(np, "little-endian-reg")) + *endian = REGMAP_ENDIAN_LITTLE; + else + *endian = REGMAP_ENDIAN_NATIVE; + break; + case REGMAP_ENDIAN_VAL: + if (of_property_read_bool(np, "big-endian-val")) + *endian = REGMAP_ENDIAN_BIG; + else if (of_property_read_bool(np, "little-endian-val")) + *endian = REGMAP_ENDIAN_LITTLE; + else + *endian = REGMAP_ENDIAN_NATIVE; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int of_regmap_get_endian(struct device *dev, + const struct regmap_bus *bus, + const struct regmap_config *config, + enum regmap_endian_type type, + enum regmap_endian *endian) +{ + int ret; + + if (!endian || !config) + return -EINVAL; + + /* + * Firstly, try to parse the endianness from driver's config, + * this is to be compatible with the none DT or the old drivers. + * From the driver's config the endianness value maybe: + * REGMAP_ENDIAN_BIG, + * REGMAP_ENDIAN_LITTLE, + * REGMAP_ENDIAN_NATIVE, + * REGMAP_ENDIAN_DEFAULT. + */ + switch (type) { + case REGMAP_ENDIAN_REG: + *endian = config->reg_format_endian; + break; + case REGMAP_ENDIAN_VAL: + *endian = config->val_format_endian; + break; + default: + return -EINVAL; + } + + /* + * If the endianness parsed from driver config is + * REGMAP_ENDIAN_DEFAULT, that means maybe we are using the DT + * node to specify the endianness information. + */ + if (*endian != REGMAP_ENDIAN_DEFAULT) + return 0; + + /* + * Secondly, try to parse the endianness from DT node if the + * driver config does not specify it. + * From the DT node the endianness value maybe: + * REGMAP_ENDIAN_BIG, + * REGMAP_ENDIAN_LITTLE, + * REGMAP_ENDIAN_NATIVE, + */ + if (dev) { + ret = of_regmap_endian_by_type(dev->of_node, type, endian); + if (ret < 0) + return ret; + } + + /* + * If the endianness parsed from DT node is REGMAP_ENDIAN_NATIVE, that + * maybe means the DT does not care the endianness or it should use + * the regmap bus's default endianness, then we should try to check + * whether the regmap bus has specified the default endianness. + */ + if (*endian != REGMAP_ENDIAN_NATIVE) + return 0; + + /* + * Finally, try to parse the endianness from regmap bus config + * if in device's DT node the endianness property is absent. + */ + switch (type) { + case REGMAP_ENDIAN_REG: + if (bus && bus->reg_format_endian_default) + *endian = bus->reg_format_endian_default; + break; + case REGMAP_ENDIAN_VAL: + if (bus && bus->val_format_endian_default) + *endian = bus->val_format_endian_default; + break; + default: + return -EINVAL; + } + + return 0; +} + /** * regmap_init(): Initialise register map * @@ -499,17 +627,15 @@ struct regmap *regmap_init(struct device *dev, map->reg_read = _regmap_bus_read; } - reg_endian = config->reg_format_endian; - if (reg_endian == REGMAP_ENDIAN_DEFAULT) - reg_endian = bus->reg_format_endian_default; - if (reg_endian == REGMAP_ENDIAN_DEFAULT) - reg_endian = REGMAP_ENDIAN_BIG; - - val_endian = config->val_format_endian; - if (val_endian == REGMAP_ENDIAN_DEFAULT) - val_endian = bus->val_format_endian_default; - if (val_endian == REGMAP_ENDIAN_DEFAULT) - val_endian = REGMAP_ENDIAN_BIG; + ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_REG, + ®_endian); + if (ret) + return ERR_PTR(ret); + + ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_VAL, + &val_endian); + if (ret) + return ERR_PTR(ret); switch (config->reg_bits + map->reg_shift) { case 2: