Commit e795e5f4 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull regmap updates from Mark Brown:
 "There's no real overall theme to the regmap changes for this release,
  it's a collection of individual features.  The main bits are:

   - Support for 64 bit registers, mainly for MMIO use, from Xiubo Li.

   - Support for trigger type configuration for regmap-irq from Laxman
     Dewangan.

   - Use native physical I/O for MMIO register maps to avoid confusion
     with the conversions that readl() and writel() do to little endian
     on big endian systems (with some DT updates to fix some workarounds
     people were doing), code from Simon Arlott.

   - Use a binary search rather than iteraton to improve the runtime
     performance of the rbtree code from Nikesh Oswal"

* tag 'regmap-v4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: debugfs: Use seq_file for the access map
  regmap: irq: add support for configuration of trigger type
  regmap: use IS_ALIGNED instead of % to improve the performance
  regmap: cache: Move the num_reg_defaults check as early as possible
  regmap: cache: Add warning info for the cache check
  regmap: missing case statement
  regmap: shift wrapping bugs in 64 bit code
  regmap: cache: Add 64-bit mode support
  regmap: cache: To suppress the noise of checkpatch
  regmap: fix the warning about unused variable
  regmap: add 64-bit mode support
  regmap: mmio: Add regmap_mmio_get_min_stride
  regmap: mmio: remove the useless code
  regmap: Fix leftover from struct reg_default to struct reg_sequence change
  regmap: replace kmalloc with kmalloc_array
  regmap: replace kzalloc with kcalloc
  regmap: rbtree: When adding a reg do a bsearch for target node
  regmap-mmio: Use native endianness for read/write
