diff options
author | Mark Brown <broonie@kernel.org> | 2016-03-05 15:30:29 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-03-05 15:30:29 +0300 |
commit | 781aab8457610d0b4d60cd85bb22e609941be721 (patch) | |
tree | 48e5454bd303417dd8fe7d2c75f9b3f481f3fca1 /drivers/base | |
parent | 0e03ae7492271a62f6085c9c7f301ac8a481b001 (diff) | |
parent | aacaaa4c8e1cd3b813a3b77c9855e53d96381f40 (diff) | |
download | linux-781aab8457610d0b4d60cd85bb22e609941be721.tar.xz |
Merge remote-tracking branch 'regmap/topic/mmio' into regmap-next
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/regcache.c | 41 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-mmio.c | 259 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 5 |
3 files changed, 174 insertions, 131 deletions
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 5c5090b68939..4170b7d95276 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -30,7 +30,7 @@ static int regcache_hw_init(struct regmap *map) int i, j; int ret; int count; - unsigned int val; + unsigned int reg, val; void *tmp_buf; if (!map->num_reg_defaults_raw) @@ -67,27 +67,46 @@ static int regcache_hw_init(struct regmap *map) ret = regmap_raw_read(map, 0, tmp_buf, map->cache_size_raw); map->cache_bypass = cache_bypass; - if (ret < 0) - goto err_cache_free; - - map->reg_defaults_raw = tmp_buf; - map->cache_free = 1; + if (ret == 0) { + map->reg_defaults_raw = tmp_buf; + map->cache_free = 1; + } else { + kfree(tmp_buf); + } } /* fill the reg_defaults */ for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) { - if (regmap_volatile(map, i * map->reg_stride)) + reg = i * map->reg_stride; + + if (!regmap_readable(map, reg)) continue; - val = regcache_get_val(map, map->reg_defaults_raw, i); - map->reg_defaults[j].reg = i * map->reg_stride; + + if (regmap_volatile(map, reg)) + continue; + + if (map->reg_defaults_raw) { + val = regcache_get_val(map, map->reg_defaults_raw, i); + } else { + bool cache_bypass = map->cache_bypass; + + map->cache_bypass = true; + ret = regmap_read(map, reg, &val); + map->cache_bypass = cache_bypass; + if (ret != 0) { + dev_err(map->dev, "Failed to read %d: %d\n", + reg, ret); + goto err_free; + } + } + + map->reg_defaults[j].reg = reg; map->reg_defaults[j].def = val; j++; } return 0; -err_cache_free: - kfree(tmp_buf); err_free: kfree(map->reg_defaults); 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 @@ struct regmap_mmio_context { void __iomem *regs; - unsigned reg_bytes; unsigned val_bytes; - unsigned pad_bytes; struct clk *clk; -}; -static inline void regmap_mmio_regsize_check(size_t reg_size) -{ - switch (reg_size) { - case 1: - case 2: - case 4: -#ifdef CONFIG_64BIT - case 8: -#endif - break; - default: - BUG(); - } -} + void (*reg_write)(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val); + unsigned int (*reg_read)(struct regmap_mmio_context *ctx, + unsigned int reg); +}; static int regmap_mmio_regbits_check(size_t reg_bits) { @@ -88,72 +76,62 @@ static int regmap_mmio_get_min_stride(size_t val_bits) return min_stride; } -static inline void regmap_mmio_count_check(size_t count, u32 offset) +static void regmap_mmio_write8(struct regmap_mmio_context *ctx, + unsigned int reg, + unsigned int val) +{ + writeb(val, ctx->regs + reg); +} + +static void regmap_mmio_write16le(struct regmap_mmio_context *ctx, + unsigned int reg, + unsigned int val) { - BUG_ON(count <= offset); + writew(val, ctx->regs + reg); } -static inline unsigned int -regmap_mmio_get_offset(const void *reg, size_t reg_size) +static void regmap_mmio_write16be(struct regmap_mmio_context *ctx, + unsigned int reg, + unsigned int val) { - switch (reg_size) { - case 1: - return *(u8 *)reg; - case 2: - return *(u16 *)reg; - case 4: - return *(u32 *)reg; + iowrite16be(val, ctx->regs + reg); +} + +static void regmap_mmio_write32le(struct regmap_mmio_context *ctx, + unsigned int reg, + unsigned int val) +{ + writel(val, ctx->regs + reg); +} + +static void regmap_mmio_write32be(struct regmap_mmio_context *ctx, + unsigned int reg, + unsigned int val) +{ + iowrite32be(val, ctx->regs + reg); +} + #ifdef CONFIG_64BIT - case 8: - return *(u64 *)reg; -#endif - default: - BUG(); - } +static void regmap_mmio_write64le(struct regmap_mmio_context *ctx, + unsigned int reg, + unsigned int val) +{ + writeq(val, ctx->regs + reg); } +#endif -static int regmap_mmio_gather_write(void *context, - const void *reg, size_t reg_size, - const void *val, size_t val_size) +static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val) { struct regmap_mmio_context *ctx = context; - unsigned int offset; int ret; - regmap_mmio_regsize_check(reg_size); - if (!IS_ERR(ctx->clk)) { ret = clk_enable(ctx->clk); if (ret < 0) return ret; } - offset = regmap_mmio_get_offset(reg, reg_size); - - while (val_size) { - switch (ctx->val_bytes) { - case 1: - writeb(*(u8 *)val, ctx->regs + offset); - break; - case 2: - writew(*(u16 *)val, ctx->regs + offset); - break; - case 4: - writel(*(u32 *)val, ctx->regs + offset); - break; -#ifdef CONFIG_64BIT - case 8: - writeq(*(u64 *)val, ctx->regs + offset); - break; -#endif - default: - /* Should be caught by regmap_mmio_check_config */ - BUG(); - } - val_size -= ctx->val_bytes; - val += ctx->val_bytes; - offset += ctx->val_bytes; - } + ctx->reg_write(ctx, reg, val); if (!IS_ERR(ctx->clk)) clk_disable(ctx->clk); @@ -161,59 +139,56 @@ static int regmap_mmio_gather_write(void *context, return 0; } -static int regmap_mmio_write(void *context, const void *data, size_t count) +static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx, + unsigned int reg) { - struct regmap_mmio_context *ctx = context; - unsigned int offset = ctx->reg_bytes + ctx->pad_bytes; + return readb(ctx->regs + reg); +} + +static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return readw(ctx->regs + reg); +} + +static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return ioread16be(ctx->regs + reg); +} + +static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return readl(ctx->regs + reg); +} - regmap_mmio_count_check(count, offset); +static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return ioread32be(ctx->regs + reg); +} - return regmap_mmio_gather_write(context, data, ctx->reg_bytes, - data + offset, count - offset); +#ifdef CONFIG_64BIT +static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return readq(ctx->regs + reg); } +#endif -static int regmap_mmio_read(void *context, - const void *reg, size_t reg_size, - void *val, size_t val_size) +static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val) { struct regmap_mmio_context *ctx = context; - unsigned int offset; int ret; - regmap_mmio_regsize_check(reg_size); - if (!IS_ERR(ctx->clk)) { ret = clk_enable(ctx->clk); if (ret < 0) return ret; } - offset = regmap_mmio_get_offset(reg, reg_size); - - while (val_size) { - switch (ctx->val_bytes) { - case 1: - *(u8 *)val = readb(ctx->regs + offset); - break; - case 2: - *(u16 *)val = readw(ctx->regs + offset); - break; - case 4: - *(u32 *)val = readl(ctx->regs + offset); - break; -#ifdef CONFIG_64BIT - case 8: - *(u64 *)val = readq(ctx->regs + offset); - break; -#endif - default: - /* Should be caught by regmap_mmio_check_config */ - BUG(); - } - val_size -= ctx->val_bytes; - val += ctx->val_bytes; - offset += ctx->val_bytes; - } + *val = ctx->reg_read(ctx, reg); if (!IS_ERR(ctx->clk)) clk_disable(ctx->clk); @@ -232,14 +207,11 @@ static void regmap_mmio_free_context(void *context) kfree(context); } -static struct regmap_bus regmap_mmio = { +static const struct regmap_bus regmap_mmio = { .fast_io = true, - .write = regmap_mmio_write, - .gather_write = regmap_mmio_gather_write, - .read = regmap_mmio_read, + .reg_write = regmap_mmio_write, + .reg_read = regmap_mmio_read, .free_context = regmap_mmio_free_context, - .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, - .val_format_endian_default = REGMAP_ENDIAN_NATIVE, }; static 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, if (config->reg_stride < min_stride) return ERR_PTR(-EINVAL); - switch (config->reg_format_endian) { - case REGMAP_ENDIAN_DEFAULT: - case REGMAP_ENDIAN_NATIVE: - break; - default: - return ERR_PTR(-EINVAL); - } - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return ERR_PTR(-ENOMEM); ctx->regs = regs; ctx->val_bytes = config->val_bits / 8; - ctx->reg_bytes = config->reg_bits / 8; - ctx->pad_bytes = config->pad_bits / 8; ctx->clk = ERR_PTR(-ENODEV); + switch (config->reg_format_endian) { + case REGMAP_ENDIAN_DEFAULT: + case REGMAP_ENDIAN_LITTLE: +#ifdef __LITTLE_ENDIAN + case REGMAP_ENDIAN_NATIVE: +#endif + switch (config->val_bits) { + case 8: + ctx->reg_read = regmap_mmio_read8; + ctx->reg_write = regmap_mmio_write8; + break; + case 16: + ctx->reg_read = regmap_mmio_read16le; + ctx->reg_write = regmap_mmio_write16le; + break; + case 32: + ctx->reg_read = regmap_mmio_read32le; + ctx->reg_write = regmap_mmio_write32le; + break; +#ifdef CONFIG_64BIT + case 64: + ctx->reg_read = regmap_mmio_read64le; + ctx->reg_write = regmap_mmio_write64le; + break; +#endif + default: + ret = -EINVAL; + goto err_free; + } + break; + case REGMAP_ENDIAN_BIG: +#ifdef __BIG_ENDIAN + case REGMAP_ENDIAN_NATIVE: +#endif + switch (config->val_bits) { + case 8: + ctx->reg_read = regmap_mmio_read8; + ctx->reg_write = regmap_mmio_write8; + break; + case 16: + ctx->reg_read = regmap_mmio_read16be; + ctx->reg_write = regmap_mmio_write16be; + break; + case 32: + ctx->reg_read = regmap_mmio_read32be; + ctx->reg_write = regmap_mmio_write32be; + break; + default: + ret = -EINVAL; + goto err_free; + } + break; + default: + ret = -EINVAL; + goto err_free; + } + if (clk_id == NULL) return ctx; diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ee54e841de4a..e2f68807d970 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -557,6 +557,8 @@ enum regmap_endian regmap_get_val_endian(struct device *dev, endian = REGMAP_ENDIAN_BIG; else if (of_property_read_bool(np, "little-endian")) endian = REGMAP_ENDIAN_LITTLE; + else if (of_property_read_bool(np, "native-endian")) + endian = REGMAP_ENDIAN_NATIVE; /* If the endianness was specified in DT, use that */ if (endian != REGMAP_ENDIAN_DEFAULT) @@ -2253,6 +2255,9 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, WARN_ON(!map->bus); + if (!map->bus || !map->bus->read) + return -EINVAL; + range = _regmap_range_lookup(map, reg); if (range) { ret = _regmap_select_page(map, ®, range, |