aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap/regmap-mmio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/regmap/regmap-mmio.c')
-rw-r--r--drivers/base/regmap/regmap-mmio.c259
1 files changed, 139 insertions, 120 deletions
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index eea51569f0eb..7526906ca080 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -25,26 +25,14 @@
25 25
26struct regmap_mmio_context { 26struct regmap_mmio_context {
27 void __iomem *regs; 27 void __iomem *regs;
28 unsigned reg_bytes;
29 unsigned val_bytes; 28 unsigned val_bytes;
30 unsigned pad_bytes;
31 struct clk *clk; 29 struct clk *clk;
32};
33 30
34static inline void regmap_mmio_regsize_check(size_t reg_size) 31 void (*reg_write)(struct regmap_mmio_context *ctx,
35{ 32 unsigned int reg, unsigned int val);
36 switch (reg_size) { 33 unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
37 case 1: 34 unsigned int reg);
38 case 2: 35};
39 case 4:
40#ifdef CONFIG_64BIT
41 case 8:
42#endif
43 break;
44 default:
45 BUG();
46 }
47}
48 36
49static int regmap_mmio_regbits_check(size_t reg_bits) 37static int regmap_mmio_regbits_check(size_t reg_bits)
50{ 38{
@@ -88,72 +76,62 @@ static int regmap_mmio_get_min_stride(size_t val_bits)
88 return min_stride; 76 return min_stride;
89} 77}
90 78
91static inline void regmap_mmio_count_check(size_t count, u32 offset) 79static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
80 unsigned int reg,
81 unsigned int val)
82{
83 writeb(val, ctx->regs + reg);
84}
85
86static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
87 unsigned int reg,
88 unsigned int val)
92{ 89{
93 BUG_ON(count <= offset); 90 writew(val, ctx->regs + reg);
94} 91}
95 92
96static inline unsigned int 93static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
97regmap_mmio_get_offset(const void *reg, size_t reg_size) 94 unsigned int reg,
95 unsigned int val)
98{ 96{
99 switch (reg_size) { 97 iowrite16be(val, ctx->regs + reg);
100 case 1: 98}
101 return *(u8 *)reg; 99
102 case 2: 100static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
103 return *(u16 *)reg; 101 unsigned int reg,
104 case 4: 102 unsigned int val)
105 return *(u32 *)reg; 103{
104 writel(val, ctx->regs + reg);
105}
106
107static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
108 unsigned int reg,
109 unsigned int val)
110{
111 iowrite32be(val, ctx->regs + reg);
112}
113
106#ifdef CONFIG_64BIT 114#ifdef CONFIG_64BIT
107 case 8: 115static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
108 return *(u64 *)reg; 116 unsigned int reg,
109#endif 117 unsigned int val)
110 default: 118{
111 BUG(); 119 writeq(val, ctx->regs + reg);
112 }
113} 120}
121#endif
114 122
115static int regmap_mmio_gather_write(void *context, 123static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
116 const void *reg, size_t reg_size,
117 const void *val, size_t val_size)
118{ 124{
119 struct regmap_mmio_context *ctx = context; 125 struct regmap_mmio_context *ctx = context;
120 unsigned int offset;
121 int ret; 126 int ret;
122 127
123 regmap_mmio_regsize_check(reg_size);
124
125 if (!IS_ERR(ctx->clk)) { 128 if (!IS_ERR(ctx->clk)) {
126 ret = clk_enable(ctx->clk); 129 ret = clk_enable(ctx->clk);
127 if (ret < 0) 130 if (ret < 0)
128 return ret; 131 return ret;
129 } 132 }
130 133
131 offset = regmap_mmio_get_offset(reg, reg_size); 134 ctx->reg_write(ctx, reg, val);
132
133 while (val_size) {
134 switch (ctx->val_bytes) {
135 case 1:
136 writeb(*(u8 *)val, ctx->regs + offset);
137 break;
138 case 2:
139 writew(*(u16 *)val, ctx->regs + offset);
140 break;
141 case 4:
142 writel(*(u32 *)val, ctx->regs + offset);
143 break;
144#ifdef CONFIG_64BIT
145 case 8:
146 writeq(*(u64 *)val, ctx->regs + offset);
147 break;
148#endif
149 default:
150 /* Should be caught by regmap_mmio_check_config */
151 BUG();
152 }
153 val_size -= ctx->val_bytes;
154 val += ctx->val_bytes;
155 offset += ctx->val_bytes;
156 }
157 135
158 if (!IS_ERR(ctx->clk)) 136 if (!IS_ERR(ctx->clk))
159 clk_disable(ctx->clk); 137 clk_disable(ctx->clk);
@@ -161,59 +139,56 @@ static int regmap_mmio_gather_write(void *context,
161 return 0; 139 return 0;
162} 140}
163 141
164static int regmap_mmio_write(void *context, const void *data, size_t count) 142static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
143 unsigned int reg)
165{ 144{
166 struct regmap_mmio_context *ctx = context; 145 return readb(ctx->regs + reg);
167 unsigned int offset = ctx->reg_bytes + ctx->pad_bytes; 146}
147
148static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
149 unsigned int reg)
150{
151 return readw(ctx->regs + reg);
152}
153
154static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
155 unsigned int reg)
156{
157 return ioread16be(ctx->regs + reg);
158}
159
160static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
161 unsigned int reg)
162{
163 return readl(ctx->regs + reg);
164}
168 165
169 regmap_mmio_count_check(count, offset); 166static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
167 unsigned int reg)
168{
169 return ioread32be(ctx->regs + reg);
170}
170 171
171 return regmap_mmio_gather_write(context, data, ctx->reg_bytes, 172#ifdef CONFIG_64BIT
172 data + offset, count - offset); 173static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
174 unsigned int reg)
175{
176 return readq(ctx->regs + reg);
173} 177}
178#endif
174 179
175static int regmap_mmio_read(void *context, 180static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
176 const void *reg, size_t reg_size,
177 void *val, size_t val_size)
178{ 181{
179 struct regmap_mmio_context *ctx = context; 182 struct regmap_mmio_context *ctx = context;
180 unsigned int offset;
181 int ret; 183 int ret;
182 184
183 regmap_mmio_regsize_check(reg_size);
184
185 if (!IS_ERR(ctx->clk)) { 185 if (!IS_ERR(ctx->clk)) {
186 ret = clk_enable(ctx->clk); 186 ret = clk_enable(ctx->clk);
187 if (ret < 0) 187 if (ret < 0)
188 return ret; 188 return ret;
189 } 189 }
190 190
191 offset = regmap_mmio_get_offset(reg, reg_size); 191 *val = ctx->reg_read(ctx, reg);
192
193 while (val_size) {
194 switch (ctx->val_bytes) {
195 case 1:
196 *(u8 *)val = readb(ctx->regs + offset);
197 break;
198 case 2:
199 *(u16 *)val = readw(ctx->regs + offset);
200 break;
201 case 4:
202 *(u32 *)val = readl(ctx->regs + offset);
203 break;
204#ifdef CONFIG_64BIT
205 case 8:
206 *(u64 *)val = readq(ctx->regs + offset);
207 break;
208#endif
209 default:
210 /* Should be caught by regmap_mmio_check_config */
211 BUG();
212 }
213 val_size -= ctx->val_bytes;
214 val += ctx->val_bytes;
215 offset += ctx->val_bytes;
216 }
217 192
218 if (!IS_ERR(ctx->clk)) 193 if (!IS_ERR(ctx->clk))
219 clk_disable(ctx->clk); 194 clk_disable(ctx->clk);
@@ -232,14 +207,11 @@ static void regmap_mmio_free_context(void *context)
232 kfree(context); 207 kfree(context);
233} 208}
234 209
235static struct regmap_bus regmap_mmio = { 210static const struct regmap_bus regmap_mmio = {
236 .fast_io = true, 211 .fast_io = true,
237 .write = regmap_mmio_write, 212 .reg_write = regmap_mmio_write,
238 .gather_write = regmap_mmio_gather_write, 213 .reg_read = regmap_mmio_read,
239 .read = regmap_mmio_read,
240 .free_context = regmap_mmio_free_context, 214 .free_context = regmap_mmio_free_context,
241 .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
242 .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
243}; 215};
244 216
245static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, 217static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
@@ -265,24 +237,71 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
265 if (config->reg_stride < min_stride) 237 if (config->reg_stride < min_stride)
266 return ERR_PTR(-EINVAL); 238 return ERR_PTR(-EINVAL);
267 239
268 switch (config->reg_format_endian) {
269 case REGMAP_ENDIAN_DEFAULT:
270 case REGMAP_ENDIAN_NATIVE:
271 break;
272 default:
273 return ERR_PTR(-EINVAL);
274 }
275
276 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 240 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
277 if (!ctx) 241 if (!ctx)
278 return ERR_PTR(-ENOMEM); 242 return ERR_PTR(-ENOMEM);
279 243
280 ctx->regs = regs; 244 ctx->regs = regs;
281 ctx->val_bytes = config->val_bits / 8; 245 ctx->val_bytes = config->val_bits / 8;
282 ctx->reg_bytes = config->reg_bits / 8;
283 ctx->pad_bytes = config->pad_bits / 8;
284 ctx->clk = ERR_PTR(-ENODEV); 246 ctx->clk = ERR_PTR(-ENODEV);
285 247
248 switch (config->reg_format_endian) {
249 case REGMAP_ENDIAN_DEFAULT:
250 case REGMAP_ENDIAN_LITTLE:
251#ifdef __LITTLE_ENDIAN
252 case REGMAP_ENDIAN_NATIVE:
253#endif
254 switch (config->val_bits) {
255 case 8:
256 ctx->reg_read = regmap_mmio_read8;
257 ctx->reg_write = regmap_mmio_write8;
258 break;
259 case 16:
260 ctx->reg_read = regmap_mmio_read16le;
261 ctx->reg_write = regmap_mmio_write16le;
262 break;
263 case 32:
264 ctx->reg_read = regmap_mmio_read32le;
265 ctx->reg_write = regmap_mmio_write32le;
266 break;
267#ifdef CONFIG_64BIT
268 case 64:
269 ctx->reg_read = regmap_mmio_read64le;
270 ctx->reg_write = regmap_mmio_write64le;
271 break;
272#endif
273 default:
274 ret = -EINVAL;
275 goto err_free;
276 }
277 break;
278 case REGMAP_ENDIAN_BIG:
279#ifdef __BIG_ENDIAN
280 case REGMAP_ENDIAN_NATIVE:
281#endif
282 switch (config->val_bits) {
283 case 8:
284 ctx->reg_read = regmap_mmio_read8;
285 ctx->reg_write = regmap_mmio_write8;
286 break;
287 case 16:
288 ctx->reg_read = regmap_mmio_read16be;
289 ctx->reg_write = regmap_mmio_write16be;
290 break;
291 case 32:
292 ctx->reg_read = regmap_mmio_read32be;
293 ctx->reg_write = regmap_mmio_write32be;
294 break;
295 default:
296 ret = -EINVAL;
297 goto err_free;
298 }
299 break;
300 default:
301 ret = -EINVAL;
302 goto err_free;
303 }
304
286 if (clk_id == NULL) 305 if (clk_id == NULL)
287 return ctx; 306 return ctx;
288 307