diff options
author | Davide Ciminaghi <ciminaghi@gnudd.com> | 2012-11-20 09:20:30 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-11-20 21:10:31 -0500 |
commit | 76aad392f75e6ce5be3f106554e16f7ff96543e5 (patch) | |
tree | 00d1ef2dad497331dca8860e7ecc9474d0bab7b5 | |
parent | 3afa24f7ad0a1ab5478f1e9a6c4df1acf52171d1 (diff) |
regmap: introduce tables for readable/writeable/volatile/precious checks
Many of the regmap enabled drivers implementing one or more of the
readable, writeable, volatile and precious methods use the same code
pattern:
return ((reg >= X && reg <= Y) || (reg >= W && reg <= Z) || ...)
Switch to a data driven approach, using tables to describe
readable/writeable/volatile and precious registers ranges instead.
The table based check can still be overridden by passing the usual function
pointers via struct regmap_config.
Signed-off-by: Davide Ciminaghi <ciminaghi@gnudd.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | drivers/base/regmap/internal.h | 4 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 46 | ||||
-rw-r--r-- | include/linux/regmap.h | 83 |
3 files changed, 122 insertions, 11 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 2cd01b57b1c4..288e135fd5f8 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -55,6 +55,10 @@ struct regmap { | |||
55 | bool (*readable_reg)(struct device *dev, unsigned int reg); | 55 | bool (*readable_reg)(struct device *dev, unsigned int reg); |
56 | bool (*volatile_reg)(struct device *dev, unsigned int reg); | 56 | bool (*volatile_reg)(struct device *dev, unsigned int reg); |
57 | bool (*precious_reg)(struct device *dev, unsigned int reg); | 57 | bool (*precious_reg)(struct device *dev, unsigned int reg); |
58 | const struct regmap_access_table *wr_table; | ||
59 | const struct regmap_access_table *rd_table; | ||
60 | const struct regmap_access_table *volatile_table; | ||
61 | const struct regmap_access_table *precious_table; | ||
58 | 62 | ||
59 | u8 read_flag_mask; | 63 | u8 read_flag_mask; |
60 | u8 write_flag_mask; | 64 | u8 write_flag_mask; |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 64eb8350a074..96f7e8523ee8 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -34,6 +34,36 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, | |||
34 | unsigned int mask, unsigned int val, | 34 | unsigned int mask, unsigned int val, |
35 | bool *change); | 35 | bool *change); |
36 | 36 | ||
37 | bool regmap_reg_in_ranges(unsigned int reg, | ||
38 | const struct regmap_range *ranges, | ||
39 | unsigned int nranges) | ||
40 | { | ||
41 | const struct regmap_range *r; | ||
42 | int i; | ||
43 | |||
44 | for (i = 0, r = ranges; i < nranges; i++, r++) | ||
45 | if (regmap_reg_in_range(reg, r)) | ||
46 | return true; | ||
47 | return false; | ||
48 | } | ||
49 | EXPORT_SYMBOL_GPL(regmap_reg_in_ranges); | ||
50 | |||
51 | static bool _regmap_check_range_table(struct regmap *map, | ||
52 | unsigned int reg, | ||
53 | const struct regmap_access_table *table) | ||
54 | { | ||
55 | /* Check "no ranges" first */ | ||
56 | if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges)) | ||
57 | return false; | ||
58 | |||
59 | /* In case zero "yes ranges" are supplied, any reg is OK */ | ||
60 | if (!table->n_yes_ranges) | ||
61 | return true; | ||
62 | |||
63 | return regmap_reg_in_ranges(reg, table->yes_ranges, | ||
64 | table->n_yes_ranges); | ||
65 | } | ||
66 | |||
37 | bool regmap_writeable(struct regmap *map, unsigned int reg) | 67 | bool regmap_writeable(struct regmap *map, unsigned int reg) |
38 | { | 68 | { |
39 | if (map->max_register && reg > map->max_register) | 69 | if (map->max_register && reg > map->max_register) |
@@ -42,6 +72,9 @@ bool regmap_writeable(struct regmap *map, unsigned int reg) | |||
42 | if (map->writeable_reg) | 72 | if (map->writeable_reg) |
43 | return map->writeable_reg(map->dev, reg); | 73 | return map->writeable_reg(map->dev, reg); |
44 | 74 | ||
75 | if (map->wr_table) | ||
76 | return _regmap_check_range_table(map, reg, map->wr_table); | ||
77 | |||
45 | return true; | 78 | return true; |
46 | } | 79 | } |
47 | 80 | ||
@@ -56,6 +89,9 @@ bool regmap_readable(struct regmap *map, unsigned int reg) | |||
56 | if (map->readable_reg) | 89 | if (map->readable_reg) |
57 | return map->readable_reg(map->dev, reg); | 90 | return map->readable_reg(map->dev, reg); |
58 | 91 | ||
92 | if (map->rd_table) | ||
93 | return _regmap_check_range_table(map, reg, map->rd_table); | ||
94 | |||
59 | return true; | 95 | return true; |
60 | } | 96 | } |
61 | 97 | ||
@@ -67,6 +103,9 @@ bool regmap_volatile(struct regmap *map, unsigned int reg) | |||
67 | if (map->volatile_reg) | 103 | if (map->volatile_reg) |
68 | return map->volatile_reg(map->dev, reg); | 104 | return map->volatile_reg(map->dev, reg); |
69 | 105 | ||
106 | if (map->volatile_table) | ||
107 | return _regmap_check_range_table(map, reg, map->volatile_table); | ||
108 | |||
70 | return true; | 109 | return true; |
71 | } | 110 | } |
72 | 111 | ||
@@ -78,6 +117,9 @@ bool regmap_precious(struct regmap *map, unsigned int reg) | |||
78 | if (map->precious_reg) | 117 | if (map->precious_reg) |
79 | return map->precious_reg(map->dev, reg); | 118 | return map->precious_reg(map->dev, reg); |
80 | 119 | ||
120 | if (map->precious_table) | ||
121 | return _regmap_check_range_table(map, reg, map->precious_table); | ||
122 | |||
81 | return false; | 123 | return false; |
82 | } | 124 | } |
83 | 125 | ||
@@ -370,6 +412,10 @@ struct regmap *regmap_init(struct device *dev, | |||
370 | map->bus = bus; | 412 | map->bus = bus; |
371 | map->bus_context = bus_context; | 413 | map->bus_context = bus_context; |
372 | map->max_register = config->max_register; | 414 | map->max_register = config->max_register; |
415 | map->wr_table = config->wr_table; | ||
416 | map->rd_table = config->rd_table; | ||
417 | map->volatile_table = config->volatile_table; | ||
418 | map->precious_table = config->precious_table; | ||
373 | map->writeable_reg = config->writeable_reg; | 419 | map->writeable_reg = config->writeable_reg; |
374 | map->readable_reg = config->readable_reg; | 420 | map->readable_reg = config->readable_reg; |
375 | map->volatile_reg = config->volatile_reg; | 421 | map->volatile_reg = config->volatile_reg; |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 0e819e3cebce..3bdb1f9a5b43 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
@@ -53,6 +53,36 @@ enum regmap_endian { | |||
53 | REGMAP_ENDIAN_NATIVE, | 53 | REGMAP_ENDIAN_NATIVE, |
54 | }; | 54 | }; |
55 | 55 | ||
56 | /** | ||
57 | * A register range, used for access related checks | ||
58 | * (readable/writeable/volatile/precious checks) | ||
59 | * | ||
60 | * @range_min: address of first register | ||
61 | * @range_max: address of last register | ||
62 | */ | ||
63 | struct regmap_range { | ||
64 | unsigned int range_min; | ||
65 | unsigned int range_max; | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * A table of ranges including some yes ranges and some no ranges. | ||
70 | * If a register belongs to a no_range, the corresponding check function | ||
71 | * will return false. If a register belongs to a yes range, the corresponding | ||
72 | * check function will return true. "no_ranges" are searched first. | ||
73 | * | ||
74 | * @yes_ranges : pointer to an array of regmap ranges used as "yes ranges" | ||
75 | * @n_yes_ranges: size of the above array | ||
76 | * @no_ranges: pointer to an array of regmap ranges used as "no ranges" | ||
77 | * @n_no_ranges: size of the above array | ||
78 | */ | ||
79 | struct regmap_access_table { | ||
80 | const struct regmap_range *yes_ranges; | ||
81 | unsigned int n_yes_ranges; | ||
82 | const struct regmap_range *no_ranges; | ||
83 | unsigned int n_no_ranges; | ||
84 | }; | ||
85 | |||
56 | typedef void (*regmap_lock)(void *); | 86 | typedef void (*regmap_lock)(void *); |
57 | typedef void (*regmap_unlock)(void *); | 87 | typedef void (*regmap_unlock)(void *); |
58 | 88 | ||
@@ -70,22 +100,39 @@ typedef void (*regmap_unlock)(void *); | |||
70 | * @val_bits: Number of bits in a register value, mandatory. | 100 | * @val_bits: Number of bits in a register value, mandatory. |
71 | * | 101 | * |
72 | * @writeable_reg: Optional callback returning true if the register | 102 | * @writeable_reg: Optional callback returning true if the register |
73 | * can be written to. | 103 | * can be written to. If this field is NULL but wr_table |
104 | * (see below) is not, the check is performed on such table | ||
105 | * (a register is writeable if it belongs to one of the ranges | ||
106 | * specified by wr_table). | ||
74 | * @readable_reg: Optional callback returning true if the register | 107 | * @readable_reg: Optional callback returning true if the register |
75 | * can be read from. | 108 | * can be read from. If this field is NULL but rd_table |
109 | * (see below) is not, the check is performed on such table | ||
110 | * (a register is readable if it belongs to one of the ranges | ||
111 | * specified by rd_table). | ||
76 | * @volatile_reg: Optional callback returning true if the register | 112 | * @volatile_reg: Optional callback returning true if the register |
77 | * value can't be cached. | 113 | * value can't be cached. If this field is NULL but |
114 | * volatile_table (see below) is not, the check is performed on | ||
115 | * such table (a register is volatile if it belongs to one of | ||
116 | * the ranges specified by volatile_table). | ||
78 | * @precious_reg: Optional callback returning true if the rgister | 117 | * @precious_reg: Optional callback returning true if the rgister |
79 | * should not be read outside of a call from the driver | 118 | * should not be read outside of a call from the driver |
80 | * (eg, a clear on read interrupt status register). | 119 | * (eg, a clear on read interrupt status register). If this |
81 | * @lock: Optional lock callback (overrides regmap's default lock | 120 | * field is NULL but precious_table (see below) is not, the |
82 | * function, based on spinlock or mutex). | 121 | * check is performed on such table (a register is precious if |
83 | * @unlock: As above for unlocking. | 122 | * it belongs to one of the ranges specified by precious_table). |
84 | * @lock_arg: this field is passed as the only argument of lock/unlock | 123 | * @lock: Optional lock callback (overrides regmap's default lock |
85 | * functions (ignored in case regular lock/unlock functions | 124 | * function, based on spinlock or mutex). |
86 | * are not overridden). | 125 | * @unlock: As above for unlocking. |
126 | * @lock_arg: this field is passed as the only argument of lock/unlock | ||
127 | * functions (ignored in case regular lock/unlock functions | ||
128 | * are not overridden). | ||
87 | * | 129 | * |
88 | * @max_register: Optional, specifies the maximum valid register index. | 130 | * @max_register: Optional, specifies the maximum valid register index. |
131 | * @wr_table: Optional, points to a struct regmap_access_table specifying | ||
132 | * valid ranges for write access. | ||
133 | * @rd_table: As above, for read access. | ||
134 | * @volatile_table: As above, for volatile registers. | ||
135 | * @precious_table: As above, for precious registers. | ||
89 | * @reg_defaults: Power on reset values for registers (for use with | 136 | * @reg_defaults: Power on reset values for registers (for use with |
90 | * register cache support). | 137 | * register cache support). |
91 | * @num_reg_defaults: Number of elements in reg_defaults. | 138 | * @num_reg_defaults: Number of elements in reg_defaults. |
@@ -130,6 +177,10 @@ struct regmap_config { | |||
130 | void *lock_arg; | 177 | void *lock_arg; |
131 | 178 | ||
132 | unsigned int max_register; | 179 | unsigned int max_register; |
180 | const struct regmap_access_table *wr_table; | ||
181 | const struct regmap_access_table *rd_table; | ||
182 | const struct regmap_access_table *volatile_table; | ||
183 | const struct regmap_access_table *precious_table; | ||
133 | const struct reg_default *reg_defaults; | 184 | const struct reg_default *reg_defaults; |
134 | unsigned int num_reg_defaults; | 185 | unsigned int num_reg_defaults; |
135 | enum regcache_type cache_type; | 186 | enum regcache_type cache_type; |
@@ -280,6 +331,16 @@ void regcache_mark_dirty(struct regmap *map); | |||
280 | int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | 331 | int regmap_register_patch(struct regmap *map, const struct reg_default *regs, |
281 | int num_regs); | 332 | int num_regs); |
282 | 333 | ||
334 | static inline bool regmap_reg_in_range(unsigned int reg, | ||
335 | const struct regmap_range *range) | ||
336 | { | ||
337 | return reg >= range->range_min && reg <= range->range_max; | ||
338 | } | ||
339 | |||
340 | bool regmap_reg_in_ranges(unsigned int reg, | ||
341 | const struct regmap_range *ranges, | ||
342 | unsigned int nranges); | ||
343 | |||
283 | /** | 344 | /** |
284 | * Description of an IRQ for the generic regmap irq_chip. | 345 | * Description of an IRQ for the generic regmap irq_chip. |
285 | * | 346 | * |