From patchwork Mon Jun 10 09:21:58 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas KANDAGATLA X-Patchwork-Id: 2697231 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork1.kernel.org (Postfix) with ESMTP id 16AA63FD4F for ; Mon, 10 Jun 2013 11:54:30 +0000 (UTC) Received: from merlin.infradead.org ([205.233.59.134]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UlyMz-0006VA-7V; Mon, 10 Jun 2013 09:26:35 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UlyLl-0005PR-PV; Mon, 10 Jun 2013 09:25:17 +0000 Received: from eu1sys200aog118.obsmtp.com ([207.126.144.145]) by merlin.infradead.org with smtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UlyLf-0005NM-4n for linux-arm-kernel@lists.infradead.org; Mon, 10 Jun 2013 09:25:14 +0000 Received: from beta.dmz-eu.st.com ([164.129.1.35]) (using TLSv1) by eu1sys200aob118.postini.com ([207.126.147.11]) with SMTP ID DSNKUbWbQIGYdPZf+q89FrJ1+p4a6x44A8v0@postini.com; Mon, 10 Jun 2013 09:25:10 UTC Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id A565119E; Mon, 10 Jun 2013 09:23:46 +0000 (GMT) Received: from mail7.sgp.st.com (unknown [164.129.223.81]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 6A13F48C8; Mon, 10 Jun 2013 09:23:26 +0000 (GMT) Received: from localhost (king.bri.st.com [10.65.51.59]) by mail7.sgp.st.com (MOS 4.3.3-GA) with ESMTP id BFB57489 (AUTH srinivak); Mon, 10 Jun 2013 11:23:44 +0200 From: Srinivas KANDAGATLA To: linux-arm-kernel@lists.infradead.org Subject: [PATCH v2 03/11] regmap: Add regmap_field APIs Date: Mon, 10 Jun 2013 10:21:58 +0100 Message-Id: <1370856118-6503-1-git-send-email-srinivas.kandagatla@st.com> X-Mailer: git-send-email 1.7.6.5 In-Reply-To: <1370855828-5318-1-git-send-email-srinivas.kandagatla@st.com> References: <1370855828-5318-1-git-send-email-srinivas.kandagatla@st.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130610_052511_598868_39414FF4 X-CRM114-Status: GOOD ( 29.06 ) X-Spam-Score: -4.2 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [207.126.144.145 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Mauro Carvalho Chehab , linux-doc@vger.kernel.org, Linus Walleij , Lars-Peter Clausen , linux@arm.linux.org.uk, Samuel Ortiz , Alexander Shiyan , Srinivas Kandagatla , Stephen Gallimore , linux-serial@vger.kernel.org, Grant Likely , Arnd Bergmann , devicetree-discuss@lists.ozlabs.org, Rob Herring , Stuart Menefy , Mark Brown , John Stultz , Thomas Gleixner , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, Rob Landley , Olof Johansson , Andrew Morton , "David S. Miller" 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: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org It is common to access regmap registers at bit level, using regmap_update_bits or regmap_read functions, however the end user has to take care of a mask or shifting. This becomes overhead when such use cases are high. Having a common function to do this is much convenient and less error prone. The idea of regmap_field is simple, regmap_field gives a logical structure to bits of the regmap register, and the driver can use this logical entity without the knowledge of the bit postions and masks all over the code. This way code looks much neat and it need not handle the masks, shifts every time it access the those entities. With this new regmap_field_read/write apis the end user can setup a regmap field using regmap_field_init and use the return regmap_field to read write the register field without worrying about the masks or shifts. Also this apis will be usefull for drivers which are based on regmaps, like some clocks or pinctrls which can work on the regmap_fields directly without having to worry about bit positions. Signed-off-by: Srinivas Kandagatla CC: Mark Brown CC: Arnd Bergmann CC: Alexander Shiyan CC: Lars-Peter Clausen --- drivers/base/regmap/internal.h | 8 +++ drivers/base/regmap/regmap.c | 104 ++++++++++++++++++++++++++++++++++++++++ include/linux/regmap.h | 42 ++++++++++++++++ 3 files changed, 154 insertions(+), 0 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index c130536..c5f6ebd 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -174,6 +174,14 @@ struct regmap_range_node { unsigned int window_len; }; +struct regmap_field { + struct regmap *regmap; + unsigned int mask; + /* lsb */ + unsigned int shift; + unsigned int reg; +}; + #ifdef CONFIG_DEBUG_FS extern void regmap_debugfs_initcall(void); extern void regmap_debugfs_init(struct regmap *map, const char *name); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index a941dcf..8d967cc 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -801,6 +801,67 @@ struct regmap *devm_regmap_init(struct device *dev, } EXPORT_SYMBOL_GPL(devm_regmap_init); +static void regmap_field_init(struct regmap_field *rm_field, + struct regmap *regmap, struct reg_field reg_field) +{ + int field_bits = reg_field.msb - reg_field.lsb + 1; + rm_field->regmap = regmap; + rm_field->reg = reg_field.reg; + rm_field->shift = reg_field.lsb; + rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb); +} + +/** + * devm_regmap_field_alloc(): Allocate and initialise a register field + * in a register map. + * + * @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 device *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; + +} +EXPORT_SYMBOL_GPL(devm_regmap_field_alloc); +/** + * regmap_field_alloc(): Allocate and initialise a register field + * in a register map. + * + * @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 should be freed by the + * user once its finished working with it using regmap_field_free(). + */ +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; +} +EXPORT_SYMBOL_GPL(regmap_field_alloc); + /** * regmap_reinit_cache(): Reinitialise the current register cache * @@ -1249,6 +1310,23 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_raw_write); +/** + * regmap_field_write(): Write a value to a single register field + * + * @field: Register field to write to + * @val: Value to be written + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ + +int regmap_field_write(struct regmap_field *field, unsigned int val) +{ + return regmap_update_bits(field->regmap, field->reg, + field->mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_field_write); + /* * regmap_bulk_write(): Write multiple registers to the device * @@ -1532,6 +1610,32 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, EXPORT_SYMBOL_GPL(regmap_raw_read); /** + * regmap_field_read(): Read a value to a single register field + * + * @field: Register field to read from + * @val: Pointer to store read value + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ + +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; +} +EXPORT_SYMBOL_GPL(regmap_field_read); + +/** * regmap_bulk_read(): Read multiple registers from the device * * @map: Register map to write to diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 02d84e2..557a54e 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -15,6 +15,8 @@ #include #include +#include +#include struct module; struct device; @@ -23,6 +25,7 @@ struct irq_domain; struct spi_device; struct regmap; struct regmap_range_cfg; +struct regmap_field; /* An enum of all the supported cache types */ enum regcache_type { @@ -412,6 +415,45 @@ bool regmap_reg_in_ranges(unsigned int reg, unsigned int nranges); /** + * Description of an register field + * + * @reg: Offset of the register within the regmap bank + * @lsb: lsb of the register field. + * @reg: msb of the register field. + */ +struct reg_field { + unsigned int reg; + unsigned int lsb; + unsigned int msb; +}; + +#define REG_FIELD(_reg, _lsb, _msb) { \ + .reg = _reg, \ + .lsb = _lsb, \ + .msb = _msb, \ + } + +struct regmap_field *regmap_field_alloc(struct regmap *regmap, + struct reg_field reg_field); + +struct regmap_field *devm_regmap_field_alloc(struct device *dev, + struct regmap *regmap, struct reg_field reg_field); + +static inline void regmap_field_free(struct regmap_field *field) +{ + kfree(field); +} + +static inline void devm_regmap_field_free(struct device *dev, + struct regmap_field *field) +{ + devm_kfree(dev, field); +} + +int regmap_field_read(struct regmap_field *field, unsigned int *val); +int regmap_field_write(struct regmap_field *field, unsigned int val); + +/** * Description of an IRQ for the generic regmap irq_chip. * * @reg_offset: Offset of the status/mask register within the bank