From patchwork Thu Sep 24 04:34:16 2020
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Pratyush Yadav
X-Patchwork-Id: 1370263
X-Patchwork-Delegate: trini@ti.com
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
Authentication-Results: ozlabs.org;
spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de
(client-ip=85.214.62.61; helo=phobos.denx.de;
envelope-from=u-boot-bounces@lists.denx.de; receiver=)
Authentication-Results: ozlabs.org;
dmarc=pass (p=quarantine dis=none) header.from=ti.com
Authentication-Results: ozlabs.org;
dkim=pass (1024-bit key;
unprotected) header.d=ti.com header.i=@ti.com header.a=rsa-sha256
header.s=ti-com-17Q1 header.b=WdyjRv3V;
dkim-atps=neutral
Received: from phobos.denx.de (phobos.denx.de [85.214.62.61])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (4096 bits))
(No client certificate requested)
by ozlabs.org (Postfix) with ESMTPS id 4Bxj1l00p4z9sTH
for ; Thu, 24 Sep 2020 14:36:58 +1000 (AEST)
Received: from h2850616.stratoserver.net (localhost [IPv6:::1])
by phobos.denx.de (Postfix) with ESMTP id 35E36824FA;
Thu, 24 Sep 2020 06:36:48 +0200 (CEST)
Authentication-Results: phobos.denx.de;
dmarc=pass (p=quarantine dis=none) header.from=ti.com
Authentication-Results: phobos.denx.de;
spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de
Authentication-Results: phobos.denx.de;
dkim=pass (1024-bit key;
unprotected) header.d=ti.com header.i=@ti.com header.b="WdyjRv3V";
dkim-atps=neutral
Received: by phobos.denx.de (Postfix, from userid 109)
id 5B29E8266A; Thu, 24 Sep 2020 06:34:40 +0200 (CEST)
X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de
X-Spam-Level:
X-Spam-Status: No, score=-3.2 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_MSPIKE_H3,
RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham
autolearn_force=no version=3.4.2
Received: from fllv0016.ext.ti.com (fllv0016.ext.ti.com [198.47.19.142])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(No client certificate requested)
by phobos.denx.de (Postfix) with ESMTPS id 044B782442
for ; Thu, 24 Sep 2020 06:34:36 +0200 (CEST)
Authentication-Results: phobos.denx.de;
dmarc=pass (p=quarantine dis=none) header.from=ti.com
Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=p.yadav@ti.com
Received: from fllv0035.itg.ti.com ([10.64.41.0])
by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id 08O4YZRu075675;
Wed, 23 Sep 2020 23:34:35 -0500
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com;
s=ti-com-17Q1; t=1600922075;
bh=ZfgPIsHPyH7g8iJcrpz6/6bGeI+gPUET/TVyqnyLTfQ=;
h=From:To:CC:Subject:Date:In-Reply-To:References;
b=WdyjRv3Vemu51Q+NoGwhAUIeM6SHb1QwPkzrITRDkxtNEf9J5DsFHZ08akPaBvkTq
fETZpLKdaNKz5qUzbKnUY7wamBABsosk9DjWlHXi7g6DRNyux6roGVtcAhg4qPkO7b
VKmdg1jPc/KEtKCi/GbQJ2CSgOWS+37pj5/bDnX4=
Received: from DFLE103.ent.ti.com (dfle103.ent.ti.com [10.64.6.24])
by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTP id 08O4YZaI089935;
Wed, 23 Sep 2020 23:34:35 -0500
Received: from DFLE110.ent.ti.com (10.64.6.31) by DFLE103.ent.ti.com
(10.64.6.24) with Microsoft SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1979.3; Wed, 23
Sep 2020 23:34:34 -0500
Received: from lelv0326.itg.ti.com (10.180.67.84) by DFLE110.ent.ti.com
(10.64.6.31) with Microsoft SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1979.3 via
Frontend Transport; Wed, 23 Sep 2020 23:34:34 -0500
Received: from pratyush-OptiPlex-790.dhcp.ti.com (ileax41-snat.itg.ti.com
[10.172.224.153])
by lelv0326.itg.ti.com (8.15.2/8.15.2) with ESMTP id 08O4YInq065200;
Wed, 23 Sep 2020 23:34:33 -0500
From: Pratyush Yadav
To: Tom Rini
CC: Pratyush Yadav , , Simon Glass
, Vignesh Raghavendra
Subject: [PATCH v3 7/9] regmap: Add support for regmap fields
Date: Thu, 24 Sep 2020 10:04:16 +0530
Message-ID: <20200924043418.5355-8-p.yadav@ti.com>
X-Mailer: git-send-email 2.28.0
In-Reply-To: <20200924043418.5355-1-p.yadav@ti.com>
References: <20200924043418.5355-1-p.yadav@ti.com>
MIME-Version: 1.0
X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180
X-BeenThere: u-boot@lists.denx.de
X-Mailman-Version: 2.1.34
Precedence: list
List-Id: U-Boot discussion
List-Unsubscribe: ,
List-Archive:
List-Post:
List-Help:
List-Subscribe: ,
Errors-To: u-boot-bounces@lists.denx.de
Sender: "U-Boot"
X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de
X-Virus-Status: Clean
From: Jean-Jacques Hiblot
A regmap field is an abstraction available in Linux. It provides to access
bitfields in a regmap without having to worry about shifts and masks.
Signed-off-by: Jean-Jacques Hiblot
Reviewed-by: Simon Glass
Signed-off-by: Pratyush Yadav
---
Notes:
No changes in v3.
drivers/core/regmap.c | 83 ++++++++++++++++++++++++++++
include/regmap.h | 122 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 205 insertions(+)
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index a3da0cf7c3..c2bed88eac 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -18,6 +18,20 @@
#include
#include
#include
+#include
+
+/*
+ * Internal representation of a regmap field. Instead of storing the MSB and
+ * LSB, store the shift and mask. This makes the code a bit cleaner and faster
+ * because the shift and mask don't have to be calculated every time.
+ */
+struct regmap_field {
+ struct regmap *regmap;
+ unsigned int mask;
+ /* lsb */
+ unsigned int shift;
+ unsigned int reg;
+};
DECLARE_GLOBAL_DATA_PTR;
@@ -547,3 +561,72 @@ int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
return regmap_write(map, offset, reg | (val & mask));
}
+
+int regmap_field_read(struct regmap_field *field, unsigned int *val)
+{
+ int ret;
+ unsigned int reg_val;
+
+ ret = regmap_read(field->regmap, field->reg, ®_val);
+ if (ret != 0)
+ return ret;
+
+ reg_val &= field->mask;
+ reg_val >>= field->shift;
+ *val = reg_val;
+
+ return ret;
+}
+
+int regmap_field_write(struct regmap_field *field, unsigned int val)
+{
+ return regmap_update_bits(field->regmap, field->reg, field->mask,
+ val << field->shift);
+}
+
+static void regmap_field_init(struct regmap_field *rm_field,
+ struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ rm_field->regmap = regmap;
+ rm_field->reg = reg_field.reg;
+ rm_field->shift = reg_field.lsb;
+ rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
+}
+
+struct regmap_field *devm_regmap_field_alloc(struct udevice *dev,
+ struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field),
+ GFP_KERNEL);
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+}
+
+void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field)
+{
+ devm_kfree(dev, field);
+}
+
+struct regmap_field *regmap_field_alloc(struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
+
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+}
+
+void regmap_field_free(struct regmap_field *field)
+{
+ kfree(field);
+}
diff --git a/include/regmap.h b/include/regmap.h
index 7a6fcc7f53..c6258face3 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -312,6 +312,43 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
regmap_read_poll_timeout_test(map, addr, val, cond, sleep_us, \
timeout_ms, 0) \
+/**
+ * regmap_field_read_poll_timeout - Poll until a condition is met or a timeout
+ * occurs
+ *
+ * @field: Regmap field to read from
+ * @val: Unsigned integer variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @sleep_us: Maximum time to sleep between reads in us (0 tight-loops).
+ * @timeout_ms: Timeout in ms, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_field_read
+ * error return value in case of a error read. In the two former cases,
+ * the last read value at @addr is stored in @val.
+ *
+ * This is modelled after the regmap_read_poll_timeout macros in linux but
+ * with millisecond timeout.
+ */
+#define regmap_field_read_poll_timeout(field, val, cond, sleep_us, timeout_ms) \
+({ \
+ unsigned long __start = get_timer(0); \
+ int __ret; \
+ for (;;) { \
+ __ret = regmap_field_read((field), &(val)); \
+ if (__ret) \
+ break; \
+ if (cond) \
+ break; \
+ if ((timeout_ms) && get_timer(__start) > (timeout_ms)) { \
+ __ret = regmap_field_read((field), &(val)); \
+ break; \
+ } \
+ if ((sleep_us)) \
+ udelay((sleep_us)); \
+ } \
+ __ret ?: ((cond) ? 0 : -ETIMEDOUT); \
+})
+
/**
* regmap_update_bits() - Perform a read/modify/write using a mask
*
@@ -407,4 +444,89 @@ void *regmap_get_range(struct regmap *map, unsigned int range_num);
*/
int regmap_uninit(struct regmap *map);
+/**
+ * struct reg_field - Description of an register field
+ *
+ * @reg: Offset of the register within the regmap bank
+ * @lsb: lsb of the register field.
+ * @msb: msb of the register field.
+ */
+struct reg_field {
+ unsigned int reg;
+ unsigned int lsb;
+ unsigned int msb;
+};
+
+struct regmap_field;
+
+/**
+ * REG_FIELD() - A convenient way to initialize a 'struct reg_feild'.
+ *
+ * @_reg: Offset of the register within the regmap bank
+ * @_lsb: lsb of the register field.
+ * @_msb: msb of the register field.
+ *
+ * Register fields are often described in terms of 3 things: the register it
+ * belongs to, its LSB, and its MSB. This macro can be used by drivers to
+ * clearly and easily initialize a 'struct regmap_field'.
+ *
+ * For example, say a device has a register at offset DEV_REG1 (0x100) and a
+ * field of DEV_REG1 is on bits [7:3]. So a driver can initialize a regmap
+ * field for this by doing:
+ * struct reg_field field = REG_FIELD(DEV_REG1, 3, 7);
+ */
+#define REG_FIELD(_reg, _lsb, _msb) { \
+ .reg = _reg, \
+ .lsb = _lsb, \
+ .msb = _msb, \
+ }
+
+/**
+ * devm_regmap_field_alloc() - Allocate and initialise a register field.
+ *
+ * @dev: Device that will be interacted with
+ * @regmap: regmap bank in which this register field is located.
+ * @reg_field: Register field with in the bank.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap_field. The regmap_field will be automatically freed
+ * by the device management code.
+ */
+struct regmap_field *devm_regmap_field_alloc(struct udevice *dev,
+ struct regmap *regmap,
+ struct reg_field reg_field);
+/**
+ * devm_regmap_field_free() - Free a register field allocated using
+ * devm_regmap_field_alloc.
+ *
+ * @dev: Device that will be interacted with
+ * @field: regmap field which should be freed.
+ *
+ * Free register field allocated using devm_regmap_field_alloc(). Usually
+ * drivers need not call this function, as the memory allocated via devm
+ * will be freed as per device-driver life-cyle.
+ */
+void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field);
+
+/**
+ * regmap_field_write() - Write a value to a regmap field
+ *
+ * @field: Regmap field to write to
+ * @val: Data to write to the regmap at the specified offset
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int regmap_field_write(struct regmap_field *field, unsigned int val);
+
+/**
+ * regmap_read() - Read a 32-bit value from a regmap
+ *
+ * @field: Regmap field to write to
+ * @valp: Pointer to the buffer to receive the data read from the regmap
+ * field
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int regmap_field_read(struct regmap_field *field, unsigned int *val);
+
#endif