aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Zabel <p.zabel@pengutronix.de>2013-02-14 11:39:08 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-02-14 11:40:28 -0500
commit878ec67b3ac528a2b6d44055f049cdbb9cfda30c (patch)
treee6907b938e9c77c84aed65f7a6f8b2d72f4eb0fd
parent836dc9e3fbbab0c30aa6e664417225f5c1fb1c39 (diff)
regmap: mmio: add register clock support
Some mmio devices have a dedicated interface clock that needs to be enabled to access their registers. This patch optionally enables a clock before accessing registers in the regmap_bus callbacks. I added (devm_)regmap_init_mmio_clk variants of the init functions that have an added clk_id string parameter. This is passed to clk_get to request the clock from the clk framework. Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--drivers/base/regmap/regmap-mmio.c79
-rw-r--r--include/linux/regmap.h47
2 files changed, 107 insertions, 19 deletions
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index f05fc74dd84a..98745dd77e8c 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -16,6 +16,7 @@
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18 18
19#include <linux/clk.h>
19#include <linux/err.h> 20#include <linux/err.h>
20#include <linux/init.h> 21#include <linux/init.h>
21#include <linux/io.h> 22#include <linux/io.h>
@@ -26,6 +27,7 @@
26struct regmap_mmio_context { 27struct regmap_mmio_context {
27 void __iomem *regs; 28 void __iomem *regs;
28 unsigned val_bytes; 29 unsigned val_bytes;
30 struct clk *clk;
29}; 31};
30 32
31static int regmap_mmio_gather_write(void *context, 33static int regmap_mmio_gather_write(void *context,
@@ -34,9 +36,16 @@ static int regmap_mmio_gather_write(void *context,
34{ 36{
35 struct regmap_mmio_context *ctx = context; 37 struct regmap_mmio_context *ctx = context;
36 u32 offset; 38 u32 offset;
39 int ret;
37 40
38 BUG_ON(reg_size != 4); 41 BUG_ON(reg_size != 4);
39 42
43 if (ctx->clk) {
44 ret = clk_enable(ctx->clk);
45 if (ret < 0)
46 return ret;
47 }
48
40 offset = *(u32 *)reg; 49 offset = *(u32 *)reg;
41 50
42 while (val_size) { 51 while (val_size) {
@@ -64,6 +73,9 @@ static int regmap_mmio_gather_write(void *context,
64 offset += ctx->val_bytes; 73 offset += ctx->val_bytes;
65 } 74 }
66 75
76 if (ctx->clk)
77 clk_disable(ctx->clk);
78
67 return 0; 79 return 0;
68} 80}
69 81
@@ -80,9 +92,16 @@ static int regmap_mmio_read(void *context,
80{ 92{
81 struct regmap_mmio_context *ctx = context; 93 struct regmap_mmio_context *ctx = context;
82 u32 offset; 94 u32 offset;
95 int ret;
83 96
84 BUG_ON(reg_size != 4); 97 BUG_ON(reg_size != 4);
85 98
99 if (ctx->clk) {
100 ret = clk_enable(ctx->clk);
101 if (ret < 0)
102 return ret;
103 }
104
86 offset = *(u32 *)reg; 105 offset = *(u32 *)reg;
87 106
88 while (val_size) { 107 while (val_size) {
@@ -110,11 +129,20 @@ static int regmap_mmio_read(void *context,
110 offset += ctx->val_bytes; 129 offset += ctx->val_bytes;
111 } 130 }
112 131
132 if (ctx->clk)
133 clk_disable(ctx->clk);
134
113 return 0; 135 return 0;
114} 136}
115 137
116static void regmap_mmio_free_context(void *context) 138static void regmap_mmio_free_context(void *context)
117{ 139{
140 struct regmap_mmio_context *ctx = context;
141
142 if (ctx->clk) {
143 clk_unprepare(ctx->clk);
144 clk_put(ctx->clk);
145 }
118 kfree(context); 146 kfree(context);
119} 147}
120 148
@@ -128,11 +156,14 @@ static struct regmap_bus regmap_mmio = {
128 .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 156 .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
129}; 157};
130 158
131static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs, 159static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
160 const char *clk_id,
161 void __iomem *regs,
132 const struct regmap_config *config) 162 const struct regmap_config *config)
133{ 163{
134 struct regmap_mmio_context *ctx; 164 struct regmap_mmio_context *ctx;
135 int min_stride; 165 int min_stride;
166 int ret;
136 167
137 if (config->reg_bits != 32) 168 if (config->reg_bits != 32)
138 return ERR_PTR(-EINVAL); 169 return ERR_PTR(-EINVAL);
@@ -179,37 +210,59 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
179 ctx->regs = regs; 210 ctx->regs = regs;
180 ctx->val_bytes = config->val_bits / 8; 211 ctx->val_bytes = config->val_bits / 8;
181 212
213 if (clk_id == NULL)
214 return ctx;
215
216 ctx->clk = clk_get(dev, clk_id);
217 if (IS_ERR(ctx->clk)) {
218 ret = PTR_ERR(ctx->clk);
219 goto err_free;
220 }
221
222 ret = clk_prepare(ctx->clk);
223 if (ret < 0) {
224 clk_put(ctx->clk);
225 goto err_free;
226 }
227
182 return ctx; 228 return ctx;
229
230err_free:
231 kfree(ctx);
232
233 return ERR_PTR(ret);
183} 234}
184 235
185/** 236/**
186 * regmap_init_mmio(): Initialise register map 237 * regmap_init_mmio_clk(): Initialise register map with register clock
187 * 238 *
188 * @dev: Device that will be interacted with 239 * @dev: Device that will be interacted with
240 * @clk_id: register clock consumer ID
189 * @regs: Pointer to memory-mapped IO region 241 * @regs: Pointer to memory-mapped IO region
190 * @config: Configuration for register map 242 * @config: Configuration for register map
191 * 243 *
192 * The return value will be an ERR_PTR() on error or a valid pointer to 244 * The return value will be an ERR_PTR() on error or a valid pointer to
193 * a struct regmap. 245 * a struct regmap.
194 */ 246 */
195struct regmap *regmap_init_mmio(struct device *dev, 247struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
196 void __iomem *regs, 248 void __iomem *regs,
197 const struct regmap_config *config) 249 const struct regmap_config *config)
198{ 250{
199 struct regmap_mmio_context *ctx; 251 struct regmap_mmio_context *ctx;
200 252
201 ctx = regmap_mmio_gen_context(regs, config); 253 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
202 if (IS_ERR(ctx)) 254 if (IS_ERR(ctx))
203 return ERR_CAST(ctx); 255 return ERR_CAST(ctx);
204 256
205 return regmap_init(dev, &regmap_mmio, ctx, config); 257 return regmap_init(dev, &regmap_mmio, ctx, config);
206} 258}
207EXPORT_SYMBOL_GPL(regmap_init_mmio); 259EXPORT_SYMBOL_GPL(regmap_init_mmio_clk);
208 260
209/** 261/**
210 * devm_regmap_init_mmio(): Initialise managed register map 262 * devm_regmap_init_mmio_clk(): Initialise managed register map with clock
211 * 263 *
212 * @dev: Device that will be interacted with 264 * @dev: Device that will be interacted with
265 * @clk_id: register clock consumer ID
213 * @regs: Pointer to memory-mapped IO region 266 * @regs: Pointer to memory-mapped IO region
214 * @config: Configuration for register map 267 * @config: Configuration for register map
215 * 268 *
@@ -217,18 +270,18 @@ EXPORT_SYMBOL_GPL(regmap_init_mmio);
217 * to a struct regmap. The regmap will be automatically freed by the 270 * to a struct regmap. The regmap will be automatically freed by the
218 * device management code. 271 * device management code.
219 */ 272 */
220struct regmap *devm_regmap_init_mmio(struct device *dev, 273struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
221 void __iomem *regs, 274 void __iomem *regs,
222 const struct regmap_config *config) 275 const struct regmap_config *config)
223{ 276{
224 struct regmap_mmio_context *ctx; 277 struct regmap_mmio_context *ctx;
225 278
226 ctx = regmap_mmio_gen_context(regs, config); 279 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
227 if (IS_ERR(ctx)) 280 if (IS_ERR(ctx))
228 return ERR_CAST(ctx); 281 return ERR_CAST(ctx);
229 282
230 return devm_regmap_init(dev, &regmap_mmio, ctx, config); 283 return devm_regmap_init(dev, &regmap_mmio, ctx, config);
231} 284}
232EXPORT_SYMBOL_GPL(devm_regmap_init_mmio); 285EXPORT_SYMBOL_GPL(devm_regmap_init_mmio_clk);
233 286
234MODULE_LICENSE("GPL v2"); 287MODULE_LICENSE("GPL v2");
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index b7e95bf942c9..f0480a3297e4 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -285,9 +285,9 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c,
285 const struct regmap_config *config); 285 const struct regmap_config *config);
286struct regmap *regmap_init_spi(struct spi_device *dev, 286struct regmap *regmap_init_spi(struct spi_device *dev,
287 const struct regmap_config *config); 287 const struct regmap_config *config);
288struct regmap *regmap_init_mmio(struct device *dev, 288struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
289 void __iomem *regs, 289 void __iomem *regs,
290 const struct regmap_config *config); 290 const struct regmap_config *config);
291 291
292struct regmap *devm_regmap_init(struct device *dev, 292struct regmap *devm_regmap_init(struct device *dev,
293 const struct regmap_bus *bus, 293 const struct regmap_bus *bus,
@@ -297,9 +297,44 @@ struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
297 const struct regmap_config *config); 297 const struct regmap_config *config);
298struct regmap *devm_regmap_init_spi(struct spi_device *dev, 298struct regmap *devm_regmap_init_spi(struct spi_device *dev,
299 const struct regmap_config *config); 299 const struct regmap_config *config);
300struct regmap *devm_regmap_init_mmio(struct device *dev, 300struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
301 void __iomem *regs, 301 void __iomem *regs,
302 const struct regmap_config *config); 302 const struct regmap_config *config);
303
304/**
305 * regmap_init_mmio(): Initialise register map
306 *
307 * @dev: Device that will be interacted with
308 * @regs: Pointer to memory-mapped IO region
309 * @config: Configuration for register map
310 *
311 * The return value will be an ERR_PTR() on error or a valid pointer to
312 * a struct regmap.
313 */
314static inline struct regmap *regmap_init_mmio(struct device *dev,
315 void __iomem *regs,
316 const struct regmap_config *config)
317{
318 return regmap_init_mmio_clk(dev, NULL, regs, config);
319}
320
321/**
322 * devm_regmap_init_mmio(): Initialise managed register map
323 *
324 * @dev: Device that will be interacted with
325 * @regs: Pointer to memory-mapped IO region
326 * @config: Configuration for register map
327 *
328 * The return value will be an ERR_PTR() on error or a valid pointer
329 * to a struct regmap. The regmap will be automatically freed by the
330 * device management code.
331 */
332static inline struct regmap *devm_regmap_init_mmio(struct device *dev,
333 void __iomem *regs,
334 const struct regmap_config *config)
335{
336 return devm_regmap_init_mmio_clk(dev, NULL, regs, config);
337}
303 338
304void regmap_exit(struct regmap *map); 339void regmap_exit(struct regmap *map);
305int regmap_reinit_cache(struct regmap *map, 340int regmap_reinit_cache(struct regmap *map,