Commit 521d04e3 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'regmap-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap

Pull regmap updates from Mark Brown:
 "This has been a busy release for regmap with one thing and other,
  there's been an especially large interest in MMIO regmaps for some
  reason. The bulk of the changes are cleanups but there are several
  user visible changes too:

   - Support for I/O ports in regmap-mmio

   - Support for accelerated noinc operations in regmap-mmio

   - Support for tracing the register values in bulk operations"

* tag 'regmap-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: mmio: replace return 0 with break in switch statement
  regmap: spi-avmm: Use swabXX_array() helpers
  regmap: mmio: Use swabXX_array() helpers
  swab: Add array operations
  regmap: trace: Remove unneeded blank lines
  regmap: trace: Remove explicit castings
  regmap: trace: Remove useless check for NULL for bulk ops
  regmap: mmio: Fix rebase error
  regmap: check right noinc bounds in debug print
  regmap: introduce value tracing for regmap bulk operations
  regmap/hexagon: Properly fix the generic IO helpers
  regmap: mmio: Support accelerared noinc operations
  regmap: Support accelerated noinc operations
  regmap: Make use of get_unaligned_be24(), put_unaligned_be24()
  regmap: mmio: Fix MMIO accessors to avoid talking to IO port
  regmap: mmio: Introduce IO accessors that can talk to IO port
  regmap: mmio: Get rid of broken 64-bit IO
  regmap: mmio: Remove mmio_relaxed member from context
