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: