Commit ae82a828 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull regmap updates from Mark Brown:
 "A surprisingly large series of updates for regmap this time, mostly
  due to all the work Stephen Warren has done to add support for MMIO
  buses.  This wasn't really the target for the framework but it turns
  out that there's a reasonable number of cases where it's very helpful
  to use the register cache support to allow the register map to remain
  available while the device is suspended.

  - A MMIO bus implementation, contributed by Stephen Warren.  Currently
    this is limited to 32 bit systems and native endian registers.
  - Support for naming register maps, mainly intended for MMIO devices
    with multiple register banks.  This was also contributed by Stephen
    Warren.
  - Support for register striding, again contributed by Stephen Warren
    and mainly intended for use with MMIO as typically the registers
    will be a fixed size but byte addressed.
  - irqdomain support for the generic regmap irq_chip, including support
    for dynamically allocate interrupt numbers.
  - A function dev_get_regmap() which allows frameworks using regmap to
    obtain the regmap for a device from the struct device, making life a
    little simpler for them.
  - Updates to regmap-irq to support more chips (contributed by Graeme
    Gregory) and to use irqdomains.
  - Support for devices with 24 bit register addresses.

  The striding support collided with all the topic branches so the
  branches look a bit messy and eventually I just gave up.  There's also
  the TI Palmas driver and a couple of other isolated MFD patches that
  all depend on new regmap features so are being merged here."

* tag 'regmap-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: (24 commits)
  mfd: palmas PMIC device support Kconfig
  mfd: palmas PMIC device support
  regmap: Fix typo in IRQ register striding
  mfd: wm8994: Update to fully use irq_domain
  regmap: add support for non contiguous status to regmap-irq
  regmap: Convert regmap_irq to use irq_domain
  regmap: Pass back the allocated regmap IRQ controller data
  mfd: da9052: Fix genirq abuse
  regmap: Implement dev_get_regmap()
  regmap: Devices using format_write don't support bulk operations
  regmap: Converts group operation into single read write operations
  regmap: Cache single values read from the chip
  regmap: fix compile errors in regmap-irq.c due to stride changes
  regmap: implement register striding
  regmap: fix compilation when !CONFIG_DEBUG_FS
  regmap: allow regmap instances to be named
  regmap: validate regmap_raw_read/write val_len
  regmap: mmio: remove some error checks now in the core
  regmap: mmio: convert some error returns to BUG()
  regmap: add MMIO bus support
  ...
parents 3bb07f1b c948ef3a
...@@ -14,5 +14,8 @@ config REGMAP_I2C ...@@ -14,5 +14,8 @@ config REGMAP_I2C
config REGMAP_SPI config REGMAP_SPI
tristate tristate
config REGMAP_MMIO
tristate
config REGMAP_IRQ config REGMAP_IRQ
bool bool
...@@ -3,4 +3,5 @@ obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o ...@@ -3,4 +3,5 @@ obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
...@@ -26,21 +26,30 @@ struct regmap_format { ...@@ -26,21 +26,30 @@ struct regmap_format {
size_t val_bytes; size_t val_bytes;
void (*format_write)(struct regmap *map, void (*format_write)(struct regmap *map,
unsigned int reg, unsigned int val); unsigned int reg, unsigned int val);
void (*format_reg)(void *buf, unsigned int reg); void (*format_reg)(void *buf, unsigned int reg, unsigned int shift);
void (*format_val)(void *buf, unsigned int val); void (*format_val)(void *buf, unsigned int val, unsigned int shift);
unsigned int (*parse_val)(void *buf); unsigned int (*parse_val)(void *buf);
}; };
typedef void (*regmap_lock)(struct regmap *map);
typedef void (*regmap_unlock)(struct regmap *map);
struct regmap { struct regmap {
struct mutex lock; struct mutex mutex;
spinlock_t spinlock;
regmap_lock lock;
regmap_unlock unlock;
struct device *dev; /* Device we do I/O on */ struct device *dev; /* Device we do I/O on */
void *work_buf; /* Scratch buffer used to format I/O */ void *work_buf; /* Scratch buffer used to format I/O */
struct regmap_format format; /* Buffer format */ struct regmap_format format; /* Buffer format */
const struct regmap_bus *bus; const struct regmap_bus *bus;
void *bus_context;
const char *name;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *debugfs; struct dentry *debugfs;
const char *debugfs_name;
#endif #endif
unsigned int max_register; unsigned int max_register;
...@@ -52,6 +61,10 @@ struct regmap { ...@@ -52,6 +61,10 @@ struct regmap {
u8 read_flag_mask; u8 read_flag_mask;
u8 write_flag_mask; u8 write_flag_mask;
/* number of bits to (left) shift the reg value when formatting*/
int reg_shift;
int reg_stride;
/* regcache specific members */ /* regcache specific members */
const struct regcache_ops *cache_ops; const struct regcache_ops *cache_ops;
enum regcache_type cache_type; enum regcache_type cache_type;
...@@ -79,6 +92,9 @@ struct regmap { ...@@ -79,6 +92,9 @@ struct regmap {
struct reg_default *patch; struct reg_default *patch;
int patch_regs; int patch_regs;
/* if set, converts bulk rw to single rw */
bool use_single_rw;
}; };
struct regcache_ops { struct regcache_ops {
...@@ -101,11 +117,11 @@ int _regmap_write(struct regmap *map, unsigned int reg, ...@@ -101,11 +117,11 @@ int _regmap_write(struct regmap *map, unsigned int reg,
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
extern void regmap_debugfs_initcall(void); extern void regmap_debugfs_initcall(void);
extern void regmap_debugfs_init(struct regmap *map); extern void regmap_debugfs_init(struct regmap *map, const char *name);
extern void regmap_debugfs_exit(struct regmap *map); extern void regmap_debugfs_exit(struct regmap *map);
#else #else
static inline void regmap_debugfs_initcall(void) { } static inline void regmap_debugfs_initcall(void) { }
static inline void regmap_debugfs_init(struct regmap *map) { } static inline void regmap_debugfs_init(struct regmap *map, const char *name) { }
static inline void regmap_debugfs_exit(struct regmap *map) { } static inline void regmap_debugfs_exit(struct regmap *map) { }
#endif #endif
......
...@@ -108,7 +108,7 @@ static int regcache_lzo_decompress_cache_block(struct regmap *map, ...@@ -108,7 +108,7 @@ static int regcache_lzo_decompress_cache_block(struct regmap *map,
static inline int regcache_lzo_get_blkindex(struct regmap *map, static inline int regcache_lzo_get_blkindex(struct regmap *map,
unsigned int reg) unsigned int reg)
{ {
return (reg * map->cache_word_size) / return ((reg / map->reg_stride) * map->cache_word_size) /
DIV_ROUND_UP(map->cache_size_raw, DIV_ROUND_UP(map->cache_size_raw,
regcache_lzo_block_count(map)); regcache_lzo_block_count(map));
} }
...@@ -116,9 +116,10 @@ static inline int regcache_lzo_get_blkindex(struct regmap *map, ...@@ -116,9 +116,10 @@ static inline int regcache_lzo_get_blkindex(struct regmap *map,
static inline int regcache_lzo_get_blkpos(struct regmap *map, static inline int regcache_lzo_get_blkpos(struct regmap *map,
unsigned int reg) unsigned int reg)
{ {
return reg % (DIV_ROUND_UP(map->cache_size_raw, return (reg / map->reg_stride) %
regcache_lzo_block_count(map)) / (DIV_ROUND_UP(map->cache_size_raw,
map->cache_word_size); regcache_lzo_block_count(map)) /
map->cache_word_size);
} }
static inline int regcache_lzo_get_blksize(struct regmap *map) static inline int regcache_lzo_get_blksize(struct regmap *map)
...@@ -322,7 +323,7 @@ static int regcache_lzo_write(struct regmap *map, ...@@ -322,7 +323,7 @@ static int regcache_lzo_write(struct regmap *map,
} }
/* set the bit so we know we have to sync this register */ /* set the bit so we know we have to sync this register */
set_bit(reg, lzo_block->sync_bmp); set_bit(reg / map->reg_stride, lzo_block->sync_bmp);
kfree(tmp_dst); kfree(tmp_dst);
kfree(lzo_block->src); kfree(lzo_block->src);
return 0; return 0;
......
...@@ -39,11 +39,12 @@ struct regcache_rbtree_ctx { ...@@ -39,11 +39,12 @@ struct regcache_rbtree_ctx {
}; };
static inline void regcache_rbtree_get_base_top_reg( static inline void regcache_rbtree_get_base_top_reg(
struct regmap *map,
struct regcache_rbtree_node *rbnode, struct regcache_rbtree_node *rbnode,
unsigned int *base, unsigned int *top) unsigned int *base, unsigned int *top)
{ {
*base = rbnode->base_reg; *base = rbnode->base_reg;
*top = rbnode->base_reg + rbnode->blklen - 1; *top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride);
} }
static unsigned int regcache_rbtree_get_register( static unsigned int regcache_rbtree_get_register(
...@@ -70,7 +71,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map, ...@@ -70,7 +71,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
rbnode = rbtree_ctx->cached_rbnode; rbnode = rbtree_ctx->cached_rbnode;
if (rbnode) { if (rbnode) {
regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg); regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
&top_reg);
if (reg >= base_reg && reg <= top_reg) if (reg >= base_reg && reg <= top_reg)
return rbnode; return rbnode;
} }
...@@ -78,7 +80,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map, ...@@ -78,7 +80,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
node = rbtree_ctx->root.rb_node; node = rbtree_ctx->root.rb_node;
while (node) { while (node) {
rbnode = container_of(node, struct regcache_rbtree_node, node); rbnode = container_of(node, struct regcache_rbtree_node, node);
regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg); regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
&top_reg);
if (reg >= base_reg && reg <= top_reg) { if (reg >= base_reg && reg <= top_reg) {
rbtree_ctx->cached_rbnode = rbnode; rbtree_ctx->cached_rbnode = rbnode;
return rbnode; return rbnode;
...@@ -92,7 +95,7 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map, ...@@ -92,7 +95,7 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
return NULL; return NULL;
} }
static int regcache_rbtree_insert(struct rb_root *root, static int regcache_rbtree_insert(struct regmap *map, struct rb_root *root,
struct regcache_rbtree_node *rbnode) struct regcache_rbtree_node *rbnode)
{ {
struct rb_node **new, *parent; struct rb_node **new, *parent;
...@@ -106,7 +109,7 @@ static int regcache_rbtree_insert(struct rb_root *root, ...@@ -106,7 +109,7 @@ static int regcache_rbtree_insert(struct rb_root *root,
rbnode_tmp = container_of(*new, struct regcache_rbtree_node, rbnode_tmp = container_of(*new, struct regcache_rbtree_node,
node); node);
/* base and top registers of the current rbnode */ /* base and top registers of the current rbnode */
regcache_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp, regcache_rbtree_get_base_top_reg(map, rbnode_tmp, &base_reg_tmp,
&top_reg_tmp); &top_reg_tmp);
/* base register of the rbnode to be added */ /* base register of the rbnode to be added */
base_reg = rbnode->base_reg; base_reg = rbnode->base_reg;
...@@ -138,19 +141,20 @@ static int rbtree_show(struct seq_file *s, void *ignored) ...@@ -138,19 +141,20 @@ static int rbtree_show(struct seq_file *s, void *ignored)
unsigned int base, top; unsigned int base, top;
int nodes = 0; int nodes = 0;
int registers = 0; int registers = 0;
int average; int this_registers, average;
mutex_lock(&map->lock); map->lock(map);
for (node = rb_first(&rbtree_ctx->root); node != NULL; for (node = rb_first(&rbtree_ctx->root); node != NULL;
node = rb_next(node)) { node = rb_next(node)) {
n = container_of(node, struct regcache_rbtree_node, node); n = container_of(node, struct regcache_rbtree_node, node);
regcache_rbtree_get_base_top_reg(n, &base, &top); regcache_rbtree_get_base_top_reg(map, n, &base, &top);
seq_printf(s, "%x-%x (%d)\n", base, top, top - base + 1); this_registers = ((top - base) / map->reg_stride) + 1;
seq_printf(s, "%x-%x (%d)\n", base, top, this_registers);
nodes++; nodes++;
registers += top - base + 1; registers += this_registers;
} }
if (nodes) if (nodes)
...@@ -161,7 +165,7 @@ static int rbtree_show(struct seq_file *s, void *ignored) ...@@ -161,7 +165,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
seq_printf(s, "%d nodes, %d registers, average %d registers\n", seq_printf(s, "%d nodes, %d registers, average %d registers\n",
nodes, registers, average); nodes, registers, average);
mutex_unlock(&map->lock); map->unlock(map);
return 0; return 0;
} }
...@@ -255,7 +259,7 @@ static int regcache_rbtree_read(struct regmap *map, ...@@ -255,7 +259,7 @@ static int regcache_rbtree_read(struct regmap *map,
rbnode = regcache_rbtree_lookup(map, reg); rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) { if (rbnode) {
reg_tmp = reg - rbnode->base_reg; reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
*value = regcache_rbtree_get_register(rbnode, reg_tmp, *value = regcache_rbtree_get_register(rbnode, reg_tmp,
map->cache_word_size); map->cache_word_size);
} else { } else {
...@@ -310,7 +314,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, ...@@ -310,7 +314,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
*/ */
rbnode = regcache_rbtree_lookup(map, reg); rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) { if (rbnode) {
reg_tmp = reg - rbnode->base_reg; reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
val = regcache_rbtree_get_register(rbnode, reg_tmp, val = regcache_rbtree_get_register(rbnode, reg_tmp,
map->cache_word_size); map->cache_word_size);
if (val == value) if (val == value)
...@@ -321,13 +325,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, ...@@ -321,13 +325,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
/* look for an adjacent register to the one we are about to add */ /* look for an adjacent register to the one we are about to add */
for (node = rb_first(&rbtree_ctx->root); node; for (node = rb_first(&rbtree_ctx->root); node;
node = rb_next(node)) { node = rb_next(node)) {
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node, node); rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
node);
for (i = 0; i < rbnode_tmp->blklen; i++) { for (i = 0; i < rbnode_tmp->blklen; i++) {
reg_tmp = rbnode_tmp->base_reg + i; reg_tmp = rbnode_tmp->base_reg +
if (abs(reg_tmp - reg) != 1) (i * map->reg_stride);
if (abs(reg_tmp - reg) != map->reg_stride)
continue; continue;
/* decide where in the block to place our register */ /* decide where in the block to place our register */
if (reg_tmp + 1 == reg) if (reg_tmp + map->reg_stride == reg)
pos = i + 1; pos = i + 1;
else else
pos = i; pos = i;
...@@ -357,7 +363,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, ...@@ -357,7 +363,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
return -ENOMEM; return -ENOMEM;
} }
regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size); regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size);
regcache_rbtree_insert(&rbtree_ctx->root, rbnode); regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
rbtree_ctx->cached_rbnode = rbnode; rbtree_ctx->cached_rbnode = rbnode;
} }
...@@ -397,7 +403,7 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min, ...@@ -397,7 +403,7 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
end = rbnode->blklen; end = rbnode->blklen;
for (i = base; i < end; i++) { for (i = base; i < end; i++) {
regtmp = rbnode->base_reg + i; regtmp = rbnode->base_reg + (i * map->reg_stride);
val = regcache_rbtree_get_register(rbnode, i, val = regcache_rbtree_get_register(rbnode, i,
map->cache_word_size); map->cache_word_size);
......
...@@ -59,7 +59,7 @@ static int regcache_hw_init(struct regmap *map) ...@@ -59,7 +59,7 @@ static int regcache_hw_init(struct regmap *map)
for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) { for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
val = regcache_get_val(map->reg_defaults_raw, val = regcache_get_val(map->reg_defaults_raw,
i, map->cache_word_size); i, map->cache_word_size);
if (regmap_volatile(map, i)) if (regmap_volatile(map, i * map->reg_stride))
continue; continue;
count++; count++;
} }
...@@ -76,9 +76,9 @@ static int regcache_hw_init(struct regmap *map) ...@@ -76,9 +76,9 @@ static int regcache_hw_init(struct regmap *map)
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) { for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
val = regcache_get_val(map->reg_defaults_raw, val = regcache_get_val(map->reg_defaults_raw,
i, map->cache_word_size); i, map->cache_word_size);
if (regmap_volatile(map, i)) if (regmap_volatile(map, i * map->reg_stride))
continue; continue;
map->reg_defaults[j].reg = i; map->reg_defaults[j].reg = i * map->reg_stride;
map->reg_defaults[j].def = val; map->reg_defaults[j].def = val;
j++; j++;
} }
...@@ -98,6 +98,10 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) ...@@ -98,6 +98,10 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
int i; int i;
void *tmp_buf; void *tmp_buf;
for (i = 0; i < config->num_reg_defaults; i++)
if (config->reg_defaults[i].reg % map->reg_stride)
return -EINVAL;
if (map->cache_type == REGCACHE_NONE) { if (map->cache_type == REGCACHE_NONE) {
map->cache_bypass = true; map->cache_bypass = true;
return 0; return 0;
...@@ -264,7 +268,7 @@ int regcache_sync(struct regmap *map) ...@@ -264,7 +268,7 @@ int regcache_sync(struct regmap *map)
BUG_ON(!map->cache_ops || !map->cache_ops->sync); BUG_ON(!map->cache_ops || !map->cache_ops->sync);
mutex_lock(&map->lock); map->lock(map);
/* Remember the initial bypass state */ /* Remember the initial bypass state */
bypass = map->cache_bypass; bypass = map->cache_bypass;
dev_dbg(map->dev, "Syncing %s cache\n", dev_dbg(map->dev, "Syncing %s cache\n",
...@@ -278,6 +282,10 @@ int regcache_sync(struct regmap *map) ...@@ -278,6 +282,10 @@ int regcache_sync(struct regmap *map)
/* Apply any patch first */ /* Apply any patch first */
map->cache_bypass = 1; map->cache_bypass = 1;
for (i = 0; i < map->patch_regs; i++) { for (i = 0; i < map->patch_regs; i++) {
if (map->patch[i].reg % map->reg_stride) {
ret = -EINVAL;
goto out;
}
ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def); ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
if (ret != 0) { if (ret != 0) {
dev_err(map->dev, "Failed to write %x = %x: %d\n", dev_err(map->dev, "Failed to write %x = %x: %d\n",
...@@ -296,7 +304,7 @@ int regcache_sync(struct regmap *map) ...@@ -296,7 +304,7 @@ int regcache_sync(struct regmap *map)
trace_regcache_sync(map->dev, name, "stop"); trace_regcache_sync(map->dev, name, "stop");
/* Restore the bypass state */ /* Restore the bypass state */
map->cache_bypass = bypass; map->cache_bypass = bypass;
mutex_unlock(&map->lock); map->unlock(map);
return ret; return ret;
} }
...@@ -323,7 +331,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min, ...@@ -323,7 +331,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
BUG_ON(!map->cache_ops || !map->cache_ops->sync); BUG_ON(!map->cache_ops || !map->cache_ops->sync);
mutex_lock(&map->lock); map->lock(map);
/* Remember the initial bypass state */ /* Remember the initial bypass state */
bypass = map->cache_bypass; bypass = map->cache_bypass;
...@@ -342,7 +350,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min, ...@@ -342,7 +350,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
trace_regcache_sync(map->dev, name, "stop region"); trace_regcache_sync(map->dev, name, "stop region");
/* Restore the bypass state */ /* Restore the bypass state */
map->cache_bypass = bypass; map->cache_bypass = bypass;
mutex_unlock(&map->lock); map->unlock(map);
return ret; return ret;
} }
...@@ -362,11 +370,11 @@ EXPORT_SYMBOL_GPL(regcache_sync_region); ...@@ -362,11 +370,11 @@ EXPORT_SYMBOL_GPL(regcache_sync_region);
*/ */
void regcache_cache_only(struct regmap *map, bool enable) void regcache_cache_only(struct regmap *map, bool enable)
{ {
mutex_lock(&map->lock); map->lock(map);
WARN_ON(map->cache_bypass && enable); WARN_ON(map->cache_bypass && enable);
map->cache_only = enable; map->cache_only = enable;
trace_regmap_cache_only(map->dev, enable); trace_regmap_cache_only(map->dev, enable);
mutex_unlock(&map->lock); map->unlock(map);
} }
EXPORT_SYMBOL_GPL(regcache_cache_only); EXPORT_SYMBOL_GPL(regcache_cache_only);
...@@ -381,9 +389,9 @@ EXPORT_SYMBOL_GPL(regcache_cache_only); ...@@ -381,9 +389,9 @@ EXPORT_SYMBOL_GPL(regcache_cache_only);
*/ */
void regcache_mark_dirty(struct regmap *map) void regcache_mark_dirty(struct regmap *map)
{ {
mutex_lock(&map->lock); map->lock(map);
map->cache_dirty = true; map->cache_dirty = true;
mutex_unlock(&map->lock); map->unlock(map);
} }
EXPORT_SYMBOL_GPL(regcache_mark_dirty); EXPORT_SYMBOL_GPL(regcache_mark_dirty);
...@@ -400,11 +408,11 @@ EXPORT_SYMBOL_GPL(regcache_mark_dirty); ...@@ -400,11 +408,11 @@ EXPORT_SYMBOL_GPL(regcache_mark_dirty);
*/ */
void regcache_cache_bypass(struct regmap *map, bool enable) void regcache_cache_bypass(struct regmap *map, bool enable)
{ {
mutex_lock(&map->lock); map->lock(map);
WARN_ON(map->cache_only && enable); WARN_ON(map->cache_only && enable);
map->cache_bypass = enable; map->cache_bypass = enable;
trace_regmap_cache_bypass(map->dev, enable); trace_regmap_cache_bypass(map->dev, enable);
mutex_unlock(&map->lock); map->unlock(map);
} }
EXPORT_SYMBOL_GPL(regcache_cache_bypass); EXPORT_SYMBOL_GPL(regcache_cache_bypass);
......
...@@ -80,7 +80,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, ...@@ -80,7 +80,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
val_len = 2 * map->format.val_bytes; val_len = 2 * map->format.val_bytes;
tot_len = reg_len + val_len + 3; /* : \n */ tot_len = reg_len + val_len + 3; /* : \n */
for (i = 0; i < map->max_register + 1; i++) { for (i = 0; i <= map->max_register; i += map->reg_stride) {
if (!regmap_readable(map, i)) if (!regmap_readable(map, i))
continue; continue;
...@@ -197,7 +197,7 @@ static ssize_t regmap_access_read_file(struct file *file, ...@@ -197,7 +197,7 @@ static ssize_t regmap_access_read_file(struct file *file,
reg_len = regmap_calc_reg_len(map->max_register, buf, count); reg_len = regmap_calc_reg_len(map->max_register, buf, count);
tot_len = reg_len + 10; /* ': R W V P\n' */ tot_len = reg_len + 10; /* ': R W V P\n' */
for (i = 0; i < map->max_register + 1; i++) { for (i = 0; i <= map->max_register; i += map->reg_stride) {
/* Ignore registers which are neither readable nor writable */ /* Ignore registers which are neither readable nor writable */
if (!regmap_readable(map, i) && !regmap_writeable(map, i)) if (!regmap_readable(map, i) && !regmap_writeable(map, i))
continue; continue;
...@@ -242,10 +242,17 @@ static const struct file_operations regmap_access_fops = { ...@@ -242,10 +242,17 @@ static const struct file_operations regmap_access_fops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
void regmap_debugfs_init(struct regmap *map) void regmap_debugfs_init(struct regmap *map, const char *name)
{ {
map->debugfs = debugfs_create_dir(dev_name(map->dev), if (name) {
regmap_debugfs_root); map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
dev_name(map->dev), name);
name = map->debugfs_name;
} else {
name = dev_name(map->dev);
}
map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
if (!map->debugfs) { if (!map->debugfs) {
dev_warn(map->dev, "Failed to create debugfs directory\n"); dev_warn(map->dev, "Failed to create debugfs directory\n");
return; return;
...@@ -274,6 +281,7 @@ void regmap_debugfs_init(struct regmap *map) ...@@ -274,6 +281,7 @@ void regmap_debugfs_init(struct regmap *map)
void regmap_debugfs_exit(struct regmap *map) void regmap_debugfs_exit(struct regmap *map)
{ {
debugfs_remove_recursive(map->debugfs); debugfs_remove_recursive(map->debugfs);
kfree(map->debugfs_name);
} }
void regmap_debugfs_initcall(void) void regmap_debugfs_initcall(void)
......
...@@ -15,8 +15,9 @@ ...@@ -15,8 +15,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
static int regmap_i2c_write(struct device *dev, const void *data, size_t count) static int regmap_i2c_write(void *context, const void *data, size_t count)
{ {
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev); struct i2c_client *i2c = to_i2c_client(dev);
int ret; int ret;
...@@ -29,10 +30,11 @@ static int regmap_i2c_write(struct device *dev, const void *data, size_t count) ...@@ -29,10 +30,11 @@ static int regmap_i2c_write(struct device *dev, const void *data, size_t count)
return -EIO; return -EIO;
} }
static int regmap_i2c_gather_write(struct device *dev, static int regmap_i2c_gather_write(void *context,
const void *reg, size_t reg_size, const void *reg, size_t reg_size,
const void *val, size_t val_size) const void *val, size_t val_size)
{ {
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev); struct i2c_client *i2c = to_i2c_client(dev);
struct i2c_msg xfer[2]; struct i2c_msg xfer[2];
int ret; int ret;
...@@ -62,10 +64,11 @@ static int regmap_i2c_gather_write(struct device *dev, ...@@ -62,10 +64,11 @@ static int regmap_i2c_gather_write(struct device *dev,
return -EIO; return -EIO;
} }
static int regmap_i2c_read(struct device *dev, static int regmap_i2c_read(void *context,
const void *reg, size_t reg_size, const void *reg, size_t reg_size,
void *val, size_t val_size) void *val, size_t val_size)
{ {
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev); struct i2c_client *i2c = to_i2c_client(dev);
struct i2c_msg xfer[2]; struct i2c_msg xfer[2];
int ret; int ret;
...@@ -107,7 +110,7 @@ static struct regmap_bus regmap_i2c = { ...@@ -107,7 +110,7 @@ static struct regmap_bus regmap_i2c = {
struct regmap *regmap_init_i2c(struct i2c_client *i2c, struct regmap *regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config) const struct regmap_config *config)
{ {
return regmap_init(&i2c->dev, &regmap_i2c, config); return regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
} }
EXPORT_SYMBOL_GPL(regmap_init_i2c); EXPORT_SYMBOL_GPL(regmap_init_i2c);
...@@ -124,7 +127,7 @@ EXPORT_SYMBOL_GPL(regmap_init_i2c); ...@@ -124,7 +127,7 @@ EXPORT_SYMBOL_GPL(regmap_init_i2c);
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config) const struct regmap_config *config)
{ {
return devm_regmap_init(&i2c->dev, &regmap_i2c, config); return devm_regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
} }
EXPORT_SYMBOL_GPL(devm_regmap_init_i2c); EXPORT_SYMBOL_GPL(devm_regmap_init_i2c);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "internal.h" #include "internal.h"
...@@ -26,18 +27,20 @@ struct regmap_irq_chip_data { ...@@ -26,18 +27,20 @@ struct regmap_irq_chip_data {
struct regmap_irq_chip *chip; struct regmap_irq_chip *chip;
int irq_base; int irq_base;
struct irq_domain *domain;
void *status_reg_buf;
unsigned int *status_buf; unsigned int *status_buf;
unsigned int *mask_buf; unsigned int *mask_buf;
unsigned int *mask_buf_def; unsigned int *mask_buf_def;
unsigned int irq_reg_stride;
}; };
static inline const static inline const
struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data, struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data,
int irq) int irq)
{ {
return &data->chip->irqs[irq - data->irq_base]; return &data->chip->irqs[irq];
} }
static void regmap_irq_lock(struct irq_data *data) static void regmap_irq_lock(struct irq_data *data)
...@@ -50,6 +53,7 @@ static void regmap_irq_lock(struct irq_data *data) ...@@ -50,6 +53,7 @@ static void regmap_irq_lock(struct irq_data *data)
static void regmap_irq_sync_unlock(struct irq_data *data) static void regmap_irq_sync_unlock(struct irq_data *data)
{ {
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
struct regmap *map = d->map;
int i, ret; int i, ret;
/* /*
...@@ -58,11 +62,13 @@ static void regmap_irq_sync_unlock(struct irq_data *data) ...@@ -58,11 +62,13 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
* suppress pointless writes. * suppress pointless writes.
*/ */
for (i = 0; i < d->chip->num_regs; i++) { for (i = 0; i < d->chip->num_regs; i++) {
ret = regmap_update_bits(d->map, d->chip->mask_base + i, ret = regmap_update_bits(d->map, d->chip->mask_base +
(i * map->reg_stride *
d->irq_reg_stride),
d->mask_buf_def[i], d->mask_buf[i]); d->mask_buf_def[i], d->mask_buf[i]);
if (ret != 0) if (ret != 0)
dev_err(d->map->dev, "Failed to sync masks in %x\n", dev_err(d->map->dev, "Failed to sync masks in %x\n",
d->chip->mask_base + i); d->chip->mask_base + (i * map->reg_stride));
} }
mutex_unlock(&d->lock); mutex_unlock(&d->lock);
...@@ -71,17 +77,19 @@ static void regmap_irq_sync_unlock(struct irq_data *data) ...@@ -71,17 +77,19 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
static void regmap_irq_enable(struct irq_data *data) static void regmap_irq_enable(struct irq_data *data)
{ {
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq); struct regmap *map = d->map;
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
d->mask_buf[irq_data->reg_offset] &= ~irq_data->mask; d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask;
} }
static void regmap_irq_disable(struct irq_data *data) static void regmap_irq_disable(struct irq_data *data)
{ {
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq); struct regmap *map = d->map;
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
d->mask_buf[irq_data->reg_offset] |= irq_data->mask; d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
} }
static struct irq_chip regmap_irq_chip = { static struct irq_chip regmap_irq_chip = {
...@@ -98,18 +106,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) ...@@ -98,18 +106,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
struct regmap_irq_chip *chip = data->chip; struct regmap_irq_chip *chip = data->chip;
struct regmap *map = data->map; struct regmap *map = data->map;
int ret, i; int ret, i;
u8 *buf8 = data->status_reg_buf;
u16 *buf16 = data->status_reg_buf;
u32 *buf32 = data->status_reg_buf;
bool handled = false; bool handled = false;
ret = regmap_bulk_read(map, chip->status_base, data->status_reg_buf,
chip->num_regs);
if (ret != 0) {
dev_err(map->dev, "Failed to read IRQ status: %d\n", ret);
return IRQ_NONE;
}
/* /*
* Ignore masked IRQs and ack if we need to; we ack early so * Ignore masked IRQs and ack if we need to; we ack early so
* there is no race between handling and acknowleding the * there is no race between handling and acknowleding the
...@@ -118,36 +116,34 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) ...@@ -118,36 +116,34 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
* doing a write per register. * doing a write per register.
*/ */
for (i = 0; i < data->chip->num_regs; i++) { for (i = 0; i < data->chip->num_regs; i++) {
switch (map->format.val_bytes) { ret = regmap_read(map, chip->status_base + (i * map->reg_stride
case 1: * data->irq_reg_stride),
data->status_buf[i] = buf8[i]; &data->status_buf[i]);
break;
case 2: if (ret != 0) {
data->status_buf[i] = buf16[i]; dev_err(map->dev, "Failed to read IRQ status: %d\n",
break; ret);
case 4:
data->status_buf[i] = buf32[i];
break;
default:
BUG();
return IRQ_NONE; return IRQ_NONE;
} }
data->status_buf[i] &= ~data->mask_buf[i]; data->status_buf[i] &= ~data->mask_buf[i];
if (data->status_buf[i] && chip->ack_base) { if (data->status_buf[i] && chip->ack_base) {
ret = regmap_write(map, chip->ack_base + i, ret = regmap_write(map, chip->ack_base +
(i * map->reg_stride *
data->irq_reg_stride),
data->status_buf[i]); data->status_buf[i]);
if (ret != 0) if (ret != 0)
dev_err(map->dev, "Failed to ack 0x%x: %d\n", dev_err(map->dev, "Failed to ack 0x%x: %d\n",
chip->ack_base + i, ret); chip->ack_base + (i * map->reg_stride),
ret);
} }
} }
for (i = 0; i < chip->num_irqs; i++) { for (i = 0; i < chip->num_irqs; i++) {
if (data->status_buf[chip->irqs[i].reg_offset] & if (data->status_buf[chip->irqs[i].reg_offset /
chip->irqs[i].mask) { map->reg_stride] & chip->irqs[i].mask) {
handle_nested_irq(data->irq_base + i); handle_nested_irq(irq_find_mapping(data->domain, i));
handled = true; handled = true;
} }
} }
...@@ -158,6 +154,31 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) ...@@ -158,6 +154,31 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
return IRQ_NONE; return IRQ_NONE;
} }
static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct regmap_irq_chip_data *data = h->host_data;
irq_set_chip_data(virq, data);
irq_set_chip_and_handler(virq, &regmap_irq_chip, handle_edge_irq);
irq_set_nested_thread(virq, 1);
/* ARM needs us to explicitly flag the IRQ as valid
* and will set them noprobe when we do so. */
#ifdef CONFIG_ARM
set_irq_flags(virq, IRQF_VALID);
#else
irq_set_noprobe(virq);
#endif
return 0;
}
static struct irq_domain_ops regmap_domain_ops = {
.map = regmap_irq_map,
.xlate = irq_domain_xlate_twocell,
};
/** /**
* regmap_add_irq_chip(): Use standard regmap IRQ controller handling * regmap_add_irq_chip(): Use standard regmap IRQ controller handling
* *
...@@ -178,30 +199,37 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -178,30 +199,37 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
struct regmap_irq_chip_data **data) struct regmap_irq_chip_data **data)
{ {
struct regmap_irq_chip_data *d; struct regmap_irq_chip_data *d;
int cur_irq, i; int i;
int ret = -ENOMEM; int ret = -ENOMEM;
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0); for (i = 0; i < chip->num_irqs; i++) {
if (irq_base < 0) { if (chip->irqs[i].reg_offset % map->reg_stride)
dev_warn(map->dev, "Failed to allocate IRQs: %d\n", return -EINVAL;
irq_base); if (chip->irqs[i].reg_offset / map->reg_stride >=
return irq_base; chip->num_regs)
return -EINVAL;
}
if (irq_base) {
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
if (irq_base < 0) {
dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
irq_base);
return irq_base;
}
} }
d = kzalloc(sizeof(*d), GFP_KERNEL); d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d) if (!d)
return -ENOMEM; return -ENOMEM;
*data = d;
d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
GFP_KERNEL); GFP_KERNEL);
if (!d->status_buf) if (!d->status_buf)
goto err_alloc; goto err_alloc;
d->status_reg_buf = kzalloc(map->format.val_bytes * chip->num_regs,
GFP_KERNEL);
if (!d->status_reg_buf)
goto err_alloc;
d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
GFP_KERNEL); GFP_KERNEL);
if (!d->mask_buf) if (!d->mask_buf)
...@@ -215,54 +243,59 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -215,54 +243,59 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
d->map = map; d->map = map;
d->chip = chip; d->chip = chip;
d->irq_base = irq_base; d->irq_base = irq_base;
if (chip->irq_reg_stride)
d->irq_reg_stride = chip->irq_reg_stride;
else
d->irq_reg_stride = 1;
mutex_init(&d->lock); mutex_init(&d->lock);
for (i = 0; i < chip->num_irqs; i++) for (i = 0; i < chip->num_irqs; i++)
d->mask_buf_def[chip->irqs[i].reg_offset] d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride]
|= chip->irqs[i].mask; |= chip->irqs[i].mask;
/* Mask all the interrupts by default */ /* Mask all the interrupts by default */
for (i = 0; i < chip->num_regs; i++) { for (i = 0; i < chip->num_regs; i++) {
d->mask_buf[i] = d->mask_buf_def[i]; d->mask_buf[i] = d->mask_buf_def[i];
ret = regmap_write(map, chip->mask_base + i, d->mask_buf[i]); ret = regmap_write(map, chip->mask_base + (i * map->reg_stride
* d->irq_reg_stride),
d->mask_buf[i]);
if (ret != 0) { if (ret != 0) {
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
chip->mask_base + i, ret); chip->mask_base + (i * map->reg_stride), ret);
goto err_alloc; goto err_alloc;
} }
} }
/* Register them with genirq */ if (irq_base)
for (cur_irq = irq_base; d->domain = irq_domain_add_legacy(map->dev->of_node,
cur_irq < chip->num_irqs + irq_base; chip->num_irqs, irq_base, 0,
cur_irq++) { &regmap_domain_ops, d);
irq_set_chip_data(cur_irq, d); else
irq_set_chip_and_handler(cur_irq, &regmap_irq_chip, d->domain = irq_domain_add_linear(map->dev->of_node,
handle_edge_irq); chip->num_irqs,
irq_set_nested_thread(cur_irq, 1); &regmap_domain_ops, d);
if (!d->domain) {
/* ARM needs us to explicitly flag the IRQ as valid dev_err(map->dev, "Failed to create IRQ domain\n");
* and will set them noprobe when we do so. */ ret = -ENOMEM;
#ifdef CONFIG_ARM goto err_alloc;
set_irq_flags(cur_irq, IRQF_VALID);
#else
irq_set_noprobe(cur_irq);
#endif
} }
ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags, ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags,
chip->name, d); chip->name, d);
if (ret != 0) { if (ret != 0) {
dev_err(map->dev, "Failed to request IRQ %d: %d\n", irq, ret); dev_err(map->dev, "Failed to request IRQ %d: %d\n", irq, ret);
goto err_alloc; goto err_domain;
} }
return 0; return 0;
err_domain:
/* Should really dispose of the domain but... */
err_alloc: err_alloc:
kfree(d->mask_buf_def); kfree(d->mask_buf_def);
kfree(d->mask_buf); kfree(d->mask_buf);
kfree(d->status_reg_buf);
kfree(d->status_buf); kfree(d->status_buf);
kfree(d); kfree(d);
return ret; return ret;
...@@ -281,9 +314,9 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) ...@@ -281,9 +314,9 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
return; return;
free_irq(irq, d); free_irq(irq, d);
/* We should unmap the domain but... */
kfree(d->mask_buf_def); kfree(d->mask_buf_def);
kfree(d->mask_buf); kfree(d->mask_buf);
kfree(d->status_reg_buf);
kfree(d->status_buf); kfree(d->status_buf);
kfree(d); kfree(d);
} }
...@@ -298,6 +331,21 @@ EXPORT_SYMBOL_GPL(regmap_del_irq_chip); ...@@ -298,6 +331,21 @@ EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
*/ */
int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data) int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data)
{ {
WARN_ON(!data->irq_base);
return data->irq_base; return data->irq_base;
} }
EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base); EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base);
/**
* regmap_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
*
* Useful for drivers to request their own IRQs.
*
* @data: regmap_irq controller to operate on.
* @irq: index of the interrupt requested in the chip IRQs
*/
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)
{
return irq_create_mapping(data->domain, irq);
}
EXPORT_SYMBOL_GPL(regmap_irq_get_virq);
/*
* Register map access API - MMIO support
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
struct regmap_mmio_context {
void __iomem *regs;
unsigned val_bytes;
};
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;
BUG_ON(reg_size != 4);
offset = be32_to_cpup(reg);
while (val_size) {
switch (ctx->val_bytes) {
case 1:
writeb(*(u8 *)val, ctx->regs + offset);
break;
case 2:
writew(be16_to_cpup(val), ctx->regs + offset);
break;
case 4:
writel(be32_to_cpup(val), ctx->regs + offset);
break;
#ifdef CONFIG_64BIT
case 8:
writeq(be64_to_cpup(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;
}
return 0;
}
static int regmap_mmio_write(void *context, const void *data, size_t count)
{
BUG_ON(count < 4);
return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4);
}
static int regmap_mmio_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
struct regmap_mmio_context *ctx = context;
u32 offset;
BUG_ON(reg_size != 4);
offset = be32_to_cpup(reg);
while (val_size) {
switch (ctx->val_bytes) {
case 1:
*(u8 *)val = readb(ctx->regs + offset);
break;
case 2:
*(u16 *)val = cpu_to_be16(readw(ctx->regs + offset));
break;
case 4:
*(u32 *)val = cpu_to_be32(readl(ctx->regs + offset));
break;
#ifdef CONFIG_64BIT
case 8:
*(u64 *)val = cpu_to_be32(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;
}
return 0;
}
static void regmap_mmio_free_context(void *context)
{
kfree(context);
}
static struct regmap_bus regmap_mmio = {
.fast_io = true,
.write = regmap_mmio_write,
.gather_write = regmap_mmio_gather_write,
.read = regmap_mmio_read,
.free_context = regmap_mmio_free_context,
};
struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
const struct regmap_config *config)
{
struct regmap_mmio_context *ctx;
int min_stride;
if (config->reg_bits != 32)
return ERR_PTR(-EINVAL);
if (config->pad_bits)
return ERR_PTR(-EINVAL);
switch (config->val_bits) {
case 8:
/* The core treats 0 as 1 */
min_stride = 0;
break;
case 16:
min_stride = 2;
break;
case 32:
min_stride = 4;
break;
#ifdef CONFIG_64BIT
case 64:
min_stride = 8;
break;
#endif
break;
default:
return ERR_PTR(-EINVAL);
}
if (config->reg_stride < min_stride)
return ERR_PTR(-EINVAL);
ctx = kzalloc(GFP_KERNEL, sizeof(*ctx));
if (!ctx)
return ERR_PTR(-ENOMEM);
ctx->regs = regs;
ctx->val_bytes = config->val_bits / 8;
return ctx;
}
/**
* regmap_init_mmio(): Initialise register map
*
* @dev: Device that will be interacted with
* @regs: Pointer to memory-mapped IO region
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
struct regmap *regmap_init_mmio(struct device *dev,
void __iomem *regs,
const struct regmap_config *config)
{
struct regmap_mmio_context *ctx;
ctx = regmap_mmio_gen_context(regs, config);
if (IS_ERR(ctx))
return ERR_CAST(ctx);
return regmap_init(dev, &regmap_mmio, ctx, config);
}
EXPORT_SYMBOL_GPL(regmap_init_mmio);
/**
* devm_regmap_init_mmio(): Initialise managed register map
*
* @dev: Device that will be interacted with
* @regs: Pointer to memory-mapped IO region
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
struct regmap *devm_regmap_init_mmio(struct device *dev,
void __iomem *regs,
const struct regmap_config *config)
{
struct regmap_mmio_context *ctx;
ctx = regmap_mmio_gen_context(regs, config);
if (IS_ERR(ctx))
return ERR_CAST(ctx);
return devm_regmap_init(dev, &regmap_mmio, ctx, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_mmio);
MODULE_LICENSE("GPL v2");
...@@ -15,17 +15,19 @@ ...@@ -15,17 +15,19 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
static int regmap_spi_write(struct device *dev, const void *data, size_t count) static int regmap_spi_write(void *context, const void *data, size_t count)
{ {
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev); struct spi_device *spi = to_spi_device(dev);
return spi_write(spi, data, count); return spi_write(spi, data, count);
} }
static int regmap_spi_gather_write(struct device *dev, static int regmap_spi_gather_write(void *context,
const void *reg, size_t reg_len, const void *reg, size_t reg_len,
const void *val, size_t val_len) const void *val, size_t val_len)
{ {
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev); struct spi_device *spi = to_spi_device(dev);
struct spi_message m; struct spi_message m;
struct spi_transfer t[2] = { { .tx_buf = reg, .len = reg_len, }, struct spi_transfer t[2] = { { .tx_buf = reg, .len = reg_len, },
...@@ -38,10 +40,11 @@ static int regmap_spi_gather_write(struct device *dev, ...@@ -38,10 +40,11 @@ static int regmap_spi_gather_write(struct device *dev,
return spi_sync(spi, &m); return spi_sync(spi, &m);
} }
static int regmap_spi_read(struct device *dev, static int regmap_spi_read(void *context,
const void *reg, size_t reg_size, const void *reg, size_t reg_size,
void *val, size_t val_size) void *val, size_t val_size)
{ {
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev); struct spi_device *spi = to_spi_device(dev);
return spi_write_then_read(spi, reg, reg_size, val, val_size); return spi_write_then_read(spi, reg, reg_size, val, val_size);
...@@ -66,7 +69,7 @@ static struct regmap_bus regmap_spi = { ...@@ -66,7 +69,7 @@ static struct regmap_bus regmap_spi = {
struct regmap *regmap_init_spi(struct spi_device *spi, struct regmap *regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config) const struct regmap_config *config)
{ {
return regmap_init(&spi->dev, &regmap_spi, config); return regmap_init(&spi->dev, &regmap_spi, &spi->dev, config);
} }
EXPORT_SYMBOL_GPL(regmap_init_spi); EXPORT_SYMBOL_GPL(regmap_init_spi);
...@@ -83,7 +86,7 @@ EXPORT_SYMBOL_GPL(regmap_init_spi); ...@@ -83,7 +86,7 @@ EXPORT_SYMBOL_GPL(regmap_init_spi);
struct regmap *devm_regmap_init_spi(struct spi_device *spi, struct regmap *devm_regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config) const struct regmap_config *config)
{ {
return devm_regmap_init(&spi->dev, &regmap_spi, config); return devm_regmap_init(&spi->dev, &regmap_spi, &spi->dev, config);
} }
EXPORT_SYMBOL_GPL(devm_regmap_init_spi); EXPORT_SYMBOL_GPL(devm_regmap_init_spi);
......
...@@ -112,25 +112,36 @@ static void regmap_format_10_14_write(struct regmap *map, ...@@ -112,25 +112,36 @@ static void regmap_format_10_14_write(struct regmap *map,
out[0] = reg >> 2; out[0] = reg >> 2;
} }
static void regmap_format_8(void *buf, unsigned int val) static void regmap_format_8(void *buf, unsigned int val, unsigned int shift)
{ {
u8 *b = buf; u8 *b = buf;
b[0] = val; b[0] = val << shift;
} }
static void regmap_format_16(void *buf, unsigned int val) static void regmap_format_16(void *buf, unsigned int val, unsigned int shift)
{ {
__be16 *b = buf; __be16 *b = buf;
b[0] = cpu_to_be16(val); b[0] = cpu_to_be16(val << shift);
} }
static void regmap_format_32(void *buf, unsigned int val) static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
{
u8 *b = buf;
val <<= shift;
b[0] = val >> 16;
b[1] = val >> 8;
b[2] = val;
}
static void regmap_format_32(void *buf, unsigned int val, unsigned int shift)
{ {
__be32 *b = buf; __be32 *b = buf;
b[0] = cpu_to_be32(val); b[0] = cpu_to_be32(val << shift);
} }
static unsigned int regmap_parse_8(void *buf) static unsigned int regmap_parse_8(void *buf)
...@@ -149,6 +160,16 @@ static unsigned int regmap_parse_16(void *buf) ...@@ -149,6 +160,16 @@ static unsigned int regmap_parse_16(void *buf)
return b[0]; return b[0];
} }
static unsigned int regmap_parse_24(void *buf)
{
u8 *b = 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(void *buf) static unsigned int regmap_parse_32(void *buf)
{ {
__be32 *b = buf; __be32 *b = buf;
...@@ -158,11 +179,41 @@ static unsigned int regmap_parse_32(void *buf) ...@@ -158,11 +179,41 @@ static unsigned int regmap_parse_32(void *buf)
return b[0]; return b[0];
} }
static void regmap_lock_mutex(struct regmap *map)
{
mutex_lock(&map->mutex);
}
static void regmap_unlock_mutex(struct regmap *map)
{
mutex_unlock(&map->mutex);
}
static void regmap_lock_spinlock(struct regmap *map)
{
spin_lock(&map->spinlock);
}
static void regmap_unlock_spinlock(struct regmap *map)
{
spin_unlock(&map->spinlock);
}
static void dev_get_regmap_release(struct device *dev, void *res)
{
/*
* We don't actually have anything to do here; the goal here
* is not to manage the regmap but to provide a simple way to
* get the regmap back given a struct device.
*/
}
/** /**
* regmap_init(): Initialise register map * regmap_init(): Initialise register map
* *
* @dev: Device that will be interacted with * @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device * @bus: Bus-specific callbacks to use with device
* @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map * @config: Configuration for register map
* *
* The return value will be an ERR_PTR() on error or a valid pointer to * The return value will be an ERR_PTR() on error or a valid pointer to
...@@ -171,9 +222,10 @@ static unsigned int regmap_parse_32(void *buf) ...@@ -171,9 +222,10 @@ static unsigned int regmap_parse_32(void *buf)
*/ */
struct regmap *regmap_init(struct device *dev, struct regmap *regmap_init(struct device *dev,
const struct regmap_bus *bus, const struct regmap_bus *bus,
void *bus_context,
const struct regmap_config *config) const struct regmap_config *config)
{ {
struct regmap *map; struct regmap *map, **m;
int ret = -EINVAL; int ret = -EINVAL;
if (!bus || !config) if (!bus || !config)
...@@ -185,20 +237,36 @@ struct regmap *regmap_init(struct device *dev, ...@@ -185,20 +237,36 @@ struct regmap *regmap_init(struct device *dev,
goto err; goto err;
} }
mutex_init(&map->lock); if (bus->fast_io) {
spin_lock_init(&map->spinlock);
map->lock = regmap_lock_spinlock;
map->unlock = regmap_unlock_spinlock;
} else {
mutex_init(&map->mutex);
map->lock = regmap_lock_mutex;
map->unlock = regmap_unlock_mutex;
}
map->format.buf_size = (config->reg_bits + config->val_bits) / 8; map->format.buf_size = (config->reg_bits + config->val_bits) / 8;
map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8);
map->format.pad_bytes = config->pad_bits / 8; map->format.pad_bytes = config->pad_bits / 8;
map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8);
map->format.buf_size += map->format.pad_bytes; map->format.buf_size += map->format.pad_bytes;
map->reg_shift = config->pad_bits % 8;
if (config->reg_stride)
map->reg_stride = config->reg_stride;
else
map->reg_stride = 1;
map->use_single_rw = config->use_single_rw;
map->dev = dev; map->dev = dev;
map->bus = bus; map->bus = bus;
map->bus_context = bus_context;
map->max_register = config->max_register; map->max_register = config->max_register;
map->writeable_reg = config->writeable_reg; map->writeable_reg = config->writeable_reg;
map->readable_reg = config->readable_reg; map->readable_reg = config->readable_reg;
map->volatile_reg = config->volatile_reg; map->volatile_reg = config->volatile_reg;
map->precious_reg = config->precious_reg; map->precious_reg = config->precious_reg;
map->cache_type = config->cache_type; map->cache_type = config->cache_type;
map->name = config->name;
if (config->read_flag_mask || config->write_flag_mask) { if (config->read_flag_mask || config->write_flag_mask) {
map->read_flag_mask = config->read_flag_mask; map->read_flag_mask = config->read_flag_mask;
...@@ -207,7 +275,7 @@ struct regmap *regmap_init(struct device *dev, ...@@ -207,7 +275,7 @@ struct regmap *regmap_init(struct device *dev,
map->read_flag_mask = bus->read_flag_mask; map->read_flag_mask = bus->read_flag_mask;
} }
switch (config->reg_bits) { switch (config->reg_bits + map->reg_shift) {
case 2: case 2:
switch (config->val_bits) { switch (config->val_bits) {
case 6: case 6:
...@@ -273,12 +341,19 @@ struct regmap *regmap_init(struct device *dev, ...@@ -273,12 +341,19 @@ struct regmap *regmap_init(struct device *dev,
map->format.format_val = regmap_format_16; map->format.format_val = regmap_format_16;
map->format.parse_val = regmap_parse_16; map->format.parse_val = regmap_parse_16;
break; break;
case 24:
map->format.format_val = regmap_format_24;
map->format.parse_val = regmap_parse_24;
break;
case 32: case 32:
map->format.format_val = regmap_format_32; map->format.format_val = regmap_format_32;
map->format.parse_val = regmap_parse_32; map->format.parse_val = regmap_parse_32;
break; break;
} }
if (map->format.format_write)
map->use_single_rw = true;
if (!map->format.format_write && if (!map->format.format_write &&
!(map->format.format_reg && map->format.format_val)) !(map->format.format_reg && map->format.format_val))
goto err_map; goto err_map;
...@@ -289,14 +364,25 @@ struct regmap *regmap_init(struct device *dev, ...@@ -289,14 +364,25 @@ struct regmap *regmap_init(struct device *dev,
goto err_map; goto err_map;
} }
regmap_debugfs_init(map); regmap_debugfs_init(map, config->name);
ret = regcache_init(map, config); ret = regcache_init(map, config);
if (ret < 0) if (ret < 0)
goto err_free_workbuf; goto err_free_workbuf;
/* Add a devres resource for dev_get_regmap() */
m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
if (!m) {
ret = -ENOMEM;
goto err_cache;
}
*m = map;
devres_add(dev, m);
return map; return map;
err_cache:
regcache_exit(map);
err_free_workbuf: err_free_workbuf:
kfree(map->work_buf); kfree(map->work_buf);
err_map: err_map:
...@@ -316,6 +402,7 @@ static void devm_regmap_release(struct device *dev, void *res) ...@@ -316,6 +402,7 @@ static void devm_regmap_release(struct device *dev, void *res)
* *
* @dev: Device that will be interacted with * @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device * @bus: Bus-specific callbacks to use with device
* @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map * @config: Configuration for register map
* *
* The return value will be an ERR_PTR() on error or a valid pointer * The return value will be an ERR_PTR() on error or a valid pointer
...@@ -325,6 +412,7 @@ static void devm_regmap_release(struct device *dev, void *res) ...@@ -325,6 +412,7 @@ static void devm_regmap_release(struct device *dev, void *res)
*/ */
struct regmap *devm_regmap_init(struct device *dev, struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus, const struct regmap_bus *bus,
void *bus_context,
const struct regmap_config *config) const struct regmap_config *config)
{ {
struct regmap **ptr, *regmap; struct regmap **ptr, *regmap;
...@@ -333,7 +421,7 @@ struct regmap *devm_regmap_init(struct device *dev, ...@@ -333,7 +421,7 @@ struct regmap *devm_regmap_init(struct device *dev,
if (!ptr) if (!ptr)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
regmap = regmap_init(dev, bus, config); regmap = regmap_init(dev, bus, bus_context, config);
if (!IS_ERR(regmap)) { if (!IS_ERR(regmap)) {
*ptr = regmap; *ptr = regmap;
devres_add(dev, ptr); devres_add(dev, ptr);
...@@ -360,7 +448,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) ...@@ -360,7 +448,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
{ {
int ret; int ret;
mutex_lock(&map->lock); map->lock(map);
regcache_exit(map); regcache_exit(map);
regmap_debugfs_exit(map); regmap_debugfs_exit(map);
...@@ -372,14 +460,14 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) ...@@ -372,14 +460,14 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
map->precious_reg = config->precious_reg; map->precious_reg = config->precious_reg;
map->cache_type = config->cache_type; map->cache_type = config->cache_type;
regmap_debugfs_init(map); regmap_debugfs_init(map, config->name);
map->cache_bypass = false; map->cache_bypass = false;
map->cache_only = false; map->cache_only = false;
ret = regcache_init(map, config); ret = regcache_init(map, config);
mutex_unlock(&map->lock); map->unlock(map);
return ret; return ret;
} }
...@@ -391,11 +479,51 @@ void regmap_exit(struct regmap *map) ...@@ -391,11 +479,51 @@ void regmap_exit(struct regmap *map)
{ {
regcache_exit(map); regcache_exit(map);
regmap_debugfs_exit(map); regmap_debugfs_exit(map);
if (map->bus->free_context)
map->bus->free_context(map->bus_context);
kfree(map->work_buf); kfree(map->work_buf);
kfree(map); kfree(map);
} }
EXPORT_SYMBOL_GPL(regmap_exit); EXPORT_SYMBOL_GPL(regmap_exit);
static int dev_get_regmap_match(struct device *dev, void *res, void *data)
{
struct regmap **r = res;
if (!r || !*r) {
WARN_ON(!r || !*r);
return 0;
}
/* If the user didn't specify a name match any */
if (data)
return (*r)->name == data;
else
return 1;
}
/**
* dev_get_regmap(): Obtain the regmap (if any) for a device
*
* @dev: Device to retrieve the map for
* @name: Optional name for the register map, usually NULL.
*
* Returns the regmap for the device if one is present, or NULL. If
* name is specified then it must match the name specified when
* registering the device, if it is NULL then the first regmap found
* will be used. Devices with multiple register maps are very rare,
* generic code should normally not need to specify a name.
*/
struct regmap *dev_get_regmap(struct device *dev, const char *name)
{
struct regmap **r = devres_find(dev, dev_get_regmap_release,
dev_get_regmap_match, (void *)name);
if (!r)
return NULL;
return *r;
}
EXPORT_SYMBOL_GPL(dev_get_regmap);
static int _regmap_raw_write(struct regmap *map, unsigned int reg, static int _regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len) const void *val, size_t val_len)
{ {
...@@ -408,7 +536,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -408,7 +536,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
/* Check for unwritable registers before we start */ /* Check for unwritable registers before we start */
if (map->writeable_reg) if (map->writeable_reg)
for (i = 0; i < val_len / map->format.val_bytes; i++) for (i = 0; i < val_len / map->format.val_bytes; i++)
if (!map->writeable_reg(map->dev, reg + i)) if (!map->writeable_reg(map->dev,
reg + (i * map->reg_stride)))
return -EINVAL; return -EINVAL;
if (!map->cache_bypass && map->format.parse_val) { if (!map->cache_bypass && map->format.parse_val) {
...@@ -417,7 +546,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -417,7 +546,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
for (i = 0; i < val_len / val_bytes; i++) { for (i = 0; i < val_len / val_bytes; i++) {
memcpy(map->work_buf, val + (i * val_bytes), val_bytes); memcpy(map->work_buf, val + (i * val_bytes), val_bytes);
ival = map->format.parse_val(map->work_buf); ival = map->format.parse_val(map->work_buf);
ret = regcache_write(map, reg + i, ival); ret = regcache_write(map, reg + (i * map->reg_stride),
ival);
if (ret) { if (ret) {
dev_err(map->dev, dev_err(map->dev,
"Error in caching of register: %u ret: %d\n", "Error in caching of register: %u ret: %d\n",
...@@ -431,7 +561,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -431,7 +561,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
} }
} }
map->format.format_reg(map->work_buf, reg); map->format.format_reg(map->work_buf, reg, map->reg_shift);
u8[0] |= map->write_flag_mask; u8[0] |= map->write_flag_mask;
...@@ -444,12 +574,12 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -444,12 +574,12 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
*/ */
if (val == (map->work_buf + map->format.pad_bytes + if (val == (map->work_buf + map->format.pad_bytes +
map->format.reg_bytes)) map->format.reg_bytes))
ret = map->bus->write(map->dev, map->work_buf, ret = map->bus->write(map->bus_context, map->work_buf,
map->format.reg_bytes + map->format.reg_bytes +
map->format.pad_bytes + map->format.pad_bytes +
val_len); val_len);
else if (map->bus->gather_write) else if (map->bus->gather_write)
ret = map->bus->gather_write(map->dev, map->work_buf, ret = map->bus->gather_write(map->bus_context, map->work_buf,
map->format.reg_bytes + map->format.reg_bytes +
map->format.pad_bytes, map->format.pad_bytes,
val, val_len); val, val_len);
...@@ -464,7 +594,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -464,7 +594,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
memcpy(buf, map->work_buf, map->format.reg_bytes); memcpy(buf, map->work_buf, map->format.reg_bytes);
memcpy(buf + map->format.reg_bytes + map->format.pad_bytes, memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
val, val_len); val, val_len);
ret = map->bus->write(map->dev, buf, len); ret = map->bus->write(map->bus_context, buf, len);
kfree(buf); kfree(buf);
} }
...@@ -498,7 +628,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, ...@@ -498,7 +628,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
trace_regmap_hw_write_start(map->dev, reg, 1); trace_regmap_hw_write_start(map->dev, reg, 1);
ret = map->bus->write(map->dev, map->work_buf, ret = map->bus->write(map->bus_context, map->work_buf,
map->format.buf_size); map->format.buf_size);
trace_regmap_hw_write_done(map->dev, reg, 1); trace_regmap_hw_write_done(map->dev, reg, 1);
...@@ -506,7 +636,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, ...@@ -506,7 +636,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
return ret; return ret;
} else { } else {
map->format.format_val(map->work_buf + map->format.reg_bytes map->format.format_val(map->work_buf + map->format.reg_bytes
+ map->format.pad_bytes, val); + map->format.pad_bytes, val, 0);
return _regmap_raw_write(map, reg, return _regmap_raw_write(map, reg,
map->work_buf + map->work_buf +
map->format.reg_bytes + map->format.reg_bytes +
...@@ -529,11 +659,14 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) ...@@ -529,11 +659,14 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
{ {
int ret; int ret;
mutex_lock(&map->lock); if (reg % map->reg_stride)
return -EINVAL;
map->lock(map);
ret = _regmap_write(map, reg, val); ret = _regmap_write(map, reg, val);
mutex_unlock(&map->lock); map->unlock(map);
return ret; return ret;
} }
...@@ -560,11 +693,16 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -560,11 +693,16 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
{ {
int ret; int ret;
mutex_lock(&map->lock); if (val_len % map->format.val_bytes)
return -EINVAL;
if (reg % map->reg_stride)
return -EINVAL;
map->lock(map);
ret = _regmap_raw_write(map, reg, val, val_len); ret = _regmap_raw_write(map, reg, val, val_len);
mutex_unlock(&map->lock); map->unlock(map);
return ret; return ret;
} }
...@@ -593,8 +731,10 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, ...@@ -593,8 +731,10 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (!map->format.parse_val) if (!map->format.parse_val)
return -EINVAL; return -EINVAL;
if (reg % map->reg_stride)
return -EINVAL;
mutex_lock(&map->lock); map->lock(map);
/* No formatting is require if val_byte is 1 */ /* No formatting is require if val_byte is 1 */
if (val_bytes == 1) { if (val_bytes == 1) {
...@@ -609,13 +749,28 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, ...@@ -609,13 +749,28 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
for (i = 0; i < val_count * val_bytes; i += val_bytes) for (i = 0; i < val_count * val_bytes; i += val_bytes)
map->format.parse_val(wval + i); map->format.parse_val(wval + i);
} }
ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); /*
* Some devices does not support bulk write, for
* them we have a series of single write operations.
*/
if (map->use_single_rw) {
for (i = 0; i < val_count; i++) {
ret = regmap_raw_write(map,
reg + (i * map->reg_stride),
val + (i * val_bytes),
val_bytes);
if (ret != 0)
return ret;
}
} else {
ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
}
if (val_bytes != 1) if (val_bytes != 1)
kfree(wval); kfree(wval);
out: out:
mutex_unlock(&map->lock); map->unlock(map);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(regmap_bulk_write); EXPORT_SYMBOL_GPL(regmap_bulk_write);
...@@ -626,7 +781,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -626,7 +781,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
u8 *u8 = map->work_buf; u8 *u8 = map->work_buf;
int ret; int ret;
map->format.format_reg(map->work_buf, reg); map->format.format_reg(map->work_buf, reg, map->reg_shift);
/* /*
* Some buses or devices flag reads by setting the high bits in the * Some buses or devices flag reads by setting the high bits in the
...@@ -639,7 +794,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -639,7 +794,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
trace_regmap_hw_read_start(map->dev, reg, trace_regmap_hw_read_start(map->dev, reg,
val_len / map->format.val_bytes); val_len / map->format.val_bytes);
ret = map->bus->read(map->dev, map->work_buf, ret = map->bus->read(map->bus_context, map->work_buf,
map->format.reg_bytes + map->format.pad_bytes, map->format.reg_bytes + map->format.pad_bytes,
val, val_len); val, val_len);
...@@ -672,6 +827,9 @@ static int _regmap_read(struct regmap *map, unsigned int reg, ...@@ -672,6 +827,9 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
trace_regmap_reg_read(map->dev, reg, *val); trace_regmap_reg_read(map->dev, reg, *val);
} }
if (ret == 0 && !map->cache_bypass)
regcache_write(map, reg, *val);
return ret; return ret;
} }
...@@ -689,11 +847,14 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) ...@@ -689,11 +847,14 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
{ {
int ret; int ret;
mutex_lock(&map->lock); if (reg % map->reg_stride)
return -EINVAL;
map->lock(map);
ret = _regmap_read(map, reg, val); ret = _regmap_read(map, reg, val);
mutex_unlock(&map->lock); map->unlock(map);
return ret; return ret;
} }
...@@ -718,7 +879,12 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -718,7 +879,12 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
unsigned int v; unsigned int v;
int ret, i; int ret, i;
mutex_lock(&map->lock); if (val_len % map->format.val_bytes)
return -EINVAL;
if (reg % map->reg_stride)
return -EINVAL;
map->lock(map);
if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass || if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
map->cache_type == REGCACHE_NONE) { map->cache_type == REGCACHE_NONE) {
...@@ -730,16 +896,17 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -730,16 +896,17 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
* cost as we expect to hit the cache. * cost as we expect to hit the cache.
*/ */
for (i = 0; i < val_count; i++) { for (i = 0; i < val_count; i++) {
ret = _regmap_read(map, reg + i, &v); ret = _regmap_read(map, reg + (i * map->reg_stride),
&v);
if (ret != 0) if (ret != 0)
goto out; goto out;
map->format.format_val(val + (i * val_bytes), v); map->format.format_val(val + (i * val_bytes), v, 0);
} }
} }
out: out:
mutex_unlock(&map->lock); map->unlock(map);
return ret; return ret;
} }
...@@ -765,18 +932,37 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, ...@@ -765,18 +932,37 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
if (!map->format.parse_val) if (!map->format.parse_val)
return -EINVAL; return -EINVAL;
if (reg % map->reg_stride)
return -EINVAL;
if (vol || map->cache_type == REGCACHE_NONE) { if (vol || map->cache_type == REGCACHE_NONE) {
ret = regmap_raw_read(map, reg, val, val_bytes * val_count); /*
if (ret != 0) * Some devices does not support bulk read, for
return ret; * them we have a series of single read operations.
*/
if (map->use_single_rw) {
for (i = 0; i < val_count; i++) {
ret = regmap_raw_read(map,
reg + (i * map->reg_stride),
val + (i * val_bytes),
val_bytes);
if (ret != 0)
return ret;
}
} else {
ret = regmap_raw_read(map, reg, val,
val_bytes * val_count);
if (ret != 0)
return ret;
}
for (i = 0; i < val_count * val_bytes; i += val_bytes) for (i = 0; i < val_count * val_bytes; i += val_bytes)
map->format.parse_val(val + i); map->format.parse_val(val + i);
} else { } else {
for (i = 0; i < val_count; i++) { for (i = 0; i < val_count; i++) {
unsigned int ival; unsigned int ival;
ret = regmap_read(map, reg + i, &ival); ret = regmap_read(map, reg + (i * map->reg_stride),
&ival);
if (ret != 0) if (ret != 0)
return ret; return ret;
memcpy(val + (i * val_bytes), &ival, val_bytes); memcpy(val + (i * val_bytes), &ival, val_bytes);
...@@ -794,7 +980,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, ...@@ -794,7 +980,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
int ret; int ret;
unsigned int tmp, orig; unsigned int tmp, orig;
mutex_lock(&map->lock); map->lock(map);
ret = _regmap_read(map, reg, &orig); ret = _regmap_read(map, reg, &orig);
if (ret != 0) if (ret != 0)
...@@ -811,7 +997,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, ...@@ -811,7 +997,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
} }
out: out:
mutex_unlock(&map->lock); map->unlock(map);
return ret; return ret;
} }
...@@ -878,7 +1064,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, ...@@ -878,7 +1064,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
if (map->patch) if (map->patch)
return -EBUSY; return -EBUSY;
mutex_lock(&map->lock); map->lock(map);
bypass = map->cache_bypass; bypass = map->cache_bypass;
...@@ -906,7 +1092,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, ...@@ -906,7 +1092,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
out: out:
map->cache_bypass = bypass; map->cache_bypass = bypass;
mutex_unlock(&map->lock); map->unlock(map);
return ret; return ret;
} }
......
...@@ -376,6 +376,7 @@ config PMIC_DA9052 ...@@ -376,6 +376,7 @@ config PMIC_DA9052
config MFD_DA9052_SPI config MFD_DA9052_SPI
bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI" bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI"
select IRQ_DOMAIN
select REGMAP_SPI select REGMAP_SPI
select REGMAP_IRQ select REGMAP_IRQ
select PMIC_DA9052 select PMIC_DA9052
...@@ -388,6 +389,7 @@ config MFD_DA9052_SPI ...@@ -388,6 +389,7 @@ config MFD_DA9052_SPI
config MFD_DA9052_I2C config MFD_DA9052_I2C
bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C" bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C"
select IRQ_DOMAIN
select REGMAP_I2C select REGMAP_I2C
select REGMAP_IRQ select REGMAP_IRQ
select PMIC_DA9052 select PMIC_DA9052
...@@ -558,6 +560,7 @@ config MFD_WM8994 ...@@ -558,6 +560,7 @@ config MFD_WM8994
bool "Support Wolfson Microelectronics WM8994" bool "Support Wolfson Microelectronics WM8994"
select MFD_CORE select MFD_CORE
select REGMAP_I2C select REGMAP_I2C
select IRQ_DOMAIN
select REGMAP_IRQ select REGMAP_IRQ
depends on I2C=y && GENERIC_HARDIRQS depends on I2C=y && GENERIC_HARDIRQS
help help
...@@ -888,6 +891,16 @@ config MFD_ANATOP ...@@ -888,6 +891,16 @@ config MFD_ANATOP
MFD controller. This controller embeds regulator and MFD controller. This controller embeds regulator and
thermal devices for Freescale i.MX platforms. thermal devices for Freescale i.MX platforms.
config MFD_PALMAS
bool "Support for the TI Palmas series chips"
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
depends on I2C=y
help
If you say yes here you get support for the Palmas
series of PMIC chips from Texas Instruments.
endmenu endmenu
endif endif
......
...@@ -113,6 +113,8 @@ obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o ...@@ -113,6 +113,8 @@ obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o
obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
...@@ -659,12 +659,11 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id) ...@@ -659,12 +659,11 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
ret = regmap_add_irq_chip(da9052->regmap, da9052->chip_irq, ret = regmap_add_irq_chip(da9052->regmap, da9052->chip_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
da9052->irq_base, &da9052_regmap_irq_chip, da9052->irq_base, &da9052_regmap_irq_chip,
NULL); &da9052->irq_data);
if (ret < 0) if (ret < 0)
goto regmap_err; goto regmap_err;
desc = irq_to_desc(da9052->chip_irq); da9052->irq_base = regmap_irq_chip_get_base(da9052->irq_data);
da9052->irq_base = regmap_irq_chip_get_base(desc->action->dev_id);
ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info, ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info,
ARRAY_SIZE(da9052_subdev_info), NULL, 0); ARRAY_SIZE(da9052_subdev_info), NULL, 0);
...@@ -681,8 +680,7 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id) ...@@ -681,8 +680,7 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
void da9052_device_exit(struct da9052 *da9052) void da9052_device_exit(struct da9052 *da9052)
{ {
regmap_del_irq_chip(da9052->chip_irq, regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data);
irq_get_irq_data(da9052->irq_base)->chip_data);
mfd_remove_devices(da9052->dev); mfd_remove_devices(da9052->dev);
} }
......
/*
* TI Palmas MFD Driver
*
* Copyright 2011-2012 Texas Instruments Inc.
*
* Author: Graeme Gregory <gg@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/regmap.h>
#include <linux/err.h>
#include <linux/mfd/core.h>
#include <linux/mfd/palmas.h>
static const struct resource gpadc_resource[] = {
{
.name = "EOC_SW",
.start = PALMAS_GPADC_EOC_SW_IRQ,
.end = PALMAS_GPADC_EOC_SW_IRQ,
.flags = IORESOURCE_IRQ,
}
};
static const struct resource usb_resource[] = {
{
.name = "ID",
.start = PALMAS_ID_OTG_IRQ,
.end = PALMAS_ID_OTG_IRQ,
.flags = IORESOURCE_IRQ,
},
{
.name = "ID_WAKEUP",
.start = PALMAS_ID_IRQ,
.end = PALMAS_ID_IRQ,
.flags = IORESOURCE_IRQ,
},
{
.name = "VBUS",
.start = PALMAS_VBUS_OTG_IRQ,
.end = PALMAS_VBUS_OTG_IRQ,
.flags = IORESOURCE_IRQ,
},
{
.name = "VBUS_WAKEUP",
.start = PALMAS_VBUS_IRQ,
.end = PALMAS_VBUS_IRQ,
.flags = IORESOURCE_IRQ,
},
};
static const struct resource rtc_resource[] = {
{
.name = "RTC_ALARM",
.start = PALMAS_RTC_ALARM_IRQ,
.end = PALMAS_RTC_ALARM_IRQ,
.flags = IORESOURCE_IRQ,
},
};
static const struct resource pwron_resource[] = {
{
.name = "PWRON_BUTTON",
.start = PALMAS_PWRON_IRQ,
.end = PALMAS_PWRON_IRQ,
.flags = IORESOURCE_IRQ,
},
};
enum palmas_ids {
PALMAS_PMIC_ID,
PALMAS_GPIO_ID,
PALMAS_LEDS_ID,
PALMAS_WDT_ID,
PALMAS_RTC_ID,
PALMAS_PWRBUTTON_ID,
PALMAS_GPADC_ID,
PALMAS_RESOURCE_ID,
PALMAS_CLK_ID,
PALMAS_PWM_ID,
PALMAS_USB_ID,
};
static const struct mfd_cell palmas_children[] = {
{
.name = "palmas-pmic",
.id = PALMAS_PMIC_ID,
},
{
.name = "palmas-gpio",
.id = PALMAS_GPIO_ID,
},
{
.name = "palmas-leds",
.id = PALMAS_LEDS_ID,
},
{
.name = "palmas-wdt",
.id = PALMAS_WDT_ID,
},
{
.name = "palmas-rtc",
.num_resources = ARRAY_SIZE(rtc_resource),
.resources = rtc_resource,
.id = PALMAS_RTC_ID,
},
{
.name = "palmas-pwrbutton",
.num_resources = ARRAY_SIZE(pwron_resource),
.resources = pwron_resource,
.id = PALMAS_PWRBUTTON_ID,
},
{
.name = "palmas-gpadc",
.num_resources = ARRAY_SIZE(gpadc_resource),
.resources = gpadc_resource,
.id = PALMAS_GPADC_ID,
},
{
.name = "palmas-resource",
.id = PALMAS_RESOURCE_ID,
},
{
.name = "palmas-clk",
.id = PALMAS_CLK_ID,
},
{
.name = "palmas-pwm",
.id = PALMAS_PWM_ID,
},
{
.name = "palmas-usb",
.num_resources = ARRAY_SIZE(usb_resource),
.resources = usb_resource,
.id = PALMAS_USB_ID,
}
};
static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = {
{
.reg_bits = 8,
.val_bits = 8,
.max_register = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
PALMAS_PRIMARY_SECONDARY_PAD3),
},
{
.reg_bits = 8,
.val_bits = 8,
.max_register = PALMAS_BASE_TO_REG(PALMAS_GPADC_BASE,
PALMAS_GPADC_SMPS_VSEL_MONITORING),
},
{
.reg_bits = 8,
.val_bits = 8,
.max_register = PALMAS_BASE_TO_REG(PALMAS_TRIM_GPADC_BASE,
PALMAS_GPADC_TRIM16),
},
};
static const struct regmap_irq palmas_irqs[] = {
/* INT1 IRQs */
[PALMAS_CHARG_DET_N_VBUS_OVV_IRQ] = {
.mask = PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV,
},
[PALMAS_PWRON_IRQ] = {
.mask = PALMAS_INT1_STATUS_PWRON,
},
[PALMAS_LONG_PRESS_KEY_IRQ] = {
.mask = PALMAS_INT1_STATUS_LONG_PRESS_KEY,
},
[PALMAS_RPWRON_IRQ] = {
.mask = PALMAS_INT1_STATUS_RPWRON,
},
[PALMAS_PWRDOWN_IRQ] = {
.mask = PALMAS_INT1_STATUS_PWRDOWN,
},
[PALMAS_HOTDIE_IRQ] = {
.mask = PALMAS_INT1_STATUS_HOTDIE,
},
[PALMAS_VSYS_MON_IRQ] = {
.mask = PALMAS_INT1_STATUS_VSYS_MON,
},
[PALMAS_VBAT_MON_IRQ] = {
.mask = PALMAS_INT1_STATUS_VBAT_MON,
},
/* INT2 IRQs*/
[PALMAS_RTC_ALARM_IRQ] = {
.mask = PALMAS_INT2_STATUS_RTC_ALARM,
.reg_offset = 1,
},
[PALMAS_RTC_TIMER_IRQ] = {
.mask = PALMAS_INT2_STATUS_RTC_TIMER,
.reg_offset = 1,
},
[PALMAS_WDT_IRQ] = {
.mask = PALMAS_INT2_STATUS_WDT,
.reg_offset = 1,
},
[PALMAS_BATREMOVAL_IRQ] = {
.mask = PALMAS_INT2_STATUS_BATREMOVAL,
.reg_offset = 1,
},
[PALMAS_RESET_IN_IRQ] = {
.mask = PALMAS_INT2_STATUS_RESET_IN,
.reg_offset = 1,
},
[PALMAS_FBI_BB_IRQ] = {
.mask = PALMAS_INT2_STATUS_FBI_BB,
.reg_offset = 1,
},
[PALMAS_SHORT_IRQ] = {
.mask = PALMAS_INT2_STATUS_SHORT,
.reg_offset = 1,
},
[PALMAS_VAC_ACOK_IRQ] = {
.mask = PALMAS_INT2_STATUS_VAC_ACOK,
.reg_offset = 1,
},
/* INT3 IRQs */
[PALMAS_GPADC_AUTO_0_IRQ] = {
.mask = PALMAS_INT3_STATUS_GPADC_AUTO_0,
.reg_offset = 2,
},
[PALMAS_GPADC_AUTO_1_IRQ] = {
.mask = PALMAS_INT3_STATUS_GPADC_AUTO_1,
.reg_offset = 2,
},
[PALMAS_GPADC_EOC_SW_IRQ] = {
.mask = PALMAS_INT3_STATUS_GPADC_EOC_SW,
.reg_offset = 2,
},
[PALMAS_GPADC_EOC_RT_IRQ] = {
.mask = PALMAS_INT3_STATUS_GPADC_EOC_RT,
.reg_offset = 2,
},
[PALMAS_ID_OTG_IRQ] = {
.mask = PALMAS_INT3_STATUS_ID_OTG,
.reg_offset = 2,
},
[PALMAS_ID_IRQ] = {
.mask = PALMAS_INT3_STATUS_ID,
.reg_offset = 2,
},
[PALMAS_VBUS_OTG_IRQ] = {
.mask = PALMAS_INT3_STATUS_VBUS_OTG,
.reg_offset = 2,
},
[PALMAS_VBUS_IRQ] = {
.mask = PALMAS_INT3_STATUS_VBUS,
.reg_offset = 2,
},
/* INT4 IRQs */
[PALMAS_GPIO_0_IRQ] = {
.mask = PALMAS_INT4_STATUS_GPIO_0,
.reg_offset = 3,
},
[PALMAS_GPIO_1_IRQ] = {
.mask = PALMAS_INT4_STATUS_GPIO_1,
.reg_offset = 3,
},
[PALMAS_GPIO_2_IRQ] = {
.mask = PALMAS_INT4_STATUS_GPIO_2,
.reg_offset = 3,
},
[PALMAS_GPIO_3_IRQ] = {
.mask = PALMAS_INT4_STATUS_GPIO_3,
.reg_offset = 3,
},
[PALMAS_GPIO_4_IRQ] = {
.mask = PALMAS_INT4_STATUS_GPIO_4,
.reg_offset = 3,
},
[PALMAS_GPIO_5_IRQ] = {
.mask = PALMAS_INT4_STATUS_GPIO_5,
.reg_offset = 3,
},
[PALMAS_GPIO_6_IRQ] = {
.mask = PALMAS_INT4_STATUS_GPIO_6,
.reg_offset = 3,
},
[PALMAS_GPIO_7_IRQ] = {
.mask = PALMAS_INT4_STATUS_GPIO_7,
.reg_offset = 3,
},
};
static struct regmap_irq_chip palmas_irq_chip = {
.name = "palmas",
.irqs = palmas_irqs,
.num_irqs = ARRAY_SIZE(palmas_irqs),
.num_regs = 4,
.irq_reg_stride = 5,
.status_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE,
PALMAS_INT1_STATUS),
.mask_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE,
PALMAS_INT1_MASK),
};
static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct palmas *palmas;
struct palmas_platform_data *pdata;
int ret = 0, i;
unsigned int reg, addr;
int slave;
struct mfd_cell *children;
pdata = dev_get_platdata(&i2c->dev);
if (!pdata)
return -EINVAL;
palmas = devm_kzalloc(&i2c->dev, sizeof(struct palmas), GFP_KERNEL);
if (palmas == NULL)
return -ENOMEM;
i2c_set_clientdata(i2c, palmas);
palmas->dev = &i2c->dev;
palmas->id = id->driver_data;
palmas->irq = i2c->irq;
for (i = 0; i < PALMAS_NUM_CLIENTS; i++) {
if (i == 0)
palmas->i2c_clients[i] = i2c;
else {
palmas->i2c_clients[i] =
i2c_new_dummy(i2c->adapter,
i2c->addr + i);
if (!palmas->i2c_clients[i]) {
dev_err(palmas->dev,
"can't attach client %d\n", i);
ret = -ENOMEM;
goto err;
}
}
palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i],
&palmas_regmap_config[i]);
if (IS_ERR(palmas->regmap[i])) {
ret = PTR_ERR(palmas->regmap[i]);
dev_err(palmas->dev,
"Failed to allocate regmap %d, err: %d\n",
i, ret);
goto err;
}
}
ret = regmap_add_irq_chip(palmas->regmap[1], palmas->irq,
IRQF_ONESHOT | IRQF_TRIGGER_LOW, -1, &palmas_irq_chip,
&palmas->irq_data);
if (ret < 0)
goto err;
slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
PALMAS_PRIMARY_SECONDARY_PAD1);
if (pdata->mux_from_pdata) {
reg = pdata->pad1;
ret = regmap_write(palmas->regmap[slave], addr, reg);
if (ret)
goto err;
} else {
ret = regmap_read(palmas->regmap[slave], addr, &reg);
if (ret)
goto err;
}
if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0))
palmas->gpio_muxed |= PALMAS_GPIO_0_MUXED;
if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK))
palmas->gpio_muxed |= PALMAS_GPIO_1_MUXED;
else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
(2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
palmas->led_muxed |= PALMAS_LED1_MUXED;
else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
(3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
palmas->pwm_muxed |= PALMAS_PWM1_MUXED;
if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK))
palmas->gpio_muxed |= PALMAS_GPIO_2_MUXED;
else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
(2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
palmas->led_muxed |= PALMAS_LED2_MUXED;
else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
(3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
palmas->pwm_muxed |= PALMAS_PWM2_MUXED;
if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3))
palmas->gpio_muxed |= PALMAS_GPIO_3_MUXED;
addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
PALMAS_PRIMARY_SECONDARY_PAD2);
if (pdata->mux_from_pdata) {
reg = pdata->pad2;
ret = regmap_write(palmas->regmap[slave], addr, reg);
if (ret)
goto err;
} else {
ret = regmap_read(palmas->regmap[slave], addr, &reg);
if (ret)
goto err;
}
if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4))
palmas->gpio_muxed |= PALMAS_GPIO_4_MUXED;
if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK))
palmas->gpio_muxed |= PALMAS_GPIO_5_MUXED;
if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6))
palmas->gpio_muxed |= PALMAS_GPIO_6_MUXED;
if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK))
palmas->gpio_muxed |= PALMAS_GPIO_7_MUXED;
dev_info(palmas->dev, "Muxing GPIO %x, PWM %x, LED %x\n",
palmas->gpio_muxed, palmas->pwm_muxed,
palmas->led_muxed);
reg = pdata->power_ctrl;
slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_POWER_CTRL);
ret = regmap_write(palmas->regmap[slave], addr, reg);
if (ret)
goto err;
children = kmemdup(palmas_children, sizeof(palmas_children),
GFP_KERNEL);
if (!children) {
ret = -ENOMEM;
goto err;
}
ret = mfd_add_devices(palmas->dev, -1,
children, ARRAY_SIZE(palmas_children),
NULL, regmap_irq_chip_get_base(palmas->irq_data));
kfree(children);
if (ret < 0)
goto err;
return ret;
err:
mfd_remove_devices(palmas->dev);
kfree(palmas);
return ret;
}
static int palmas_i2c_remove(struct i2c_client *i2c)
{
struct palmas *palmas = i2c_get_clientdata(i2c);
mfd_remove_devices(palmas->dev);
regmap_del_irq_chip(palmas->irq, palmas->irq_data);
return 0;
}
static const struct i2c_device_id palmas_i2c_id[] = {
{ "palmas", },
{ "twl6035", },
{ "twl6037", },
{ "tps65913", },
};
MODULE_DEVICE_TABLE(i2c, palmas_i2c_id);
static struct of_device_id __devinitdata of_palmas_match_tbl[] = {
{ .compatible = "ti,palmas", },
{ /* end */ }
};
static struct i2c_driver palmas_i2c_driver = {
.driver = {
.name = "palmas",
.of_match_table = of_palmas_match_tbl,
.owner = THIS_MODULE,
},
.probe = palmas_i2c_probe,
.remove = palmas_i2c_remove,
.id_table = palmas_i2c_id,
};
static int __init palmas_i2c_init(void)
{
return i2c_add_driver(&palmas_i2c_driver);
}
/* init early so consumer devices can complete system boot */
subsys_initcall(palmas_i2c_init);
static void __exit palmas_i2c_exit(void)
{
i2c_del_driver(&palmas_i2c_driver);
}
module_exit(palmas_i2c_exit);
MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
MODULE_DESCRIPTION("Palmas chip family multi-function driver");
MODULE_LICENSE("GPL");
...@@ -147,12 +147,6 @@ int wm8994_irq_init(struct wm8994 *wm8994) ...@@ -147,12 +147,6 @@ int wm8994_irq_init(struct wm8994 *wm8994)
return 0; return 0;
} }
if (!wm8994->irq_base) {
dev_err(wm8994->dev,
"No interrupt base specified, no interrupts\n");
return 0;
}
ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq, ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
wm8994->irq_base, &wm8994_irq_chip, wm8994->irq_base, &wm8994_irq_chip,
......
...@@ -80,6 +80,7 @@ struct da9052 { ...@@ -80,6 +80,7 @@ struct da9052 {
struct regmap *regmap; struct regmap *regmap;
int irq_base; int irq_base;
struct regmap_irq_chip_data *irq_data;
u8 chip_id; u8 chip_id;
int chip_irq; int chip_irq;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/regmap.h>
enum wm8994_type { enum wm8994_type {
WM8994 = 0, WM8994 = 0,
...@@ -26,7 +27,6 @@ enum wm8994_type { ...@@ -26,7 +27,6 @@ enum wm8994_type {
struct regulator_dev; struct regulator_dev;
struct regulator_bulk_data; struct regulator_bulk_data;
struct regmap;
#define WM8994_NUM_GPIO_REGS 11 #define WM8994_NUM_GPIO_REGS 11
#define WM8994_NUM_LDO_REGS 2 #define WM8994_NUM_LDO_REGS 2
...@@ -94,17 +94,17 @@ static inline int wm8994_request_irq(struct wm8994 *wm8994, int irq, ...@@ -94,17 +94,17 @@ static inline int wm8994_request_irq(struct wm8994 *wm8994, int irq,
irq_handler_t handler, const char *name, irq_handler_t handler, const char *name,
void *data) void *data)
{ {
if (!wm8994->irq_base) if (!wm8994->irq_data)
return -EINVAL; return -EINVAL;
return request_threaded_irq(wm8994->irq_base + irq, NULL, handler, return request_threaded_irq(regmap_irq_get_virq(wm8994->irq_data, irq),
IRQF_TRIGGER_RISING, name, NULL, handler, IRQF_TRIGGER_RISING, name,
data); data);
} }
static inline void wm8994_free_irq(struct wm8994 *wm8994, int irq, void *data) static inline void wm8994_free_irq(struct wm8994 *wm8994, int irq, void *data)
{ {
if (!wm8994->irq_base) if (!wm8994->irq_data)
return; return;
free_irq(wm8994->irq_base + irq, data); free_irq(regmap_irq_get_virq(wm8994->irq_data, irq), data);
} }
int wm8994_irq_init(struct wm8994 *wm8994); int wm8994_irq_init(struct wm8994 *wm8994);
......
...@@ -46,7 +46,13 @@ struct reg_default { ...@@ -46,7 +46,13 @@ struct reg_default {
/** /**
* Configuration for the register map of a device. * Configuration for the register map of a device.
* *
* @name: Optional name of the regmap. Useful when a device has multiple
* register regions.
*
* @reg_bits: Number of bits in a register address, mandatory. * @reg_bits: Number of bits in a register address, mandatory.
* @reg_stride: The register address stride. Valid register addresses are a
* multiple of this value. If set to 0, a value of 1 will be
* used.
* @pad_bits: Number of bits of padding between register and value. * @pad_bits: Number of bits of padding between register and value.
* @val_bits: Number of bits in a register value, mandatory. * @val_bits: Number of bits in a register value, mandatory.
* *
...@@ -70,6 +76,9 @@ struct reg_default { ...@@ -70,6 +76,9 @@ struct reg_default {
* @write_flag_mask: Mask to be set in the top byte of the register when doing * @write_flag_mask: Mask to be set in the top byte of the register when doing
* a write. If both read_flag_mask and write_flag_mask are * a write. If both read_flag_mask and write_flag_mask are
* empty the regmap_bus default masks are used. * empty the regmap_bus default masks are used.
* @use_single_rw: If set, converts the bulk read and write operations into
* a series of single read and write operations. This is useful
* for device that does not support bulk read and write.
* *
* @cache_type: The actual cache type. * @cache_type: The actual cache type.
* @reg_defaults_raw: Power on reset values for registers (for use with * @reg_defaults_raw: Power on reset values for registers (for use with
...@@ -77,7 +86,10 @@ struct reg_default { ...@@ -77,7 +86,10 @@ struct reg_default {
* @num_reg_defaults_raw: Number of elements in reg_defaults_raw. * @num_reg_defaults_raw: Number of elements in reg_defaults_raw.
*/ */
struct regmap_config { struct regmap_config {
const char *name;
int reg_bits; int reg_bits;
int reg_stride;
int pad_bits; int pad_bits;
int val_bits; int val_bits;
...@@ -95,20 +107,25 @@ struct regmap_config { ...@@ -95,20 +107,25 @@ struct regmap_config {
u8 read_flag_mask; u8 read_flag_mask;
u8 write_flag_mask; u8 write_flag_mask;
bool use_single_rw;
}; };
typedef int (*regmap_hw_write)(struct device *dev, const void *data, typedef int (*regmap_hw_write)(void *context, const void *data,
size_t count); size_t count);
typedef int (*regmap_hw_gather_write)(struct device *dev, typedef int (*regmap_hw_gather_write)(void *context,
const void *reg, size_t reg_len, const void *reg, size_t reg_len,
const void *val, size_t val_len); const void *val, size_t val_len);
typedef int (*regmap_hw_read)(struct device *dev, typedef int (*regmap_hw_read)(void *context,
const void *reg_buf, size_t reg_size, const void *reg_buf, size_t reg_size,
void *val_buf, size_t val_size); void *val_buf, size_t val_size);
typedef void (*regmap_hw_free_context)(void *context);
/** /**
* Description of a hardware bus for the register map infrastructure. * Description of a hardware bus for the register map infrastructure.
* *
* @fast_io: Register IO is fast. Use a spinlock instead of a mutex
* to perform locking.
* @write: Write operation. * @write: Write operation.
* @gather_write: Write operation with split register/value, return -ENOTSUPP * @gather_write: Write operation with split register/value, return -ENOTSUPP
* if not implemented on a given device. * if not implemented on a given device.
...@@ -118,31 +135,42 @@ typedef int (*regmap_hw_read)(struct device *dev, ...@@ -118,31 +135,42 @@ typedef int (*regmap_hw_read)(struct device *dev,
* a read. * a read.
*/ */
struct regmap_bus { struct regmap_bus {
bool fast_io;
regmap_hw_write write; regmap_hw_write write;
regmap_hw_gather_write gather_write; regmap_hw_gather_write gather_write;
regmap_hw_read read; regmap_hw_read read;
regmap_hw_free_context free_context;
u8 read_flag_mask; u8 read_flag_mask;
}; };
struct regmap *regmap_init(struct device *dev, struct regmap *regmap_init(struct device *dev,
const struct regmap_bus *bus, const struct regmap_bus *bus,
void *bus_context,
const struct regmap_config *config); const struct regmap_config *config);
struct regmap *regmap_init_i2c(struct i2c_client *i2c, struct regmap *regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config); const struct regmap_config *config);
struct regmap *regmap_init_spi(struct spi_device *dev, struct regmap *regmap_init_spi(struct spi_device *dev,
const struct regmap_config *config); const struct regmap_config *config);
struct regmap *regmap_init_mmio(struct device *dev,
void __iomem *regs,
const struct regmap_config *config);
struct regmap *devm_regmap_init(struct device *dev, struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus, const struct regmap_bus *bus,
void *bus_context,
const struct regmap_config *config); const struct regmap_config *config);
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config); const struct regmap_config *config);
struct regmap *devm_regmap_init_spi(struct spi_device *dev, struct regmap *devm_regmap_init_spi(struct spi_device *dev,
const struct regmap_config *config); const struct regmap_config *config);
struct regmap *devm_regmap_init_mmio(struct device *dev,
void __iomem *regs,
const struct regmap_config *config);
void regmap_exit(struct regmap *map); void regmap_exit(struct regmap *map);
int regmap_reinit_cache(struct regmap *map, int regmap_reinit_cache(struct regmap *map,
const struct regmap_config *config); const struct regmap_config *config);
struct regmap *dev_get_regmap(struct device *dev, const char *name);
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
int regmap_raw_write(struct regmap *map, unsigned int reg, int regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len); const void *val, size_t val_len);
...@@ -191,6 +219,7 @@ struct regmap_irq { ...@@ -191,6 +219,7 @@ struct regmap_irq {
* @status_base: Base status register address. * @status_base: Base status register address.
* @mask_base: Base mask register address. * @mask_base: Base mask register address.
* @ack_base: Base ack address. If zero then the chip is clear on read. * @ack_base: Base ack address. If zero then the chip is clear on read.
* @irq_reg_stride: Stride to use for chips where registers are not contiguous.
* *
* @num_regs: Number of registers in each control bank. * @num_regs: Number of registers in each control bank.
* @irqs: Descriptors for individual IRQs. Interrupt numbers are * @irqs: Descriptors for individual IRQs. Interrupt numbers are
...@@ -203,6 +232,7 @@ struct regmap_irq_chip { ...@@ -203,6 +232,7 @@ struct regmap_irq_chip {
unsigned int status_base; unsigned int status_base;
unsigned int mask_base; unsigned int mask_base;
unsigned int ack_base; unsigned int ack_base;
unsigned int irq_reg_stride;
int num_regs; int num_regs;
...@@ -217,6 +247,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -217,6 +247,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
struct regmap_irq_chip_data **data); struct regmap_irq_chip_data **data);
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data); void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data); int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq);
#else #else
...@@ -327,6 +358,13 @@ static inline int regmap_register_patch(struct regmap *map, ...@@ -327,6 +358,13 @@ static inline int regmap_register_patch(struct regmap *map,
return -EINVAL; return -EINVAL;
} }
static inline struct regmap *dev_get_regmap(struct device *dev,
const char *name)
{
WARN_ONCE(1, "regmap API is disabled");
return NULL;
}
#endif #endif
#endif #endif
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