parents 0baf6dcc 01ed2307
...@@ -308,6 +308,31 @@ static inline void outsl(unsigned long port, const void *buffer, int count) ...@@ -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 /* __KERNEL__ */
#endif #endif
...@@ -10,13 +10,14 @@ ...@@ -10,13 +10,14 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/swab.h>
#include "internal.h" #include "internal.h"
struct regmap_mmio_context { struct regmap_mmio_context {
void __iomem *regs; void __iomem *regs;
unsigned int val_bytes; unsigned int val_bytes;
bool relaxed_mmio; bool big_endian;
bool attached_clk; bool attached_clk;
struct clk *clk; struct clk *clk;
...@@ -33,9 +34,6 @@ static int regmap_mmio_regbits_check(size_t reg_bits) ...@@ -33,9 +34,6 @@ static int regmap_mmio_regbits_check(size_t reg_bits)
case 8: case 8:
case 16: case 16:
case 32: case 32:
#ifdef CONFIG_64BIT
case 64:
#endif
return 0; return 0;
default: default:
return -EINVAL; return -EINVAL;
...@@ -50,18 +48,13 @@ static int regmap_mmio_get_min_stride(size_t val_bits) ...@@ -50,18 +48,13 @@ static int regmap_mmio_get_min_stride(size_t val_bits)
case 8: case 8:
/* The core treats 0 as 1 */ /* The core treats 0 as 1 */
min_stride = 0; min_stride = 0;
return 0; break;
case 16: case 16:
min_stride = 2; min_stride = 2;
break; break;
case 32: case 32:
min_stride = 4; min_stride = 4;
break; break;
#ifdef CONFIG_64BIT
case 64:
min_stride = 8;
break;
#endif
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -83,6 +76,12 @@ static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx, ...@@ -83,6 +76,12 @@ static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx,
writeb_relaxed(val, ctx->regs + reg); 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, static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
unsigned int reg, unsigned int reg,
unsigned int val) unsigned int val)
...@@ -97,9 +96,21 @@ static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx, ...@@ -97,9 +96,21 @@ static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx,
writew_relaxed(val, ctx->regs + reg); 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, static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
unsigned int reg, unsigned int reg,
unsigned int val) 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); iowrite16be(val, ctx->regs + reg);
} }
...@@ -118,28 +129,24 @@ static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx, ...@@ -118,28 +129,24 @@ static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx,
writel_relaxed(val, ctx->regs + reg); writel_relaxed(val, ctx->regs + reg);
} }
static void regmap_mmio_write32be(struct regmap_mmio_context *ctx, static void regmap_mmio_iowrite32le(struct regmap_mmio_context *ctx,
unsigned int reg, unsigned int reg, unsigned int val)
unsigned int val)
{ {
iowrite32be(val, ctx->regs + reg); iowrite32(val, ctx->regs + reg);
} }
#ifdef CONFIG_64BIT static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
unsigned int reg, unsigned int reg,
unsigned int val) 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, static void regmap_mmio_iowrite32be(struct regmap_mmio_context *ctx,
unsigned int reg, unsigned int reg, unsigned int val)
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) 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) ...@@ -160,6 +167,83 @@ static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
return 0; 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, static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
unsigned int reg) unsigned int reg)
{ {
...@@ -172,6 +256,12 @@ static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx, ...@@ -172,6 +256,12 @@ static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx,
return readb_relaxed(ctx->regs + reg); 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, static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
unsigned int reg) unsigned int reg)
{ {
...@@ -184,8 +274,20 @@ static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx ...@@ -184,8 +274,20 @@ static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx
return readw_relaxed(ctx->regs + reg); 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, static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
unsigned int reg) 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); return ioread16be(ctx->regs + reg);
} }
...@@ -202,25 +304,23 @@ static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx ...@@ -202,25 +304,23 @@ static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx
return readl_relaxed(ctx->regs + reg); return readl_relaxed(ctx->regs + reg);
} }
static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx, static unsigned int regmap_mmio_ioread32le(struct regmap_mmio_context *ctx,
unsigned int reg) unsigned int reg)
{ {
return ioread32be(ctx->regs + reg); return ioread32(ctx->regs + reg);
} }
#ifdef CONFIG_64BIT static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
unsigned int reg) 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, static unsigned int regmap_mmio_ioread32be(struct regmap_mmio_context *ctx,
unsigned int reg) 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) 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) ...@@ -241,6 +341,71 @@ static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
return 0; 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) static void regmap_mmio_free_context(void *context)
{ {
struct regmap_mmio_context *ctx = context; struct regmap_mmio_context *ctx = context;
...@@ -257,6 +422,8 @@ static const struct regmap_bus regmap_mmio = { ...@@ -257,6 +422,8 @@ static const struct regmap_bus regmap_mmio = {
.fast_io = true, .fast_io = true,
.reg_write = regmap_mmio_write, .reg_write = regmap_mmio_write,
.reg_read = regmap_mmio_read, .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, .free_context = regmap_mmio_free_context,
.val_format_endian_default = REGMAP_ENDIAN_LITTLE, .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
}; };
...@@ -284,13 +451,15 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ...@@ -284,13 +451,15 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
if (config->reg_stride < min_stride) if (config->reg_stride < min_stride)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (config->use_relaxed_mmio && config->io_port)
return ERR_PTR(-EINVAL);
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) if (!ctx)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ctx->regs = regs; ctx->regs = regs;
ctx->val_bytes = config->val_bits / 8; ctx->val_bytes = config->val_bits / 8;
ctx->relaxed_mmio = config->use_relaxed_mmio;
ctx->clk = ERR_PTR(-ENODEV); ctx->clk = ERR_PTR(-ENODEV);
switch (regmap_get_val_endian(dev, &regmap_mmio, config)) { switch (regmap_get_val_endian(dev, &regmap_mmio, config)) {
...@@ -301,7 +470,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ...@@ -301,7 +470,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
#endif #endif
switch (config->val_bits) { switch (config->val_bits) {
case 8: 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_read = regmap_mmio_read8_relaxed;
ctx->reg_write = regmap_mmio_write8_relaxed; ctx->reg_write = regmap_mmio_write8_relaxed;
} else { } else {
...@@ -310,7 +482,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ...@@ -310,7 +482,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
} }
break; break;
case 16: 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_read = regmap_mmio_read16le_relaxed;
ctx->reg_write = regmap_mmio_write16le_relaxed; ctx->reg_write = regmap_mmio_write16le_relaxed;
} else { } else {
...@@ -319,7 +494,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ...@@ -319,7 +494,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
} }
break; break;
case 32: 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_read = regmap_mmio_read32le_relaxed;
ctx->reg_write = regmap_mmio_write32le_relaxed; ctx->reg_write = regmap_mmio_write32le_relaxed;
} else { } else {
...@@ -327,17 +505,6 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ...@@ -327,17 +505,6 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
ctx->reg_write = regmap_mmio_write32le; ctx->reg_write = regmap_mmio_write32le;
} }
break; 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: default:
ret = -EINVAL; ret = -EINVAL;
goto err_free; goto err_free;
...@@ -347,18 +514,34 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ...@@ -347,18 +514,34 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
#ifdef __BIG_ENDIAN #ifdef __BIG_ENDIAN
case REGMAP_ENDIAN_NATIVE: case REGMAP_ENDIAN_NATIVE:
#endif #endif
ctx->big_endian = true;
switch (config->val_bits) { switch (config->val_bits) {
case 8: case 8:
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_read = regmap_mmio_read8;
ctx->reg_write = regmap_mmio_write8; ctx->reg_write = regmap_mmio_write8;
}
break; break;
case 16: case 16:
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_read = regmap_mmio_read16be;
ctx->reg_write = regmap_mmio_write16be; ctx->reg_write = regmap_mmio_write16be;
}
break; break;
case 32: case 32:
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_read = regmap_mmio_read32be;
ctx->reg_write = regmap_mmio_write32be; ctx->reg_write = regmap_mmio_write32be;
}
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/swab.h>
/* /*
* This driver implements the regmap operations for a generic SPI * This driver implements the regmap operations for a generic SPI
...@@ -162,19 +163,12 @@ struct spi_avmm_bridge { ...@@ -162,19 +163,12 @@ struct spi_avmm_bridge {
/* bridge buffer used in translation between protocol layers */ /* bridge buffer used in translation between protocol layers */
char trans_buf[TRANS_BUF_SIZE]; char trans_buf[TRANS_BUF_SIZE];
char phy_buf[PHY_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; swab32_array(buf, len / 4);
unsigned int count;
count = len / 4;
while (count--) {
*p = swab32p(p);
p++;
}
} }
/* /*
......
...@@ -288,15 +288,9 @@ static void regmap_format_16_native(void *buf, unsigned int val, ...@@ -288,15 +288,9 @@ static void regmap_format_16_native(void *buf, unsigned int val,
memcpy(buf, &v, sizeof(v)); 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; put_unaligned_be24(val << shift, buf);
val <<= shift;
b[0] = val >> 16;
b[1] = val >> 8;
b[2] = val;
} }
static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift) 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) ...@@ -380,14 +374,9 @@ static unsigned int regmap_parse_16_native(const void *buf)
return v; 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; return get_unaligned_be24(buf);
unsigned int ret = b[2];
ret |= ((unsigned int)b[1]) << 8;
ret |= ((unsigned int)b[0]) << 16;
return ret;
} }
static unsigned int regmap_parse_32_be(const void *buf) static unsigned int regmap_parse_32_be(const void *buf)
...@@ -991,9 +980,13 @@ struct regmap *__regmap_init(struct device *dev, ...@@ -991,9 +980,13 @@ struct regmap *__regmap_init(struct device *dev,
break; break;
case 24: 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; goto err_hwlock;
map->format.format_reg = regmap_format_24; }
break; break;
case 32: case 32:
...@@ -1064,10 +1057,14 @@ struct regmap *__regmap_init(struct device *dev, ...@@ -1064,10 +1057,14 @@ struct regmap *__regmap_init(struct device *dev,
} }
break; break;
case 24: 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; goto err_hwlock;
map->format.format_val = regmap_format_24; }
map->format.parse_val = regmap_parse_24;
break; break;
case 32: case 32:
switch (val_endian) { switch (val_endian) {
...@@ -2132,6 +2129,99 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -2132,6 +2129,99 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
} }
EXPORT_SYMBOL_GPL(regmap_raw_write); 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 * regmap_noinc_write(): Write data from a register without incrementing the
* register number * register number
...@@ -2159,9 +2249,8 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg, ...@@ -2159,9 +2249,8 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
size_t write_len; size_t write_len;
int ret; int ret;
if (!map->write) if (!map->write && !(map->bus && map->bus->reg_noinc_write))
return -ENOTSUPP; return -EINVAL;
if (val_len % map->format.val_bytes) if (val_len % map->format.val_bytes)
return -EINVAL; return -EINVAL;
if (!IS_ALIGNED(reg, map->reg_stride)) if (!IS_ALIGNED(reg, map->reg_stride))
...@@ -2176,6 +2265,15 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg, ...@@ -2176,6 +2265,15 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
goto out_unlock; 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) { while (val_len) {
if (map->max_raw_write && map->max_raw_write < val_len) if (map->max_raw_write && map->max_raw_write < val_len)
write_len = map->max_raw_write; write_len = map->max_raw_write;
...@@ -2350,6 +2448,10 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, ...@@ -2350,6 +2448,10 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
kfree(wval); kfree(wval);
} }
if (!ret)
trace_regmap_bulk_write(map, reg, val, val_bytes * val_count);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(regmap_bulk_write); EXPORT_SYMBOL_GPL(regmap_bulk_write);
...@@ -2946,6 +3048,22 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg, ...@@ -2946,6 +3048,22 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
goto out_unlock; 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) { while (val_len) {
if (map->max_raw_read && map->max_raw_read < val_len) if (map->max_raw_read && map->max_raw_read < val_len)
read_len = map->max_raw_read; read_len = map->max_raw_read;
...@@ -3095,6 +3213,9 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, ...@@ -3095,6 +3213,9 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
map->unlock(map->lock_arg); map->unlock(map->lock_arg);
} }
if (!ret)
trace_regmap_bulk_read(map, reg, val, val_bytes * val_count);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(regmap_bulk_read); EXPORT_SYMBOL_GPL(regmap_bulk_read);
......
...@@ -32,9 +32,7 @@ DECLARE_EVENT_CLASS(regmap_reg, ...@@ -32,9 +32,7 @@ DECLARE_EVENT_CLASS(regmap_reg,
__entry->val = val; __entry->val = val;
), ),
TP_printk("%s reg=%x val=%x", __get_str(name), TP_printk("%s reg=%x val=%x", __get_str(name), __entry->reg, __entry->val)
(unsigned int)__entry->reg,
(unsigned int)__entry->val)
); );
DEFINE_EVENT(regmap_reg, regmap_reg_write, DEFINE_EVENT(regmap_reg, regmap_reg_write,
...@@ -43,7 +41,6 @@ DEFINE_EVENT(regmap_reg, regmap_reg_write, ...@@ -43,7 +41,6 @@ DEFINE_EVENT(regmap_reg, regmap_reg_write,
unsigned int val), unsigned int val),
TP_ARGS(map, reg, val) TP_ARGS(map, reg, val)
); );
DEFINE_EVENT(regmap_reg, regmap_reg_read, DEFINE_EVENT(regmap_reg, regmap_reg_read,
...@@ -52,7 +49,6 @@ DEFINE_EVENT(regmap_reg, regmap_reg_read, ...@@ -52,7 +49,6 @@ DEFINE_EVENT(regmap_reg, regmap_reg_read,
unsigned int val), unsigned int val),
TP_ARGS(map, reg, val) TP_ARGS(map, reg, val)
); );
DEFINE_EVENT(regmap_reg, regmap_reg_read_cache, DEFINE_EVENT(regmap_reg, regmap_reg_read_cache,
...@@ -61,7 +57,47 @@ DEFINE_EVENT(regmap_reg, regmap_reg_read_cache, ...@@ -61,7 +57,47 @@ DEFINE_EVENT(regmap_reg, regmap_reg_read_cache,
unsigned int val), unsigned int val),
TP_ARGS(map, reg, 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, DECLARE_EVENT_CLASS(regmap_block,
...@@ -82,9 +118,7 @@ DECLARE_EVENT_CLASS(regmap_block, ...@@ -82,9 +118,7 @@ DECLARE_EVENT_CLASS(regmap_block,
__entry->count = count; __entry->count = count;
), ),
TP_printk("%s reg=%x count=%d", __get_str(name), TP_printk("%s reg=%x count=%d", __get_str(name), __entry->reg, __entry->count)
(unsigned int)__entry->reg,
(int)__entry->count)
); );
DEFINE_EVENT(regmap_block, regmap_hw_read_start, DEFINE_EVENT(regmap_block, regmap_hw_read_start,
...@@ -154,8 +188,7 @@ DECLARE_EVENT_CLASS(regmap_bool, ...@@ -154,8 +188,7 @@ DECLARE_EVENT_CLASS(regmap_bool,
__entry->flag = flag; __entry->flag = flag;
), ),
TP_printk("%s flag=%d", __get_str(name), TP_printk("%s flag=%d", __get_str(name), __entry->flag)
(int)__entry->flag)
); );
DEFINE_EVENT(regmap_bool, regmap_cache_only, DEFINE_EVENT(regmap_bool, regmap_cache_only,
...@@ -163,7 +196,6 @@ 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_PROTO(struct regmap *map, bool flag),
TP_ARGS(map, flag) TP_ARGS(map, flag)
); );
DEFINE_EVENT(regmap_bool, regmap_cache_bypass, DEFINE_EVENT(regmap_bool, regmap_cache_bypass,
...@@ -171,7 +203,6 @@ 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_PROTO(struct regmap *map, bool flag),
TP_ARGS(map, flag) TP_ARGS(map, flag)
); );
DECLARE_EVENT_CLASS(regmap_async, DECLARE_EVENT_CLASS(regmap_async,
...@@ -203,7 +234,6 @@ DEFINE_EVENT(regmap_async, regmap_async_io_complete, ...@@ -203,7 +234,6 @@ DEFINE_EVENT(regmap_async, regmap_async_io_complete,
TP_PROTO(struct regmap *map), TP_PROTO(struct regmap *map),
TP_ARGS(map) TP_ARGS(map)
); );
DEFINE_EVENT(regmap_async, regmap_async_complete_start, DEFINE_EVENT(regmap_async, regmap_async_complete_start,
...@@ -211,7 +241,6 @@ 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_PROTO(struct regmap *map),
TP_ARGS(map) TP_ARGS(map)
); );
DEFINE_EVENT(regmap_async, regmap_async_complete_done, DEFINE_EVENT(regmap_async, regmap_async_complete_done,
...@@ -219,7 +248,6 @@ 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_PROTO(struct regmap *map),
TP_ARGS(map) TP_ARGS(map)
); );
TRACE_EVENT(regcache_drop_region, TRACE_EVENT(regcache_drop_region,
...@@ -241,8 +269,7 @@ TRACE_EVENT(regcache_drop_region, ...@@ -241,8 +269,7 @@ TRACE_EVENT(regcache_drop_region,
__entry->to = to; __entry->to = to;
), ),
TP_printk("%s %u-%u", __get_str(name), (unsigned int)__entry->from, TP_printk("%s %u-%u", __get_str(name), __entry->from, __entry->to)
(unsigned int)__entry->to)
); );
#endif /* _TRACE_REGMAP_H */ #endif /* _TRACE_REGMAP_H */
......
...@@ -311,6 +311,8 @@ typedef void (*regmap_unlock)(void *); ...@@ -311,6 +311,8 @@ typedef void (*regmap_unlock)(void *);
* This field is a duplicate of a similar file in * This field is a duplicate of a similar file in
* 'struct regmap_bus' and serves exact same purpose. * 'struct regmap_bus' and serves exact same purpose.
* Use it only for "no-bus" cases. * 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. * @max_register: Optional, specifies the maximum valid register address.
* @wr_table: Optional, points to a struct regmap_access_table specifying * @wr_table: Optional, points to a struct regmap_access_table specifying
* valid ranges for write access. * valid ranges for write access.
...@@ -399,6 +401,7 @@ struct regmap_config { ...@@ -399,6 +401,7 @@ struct regmap_config {
size_t max_raw_write; size_t max_raw_write;
bool fast_io; bool fast_io;
bool io_port;
unsigned int max_register; unsigned int max_register;
const struct regmap_access_table *wr_table; const struct regmap_access_table *wr_table;
...@@ -489,8 +492,12 @@ typedef int (*regmap_hw_read)(void *context, ...@@ -489,8 +492,12 @@ typedef int (*regmap_hw_read)(void *context,
void *val_buf, size_t val_size); void *val_buf, size_t val_size);
typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg, typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg,
unsigned int *val); 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, typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg,
unsigned int val); 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, typedef int (*regmap_hw_reg_update_bits)(void *context, unsigned int reg,
unsigned int mask, unsigned int val); unsigned int mask, unsigned int val);
typedef struct regmap_async *(*regmap_hw_async_alloc)(void); typedef struct regmap_async *(*regmap_hw_async_alloc)(void);
...@@ -511,6 +518,8 @@ typedef void (*regmap_hw_free_context)(void *context); ...@@ -511,6 +518,8 @@ typedef void (*regmap_hw_free_context)(void *context);
* must serialise with respect to non-async I/O. * must serialise with respect to non-async I/O.
* @reg_write: Write a single register value to the given register address. This * @reg_write: Write a single register value to the given register address. This
* write operation has to complete when returning from the function. * 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 * @reg_update_bits: Update bits operation to be used against volatile
* registers, intended for devices supporting some mechanism * registers, intended for devices supporting some mechanism
* for setting clearing bits without having to * for setting clearing bits without having to
...@@ -538,9 +547,11 @@ struct regmap_bus { ...@@ -538,9 +547,11 @@ struct regmap_bus {
regmap_hw_gather_write gather_write; regmap_hw_gather_write gather_write;
regmap_hw_async_write async_write; regmap_hw_async_write async_write;
regmap_hw_reg_write reg_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_reg_update_bits reg_update_bits;
regmap_hw_read read; regmap_hw_read read;
regmap_hw_reg_read reg_read; regmap_hw_reg_read reg_read;
regmap_hw_reg_noinc_read reg_noinc_read;
regmap_hw_free_context free_context; regmap_hw_free_context free_context;
regmap_hw_async_alloc async_alloc; regmap_hw_async_alloc async_alloc;
u8 read_flag_mask; u8 read_flag_mask;
......
...@@ -20,4 +20,29 @@ ...@@ -20,4 +20,29 @@
# define swab64s __swab64s # define swab64s __swab64s
# define swahw32s __swahw32s # define swahw32s __swahw32s
# define swahb32s __swahb32s # 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 */ #endif /* _LINUX_SWAB_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment