diff options
-rw-r--r-- | arch/hexagon/include/asm/io.h | 25 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-mmio.c | 289 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-spi-avmm.c | 14 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 167 | ||||
-rw-r--r-- | drivers/base/regmap/trace.h | 61 | ||||
-rw-r--r-- | include/linux/regmap.h | 11 | ||||
-rw-r--r-- | include/linux/swab.h | 25 |
7 files changed, 489 insertions, 103 deletions
diff --git a/arch/hexagon/include/asm/io.h b/arch/hexagon/include/asm/io.h index c33241425a5c..46a099de85b7 100644 --- a/arch/hexagon/include/asm/io.h +++ b/arch/hexagon/include/asm/io.h @@ -308,6 +308,31 @@ static inline void outsl(unsigned long port, const void *buffer, int count) } } +/* + * These defines are necessary to use the generic io.h for filling in + * the missing parts of the API contract. This is because the platform + * uses (inline) functions rather than defines and the generic helper + * fills in the undefined. + */ +#define virt_to_phys virt_to_phys +#define phys_to_virt phys_to_virt +#define memset_io memset_io +#define memcpy_fromio memcpy_fromio +#define memcpy_toio memcpy_toio +#define readb readb +#define readw readw +#define readl readl +#define writeb writeb +#define writew writew +#define writel writel +#define insb insb +#define insw insw +#define insl insl +#define outsb outsb +#define outsw outsw +#define outsl outsl +#include <asm-generic/io.h> + #endif /* __KERNEL__ */ #endif diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 71f16be7e717..3ccdd86a97e7 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -10,13 +10,14 @@ #include <linux/module.h> #include <linux/regmap.h> #include <linux/slab.h> +#include <linux/swab.h> #include "internal.h" struct regmap_mmio_context { void __iomem *regs; unsigned int val_bytes; - bool relaxed_mmio; + bool big_endian; bool attached_clk; struct clk *clk; @@ -33,9 +34,6 @@ static int regmap_mmio_regbits_check(size_t reg_bits) case 8: case 16: case 32: -#ifdef CONFIG_64BIT - case 64: -#endif return 0; default: return -EINVAL; @@ -50,18 +48,13 @@ static int regmap_mmio_get_min_stride(size_t val_bits) case 8: /* The core treats 0 as 1 */ min_stride = 0; - return 0; + break; case 16: min_stride = 2; break; case 32: min_stride = 4; break; -#ifdef CONFIG_64BIT - case 64: - min_stride = 8; - break; -#endif default: return -EINVAL; } @@ -83,6 +76,12 @@ static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx, writeb_relaxed(val, ctx->regs + reg); } +static void regmap_mmio_iowrite8(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val) +{ + iowrite8(val, ctx->regs + reg); +} + static void regmap_mmio_write16le(struct regmap_mmio_context *ctx, unsigned int reg, unsigned int val) @@ -97,10 +96,22 @@ static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx, writew_relaxed(val, ctx->regs + reg); } +static void regmap_mmio_iowrite16le(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val) +{ + iowrite16(val, ctx->regs + reg); +} + static void regmap_mmio_write16be(struct regmap_mmio_context *ctx, unsigned int reg, unsigned int val) { + writew(swab16(val), ctx->regs + reg); +} + +static void regmap_mmio_iowrite16be(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val) +{ iowrite16be(val, ctx->regs + reg); } @@ -118,28 +129,24 @@ static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx, writel_relaxed(val, ctx->regs + reg); } -static void regmap_mmio_write32be(struct regmap_mmio_context *ctx, - unsigned int reg, - unsigned int val) +static void regmap_mmio_iowrite32le(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val) { - iowrite32be(val, ctx->regs + reg); + iowrite32(val, ctx->regs + reg); } -#ifdef CONFIG_64BIT -static void regmap_mmio_write64le(struct regmap_mmio_context *ctx, +static void regmap_mmio_write32be(struct regmap_mmio_context *ctx, unsigned int reg, unsigned int val) { - writeq(val, ctx->regs + reg); + writel(swab32(val), ctx->regs + reg); } -static void regmap_mmio_write64le_relaxed(struct regmap_mmio_context *ctx, - unsigned int reg, - unsigned int val) +static void regmap_mmio_iowrite32be(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val) { - writeq_relaxed(val, ctx->regs + reg); + iowrite32be(val, ctx->regs + reg); } -#endif static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val) { @@ -160,6 +167,83 @@ static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val) return 0; } +static int regmap_mmio_noinc_write(void *context, unsigned int reg, + const void *val, size_t val_count) +{ + struct regmap_mmio_context *ctx = context; + int ret = 0; + int i; + + if (!IS_ERR(ctx->clk)) { + ret = clk_enable(ctx->clk); + if (ret < 0) + return ret; + } + + /* + * There are no native, assembly-optimized write single register + * operations for big endian, so fall back to emulation if this + * is needed. (Single bytes are fine, they are not affected by + * endianness.) + */ + if (ctx->big_endian && (ctx->val_bytes > 1)) { + switch (ctx->val_bytes) { + case 2: + { + const u16 *valp = (const u16 *)val; + for (i = 0; i < val_count; i++) + writew(swab16(valp[i]), ctx->regs + reg); + goto out_clk; + } + case 4: + { + const u32 *valp = (const u32 *)val; + for (i = 0; i < val_count; i++) + writel(swab32(valp[i]), ctx->regs + reg); + goto out_clk; + } +#ifdef CONFIG_64BIT + case 8: + { + const u64 *valp = (const u64 *)val; + for (i = 0; i < val_count; i++) + writeq(swab64(valp[i]), ctx->regs + reg); + goto out_clk; + } +#endif + default: + ret = -EINVAL; + goto out_clk; + } + } + + switch (ctx->val_bytes) { + case 1: + writesb(ctx->regs + reg, (const u8 *)val, val_count); + break; + case 2: + writesw(ctx->regs + reg, (const u16 *)val, val_count); + break; + case 4: + writesl(ctx->regs + reg, (const u32 *)val, val_count); + break; +#ifdef CONFIG_64BIT + case 8: + writesq(ctx->regs + reg, (const u64 *)val, val_count); + break; +#endif + default: + ret = -EINVAL; + break; + } + +out_clk: + if (!IS_ERR(ctx->clk)) + clk_disable(ctx->clk); + + return ret; +} + static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx, unsigned int reg) { @@ -172,6 +256,12 @@ static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx, return readb_relaxed(ctx->regs + reg); } +static unsigned int regmap_mmio_ioread8(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return ioread8(ctx->regs + reg); +} + static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx, unsigned int reg) { @@ -184,9 +274,21 @@ static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx return readw_relaxed(ctx->regs + reg); } +static unsigned int regmap_mmio_ioread16le(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return ioread16(ctx->regs + reg); +} + static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx, unsigned int reg) { + return swab16(readw(ctx->regs + reg)); +} + +static unsigned int regmap_mmio_ioread16be(struct regmap_mmio_context *ctx, + unsigned int reg) +{ return ioread16be(ctx->regs + reg); } @@ -202,25 +304,23 @@ static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx return readl_relaxed(ctx->regs + reg); } -static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx, - unsigned int reg) +static unsigned int regmap_mmio_ioread32le(struct regmap_mmio_context *ctx, + unsigned int reg) { - return ioread32be(ctx->regs + reg); + return ioread32(ctx->regs + reg); } -#ifdef CONFIG_64BIT -static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx, +static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx, unsigned int reg) { - return readq(ctx->regs + reg); + return swab32(readl(ctx->regs + reg)); } -static unsigned int regmap_mmio_read64le_relaxed(struct regmap_mmio_context *ctx, - unsigned int reg) +static unsigned int regmap_mmio_ioread32be(struct regmap_mmio_context *ctx, + unsigned int reg) { - return readq_relaxed(ctx->regs + reg); + return ioread32be(ctx->regs + reg); } -#endif static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val) { @@ -241,6 +341,71 @@ static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val) return 0; } +static int regmap_mmio_noinc_read(void *context, unsigned int reg, + void *val, size_t val_count) +{ + struct regmap_mmio_context *ctx = context; + int ret = 0; + + if (!IS_ERR(ctx->clk)) { + ret = clk_enable(ctx->clk); + if (ret < 0) + return ret; + } + + switch (ctx->val_bytes) { + case 1: + readsb(ctx->regs + reg, (u8 *)val, val_count); + break; + case 2: + readsw(ctx->regs + reg, (u16 *)val, val_count); + break; + case 4: + readsl(ctx->regs + reg, (u32 *)val, val_count); + break; +#ifdef CONFIG_64BIT + case 8: + readsq(ctx->regs + reg, (u64 *)val, val_count); + break; +#endif + default: + ret = -EINVAL; + goto out_clk; + } + + /* + * There are no native, assembly-optimized write single register + * operations for big endian, so fall back to emulation if this + * is needed. (Single bytes are fine, they are not affected by + * endianness.) + */ + if (ctx->big_endian && (ctx->val_bytes > 1)) { + switch (ctx->val_bytes) { + case 2: + swab16_array(val, val_count); + break; + case 4: + swab32_array(val, val_count); + break; +#ifdef CONFIG_64BIT + case 8: + swab64_array(val, val_count); + break; +#endif + default: + ret = -EINVAL; + break; + } + } + +out_clk: + if (!IS_ERR(ctx->clk)) + clk_disable(ctx->clk); + + return ret; +} + + static void regmap_mmio_free_context(void *context) { struct regmap_mmio_context *ctx = context; @@ -257,6 +422,8 @@ static const struct regmap_bus regmap_mmio = { .fast_io = true, .reg_write = regmap_mmio_write, .reg_read = regmap_mmio_read, + .reg_noinc_write = regmap_mmio_noinc_write, + .reg_noinc_read = regmap_mmio_noinc_read, .free_context = regmap_mmio_free_context, .val_format_endian_default = REGMAP_ENDIAN_LITTLE, }; @@ -284,13 +451,15 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, if (config->reg_stride < min_stride) return ERR_PTR(-EINVAL); + if (config->use_relaxed_mmio && config->io_port) + 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->relaxed_mmio = config->use_relaxed_mmio; ctx->clk = ERR_PTR(-ENODEV); switch (regmap_get_val_endian(dev, ®map_mmio, config)) { @@ -301,7 +470,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, #endif switch (config->val_bits) { case 8: - if (ctx->relaxed_mmio) { + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread8; + ctx->reg_write = regmap_mmio_iowrite8; + } else if (config->use_relaxed_mmio) { ctx->reg_read = regmap_mmio_read8_relaxed; ctx->reg_write = regmap_mmio_write8_relaxed; } else { @@ -310,7 +482,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, } break; case 16: - if (ctx->relaxed_mmio) { + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread16le; + ctx->reg_write = regmap_mmio_iowrite16le; + } else if (config->use_relaxed_mmio) { ctx->reg_read = regmap_mmio_read16le_relaxed; ctx->reg_write = regmap_mmio_write16le_relaxed; } else { @@ -319,7 +494,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, } break; case 32: - if (ctx->relaxed_mmio) { + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread32le; + ctx->reg_write = regmap_mmio_iowrite32le; + } else if (config->use_relaxed_mmio) { ctx->reg_read = regmap_mmio_read32le_relaxed; ctx->reg_write = regmap_mmio_write32le_relaxed; } else { @@ -327,17 +505,6 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ctx->reg_write = regmap_mmio_write32le; } break; -#ifdef CONFIG_64BIT - case 64: - if (ctx->relaxed_mmio) { - ctx->reg_read = regmap_mmio_read64le_relaxed; - ctx->reg_write = regmap_mmio_write64le_relaxed; - } else { - ctx->reg_read = regmap_mmio_read64le; - ctx->reg_write = regmap_mmio_write64le; - } - break; -#endif default: ret = -EINVAL; goto err_free; @@ -347,18 +514,34 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, #ifdef __BIG_ENDIAN case REGMAP_ENDIAN_NATIVE: #endif + ctx->big_endian = true; switch (config->val_bits) { case 8: - ctx->reg_read = regmap_mmio_read8; - ctx->reg_write = regmap_mmio_write8; + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread8; + ctx->reg_write = regmap_mmio_iowrite8; + } else { + 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; + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread16be; + ctx->reg_write = regmap_mmio_iowrite16be; + } else { + 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; + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread32be; + ctx->reg_write = regmap_mmio_iowrite32be; + } else { + ctx->reg_read = regmap_mmio_read32be; + ctx->reg_write = regmap_mmio_write32be; + } break; default: ret = -EINVAL; diff --git a/drivers/base/regmap/regmap-spi-avmm.c b/drivers/base/regmap/regmap-spi-avmm.c index ad1da83e849f..4c2b94b3e30b 100644 --- a/drivers/base/regmap/regmap-spi-avmm.c +++ b/drivers/base/regmap/regmap-spi-avmm.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> +#include <linux/swab.h> /* * This driver implements the regmap operations for a generic SPI @@ -162,19 +163,12 @@ struct spi_avmm_bridge { /* bridge buffer used in translation between protocol layers */ char trans_buf[TRANS_BUF_SIZE]; char phy_buf[PHY_BUF_SIZE]; - void (*swap_words)(char *buf, unsigned int len); + void (*swap_words)(void *buf, unsigned int len); }; -static void br_swap_words_32(char *buf, unsigned int len) +static void br_swap_words_32(void *buf, unsigned int len) { - u32 *p = (u32 *)buf; - unsigned int count; - - count = len / 4; - while (count--) { - *p = swab32p(p); - p++; - } + swab32_array(buf, len / 4); } /* diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index fee221c5008c..c6d6d53e8cd3 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -288,15 +288,9 @@ static void regmap_format_16_native(void *buf, unsigned int val, memcpy(buf, &v, sizeof(v)); } -static void regmap_format_24(void *buf, unsigned int val, unsigned int shift) +static void regmap_format_24_be(void *buf, unsigned int val, unsigned int shift) { - u8 *b = buf; - - val <<= shift; - - b[0] = val >> 16; - b[1] = val >> 8; - b[2] = val; + put_unaligned_be24(val << shift, buf); } static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift) @@ -380,14 +374,9 @@ static unsigned int regmap_parse_16_native(const void *buf) return v; } -static unsigned int regmap_parse_24(const void *buf) +static unsigned int regmap_parse_24_be(const void *buf) { - const u8 *b = buf; - unsigned int ret = b[2]; - ret |= ((unsigned int)b[1]) << 8; - ret |= ((unsigned int)b[0]) << 16; - - return ret; + return get_unaligned_be24(buf); } static unsigned int regmap_parse_32_be(const void *buf) @@ -991,9 +980,13 @@ struct regmap *__regmap_init(struct device *dev, break; case 24: - if (reg_endian != REGMAP_ENDIAN_BIG) + switch (reg_endian) { + case REGMAP_ENDIAN_BIG: + map->format.format_reg = regmap_format_24_be; + break; + default: goto err_hwlock; - map->format.format_reg = regmap_format_24; + } break; case 32: @@ -1064,10 +1057,14 @@ struct regmap *__regmap_init(struct device *dev, } break; case 24: - if (val_endian != REGMAP_ENDIAN_BIG) + switch (val_endian) { + case REGMAP_ENDIAN_BIG: + map->format.format_val = regmap_format_24_be; + map->format.parse_val = regmap_parse_24_be; + break; + default: goto err_hwlock; - map->format.format_val = regmap_format_24; - map->format.parse_val = regmap_parse_24; + } break; case 32: switch (val_endian) { @@ -2132,6 +2129,99 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_raw_write); +static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg, + void *val, unsigned int val_len, bool write) +{ + size_t val_bytes = map->format.val_bytes; + size_t val_count = val_len / val_bytes; + unsigned int lastval; + u8 *u8p; + u16 *u16p; + u32 *u32p; +#ifdef CONFIG_64BIT + u64 *u64p; +#endif + int ret; + int i; + + switch (val_bytes) { + case 1: + u8p = val; + if (write) + lastval = (unsigned int)u8p[val_count - 1]; + break; + case 2: + u16p = val; + if (write) + lastval = (unsigned int)u16p[val_count - 1]; + break; + case 4: + u32p = val; + if (write) + lastval = (unsigned int)u32p[val_count - 1]; + break; +#ifdef CONFIG_64BIT + case 8: + u64p = val; + if (write) + lastval = (unsigned int)u64p[val_count - 1]; + break; +#endif + default: + return -EINVAL; + } + + /* + * Update the cache with the last value we write, the rest is just + * gone down in the hardware FIFO. We can't cache FIFOs. This makes + * sure a single read from the cache will work. + */ + if (write) { + if (!map->cache_bypass && !map->defer_caching) { + ret = regcache_write(map, reg, lastval); + if (ret != 0) + return ret; + if (map->cache_only) { + map->cache_dirty = true; + return 0; + } + } + ret = map->bus->reg_noinc_write(map->bus_context, reg, val, val_count); + } else { + ret = map->bus->reg_noinc_read(map->bus_context, reg, val, val_count); + } + + if (!ret && regmap_should_log(map)) { + dev_info(map->dev, "%x %s [", reg, write ? "<=" : "=>"); + for (i = 0; i < val_count; i++) { + switch (val_bytes) { + case 1: + pr_cont("%x", u8p[i]); + break; + case 2: + pr_cont("%x", u16p[i]); + break; + case 4: + pr_cont("%x", u32p[i]); + break; +#ifdef CONFIG_64BIT + case 8: + pr_cont("%llx", u64p[i]); + break; +#endif + default: + break; + } + if (i == (val_count - 1)) + pr_cont("]\n"); + else + pr_cont(","); + } + } + + return 0; +} + /** * regmap_noinc_write(): Write data from a register without incrementing the * register number @@ -2159,9 +2249,8 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg, size_t write_len; int ret; - if (!map->write) - return -ENOTSUPP; - + if (!map->write && !(map->bus && map->bus->reg_noinc_write)) + return -EINVAL; if (val_len % map->format.val_bytes) return -EINVAL; if (!IS_ALIGNED(reg, map->reg_stride)) @@ -2176,6 +2265,15 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg, goto out_unlock; } + /* + * Use the accelerated operation if we can. The val drops the const + * typing in order to facilitate code reuse in regmap_noinc_readwrite(). + */ + if (map->bus->reg_noinc_write) { + ret = regmap_noinc_readwrite(map, reg, (void *)val, val_len, true); + goto out_unlock; + } + while (val_len) { if (map->max_raw_write && map->max_raw_write < val_len) write_len = map->max_raw_write; @@ -2350,6 +2448,10 @@ out: kfree(wval); } + + if (!ret) + trace_regmap_bulk_write(map, reg, val, val_bytes * val_count); + return ret; } EXPORT_SYMBOL_GPL(regmap_bulk_write); @@ -2946,6 +3048,22 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg, goto out_unlock; } + /* Use the accelerated operation if we can */ + if (map->bus->reg_noinc_read) { + /* + * We have not defined the FIFO semantics for cache, as the + * cache is just one value deep. Should we return the last + * written value? Just avoid this by always reading the FIFO + * even when using cache. Cache only will not work. + */ + if (map->cache_only) { + ret = -EBUSY; + goto out_unlock; + } + ret = regmap_noinc_readwrite(map, reg, val, val_len, false); + goto out_unlock; + } + while (val_len) { if (map->max_raw_read && map->max_raw_read < val_len) read_len = map->max_raw_read; @@ -3095,6 +3213,9 @@ out: map->unlock(map->lock_arg); } + if (!ret) + trace_regmap_bulk_read(map, reg, val, val_bytes * val_count); + return ret; } EXPORT_SYMBOL_GPL(regmap_bulk_read); diff --git a/drivers/base/regmap/trace.h b/drivers/base/regmap/trace.h index 9abee14df9ee..704e106e5dbd 100644 --- a/drivers/base/regmap/trace.h +++ b/drivers/base/regmap/trace.h @@ -32,9 +32,7 @@ DECLARE_EVENT_CLASS(regmap_reg, __entry->val = val; ), - TP_printk("%s reg=%x val=%x", __get_str(name), - (unsigned int)__entry->reg, - (unsigned int)__entry->val) + TP_printk("%s reg=%x val=%x", __get_str(name), __entry->reg, __entry->val) ); DEFINE_EVENT(regmap_reg, regmap_reg_write, @@ -43,7 +41,6 @@ DEFINE_EVENT(regmap_reg, regmap_reg_write, unsigned int val), TP_ARGS(map, reg, val) - ); DEFINE_EVENT(regmap_reg, regmap_reg_read, @@ -52,7 +49,6 @@ DEFINE_EVENT(regmap_reg, regmap_reg_read, unsigned int val), TP_ARGS(map, reg, val) - ); DEFINE_EVENT(regmap_reg, regmap_reg_read_cache, @@ -61,7 +57,47 @@ DEFINE_EVENT(regmap_reg, regmap_reg_read_cache, unsigned int val), TP_ARGS(map, reg, val) +); + +DECLARE_EVENT_CLASS(regmap_bulk, + + TP_PROTO(struct regmap *map, unsigned int reg, + const void *val, int val_len), + + TP_ARGS(map, reg, val, val_len), + + TP_STRUCT__entry( + __string(name, regmap_name(map)) + __field(unsigned int, reg) + __dynamic_array(char, buf, val_len) + __field(int, val_len) + ), + + TP_fast_assign( + __assign_str(name, regmap_name(map)); + __entry->reg = reg; + __entry->val_len = val_len; + memcpy(__get_dynamic_array(buf), val, val_len); + ), + TP_printk("%s reg=%x val=%s", __get_str(name), __entry->reg, + __print_hex(__get_dynamic_array(buf), __entry->val_len)) +); + +DEFINE_EVENT(regmap_bulk, regmap_bulk_write, + + TP_PROTO(struct regmap *map, unsigned int reg, + const void *val, int val_len), + + TP_ARGS(map, reg, val, val_len) +); + +DEFINE_EVENT(regmap_bulk, regmap_bulk_read, + + TP_PROTO(struct regmap *map, unsigned int reg, + const void *val, int val_len), + + TP_ARGS(map, reg, val, val_len) ); DECLARE_EVENT_CLASS(regmap_block, @@ -82,9 +118,7 @@ DECLARE_EVENT_CLASS(regmap_block, __entry->count = count; ), - TP_printk("%s reg=%x count=%d", __get_str(name), - (unsigned int)__entry->reg, - (int)__entry->count) + TP_printk("%s reg=%x count=%d", __get_str(name), __entry->reg, __entry->count) ); DEFINE_EVENT(regmap_block, regmap_hw_read_start, @@ -154,8 +188,7 @@ DECLARE_EVENT_CLASS(regmap_bool, __entry->flag = flag; ), - TP_printk("%s flag=%d", __get_str(name), - (int)__entry->flag) + TP_printk("%s flag=%d", __get_str(name), __entry->flag) ); DEFINE_EVENT(regmap_bool, regmap_cache_only, @@ -163,7 +196,6 @@ DEFINE_EVENT(regmap_bool, regmap_cache_only, TP_PROTO(struct regmap *map, bool flag), TP_ARGS(map, flag) - ); DEFINE_EVENT(regmap_bool, regmap_cache_bypass, @@ -171,7 +203,6 @@ DEFINE_EVENT(regmap_bool, regmap_cache_bypass, TP_PROTO(struct regmap *map, bool flag), TP_ARGS(map, flag) - ); DECLARE_EVENT_CLASS(regmap_async, @@ -203,7 +234,6 @@ DEFINE_EVENT(regmap_async, regmap_async_io_complete, TP_PROTO(struct regmap *map), TP_ARGS(map) - ); DEFINE_EVENT(regmap_async, regmap_async_complete_start, @@ -211,7 +241,6 @@ DEFINE_EVENT(regmap_async, regmap_async_complete_start, TP_PROTO(struct regmap *map), TP_ARGS(map) - ); DEFINE_EVENT(regmap_async, regmap_async_complete_done, @@ -219,7 +248,6 @@ DEFINE_EVENT(regmap_async, regmap_async_complete_done, TP_PROTO(struct regmap *map), TP_ARGS(map) - ); TRACE_EVENT(regcache_drop_region, @@ -241,8 +269,7 @@ TRACE_EVENT(regcache_drop_region, __entry->to = to; ), - TP_printk("%s %u-%u", __get_str(name), (unsigned int)__entry->from, - (unsigned int)__entry->to) + TP_printk("%s %u-%u", __get_str(name), __entry->from, __entry->to) ); #endif /* _TRACE_REGMAP_H */ diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 7cf2157134ac..ca3434dca3a0 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -311,6 +311,8 @@ typedef void (*regmap_unlock)(void *); * This field is a duplicate of a similar file in * 'struct regmap_bus' and serves exact same purpose. * Use it only for "no-bus" cases. + * @io_port: Support IO port accessors. Makes sense only when MMIO vs. IO port + * access can be distinguished. * @max_register: Optional, specifies the maximum valid register address. * @wr_table: Optional, points to a struct regmap_access_table specifying * valid ranges for write access. @@ -399,6 +401,7 @@ struct regmap_config { size_t max_raw_write; bool fast_io; + bool io_port; unsigned int max_register; const struct regmap_access_table *wr_table; @@ -489,8 +492,12 @@ typedef int (*regmap_hw_read)(void *context, void *val_buf, size_t val_size); typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg, unsigned int *val); +typedef int (*regmap_hw_reg_noinc_read)(void *context, unsigned int reg, + void *val, size_t val_count); typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg, unsigned int val); +typedef int (*regmap_hw_reg_noinc_write)(void *context, unsigned int reg, + const void *val, size_t val_count); typedef int (*regmap_hw_reg_update_bits)(void *context, unsigned int reg, unsigned int mask, unsigned int val); typedef struct regmap_async *(*regmap_hw_async_alloc)(void); @@ -511,6 +518,8 @@ typedef void (*regmap_hw_free_context)(void *context); * must serialise with respect to non-async I/O. * @reg_write: Write a single register value to the given register address. This * write operation has to complete when returning from the function. + * @reg_write_noinc: Write multiple register value to the same register. This + * write operation has to complete when returning from the function. * @reg_update_bits: Update bits operation to be used against volatile * registers, intended for devices supporting some mechanism * for setting clearing bits without having to @@ -538,9 +547,11 @@ struct regmap_bus { regmap_hw_gather_write gather_write; regmap_hw_async_write async_write; regmap_hw_reg_write reg_write; + regmap_hw_reg_noinc_write reg_noinc_write; regmap_hw_reg_update_bits reg_update_bits; regmap_hw_read read; regmap_hw_reg_read reg_read; + regmap_hw_reg_noinc_read reg_noinc_read; regmap_hw_free_context free_context; regmap_hw_async_alloc async_alloc; u8 read_flag_mask; diff --git a/include/linux/swab.h b/include/linux/swab.h index bcff5149861a..9b804dbb0d79 100644 --- a/include/linux/swab.h +++ b/include/linux/swab.h @@ -20,4 +20,29 @@ # define swab64s __swab64s # define swahw32s __swahw32s # define swahb32s __swahb32s + +static inline void swab16_array(u16 *buf, unsigned int words) +{ + while (words--) { + swab16s(buf); + buf++; + } +} + +static inline void swab32_array(u32 *buf, unsigned int words) +{ + while (words--) { + swab32s(buf); + buf++; + } +} + +static inline void swab64_array(u64 *buf, unsigned int words) +{ + while (words--) { + swab64s(buf); + buf++; + } +} + #endif /* _LINUX_SWAB_H */ |