parents 581dbc8b 6cb07abc
...@@ -73,7 +73,6 @@ uart0: serial@10000100 { ...@@ -73,7 +73,6 @@ uart0: serial@10000100 {
timer: timer@10000040 { timer: timer@10000040 {
compatible = "syscon"; compatible = "syscon";
reg = <0x10000040 0x2c>; reg = <0x10000040 0x2c>;
little-endian;
}; };
reboot { reboot {
......
...@@ -98,7 +98,6 @@ upg_irq0_intc: upg_irq0_intc@406780 { ...@@ -98,7 +98,6 @@ upg_irq0_intc: upg_irq0_intc@406780 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7125-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7125-sun-top-ctrl", "syscon";
reg = <0x404000 0x60c>; reg = <0x404000 0x60c>;
little-endian;
}; };
reboot { reboot {
......
...@@ -118,7 +118,6 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { ...@@ -118,7 +118,6 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7346-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7346-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian;
}; };
reboot { reboot {
......
...@@ -112,7 +112,6 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { ...@@ -112,7 +112,6 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7358-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7358-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian;
}; };
reboot { reboot {
......
...@@ -112,7 +112,6 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { ...@@ -112,7 +112,6 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7360-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7360-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian;
}; };
reboot { reboot {
......
...@@ -118,7 +118,6 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { ...@@ -118,7 +118,6 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7362-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7362-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian;
}; };
reboot { reboot {
......
...@@ -99,7 +99,6 @@ upg_irq0_intc: upg_irq0_intc@406780 { ...@@ -99,7 +99,6 @@ upg_irq0_intc: upg_irq0_intc@406780 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7420-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7420-sun-top-ctrl", "syscon";
reg = <0x404000 0x60c>; reg = <0x404000 0x60c>;
little-endian;
}; };
reboot { reboot {
......
...@@ -100,7 +100,6 @@ upg_irq0_intc: upg_irq0_intc@406780 { ...@@ -100,7 +100,6 @@ upg_irq0_intc: upg_irq0_intc@406780 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian;
}; };
reboot { reboot {
......
...@@ -114,7 +114,6 @@ upg_irq0_intc: upg_irq0_intc@406780 { ...@@ -114,7 +114,6 @@ upg_irq0_intc: upg_irq0_intc@406780 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian;
}; };
reboot { reboot {
......
...@@ -21,7 +21,7 @@ static int regcache_flat_init(struct regmap *map) ...@@ -21,7 +21,7 @@ static int regcache_flat_init(struct regmap *map)
int i; int i;
unsigned int *cache; unsigned int *cache;
map->cache = kzalloc(sizeof(unsigned int) * (map->max_register + 1), map->cache = kcalloc(map->max_register + 1, sizeof(unsigned int),
GFP_KERNEL); GFP_KERNEL);
if (!map->cache) if (!map->cache)
return -ENOMEM; return -ENOMEM;
......
...@@ -139,7 +139,7 @@ static int regcache_lzo_init(struct regmap *map) ...@@ -139,7 +139,7 @@ static int regcache_lzo_init(struct regmap *map)
ret = 0; ret = 0;
blkcount = regcache_lzo_block_count(map); blkcount = regcache_lzo_block_count(map);
map->cache = kzalloc(blkcount * sizeof *lzo_blocks, map->cache = kcalloc(blkcount, sizeof(*lzo_blocks),
GFP_KERNEL); GFP_KERNEL);
if (!map->cache) if (!map->cache)
return -ENOMEM; return -ENOMEM;
...@@ -152,7 +152,7 @@ static int regcache_lzo_init(struct regmap *map) ...@@ -152,7 +152,7 @@ static int regcache_lzo_init(struct regmap *map)
* that register. * that register.
*/ */
bmp_size = map->num_reg_defaults_raw; bmp_size = map->num_reg_defaults_raw;
sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long), sync_bmp = kmalloc_array(BITS_TO_LONGS(bmp_size), sizeof(long),
GFP_KERNEL); GFP_KERNEL);
if (!sync_bmp) { if (!sync_bmp) {
ret = -ENOMEM; ret = -ENOMEM;
......
...@@ -361,13 +361,14 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg) ...@@ -361,13 +361,14 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
rbnode->base_reg = reg; rbnode->base_reg = reg;
} }
rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size, rbnode->block = kmalloc_array(rbnode->blklen, map->cache_word_size,
GFP_KERNEL); GFP_KERNEL);
if (!rbnode->block) if (!rbnode->block)
goto err_free; goto err_free;
rbnode->cache_present = kzalloc(BITS_TO_LONGS(rbnode->blklen) * rbnode->cache_present = kcalloc(BITS_TO_LONGS(rbnode->blklen),
sizeof(*rbnode->cache_present), GFP_KERNEL); sizeof(*rbnode->cache_present),
GFP_KERNEL);
if (!rbnode->cache_present) if (!rbnode->cache_present)
goto err_free_block; goto err_free_block;
...@@ -413,8 +414,8 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, ...@@ -413,8 +414,8 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
max = reg + max_dist; max = reg + max_dist;
/* 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; node = rbtree_ctx->root.rb_node;
node = rb_next(node)) { while (node) {
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node, rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
node); node);
...@@ -425,6 +426,11 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, ...@@ -425,6 +426,11 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
new_base_reg = min(reg, base_reg); new_base_reg = min(reg, base_reg);
new_top_reg = max(reg, top_reg); new_top_reg = max(reg, top_reg);
} else { } else {
if (max < base_reg)
node = node->rb_left;
else
node = node->rb_right;
continue; continue;
} }
......
...@@ -100,15 +100,25 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) ...@@ -100,15 +100,25 @@ 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) {
if (config->reg_defaults || config->num_reg_defaults_raw)
dev_warn(map->dev,
"No cache used with register defaults set!\n");
map->cache_bypass = true; map->cache_bypass = true;
return 0; return 0;
} }
if (config->reg_defaults && !config->num_reg_defaults) {
dev_err(map->dev,
"Register defaults are set without the number!\n");
return -EINVAL;
}
for (i = 0; i < config->num_reg_defaults; i++)
if (config->reg_defaults[i].reg % map->reg_stride)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(cache_types); i++) for (i = 0; i < ARRAY_SIZE(cache_types); i++)
if (cache_types[i]->type == map->cache_type) if (cache_types[i]->type == map->cache_type)
break; break;
...@@ -138,8 +148,6 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) ...@@ -138,8 +148,6 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
* a copy of it. * a copy of it.
*/ */
if (config->reg_defaults) { if (config->reg_defaults) {
if (!map->num_reg_defaults)
return -EINVAL;
tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults * tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults *
sizeof(struct reg_default), GFP_KERNEL); sizeof(struct reg_default), GFP_KERNEL);
if (!tmp_buf) if (!tmp_buf)
...@@ -535,19 +543,30 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, ...@@ -535,19 +543,30 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
switch (map->cache_word_size) { switch (map->cache_word_size) {
case 1: { case 1: {
u8 *cache = base; u8 *cache = base;
cache[idx] = val; cache[idx] = val;
break; break;
} }
case 2: { case 2: {
u16 *cache = base; u16 *cache = base;
cache[idx] = val; cache[idx] = val;
break; break;
} }
case 4: { case 4: {
u32 *cache = base; u32 *cache = base;
cache[idx] = val;
break;
}
#ifdef CONFIG_64BIT
case 8: {
u64 *cache = base;
cache[idx] = val; cache[idx] = val;
break; break;
} }
#endif
default: default:
BUG(); BUG();
} }
...@@ -568,16 +587,26 @@ unsigned int regcache_get_val(struct regmap *map, const void *base, ...@@ -568,16 +587,26 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
switch (map->cache_word_size) { switch (map->cache_word_size) {
case 1: { case 1: {
const u8 *cache = base; const u8 *cache = base;
return cache[idx]; return cache[idx];
} }
case 2: { case 2: {
const u16 *cache = base; const u16 *cache = base;
return cache[idx]; return cache[idx];
} }
case 4: { case 4: {
const u32 *cache = base; const u32 *cache = base;
return cache[idx];
}
#ifdef CONFIG_64BIT
case 8: {
const u64 *cache = base;
return cache[idx]; return cache[idx];
} }
#endif
default: default:
BUG(); BUG();
} }
......
...@@ -397,72 +397,39 @@ static const struct file_operations regmap_reg_ranges_fops = { ...@@ -397,72 +397,39 @@ static const struct file_operations regmap_reg_ranges_fops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t regmap_access_read_file(struct file *file, static int regmap_access_show(struct seq_file *s, void *ignored)
char __user *user_buf, size_t count,
loff_t *ppos)
{ {
int reg_len, tot_len; struct regmap *map = s->private;
size_t buf_pos = 0; int i, reg_len;
loff_t p = 0;
ssize_t ret;
int i;
struct regmap *map = file->private_data;
char *buf;
if (*ppos < 0 || !count)
return -EINVAL;
buf = kmalloc(count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
/* Calculate the length of a fixed format */
reg_len = regmap_calc_reg_len(map->max_register); reg_len = regmap_calc_reg_len(map->max_register);
tot_len = reg_len + 10; /* ': R W V P\n' */
for (i = 0; i <= map->max_register; i += map->reg_stride) { 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;
/* If we're in the region the user is trying to read */
if (p >= *ppos) {
/* ...but not beyond it */
if (buf_pos + tot_len + 1 >= count)
break;
/* Format the register */ /* Format the register */
snprintf(buf + buf_pos, count - buf_pos, seq_printf(s, "%.*x: %c %c %c %c\n", reg_len, i,
"%.*x: %c %c %c %c\n",
reg_len, i,
regmap_readable(map, i) ? 'y' : 'n', regmap_readable(map, i) ? 'y' : 'n',
regmap_writeable(map, i) ? 'y' : 'n', regmap_writeable(map, i) ? 'y' : 'n',
regmap_volatile(map, i) ? 'y' : 'n', regmap_volatile(map, i) ? 'y' : 'n',
regmap_precious(map, i) ? 'y' : 'n'); regmap_precious(map, i) ? 'y' : 'n');
buf_pos += tot_len;
} }
p += tot_len;
}
ret = buf_pos;
if (copy_to_user(user_buf, buf, buf_pos)) { return 0;
ret = -EFAULT; }
goto out;
}
*ppos += buf_pos;
out: static int access_open(struct inode *inode, struct file *file)
kfree(buf); {
return ret; return single_open(file, regmap_access_show, inode->i_private);
} }
static const struct file_operations regmap_access_fops = { static const struct file_operations regmap_access_fops = {
.open = simple_open, .open = access_open,
.read = regmap_access_read_file, .read = seq_read,
.llseek = default_llseek, .llseek = seq_lseek,
.release = single_release,
}; };
static ssize_t regmap_cache_only_write_file(struct file *file, static ssize_t regmap_cache_only_write_file(struct file *file,
......
...@@ -39,8 +39,11 @@ struct regmap_irq_chip_data { ...@@ -39,8 +39,11 @@ struct regmap_irq_chip_data {
unsigned int *mask_buf; unsigned int *mask_buf;
unsigned int *mask_buf_def; unsigned int *mask_buf_def;
unsigned int *wake_buf; unsigned int *wake_buf;
unsigned int *type_buf;
unsigned int *type_buf_def;
unsigned int irq_reg_stride; unsigned int irq_reg_stride;
unsigned int type_reg_stride;
}; };
static inline const static inline const
...@@ -144,6 +147,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data) ...@@ -144,6 +147,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
} }
} }
for (i = 0; i < d->chip->num_type_reg; i++) {
if (!d->type_buf_def[i])
continue;
reg = d->chip->type_base +
(i * map->reg_stride * d->type_reg_stride);
if (d->chip->type_invert)
ret = regmap_update_bits(d->map, reg,
d->type_buf_def[i], ~d->type_buf[i]);
else
ret = regmap_update_bits(d->map, reg,
d->type_buf_def[i], d->type_buf[i]);
if (ret != 0)
dev_err(d->map->dev, "Failed to sync type in %x\n",
reg);
}
if (d->chip->runtime_pm) if (d->chip->runtime_pm)
pm_runtime_put(map->dev); pm_runtime_put(map->dev);
...@@ -178,6 +197,38 @@ static void regmap_irq_disable(struct irq_data *data) ...@@ -178,6 +197,38 @@ static void regmap_irq_disable(struct irq_data *data)
d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
} }
static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
struct regmap *map = d->map;
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
int reg = irq_data->type_reg_offset / map->reg_stride;
if (!(irq_data->type_rising_mask | irq_data->type_falling_mask))
return 0;
d->type_buf[reg] &= ~(irq_data->type_falling_mask |
irq_data->type_rising_mask);
switch (type) {
case IRQ_TYPE_EDGE_FALLING:
d->type_buf[reg] |= irq_data->type_falling_mask;
break;
case IRQ_TYPE_EDGE_RISING:
d->type_buf[reg] |= irq_data->type_rising_mask;
break;
case IRQ_TYPE_EDGE_BOTH:
d->type_buf[reg] |= (irq_data->type_falling_mask |
irq_data->type_rising_mask);
break;
default:
return -EINVAL;
}
return 0;
}
static int regmap_irq_set_wake(struct irq_data *data, unsigned int on) static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
{ {
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);
...@@ -204,6 +255,7 @@ static const struct irq_chip regmap_irq_chip = { ...@@ -204,6 +255,7 @@ static const struct irq_chip regmap_irq_chip = {
.irq_bus_sync_unlock = regmap_irq_sync_unlock, .irq_bus_sync_unlock = regmap_irq_sync_unlock,
.irq_disable = regmap_irq_disable, .irq_disable = regmap_irq_disable,
.irq_enable = regmap_irq_enable, .irq_enable = regmap_irq_enable,
.irq_set_type = regmap_irq_set_type,
.irq_set_wake = regmap_irq_set_wake, .irq_set_wake = regmap_irq_set_wake,
}; };
...@@ -386,28 +438,40 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -386,28 +438,40 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (!d) if (!d)
return -ENOMEM; return -ENOMEM;
d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, d->status_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL); GFP_KERNEL);
if (!d->status_buf) if (!d->status_buf)
goto err_alloc; goto err_alloc;
d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, d->mask_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL); GFP_KERNEL);
if (!d->mask_buf) if (!d->mask_buf)
goto err_alloc; goto err_alloc;
d->mask_buf_def = kzalloc(sizeof(unsigned int) * chip->num_regs, d->mask_buf_def = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL); GFP_KERNEL);
if (!d->mask_buf_def) if (!d->mask_buf_def)
goto err_alloc; goto err_alloc;
if (chip->wake_base) { if (chip->wake_base) {
d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, d->wake_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL); GFP_KERNEL);
if (!d->wake_buf) if (!d->wake_buf)
goto err_alloc; goto err_alloc;
} }
if (chip->num_type_reg) {
d->type_buf_def = kcalloc(chip->num_type_reg,
sizeof(unsigned int), GFP_KERNEL);
if (!d->type_buf_def)
goto err_alloc;
d->type_buf = kcalloc(chip->num_type_reg, sizeof(unsigned int),
GFP_KERNEL);
if (!d->type_buf)
goto err_alloc;
}
d->irq_chip = regmap_irq_chip; d->irq_chip = regmap_irq_chip;
d->irq_chip.name = chip->name; d->irq_chip.name = chip->name;
d->irq = irq; d->irq = irq;
...@@ -420,10 +484,16 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -420,10 +484,16 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
else else
d->irq_reg_stride = 1; d->irq_reg_stride = 1;
if (chip->type_reg_stride)
d->type_reg_stride = chip->type_reg_stride;
else
d->type_reg_stride = 1;
if (!map->use_single_read && map->reg_stride == 1 && if (!map->use_single_read && map->reg_stride == 1 &&
d->irq_reg_stride == 1) { d->irq_reg_stride == 1) {
d->status_reg_buf = kmalloc(map->format.val_bytes * d->status_reg_buf = kmalloc_array(chip->num_regs,
chip->num_regs, GFP_KERNEL); map->format.val_bytes,
GFP_KERNEL);
if (!d->status_reg_buf) if (!d->status_reg_buf)
goto err_alloc; goto err_alloc;
} }
...@@ -511,6 +581,33 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -511,6 +581,33 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
} }
} }
if (chip->num_type_reg) {
for (i = 0; i < chip->num_irqs; i++) {
reg = chip->irqs[i].type_reg_offset / map->reg_stride;
d->type_buf_def[reg] |= chip->irqs[i].type_rising_mask |
chip->irqs[i].type_falling_mask;
}
for (i = 0; i < chip->num_type_reg; ++i) {
if (!d->type_buf_def[i])
continue;
reg = chip->type_base +
(i * map->reg_stride * d->type_reg_stride);
if (chip->type_invert)
ret = regmap_update_bits(map, reg,
d->type_buf_def[i], 0xFF);
else
ret = regmap_update_bits(map, reg,
d->type_buf_def[i], 0x0);
if (ret != 0) {
dev_err(map->dev,
"Failed to set type in 0x%x: %x\n",
reg, ret);
goto err_alloc;
}
}
}
if (irq_base) if (irq_base)
d->domain = irq_domain_add_legacy(map->dev->of_node, d->domain = irq_domain_add_legacy(map->dev->of_node,
chip->num_irqs, irq_base, 0, chip->num_irqs, irq_base, 0,
...@@ -541,6 +638,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -541,6 +638,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
err_domain: err_domain:
/* Should really dispose of the domain but... */ /* Should really dispose of the domain but... */
err_alloc: err_alloc:
kfree(d->type_buf);
kfree(d->type_buf_def);
kfree(d->wake_buf); kfree(d->wake_buf);
kfree(d->mask_buf_def); kfree(d->mask_buf_def);
kfree(d->mask_buf); kfree(d->mask_buf);
...@@ -564,6 +663,8 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) ...@@ -564,6 +663,8 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
free_irq(irq, d); free_irq(irq, d);
irq_domain_remove(d->domain); irq_domain_remove(d->domain);
kfree(d->type_buf);
kfree(d->type_buf_def);
kfree(d->wake_buf); kfree(d->wake_buf);
kfree(d->mask_buf_def); kfree(d->mask_buf_def);
kfree(d->mask_buf); kfree(d->mask_buf);
......
...@@ -61,6 +61,33 @@ static int regmap_mmio_regbits_check(size_t reg_bits) ...@@ -61,6 +61,33 @@ static int regmap_mmio_regbits_check(size_t reg_bits)
} }
} }
static int regmap_mmio_get_min_stride(size_t val_bits)
{
int min_stride;
switch (val_bits) {
case 8:
/* The core treats 0 as 1 */
min_stride = 0;
return 0;
case 16:
min_stride = 2;
break;
case 32:
min_stride = 4;
break;
#ifdef CONFIG_64BIT
case 64:
min_stride = 8;
break;
#endif
default:
return -EINVAL;
}
return min_stride;
}
static inline void regmap_mmio_count_check(size_t count, u32 offset) static inline void regmap_mmio_count_check(size_t count, u32 offset)
{ {
BUG_ON(count <= offset); BUG_ON(count <= offset);
...@@ -106,17 +133,17 @@ static int regmap_mmio_gather_write(void *context, ...@@ -106,17 +133,17 @@ static int regmap_mmio_gather_write(void *context,
while (val_size) { while (val_size) {
switch (ctx->val_bytes) { switch (ctx->val_bytes) {
case 1: case 1:
writeb(*(u8 *)val, ctx->regs + offset); __raw_writeb(*(u8 *)val, ctx->regs + offset);
break; break;
case 2: case 2:
writew(*(u16 *)val, ctx->regs + offset); __raw_writew(*(u16 *)val, ctx->regs + offset);
break; break;
case 4: case 4:
writel(*(u32 *)val, ctx->regs + offset); __raw_writel(*(u32 *)val, ctx->regs + offset);
break; break;
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
case 8: case 8:
writeq(*(u64 *)val, ctx->regs + offset); __raw_writeq(*(u64 *)val, ctx->regs + offset);
break; break;
#endif #endif
default: default:
...@@ -166,17 +193,17 @@ static int regmap_mmio_read(void *context, ...@@ -166,17 +193,17 @@ static int regmap_mmio_read(void *context,
while (val_size) { while (val_size) {
switch (ctx->val_bytes) { switch (ctx->val_bytes) {
case 1: case 1:
*(u8 *)val = readb(ctx->regs + offset); *(u8 *)val = __raw_readb(ctx->regs + offset);
break; break;
case 2: case 2:
*(u16 *)val = readw(ctx->regs + offset); *(u16 *)val = __raw_readw(ctx->regs + offset);
break; break;
case 4: case 4:
*(u32 *)val = readl(ctx->regs + offset); *(u32 *)val = __raw_readl(ctx->regs + offset);
break; break;
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
case 8: case 8:
*(u64 *)val = readq(ctx->regs + offset); *(u64 *)val = __raw_readq(ctx->regs + offset);
break; break;
#endif #endif
default: default:
...@@ -231,26 +258,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ...@@ -231,26 +258,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
if (config->pad_bits) if (config->pad_bits)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
switch (config->val_bits) { min_stride = regmap_mmio_get_min_stride(config->val_bits);
case 8: if (min_stride < 0)
/* The core treats 0 as 1 */ return ERR_PTR(min_stride);
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) if (config->reg_stride < min_stride)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
......
...@@ -245,6 +245,28 @@ static void regmap_format_32_native(void *buf, unsigned int val, ...@@ -245,6 +245,28 @@ static void regmap_format_32_native(void *buf, unsigned int val,
*(u32 *)buf = val << shift; *(u32 *)buf = val << shift;
} }
#ifdef CONFIG_64BIT
static void regmap_format_64_be(void *buf, unsigned int val, unsigned int shift)
{
__be64 *b = buf;
b[0] = cpu_to_be64((u64)val << shift);
}
static void regmap_format_64_le(void *buf, unsigned int val, unsigned int shift)
{
__le64 *b = buf;
b[0] = cpu_to_le64((u64)val << shift);
}
static void regmap_format_64_native(void *buf, unsigned int val,
unsigned int shift)
{
*(u64 *)buf = (u64)val << shift;
}
#endif
static void regmap_parse_inplace_noop(void *buf) static void regmap_parse_inplace_noop(void *buf)
{ {
} }
...@@ -332,6 +354,41 @@ static unsigned int regmap_parse_32_native(const void *buf) ...@@ -332,6 +354,41 @@ static unsigned int regmap_parse_32_native(const void *buf)
return *(u32 *)buf; return *(u32 *)buf;
} }
#ifdef CONFIG_64BIT
static unsigned int regmap_parse_64_be(const void *buf)
{
const __be64 *b = buf;
return be64_to_cpu(b[0]);
}
static unsigned int regmap_parse_64_le(const void *buf)
{
const __le64 *b = buf;
return le64_to_cpu(b[0]);
}
static void regmap_parse_64_be_inplace(void *buf)
{
__be64 *b = buf;
b[0] = be64_to_cpu(b[0]);
}
static void regmap_parse_64_le_inplace(void *buf)
{
__le64 *b = buf;
b[0] = le64_to_cpu(b[0]);
}
static unsigned int regmap_parse_64_native(const void *buf)
{
return *(u64 *)buf;
}
#endif
static void regmap_lock_mutex(void *__map) static void regmap_lock_mutex(void *__map)
{ {
struct regmap *map = __map; struct regmap *map = __map;
...@@ -712,6 +769,21 @@ struct regmap *__regmap_init(struct device *dev, ...@@ -712,6 +769,21 @@ struct regmap *__regmap_init(struct device *dev,
} }
break; break;
#ifdef CONFIG_64BIT
case 64:
switch (reg_endian) {
case REGMAP_ENDIAN_BIG:
map->format.format_reg = regmap_format_64_be;
break;
case REGMAP_ENDIAN_NATIVE:
map->format.format_reg = regmap_format_64_native;
break;
default:
goto err_map;
}
break;
#endif
default: default:
goto err_map; goto err_map;
} }
...@@ -771,6 +843,28 @@ struct regmap *__regmap_init(struct device *dev, ...@@ -771,6 +843,28 @@ struct regmap *__regmap_init(struct device *dev,
goto err_map; goto err_map;
} }
break; break;
#ifdef CONFIG_64BIT
case 64:
switch (val_endian) {
case REGMAP_ENDIAN_BIG:
map->format.format_val = regmap_format_64_be;
map->format.parse_val = regmap_parse_64_be;
map->format.parse_inplace = regmap_parse_64_be_inplace;
break;
case REGMAP_ENDIAN_LITTLE:
map->format.format_val = regmap_format_64_le;
map->format.parse_val = regmap_parse_64_le;
map->format.parse_inplace = regmap_parse_64_le_inplace;
break;
case REGMAP_ENDIAN_NATIVE:
map->format.format_val = regmap_format_64_native;
map->format.parse_val = regmap_parse_64_native;
break;
default:
goto err_map;
}
break;
#endif
} }
if (map->format.format_write) { if (map->format.format_write) {
...@@ -1513,7 +1607,7 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) ...@@ -1513,7 +1607,7 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
{ {
int ret; int ret;
if (reg % map->reg_stride) if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL; return -EINVAL;
map->lock(map->lock_arg); map->lock(map->lock_arg);
...@@ -1540,7 +1634,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val) ...@@ -1540,7 +1634,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val)
{ {
int ret; int ret;
if (reg % map->reg_stride) if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL; return -EINVAL;
map->lock(map->lock_arg); map->lock(map->lock_arg);
...@@ -1714,7 +1808,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, ...@@ -1714,7 +1808,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (map->bus && !map->format.parse_inplace) if (map->bus && !map->format.parse_inplace)
return -EINVAL; return -EINVAL;
if (reg % map->reg_stride) if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL; return -EINVAL;
/* /*
...@@ -1983,7 +2077,7 @@ static int _regmap_multi_reg_write(struct regmap *map, ...@@ -1983,7 +2077,7 @@ static int _regmap_multi_reg_write(struct regmap *map,
int reg = regs[i].reg; int reg = regs[i].reg;
if (!map->writeable_reg(map->dev, reg)) if (!map->writeable_reg(map->dev, reg))
return -EINVAL; return -EINVAL;
if (reg % map->reg_stride) if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL; return -EINVAL;
} }
...@@ -2133,7 +2227,7 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg, ...@@ -2133,7 +2227,7 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
if (val_len % map->format.val_bytes) if (val_len % map->format.val_bytes)
return -EINVAL; return -EINVAL;
if (reg % map->reg_stride) if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL; return -EINVAL;
map->lock(map->lock_arg); map->lock(map->lock_arg);
...@@ -2260,7 +2354,7 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) ...@@ -2260,7 +2354,7 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
{ {
int ret; int ret;
if (reg % map->reg_stride) if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL; return -EINVAL;
map->lock(map->lock_arg); map->lock(map->lock_arg);
...@@ -2296,7 +2390,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -2296,7 +2390,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
return -EINVAL; return -EINVAL;
if (val_len % map->format.val_bytes) if (val_len % map->format.val_bytes)
return -EINVAL; return -EINVAL;
if (reg % map->reg_stride) if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL; return -EINVAL;
if (val_count == 0) if (val_count == 0)
return -EINVAL; return -EINVAL;
...@@ -2414,7 +2508,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, ...@@ -2414,7 +2508,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
size_t val_bytes = map->format.val_bytes; size_t val_bytes = map->format.val_bytes;
bool vol = regmap_volatile_range(map, reg, val_count); bool vol = regmap_volatile_range(map, reg, val_count);
if (reg % map->reg_stride) if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL; return -EINVAL;
if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) { if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
...@@ -2488,11 +2582,19 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, ...@@ -2488,11 +2582,19 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
* we assume that the values are native * we assume that the values are native
* endian. * endian.
*/ */
#ifdef CONFIG_64BIT
u64 *u64 = val;
#endif
u32 *u32 = val; u32 *u32 = val;
u16 *u16 = val; u16 *u16 = val;
u8 *u8 = val; u8 *u8 = val;
switch (map->format.val_bytes) { switch (map->format.val_bytes) {
#ifdef CONFIG_64BIT
case 8:
u64[i] = ival;
break;
#endif
case 4: case 4:
u32[i] = ival; u32[i] = ival;
break; break;
......
...@@ -788,10 +788,16 @@ int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, ...@@ -788,10 +788,16 @@ int regmap_fields_update_bits(struct regmap_field *field, unsigned int id,
* *
* @reg_offset: Offset of the status/mask register within the bank * @reg_offset: Offset of the status/mask register within the bank
* @mask: Mask used to flag/control the register. * @mask: Mask used to flag/control the register.
* @type_reg_offset: Offset register for the irq type setting.
* @type_rising_mask: Mask bit to configure RISING type irq.
* @type_falling_mask: Mask bit to configure FALLING type irq.
*/ */
struct regmap_irq { struct regmap_irq {
unsigned int reg_offset; unsigned int reg_offset;
unsigned int mask; unsigned int mask;
unsigned int type_reg_offset;
unsigned int type_rising_mask;
unsigned int type_falling_mask;
}; };
#define REGMAP_IRQ_REG(_irq, _off, _mask) \ #define REGMAP_IRQ_REG(_irq, _off, _mask) \
...@@ -811,18 +817,23 @@ struct regmap_irq { ...@@ -811,18 +817,23 @@ struct regmap_irq {
* @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.
* Using zero value is possible with @use_ack bit. * Using zero value is possible with @use_ack bit.
* @wake_base: Base address for wake enables. If zero unsupported. * @wake_base: Base address for wake enables. If zero unsupported.
* @type_base: Base address for irq type. If zero unsupported.
* @irq_reg_stride: Stride to use for chips where registers are not contiguous. * @irq_reg_stride: Stride to use for chips where registers are not contiguous.
* @init_ack_masked: Ack all masked interrupts once during initalization. * @init_ack_masked: Ack all masked interrupts once during initalization.
* @mask_invert: Inverted mask register: cleared bits are masked out. * @mask_invert: Inverted mask register: cleared bits are masked out.
* @use_ack: Use @ack register even if it is zero. * @use_ack: Use @ack register even if it is zero.
* @ack_invert: Inverted ack register: cleared bits for ack. * @ack_invert: Inverted ack register: cleared bits for ack.
* @wake_invert: Inverted wake register: cleared bits are wake enabled. * @wake_invert: Inverted wake register: cleared bits are wake enabled.
* @type_invert: Invert the type flags.
* @runtime_pm: Hold a runtime PM lock on the device when accessing it. * @runtime_pm: Hold a runtime PM lock on the device when accessing it.
* *
* @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
* assigned based on the index in the array of the interrupt. * assigned based on the index in the array of the interrupt.
* @num_irqs: Number of descriptors. * @num_irqs: Number of descriptors.
* @num_type_reg: Number of type registers.
* @type_reg_stride: Stride to use for chips where type registers are not
* contiguous.
*/ */
struct regmap_irq_chip { struct regmap_irq_chip {
const char *name; const char *name;
...@@ -832,6 +843,7 @@ struct regmap_irq_chip { ...@@ -832,6 +843,7 @@ struct regmap_irq_chip {
unsigned int unmask_base; unsigned int unmask_base;
unsigned int ack_base; unsigned int ack_base;
unsigned int wake_base; unsigned int wake_base;
unsigned int type_base;
unsigned int irq_reg_stride; unsigned int irq_reg_stride;
bool init_ack_masked:1; bool init_ack_masked:1;
bool mask_invert:1; bool mask_invert:1;
...@@ -839,11 +851,15 @@ struct regmap_irq_chip { ...@@ -839,11 +851,15 @@ struct regmap_irq_chip {
bool ack_invert:1; bool ack_invert:1;
bool wake_invert:1; bool wake_invert:1;
bool runtime_pm:1; bool runtime_pm:1;
bool type_invert:1;
int num_regs; int num_regs;
const struct regmap_irq *irqs; const struct regmap_irq *irqs;
int num_irqs; int num_irqs;
int num_type_reg;
unsigned int type_reg_stride;
}; };
struct regmap_irq_chip_data; struct regmap_irq_chip_data;
...@@ -1021,7 +1037,7 @@ static inline void regmap_async_complete(struct regmap *map) ...@@ -1021,7 +1037,7 @@ static inline void regmap_async_complete(struct regmap *map)
} }
static inline int regmap_register_patch(struct regmap *map, static inline int regmap_register_patch(struct regmap *map,
const struct reg_default *regs, const struct reg_sequence *regs,
int num_regs) int num_regs)
{ {
WARN_ONCE(1, "regmap API is disabled"); WARN_ONCE(1, "regmap API is disabled");
......
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