From patchwork Thu Apr 17 23:06:27 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Max Schwarz X-Patchwork-Id: 4011861 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 1BE309F319 for ; Thu, 17 Apr 2014 23:10:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2322720270 for ; Thu, 17 Apr 2014 23:10:41 +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 312922026C for ; Thu, 17 Apr 2014 23:10:40 +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 1WavOf-00018U-8b; Thu, 17 Apr 2014 23:07:09 +0000 Received: from moutng.kundenserver.de ([212.227.126.130]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WavOa-00012V-MD for linux-arm-kernel@lists.infradead.org; Thu, 17 Apr 2014 23:07:07 +0000 Received: from typ.localnet (xdsl-89-0-94-55.netcologne.de [89.0.94.55]) by mrelayeu.kundenserver.de (node=mreue003) with ESMTP (Nemesis) id 0MLTC2-1WbTLu0Jyk-000byE; Fri, 18 Apr 2014 01:06:32 +0200 From: Max Schwarz To: Heiko =?ISO-8859-1?Q?St=FCbner?= Subject: Re: Rockchip RK3188 I2C driver Date: Fri, 18 Apr 2014 01:06:27 +0200 Message-ID: <15224827.56gI5cqpbK@typ> User-Agent: KMail/4.11.5 (Linux/3.11.0-19-generic; KDE/4.11.5; x86_64; ; ) In-Reply-To: <20140417183835.GG12304@sirena.org.uk> References: <3748421.ND1tAjvgKS@typ> <5059282.MitP6iZ8n1@typ> <20140417183835.GG12304@sirena.org.uk> MIME-Version: 1.0 X-Provags-ID: V02:K0:AqbcWlIOuhNPq4ogMkLIKhL+Lq1J9btB7M9QJmSOJKq ykO8AYxi+nWqpq3Es0NlAiJH9Gmo6oHlEdEPJQvmpmeZYCpnJQ s+Np7go6CzQmOe9oox/hfDmAhKtWdcxcV6YnR1gP8XXxq2u3Gk fBmhGZ1fxKKkYJBBIonHX3aQjKelm+1xyAA4oDAmBaNaq9cmaf t97KoEFC1/R6sJGanhzMmDlVwK6tnPUC586q15BL1NePtvHbA3 wTMInOQCw3K9UjHJXyeTfHojlXssUjACxrEaWQvoky1gspYu6q G6sjj2b2LW5eJybbj3hsA4BoObcs1u9V1nEcyJPlZbt801L3Q= = X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140417_160705_146284_81787D64 X-CRM114-Status: GOOD ( 22.52 ) X-Spam-Score: -0.0 (/) Cc: Mark Brown , Linux ARM Kernel 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.6 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 On Thursday 17 April 2014 at 19:38:35, Mark Brown wrote: > If you're only doing a few accesses then surely there's no meaningful > overhead from just writing what you want? So long as you don't cache > these registers regmap won't really get in the way. I think Heiko and I have been operating under the misconception that caching is somehow enabled by default - which is not the case. Thanks for clearing that up ;-) Heiko - I'm now sure that we are fine with the access pattern we employ right now (always set the mask bits for writes). We also don't need to mark registers as volatile (has no meaning without caching). In the meantime I developed a patch for regmap, but I think the better route would be to leave things as they are. If you guys still think "proper" regmap support is the way to go, the patch is attached. Cheers, Max From 5469f52601c8714cf20b2f4dd6e78481f9d17bf1 Mon Sep 17 00:00:00 2001 From: Max Schwarz Date: Fri, 18 Apr 2014 00:38:47 +0200 Subject: [PATCH] regmap: support for registers with write mask in upper half Rockchip RK3xxx SoCs have some registers which use the upper half as the write enable mask for the lower half. We support this by always writing ones to the upper half if requested by config->write_mask. This patch adds wrappers around the format_val and format_write hooks, which apply the write mask before calling the real formatting hooks. Signed-off-by: Max Schwarz --- drivers/base/regmap/internal.h | 7 +++++++ drivers/base/regmap/regmap.c | 41 ++++++++++++++++++++++++++++++++++++----- include/linux/regmap.h | 5 +++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 7d13269..8043519 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -34,9 +34,13 @@ struct regmap_format { size_t reg_bytes; size_t pad_bytes; size_t val_bytes; + + /* don't use directly, use regmap_format_write */ void (*format_write)(struct regmap *map, unsigned int reg, unsigned int val); void (*format_reg)(void *buf, unsigned int reg, unsigned int shift); + + /* don't use directly, use regmap_format_val */ void (*format_val)(void *buf, unsigned int val, unsigned int shift); unsigned int (*parse_val)(const void *buf); void (*parse_inplace)(void *buf); @@ -139,6 +143,9 @@ struct regmap { struct rb_root range_tree; void *selector_work_buf; /* Scratch buffer used for selector */ + + /* applied during write */ + unsigned int write_mask; }; struct regcache_ops { diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 63e30ef..95e5816 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -42,6 +42,28 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, static int _regmap_bus_raw_write(void *context, unsigned int reg, unsigned int val); +/* + * Some targets use the upper half of the register for write masking of the + * lower bits. To use regmap on those registers, we always have to set the + * upper bits to ones during write. + */ + +static void regmap_format_val(struct regmap *map, void *buf, unsigned int val, + unsigned int shift) +{ + val |= map->write_mask; + + return map->format.format_val(buf, val, shift); +} + +static void regmap_format_write(struct regmap *map, unsigned int reg, + unsigned int val) +{ + val |= map->write_mask; + + return map->format.format_write(map, reg, val); +} + bool regmap_reg_in_ranges(unsigned int reg, const struct regmap_range *ranges, unsigned int nranges) @@ -489,6 +511,15 @@ struct regmap *regmap_init(struct device *dev, map->read_flag_mask = bus->read_flag_mask; } + if (config->write_mask) { + /* that's only possible with an even number of bits */ + if (config->val_bits % 2) + goto err; + + /* generate a mask with the upper half of val_bits set to 1 */ + map->write_mask = -(1LL << (config->val_bits/2)); + } + if (!bus) { map->reg_read = config->reg_read; map->reg_write = config->reg_write; @@ -1272,7 +1303,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, return ret; } - map->format.format_write(map, reg, val); + regmap_format_write(map, reg, val); trace_regmap_hw_write_start(map->dev, reg, 1); @@ -1291,8 +1322,8 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg, WARN_ON(!map->bus || !map->format.format_val); - map->format.format_val(map->work_buf + map->format.reg_bytes - + map->format.pad_bytes, val, 0); + regmap_format_val(map, map->work_buf + map->format.reg_bytes + + map->format.pad_bytes, val, 0); return _regmap_raw_write(map, reg, map->work_buf + map->format.reg_bytes + @@ -1629,7 +1660,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map, trace_regmap_hw_write_start(map->dev, reg, 1); map->format.format_reg(u8, reg, map->reg_shift); u8 += reg_bytes + pad_bytes; - map->format.format_val(u8, val, 0); + regmap_format_val(map, u8, val, 0); u8 += val_bytes; } u8 = buf; @@ -2047,7 +2078,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, if (ret != 0) goto out; - map->format.format_val(val + (i * val_bytes), v, 0); + regmap_format_val(map, val + (i * val_bytes), v, 0); } } diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 85691b9..3eda5cf 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -146,6 +146,9 @@ typedef void (*regmap_unlock)(void *); * This field is a duplicate of a similar file in * 'struct regmap_bus' and serves exact same purpose. * Use it only for "no-bus" cases. + * @write_mask: The hardware uses the upper half of the register for + * write masking. If this is enabled, regmap will force all + * upper bits to ones during writes. * @max_register: Optional, specifies the maximum valid register index. * @wr_table: Optional, points to a struct regmap_access_table specifying * valid ranges for write access. @@ -203,6 +206,8 @@ struct regmap_config { bool fast_io; + bool write_mask; + unsigned int max_register; const struct regmap_access_table *wr_table; const struct regmap_access_table *rd_table; -- 1.8.3.2