Merge tag 'regmap-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Mar 2024 18:01:21 +0000 (11:01 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Mar 2024 18:01:21 +0000 (11:01 -0700)
Pull regmap updates from Mark Brown:
 "Just two updates this time around, a rework of max_register handling
  which enables us to support devices with only one register better and
  a new test which will be used to validate use of some new SPI
  optimisations which will be coming in during this merge window"

* tag 'regmap-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: kunit: Add a test for ranges in combination with windows
  regmap: rework ->max_register handling

drivers/base/regmap/internal.h
drivers/base/regmap/regcache-flat.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-kunit.c
drivers/base/regmap/regmap.c
include/linux/regmap.h

index 583dd5d7d46bf3a5ad0ddd4d7dcd1d8bcc93be97..bcdb25bec77c0f3f993603cbf7673f33de346a4d 100644 (file)
@@ -93,6 +93,7 @@ struct regmap {
 #endif
 
        unsigned int max_register;
+       bool max_register_is_set;
        bool (*writeable_reg)(struct device *dev, unsigned int reg);
        bool (*readable_reg)(struct device *dev, unsigned int reg);
        bool (*volatile_reg)(struct device *dev, unsigned int reg);
index b7e4b2464102392a8dd8b8d9955be72de1c66301..9b17c77dec9d7ebbacd5bde16012d44bbae4c696 100644 (file)
@@ -23,7 +23,7 @@ static int regcache_flat_init(struct regmap *map)
        int i;
        unsigned int *cache;
 
-       if (!map || map->reg_stride_order < 0 || !map->max_register)
+       if (!map || map->reg_stride_order < 0 || !map->max_register_is_set)
                return -EINVAL;
 
        map->cache = kcalloc(regcache_flat_get_index(map, map->max_register)
index ac63a73ccdaaa23f119966c10f71f0bd28fb43a8..2e41cb12b8e28284d65ef5d0ee8949d970a2e69d 100644 (file)
@@ -187,8 +187,10 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
                        return 0;
        }
 
-       if (!map->max_register && map->num_reg_defaults_raw)
+       if (!map->max_register_is_set && map->num_reg_defaults_raw) {
                map->max_register = (map->num_reg_defaults_raw  - 1) * map->reg_stride;
+               map->max_register_is_set = true;
+       }
 
        if (map->cache_ops->init) {
                dev_dbg(map->dev, "Initializing %s cache\n",
index 0d957c5f1bcc987a585abaad9ed53623c33b4189..bb2ab6129f389d7d6feaac98fcf3851319ad7958 100644 (file)
@@ -1341,6 +1341,71 @@ static void raw_sync(struct kunit *test)
        regmap_exit(map);
 }
 
+static void raw_ranges(struct kunit *test)
+{
+       struct raw_test_types *t = (struct raw_test_types *)test->param_value;
+       struct regmap *map;
+       struct regmap_config config;
+       struct regmap_ram_data *data;
+       unsigned int val;
+       int i;
+
+       config = raw_regmap_config;
+       config.volatile_reg = test_range_all_volatile;
+       config.ranges = &test_range;
+       config.num_ranges = 1;
+       config.max_register = test_range.range_max;
+
+       map = gen_raw_regmap(&config, t, &data);
+       KUNIT_ASSERT_FALSE(test, IS_ERR(map));
+       if (IS_ERR(map))
+               return;
+
+       /* Reset the page to a non-zero value to trigger a change */
+       KUNIT_EXPECT_EQ(test, 0, regmap_write(map, test_range.selector_reg,
+                                             test_range.range_max));
+
+       /* Check we set the page and use the window for writes */
+       data->written[test_range.selector_reg] = false;
+       data->written[test_range.window_start] = false;
+       KUNIT_EXPECT_EQ(test, 0, regmap_write(map, test_range.range_min, 0));
+       KUNIT_EXPECT_TRUE(test, data->written[test_range.selector_reg]);
+       KUNIT_EXPECT_TRUE(test, data->written[test_range.window_start]);
+
+       data->written[test_range.selector_reg] = false;
+       data->written[test_range.window_start] = false;
+       KUNIT_EXPECT_EQ(test, 0, regmap_write(map,
+                                             test_range.range_min +
+                                             test_range.window_len,
+                                             0));
+       KUNIT_EXPECT_TRUE(test, data->written[test_range.selector_reg]);
+       KUNIT_EXPECT_TRUE(test, data->written[test_range.window_start]);
+
+       /* Same for reads */
+       data->written[test_range.selector_reg] = false;
+       data->read[test_range.window_start] = false;
+       KUNIT_EXPECT_EQ(test, 0, regmap_read(map, test_range.range_min, &val));
+       KUNIT_EXPECT_TRUE(test, data->written[test_range.selector_reg]);
+       KUNIT_EXPECT_TRUE(test, data->read[test_range.window_start]);
+
+       data->written[test_range.selector_reg] = false;
+       data->read[test_range.window_start] = false;
+       KUNIT_EXPECT_EQ(test, 0, regmap_read(map,
+                                            test_range.range_min +
+                                            test_range.window_len,
+                                            &val));
+       KUNIT_EXPECT_TRUE(test, data->written[test_range.selector_reg]);
+       KUNIT_EXPECT_TRUE(test, data->read[test_range.window_start]);
+
+       /* No physical access triggered in the virtual range */
+       for (i = test_range.range_min; i < test_range.range_max; i++) {
+               KUNIT_EXPECT_FALSE(test, data->read[i]);
+               KUNIT_EXPECT_FALSE(test, data->written[i]);
+       }
+
+       regmap_exit(map);
+}
+
 static struct kunit_case regmap_test_cases[] = {
        KUNIT_CASE_PARAM(basic_read_write, regcache_types_gen_params),
        KUNIT_CASE_PARAM(bulk_write, regcache_types_gen_params),
@@ -1368,6 +1433,7 @@ static struct kunit_case regmap_test_cases[] = {
        KUNIT_CASE_PARAM(raw_write, raw_test_types_gen_params),
        KUNIT_CASE_PARAM(raw_noinc_write, raw_test_types_gen_params),
        KUNIT_CASE_PARAM(raw_sync, raw_test_cache_types_gen_params),
+       KUNIT_CASE_PARAM(raw_ranges, raw_test_cache_types_gen_params),
        {}
 };
 
index 6db77d8e45f9249fe2bd379023aa7edcf2eaa2d7..5cb425f6f02d4bd1e4aa4f0e58d846a52896fdca 100644 (file)
@@ -89,7 +89,7 @@ EXPORT_SYMBOL_GPL(regmap_check_range_table);
 
 bool regmap_writeable(struct regmap *map, unsigned int reg)
 {
-       if (map->max_register && reg > map->max_register)
+       if (map->max_register_is_set && reg > map->max_register)
                return false;
 
        if (map->writeable_reg)
@@ -112,7 +112,7 @@ bool regmap_cached(struct regmap *map, unsigned int reg)
        if (!map->cache_ops)
                return false;
 
-       if (map->max_register && reg > map->max_register)
+       if (map->max_register_is_set && reg > map->max_register)
                return false;
 
        map->lock(map->lock_arg);
@@ -129,7 +129,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
        if (!map->reg_read)
                return false;
 
-       if (map->max_register && reg > map->max_register)
+       if (map->max_register_is_set && reg > map->max_register)
                return false;
 
        if (map->format.format_write)
@@ -787,6 +787,7 @@ struct regmap *__regmap_init(struct device *dev,
        map->bus = bus;
        map->bus_context = bus_context;
        map->max_register = config->max_register;
+       map->max_register_is_set = map->max_register ?: config->max_register_is_0;
        map->wr_table = config->wr_table;
        map->rd_table = config->rd_table;
        map->volatile_table = config->volatile_table;
@@ -1412,6 +1413,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
        regmap_debugfs_exit(map);
 
        map->max_register = config->max_register;
+       map->max_register_is_set = map->max_register ?: config->max_register_is_0;
        map->writeable_reg = config->writeable_reg;
        map->readable_reg = config->readable_reg;
        map->volatile_reg = config->volatile_reg;
@@ -3383,7 +3385,7 @@ EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
  */
 int regmap_get_max_register(struct regmap *map)
 {
-       return map->max_register ? map->max_register : -EINVAL;
+       return map->max_register_is_set ? map->max_register : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(regmap_get_max_register);
 
index c9182a47736ef883517ad571fb359f4f90d93d6d..b743241cfb7caa22da0e12098da3ea7dead08a9b 100644 (file)
@@ -332,6 +332,10 @@ typedef void (*regmap_unlock)(void *);
  * @io_port:     Support IO port accessors. Makes sense only when MMIO vs. IO port
  *               access can be distinguished.
  * @max_register: Optional, specifies the maximum valid register address.
+ * @max_register_is_0: Optional, specifies that zero value in @max_register
+ *                     should be taken into account. This is a workaround to
+ *                     apply handling of @max_register for regmap that contains
+ *                     only one register.
  * @wr_table:     Optional, points to a struct regmap_access_table specifying
  *                valid ranges for write access.
  * @rd_table:     As above, for read access.
@@ -422,6 +426,7 @@ struct regmap_config {
        bool io_port;
 
        unsigned int max_register;
+       bool max_register_is_0;
        const struct regmap_access_table *wr_table;
        const struct regmap_access_table *rd_table;
        const struct regmap_access_table *volatile_table;