From patchwork Wed Aug 12 10:12:37 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Markus Pargmann X-Patchwork-Id: 7000031 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.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 7C8E7C05AC for ; Wed, 12 Aug 2015 10:23:39 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7DB86204DE for ; Wed, 12 Aug 2015 10:23:38 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 865A4205BB for ; Wed, 12 Aug 2015 10:23:37 +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 1ZPT8h-0005Zd-9Z; Wed, 12 Aug 2015 10:20:07 +0000 Received: from metis.ext.pengutronix.de ([92.198.50.35]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZPT3E-0007co-MV for linux-arm-kernel@lists.infradead.org; Wed, 12 Aug 2015 10:14:30 +0000 Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from ) id 1ZPT2O-0008Um-6S; Wed, 12 Aug 2015 12:13:36 +0200 Received: from mpa by dude.hi.pengutronix.de with local (Exim 4.86) (envelope-from ) id 1ZPT2N-0001EO-M1; Wed, 12 Aug 2015 12:13:35 +0200 From: Markus Pargmann To: Mark Brown , Jonathan Cameron Subject: [PATCH 12/20] regmap: Introduce max_raw_io for regmap_bulk_read/write Date: Wed, 12 Aug 2015 12:12:37 +0200 Message-Id: <1439374365-20623-13-git-send-email-mpa@pengutronix.de> X-Mailer: git-send-email 2.4.6 In-Reply-To: <1439374365-20623-1-git-send-email-mpa@pengutronix.de> References: <1439374365-20623-1-git-send-email-mpa@pengutronix.de> X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: mpa@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-arm-kernel@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150812_031429_040958_BA4D6E1E X-CRM114-Status: GOOD ( 21.33 ) X-Spam-Score: -2.8 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, kernel@pengutronix.de, Srinivas Pandruvada , Markus Pargmann , linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, 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 There are some busses which have a limit on the maximum number of bytes that can be send/received. An example for this is I2C_FUNC_SMBUS_I2C_BLOCK which does not support any reads/writes of more than 32 bytes. The regmap_bulk operations should still be able to utilize the full 32 bytes. Signed-off-by: Markus Pargmann --- drivers/base/regmap/internal.h | 3 ++ drivers/base/regmap/regmap.c | 82 ++++++++++++++++++++++++++++++++---------- include/linux/regmap.h | 2 ++ 3 files changed, 69 insertions(+), 18 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index b2b2849fc6d3..f94041658397 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -144,6 +144,9 @@ struct regmap { /* if set, the device supports multi write mode */ bool can_multi_write; + /* if set, raw reads/writes are limited to this size */ + size_t max_raw_io; + struct rb_root range_tree; void *selector_work_buf; /* Scratch buffer used for selector */ }; diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 3b663350c573..6ad4ca849055 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -574,6 +574,7 @@ struct regmap *regmap_init(struct device *dev, else map->reg_stride = 1; map->use_single_rw = config->use_single_rw || !bus->read || !bus->write; + map->max_raw_io = bus->max_raw_io; map->can_multi_write = config->can_multi_write; map->dev = dev; map->bus = bus; @@ -1675,6 +1676,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, { int ret = 0, i; size_t val_bytes = map->format.val_bytes; + size_t total_bytes = val_bytes * val_count; if (map->bus && !map->format.parse_inplace) return -EINVAL; @@ -1715,20 +1717,39 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, } out: map->unlock(map->lock_arg); - } else if (map->use_single_rw) { + } else if (map->use_single_rw || + (map->max_raw_io && map->max_raw_io < total_bytes)) { /* * We need to handle bus writes separate to support val_bytes * that are not powers of 2. */ + int reg_stride = map->reg_stride; + size_t write_bytes = val_bytes; + size_t write_count = val_count; + + if (!map->use_single_rw) { + write_count = total_bytes / map->max_raw_io; + write_bytes = map->max_raw_io; + reg_stride *= write_bytes / val_bytes; + } + map->lock(map->lock_arg); + /* Write as many bytes as possible with maximum write size */ for (i = 0; i < val_count; i++) { ret = _regmap_raw_write(map, - reg + (i * map->reg_stride), - val + (i * val_bytes), - val_bytes); + reg + (i * reg_stride), + val + (i * write_bytes), + write_bytes); if (ret) break; } + + /* Write remaining bytes */ + if (!ret && write_bytes * i < total_bytes) { + ret = _regmap_raw_write(map, reg + (i * reg_stride), + val + (i * write_bytes), + total_bytes - i * write_bytes); + } map->unlock(map->lock_arg); } else { void *wval; @@ -2336,24 +2357,49 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, return -EINVAL; if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) { - /* - * Some devices does not support bulk read, for - * them we have a series of single read operations. - */ - if (map->use_single_rw) { - for (i = 0; i < val_count; i++) { - ret = regmap_raw_read(map, - reg + (i * map->reg_stride), - val + (i * val_bytes), - val_bytes); - if (ret != 0) - return ret; - } - } else { + size_t total_size = val_bytes * val_count; + + if (!map->use_single_rw && + (!map->max_raw_io || map->max_raw_io > total_size)) { ret = regmap_raw_read(map, reg, val, val_bytes * val_count); if (ret != 0) return ret; + } else { + /* + * Some devices do not support bulk read or do not + * support large bulk reads, for them we have a series + * of read operations. + */ + int reg_stride = map->reg_stride; + size_t read_bytes = val_bytes; + size_t read_count = val_count; + + if (!map->use_single_rw) { + read_count = total_size / map->max_raw_io; + read_bytes = map->max_raw_io; + reg_stride *= read_bytes / val_bytes; + } + + /* Read bytes that fit into the max_raw_io size */ + for (i = 0; i < read_count; i++) { + ret = regmap_raw_read(map, + reg + (i * reg_stride), + val + (i * read_bytes), + read_bytes); + if (ret != 0) + return ret; + } + + /* Read remaining bytes */ + if (read_bytes * i < total_size) { + ret = regmap_raw_read(map, + reg + (i * reg_stride), + val + (i * read_bytes), + total_size - i * read_bytes); + if (ret != 0) + return ret; + } } for (i = 0; i < val_count * val_bytes; i += val_bytes) diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 6ff83c9ddb45..2cb62d141761 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -310,6 +310,7 @@ typedef void (*regmap_hw_free_context)(void *context); * @val_format_endian_default: Default endianness for formatted register * values. Used when the regmap_config specifies DEFAULT. If this is * DEFAULT, BIG is assumed. + * @max_raw_io: Max raw read/write size that can be used on the bus. */ struct regmap_bus { bool fast_io; @@ -324,6 +325,7 @@ struct regmap_bus { u8 read_flag_mask; enum regmap_endian reg_format_endian_default; enum regmap_endian val_format_endian_default; + size_t max_raw_io; }; struct regmap *regmap_init(struct device *dev,