1 /* 2 * Register map access API - MMIO support 3 * 4 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <linux/clk.h> 20 #include <linux/err.h> 21 #include <linux/init.h> 22 #include <linux/io.h> 23 #include <linux/module.h> 24 #include <linux/regmap.h> 25 #include <linux/slab.h> 26 27 struct regmap_mmio_context { 28 void __iomem *regs; 29 unsigned val_bytes; 30 struct clk *clk; 31 }; 32 33 static int regmap_mmio_gather_write(void *context, 34 const void *reg, size_t reg_size, 35 const void *val, size_t val_size) 36 { 37 struct regmap_mmio_context *ctx = context; 38 u32 offset; 39 int ret; 40 41 BUG_ON(reg_size != 4); 42 43 if (!IS_ERR(ctx->clk)) { 44 ret = clk_enable(ctx->clk); 45 if (ret < 0) 46 return ret; 47 } 48 49 offset = *(u32 *)reg; 50 51 while (val_size) { 52 switch (ctx->val_bytes) { 53 case 1: 54 writeb(*(u8 *)val, ctx->regs + offset); 55 break; 56 case 2: 57 writew(*(u16 *)val, ctx->regs + offset); 58 break; 59 case 4: 60 writel(*(u32 *)val, ctx->regs + offset); 61 break; 62 #ifdef CONFIG_64BIT 63 case 8: 64 writeq(*(u64 *)val, ctx->regs + offset); 65 break; 66 #endif 67 default: 68 /* Should be caught by regmap_mmio_check_config */ 69 BUG(); 70 } 71 val_size -= ctx->val_bytes; 72 val += ctx->val_bytes; 73 offset += ctx->val_bytes; 74 } 75 76 if (!IS_ERR(ctx->clk)) 77 clk_disable(ctx->clk); 78 79 return 0; 80 } 81 82 static int regmap_mmio_write(void *context, const void *data, size_t count) 83 { 84 BUG_ON(count < 4); 85 86 return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4); 87 } 88 89 static int regmap_mmio_read(void *context, 90 const void *reg, size_t reg_size, 91 void *val, size_t val_size) 92 { 93 struct regmap_mmio_context *ctx = context; 94 u32 offset; 95 int ret; 96 97 BUG_ON(reg_size != 4); 98 99 if (!IS_ERR(ctx->clk)) { 100 ret = clk_enable(ctx->clk); 101 if (ret < 0) 102 return ret; 103 } 104 105 offset = *(u32 *)reg; 106 107 while (val_size) { 108 switch (ctx->val_bytes) { 109 case 1: 110 *(u8 *)val = readb(ctx->regs + offset); 111 break; 112 case 2: 113 *(u16 *)val = readw(ctx->regs + offset); 114 break; 115 case 4: 116 *(u32 *)val = readl(ctx->regs + offset); 117 break; 118 #ifdef CONFIG_64BIT 119 case 8: 120 *(u64 *)val = readq(ctx->regs + offset); 121 break; 122 #endif 123 default: 124 /* Should be caught by regmap_mmio_check_config */ 125 BUG(); 126 } 127 val_size -= ctx->val_bytes; 128 val += ctx->val_bytes; 129 offset += ctx->val_bytes; 130 } 131 132 if (!IS_ERR(ctx->clk)) 133 clk_disable(ctx->clk); 134 135 return 0; 136 } 137 138 static void regmap_mmio_free_context(void *context) 139 { 140 struct regmap_mmio_context *ctx = context; 141 142 if (!IS_ERR(ctx->clk)) { 143 clk_unprepare(ctx->clk); 144 clk_put(ctx->clk); 145 } 146 kfree(context); 147 } 148 149 static struct regmap_bus regmap_mmio = { 150 .fast_io = true, 151 .write = regmap_mmio_write, 152 .gather_write = regmap_mmio_gather_write, 153 .read = regmap_mmio_read, 154 .free_context = regmap_mmio_free_context, 155 .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 156 .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 157 }; 158 159 static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, 160 const char *clk_id, 161 void __iomem *regs, 162 const struct regmap_config *config) 163 { 164 struct regmap_mmio_context *ctx; 165 int min_stride; 166 int ret; 167 168 if (config->reg_bits != 32) 169 return ERR_PTR(-EINVAL); 170 171 if (config->pad_bits) 172 return ERR_PTR(-EINVAL); 173 174 switch (config->val_bits) { 175 case 8: 176 /* The core treats 0 as 1 */ 177 min_stride = 0; 178 break; 179 case 16: 180 min_stride = 2; 181 break; 182 case 32: 183 min_stride = 4; 184 break; 185 #ifdef CONFIG_64BIT 186 case 64: 187 min_stride = 8; 188 break; 189 #endif 190 break; 191 default: 192 return ERR_PTR(-EINVAL); 193 } 194 195 if (config->reg_stride < min_stride) 196 return ERR_PTR(-EINVAL); 197 198 switch (config->reg_format_endian) { 199 case REGMAP_ENDIAN_DEFAULT: 200 case REGMAP_ENDIAN_NATIVE: 201 break; 202 default: 203 return ERR_PTR(-EINVAL); 204 } 205 206 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 207 if (!ctx) 208 return ERR_PTR(-ENOMEM); 209 210 ctx->regs = regs; 211 ctx->val_bytes = config->val_bits / 8; 212 ctx->clk = ERR_PTR(-ENODEV); 213 214 if (clk_id == NULL) 215 return ctx; 216 217 ctx->clk = clk_get(dev, clk_id); 218 if (IS_ERR(ctx->clk)) { 219 ret = PTR_ERR(ctx->clk); 220 goto err_free; 221 } 222 223 ret = clk_prepare(ctx->clk); 224 if (ret < 0) { 225 clk_put(ctx->clk); 226 goto err_free; 227 } 228 229 return ctx; 230 231 err_free: 232 kfree(ctx); 233 234 return ERR_PTR(ret); 235 } 236 237 /** 238 * regmap_init_mmio_clk(): Initialise register map with register clock 239 * 240 * @dev: Device that will be interacted with 241 * @clk_id: register clock consumer ID 242 * @regs: Pointer to memory-mapped IO region 243 * @config: Configuration for register map 244 * 245 * The return value will be an ERR_PTR() on error or a valid pointer to 246 * a struct regmap. 247 */ 248 struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, 249 void __iomem *regs, 250 const struct regmap_config *config) 251 { 252 struct regmap_mmio_context *ctx; 253 254 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); 255 if (IS_ERR(ctx)) 256 return ERR_CAST(ctx); 257 258 return regmap_init(dev, ®map_mmio, ctx, config); 259 } 260 EXPORT_SYMBOL_GPL(regmap_init_mmio_clk); 261 262 /** 263 * devm_regmap_init_mmio_clk(): Initialise managed register map with clock 264 * 265 * @dev: Device that will be interacted with 266 * @clk_id: register clock consumer ID 267 * @regs: Pointer to memory-mapped IO region 268 * @config: Configuration for register map 269 * 270 * The return value will be an ERR_PTR() on error or a valid pointer 271 * to a struct regmap. The regmap will be automatically freed by the 272 * device management code. 273 */ 274 struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, 275 void __iomem *regs, 276 const struct regmap_config *config) 277 { 278 struct regmap_mmio_context *ctx; 279 280 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); 281 if (IS_ERR(ctx)) 282 return ERR_CAST(ctx); 283 284 return devm_regmap_init(dev, ®map_mmio, ctx, config); 285 } 286 EXPORT_SYMBOL_GPL(devm_regmap_init_mmio_clk); 287 288 MODULE_LICENSE("GPL v2"); 289