diff options
Diffstat (limited to 'drivers/base/regmap/regmap-mmio.c')
| -rw-r--r-- | drivers/base/regmap/regmap-mmio.c | 95 | 
1 files changed, 79 insertions, 16 deletions
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 98745dd77e8..04a329a377e 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -18,7 +18,6 @@  #include <linux/clk.h>  #include <linux/err.h> -#include <linux/init.h>  #include <linux/io.h>  #include <linux/module.h>  #include <linux/regmap.h> @@ -26,27 +25,83 @@  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(); +	} +} + +static int regmap_mmio_regbits_check(size_t reg_bits) +{ +	switch (reg_bits) { +	case 8: +	case 16: +	case 32: +#ifdef CONFIG_64BIT +	case 64: +#endif +		return 0; +	default: +		return -EINVAL; +	} +} + +static inline void regmap_mmio_count_check(size_t count, u32 offset) +{ +	BUG_ON(count <= offset); +} + +static inline unsigned int +regmap_mmio_get_offset(const void *reg, size_t reg_size) +{ +	switch (reg_size) { +	case 1: +		return *(u8 *)reg; +	case 2: +		return *(u16 *)reg; +	case 4: +		return *(u32 *)reg; +#ifdef CONFIG_64BIT +	case 8: +		return *(u64 *)reg; +#endif +	default: +		BUG(); +	} +} +  static int regmap_mmio_gather_write(void *context,  				    const void *reg, size_t reg_size,  				    const void *val, size_t val_size)  {  	struct regmap_mmio_context *ctx = context; -	u32 offset; +	unsigned int offset;  	int ret; -	BUG_ON(reg_size != 4); +	regmap_mmio_regsize_check(reg_size); -	if (ctx->clk) { +	if (!IS_ERR(ctx->clk)) {  		ret = clk_enable(ctx->clk);  		if (ret < 0)  			return ret;  	} -	offset = *(u32 *)reg; +	offset = regmap_mmio_get_offset(reg, reg_size);  	while (val_size) {  		switch (ctx->val_bytes) { @@ -73,7 +128,7 @@ static int regmap_mmio_gather_write(void *context,  		offset += ctx->val_bytes;  	} -	if (ctx->clk) +	if (!IS_ERR(ctx->clk))  		clk_disable(ctx->clk);  	return 0; @@ -81,9 +136,13 @@ static int regmap_mmio_gather_write(void *context,  static int regmap_mmio_write(void *context, const void *data, size_t count)  { -	BUG_ON(count < 4); +	struct regmap_mmio_context *ctx = context; +	unsigned int offset = ctx->reg_bytes + ctx->pad_bytes; -	return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4); +	regmap_mmio_count_check(count, offset); + +	return regmap_mmio_gather_write(context, data, ctx->reg_bytes, +					data + offset, count - offset);  }  static int regmap_mmio_read(void *context, @@ -91,18 +150,18 @@ static int regmap_mmio_read(void *context,  			    void *val, size_t val_size)  {  	struct regmap_mmio_context *ctx = context; -	u32 offset; +	unsigned int offset;  	int ret; -	BUG_ON(reg_size != 4); +	regmap_mmio_regsize_check(reg_size); -	if (ctx->clk) { +	if (!IS_ERR(ctx->clk)) {  		ret = clk_enable(ctx->clk);  		if (ret < 0)  			return ret;  	} -	offset = *(u32 *)reg; +	offset = regmap_mmio_get_offset(reg, reg_size);  	while (val_size) {  		switch (ctx->val_bytes) { @@ -129,7 +188,7 @@ static int regmap_mmio_read(void *context,  		offset += ctx->val_bytes;  	} -	if (ctx->clk) +	if (!IS_ERR(ctx->clk))  		clk_disable(ctx->clk);  	return 0; @@ -139,7 +198,7 @@ static void regmap_mmio_free_context(void *context)  {  	struct regmap_mmio_context *ctx = context; -	if (ctx->clk) { +	if (!IS_ERR(ctx->clk)) {  		clk_unprepare(ctx->clk);  		clk_put(ctx->clk);  	} @@ -165,8 +224,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,  	int min_stride;  	int ret; -	if (config->reg_bits != 32) -		return ERR_PTR(-EINVAL); +	ret = regmap_mmio_regbits_check(config->reg_bits); +	if (ret) +		return ERR_PTR(ret);  	if (config->pad_bits)  		return ERR_PTR(-EINVAL); @@ -209,6 +269,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,  	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);  	if (clk_id == NULL)  		return ctx;  | 
