aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2013-02-14 12:11:08 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-02-14 12:11:08 -0500
commita31f68497e07f5fec7155bc07dc633fc6eaa0adb (patch)
tree9324a5f1327a5a9dc0548dd21d5dcb569149a834 /drivers/base
parent5dea215028686a67e815c32a54dc89fb3467ab05 (diff)
parent878ec67b3ac528a2b6d44055f049cdbb9cfda30c (diff)
Merge remote-tracking branch 'regmap/topic/mmio' into regmap-next
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/regmap-mmio.c79
1 files changed, 66 insertions, 13 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");