regmap: Changes for v4.5
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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJWk9fCAAoJECTWi3JdVIfQpn4H/0nJwe03NcY829ioXEP+ICHF yE1Y8FH5q+NeVAo+bbQQYiTEGRQbp+E82S7OTfNKY0Z3QkPRZVtz5yMI/L2yK8I0 HT2WJakJY6LhQfJcWgjRRfBrQvH/+2fk+3mAs0q0r+mrOoitfCb1V7uaNoVF+Hyk 0mli7lcf2MB1akF98SwcaM3v3HhGXUUxFnclvzsMWTEp4GCt/xqwEkTm/0xn0N17 rlxLe1RtaGMM0xfbEN3sfDX5YAPmtBi4m+CdrP6l5qgisnABPIq83RKRFNyQBcGD 8OkA2Iu0B7eJPFPQ8sD/hELBNYyrVTwvhJQdJnle7++/Dis9EMiffMRSW8eZh+0= =JaJb -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
e795e5f4e0
|
@ -73,7 +73,6 @@
|
|||
timer: timer@10000040 {
|
||||
compatible = "syscon";
|
||||
reg = <0x10000040 0x2c>;
|
||||
little-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -98,7 +98,6 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7125-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x60c>;
|
||||
little-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -118,7 +118,6 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7346-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -112,7 +112,6 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7358-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -112,7 +112,6 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7360-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -118,7 +118,6 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7362-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -99,7 +99,6 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7420-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x60c>;
|
||||
little-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -100,7 +100,6 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -114,7 +114,6 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -21,7 +21,7 @@ static int regcache_flat_init(struct regmap *map)
|
|||
int i;
|
||||
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);
|
||||
if (!map->cache)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -139,7 +139,7 @@ static int regcache_lzo_init(struct regmap *map)
|
|||
ret = 0;
|
||||
|
||||
blkcount = regcache_lzo_block_count(map);
|
||||
map->cache = kzalloc(blkcount * sizeof *lzo_blocks,
|
||||
map->cache = kcalloc(blkcount, sizeof(*lzo_blocks),
|
||||
GFP_KERNEL);
|
||||
if (!map->cache)
|
||||
return -ENOMEM;
|
||||
|
@ -152,8 +152,8 @@ static int regcache_lzo_init(struct regmap *map)
|
|||
* that register.
|
||||
*/
|
||||
bmp_size = map->num_reg_defaults_raw;
|
||||
sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
|
||||
GFP_KERNEL);
|
||||
sync_bmp = kmalloc_array(BITS_TO_LONGS(bmp_size), sizeof(long),
|
||||
GFP_KERNEL);
|
||||
if (!sync_bmp) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
|
|
|
@ -361,13 +361,14 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
|
|||
rbnode->base_reg = reg;
|
||||
}
|
||||
|
||||
rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
|
||||
GFP_KERNEL);
|
||||
rbnode->block = kmalloc_array(rbnode->blklen, map->cache_word_size,
|
||||
GFP_KERNEL);
|
||||
if (!rbnode->block)
|
||||
goto err_free;
|
||||
|
||||
rbnode->cache_present = kzalloc(BITS_TO_LONGS(rbnode->blklen) *
|
||||
sizeof(*rbnode->cache_present), GFP_KERNEL);
|
||||
rbnode->cache_present = kcalloc(BITS_TO_LONGS(rbnode->blklen),
|
||||
sizeof(*rbnode->cache_present),
|
||||
GFP_KERNEL);
|
||||
if (!rbnode->cache_present)
|
||||
goto err_free_block;
|
||||
|
||||
|
@ -413,8 +414,8 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
|||
max = reg + max_dist;
|
||||
|
||||
/* look for an adjacent register to the one we are about to add */
|
||||
for (node = rb_first(&rbtree_ctx->root); node;
|
||||
node = rb_next(node)) {
|
||||
node = rbtree_ctx->root.rb_node;
|
||||
while (node) {
|
||||
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
|
||||
node);
|
||||
|
||||
|
@ -425,6 +426,11 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
|||
new_base_reg = min(reg, base_reg);
|
||||
new_top_reg = max(reg, top_reg);
|
||||
} else {
|
||||
if (max < base_reg)
|
||||
node = node->rb_left;
|
||||
else
|
||||
node = node->rb_right;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,15 +100,25 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
|
|||
int i;
|
||||
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 (config->reg_defaults || config->num_reg_defaults_raw)
|
||||
dev_warn(map->dev,
|
||||
"No cache used with register defaults set!\n");
|
||||
|
||||
map->cache_bypass = true;
|
||||
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++)
|
||||
if (cache_types[i]->type == map->cache_type)
|
||||
break;
|
||||
|
@ -138,8 +148,6 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
|
|||
* a copy of it.
|
||||
*/
|
||||
if (config->reg_defaults) {
|
||||
if (!map->num_reg_defaults)
|
||||
return -EINVAL;
|
||||
tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults *
|
||||
sizeof(struct reg_default), GFP_KERNEL);
|
||||
if (!tmp_buf)
|
||||
|
@ -535,19 +543,30 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
|
|||
switch (map->cache_word_size) {
|
||||
case 1: {
|
||||
u8 *cache = base;
|
||||
|
||||
cache[idx] = val;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
u16 *cache = base;
|
||||
|
||||
cache[idx] = val;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
u32 *cache = base;
|
||||
|
||||
cache[idx] = val;
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8: {
|
||||
u64 *cache = base;
|
||||
|
||||
cache[idx] = val;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
@ -568,16 +587,26 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
|
|||
switch (map->cache_word_size) {
|
||||
case 1: {
|
||||
const u8 *cache = base;
|
||||
|
||||
return cache[idx];
|
||||
}
|
||||
case 2: {
|
||||
const u16 *cache = base;
|
||||
|
||||
return cache[idx];
|
||||
}
|
||||
case 4: {
|
||||
const u32 *cache = base;
|
||||
|
||||
return cache[idx];
|
||||
}
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8: {
|
||||
const u64 *cache = base;
|
||||
|
||||
return cache[idx];
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
|
|
@ -397,72 +397,39 @@ static const struct file_operations regmap_reg_ranges_fops = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t regmap_access_read_file(struct file *file,
|
||||
char __user *user_buf, size_t count,
|
||||
loff_t *ppos)
|
||||
static int regmap_access_show(struct seq_file *s, void *ignored)
|
||||
{
|
||||
int reg_len, tot_len;
|
||||
size_t buf_pos = 0;
|
||||
loff_t p = 0;
|
||||
ssize_t ret;
|
||||
int i;
|
||||
struct regmap *map = file->private_data;
|
||||
char *buf;
|
||||
struct regmap *map = s->private;
|
||||
int i, reg_len;
|
||||
|
||||
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);
|
||||
tot_len = reg_len + 10; /* ': R W V P\n' */
|
||||
|
||||
for (i = 0; i <= map->max_register; i += map->reg_stride) {
|
||||
/* Ignore registers which are neither readable nor writable */
|
||||
if (!regmap_readable(map, i) && !regmap_writeable(map, i))
|
||||
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 */
|
||||
snprintf(buf + buf_pos, count - buf_pos,
|
||||
"%.*x: %c %c %c %c\n",
|
||||
reg_len, i,
|
||||
regmap_readable(map, i) ? 'y' : 'n',
|
||||
regmap_writeable(map, i) ? 'y' : 'n',
|
||||
regmap_volatile(map, i) ? 'y' : 'n',
|
||||
regmap_precious(map, i) ? 'y' : 'n');
|
||||
|
||||
buf_pos += tot_len;
|
||||
}
|
||||
p += tot_len;
|
||||
/* Format the register */
|
||||
seq_printf(s, "%.*x: %c %c %c %c\n", reg_len, i,
|
||||
regmap_readable(map, i) ? 'y' : 'n',
|
||||
regmap_writeable(map, i) ? 'y' : 'n',
|
||||
regmap_volatile(map, i) ? 'y' : 'n',
|
||||
regmap_precious(map, i) ? 'y' : 'n');
|
||||
}
|
||||
|
||||
ret = buf_pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (copy_to_user(user_buf, buf, buf_pos)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*ppos += buf_pos;
|
||||
|
||||
out:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
static int access_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, regmap_access_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations regmap_access_fops = {
|
||||
.open = simple_open,
|
||||
.read = regmap_access_read_file,
|
||||
.llseek = default_llseek,
|
||||
.open = access_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static ssize_t regmap_cache_only_write_file(struct file *file,
|
||||
|
|
|
@ -39,8 +39,11 @@ struct regmap_irq_chip_data {
|
|||
unsigned int *mask_buf;
|
||||
unsigned int *mask_buf_def;
|
||||
unsigned int *wake_buf;
|
||||
unsigned int *type_buf;
|
||||
unsigned int *type_buf_def;
|
||||
|
||||
unsigned int irq_reg_stride;
|
||||
unsigned int type_reg_stride;
|
||||
};
|
||||
|
||||
static inline const
|
||||
|
@ -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)
|
||||
pm_runtime_put(map->dev);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 = {
|
|||
.irq_bus_sync_unlock = regmap_irq_sync_unlock,
|
||||
.irq_disable = regmap_irq_disable,
|
||||
.irq_enable = regmap_irq_enable,
|
||||
.irq_set_type = regmap_irq_set_type,
|
||||
.irq_set_wake = regmap_irq_set_wake,
|
||||
};
|
||||
|
||||
|
@ -386,28 +438,40 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
|
|||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
|
||||
d->status_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
|
||||
GFP_KERNEL);
|
||||
if (!d->status_buf)
|
||||
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);
|
||||
if (!d->mask_buf)
|
||||
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);
|
||||
if (!d->mask_buf_def)
|
||||
goto err_alloc;
|
||||
|
||||
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);
|
||||
if (!d->wake_buf)
|
||||
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.name = chip->name;
|
||||
d->irq = irq;
|
||||
|
@ -420,10 +484,16 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
|
|||
else
|
||||
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 &&
|
||||
d->irq_reg_stride == 1) {
|
||||
d->status_reg_buf = kmalloc(map->format.val_bytes *
|
||||
chip->num_regs, GFP_KERNEL);
|
||||
d->status_reg_buf = kmalloc_array(chip->num_regs,
|
||||
map->format.val_bytes,
|
||||
GFP_KERNEL);
|
||||
if (!d->status_reg_buf)
|
||||
goto err_alloc;
|
||||
}
|
||||
|
@ -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)
|
||||
d->domain = irq_domain_add_legacy(map->dev->of_node,
|
||||
chip->num_irqs, irq_base, 0,
|
||||
|
@ -541,6 +638,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
|
|||
err_domain:
|
||||
/* Should really dispose of the domain but... */
|
||||
err_alloc:
|
||||
kfree(d->type_buf);
|
||||
kfree(d->type_buf_def);
|
||||
kfree(d->wake_buf);
|
||||
kfree(d->mask_buf_def);
|
||||
kfree(d->mask_buf);
|
||||
|
@ -564,6 +663,8 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
|
|||
|
||||
free_irq(irq, d);
|
||||
irq_domain_remove(d->domain);
|
||||
kfree(d->type_buf);
|
||||
kfree(d->type_buf_def);
|
||||
kfree(d->wake_buf);
|
||||
kfree(d->mask_buf_def);
|
||||
kfree(d->mask_buf);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
BUG_ON(count <= offset);
|
||||
|
@ -106,17 +133,17 @@ static int regmap_mmio_gather_write(void *context,
|
|||
while (val_size) {
|
||||
switch (ctx->val_bytes) {
|
||||
case 1:
|
||||
writeb(*(u8 *)val, ctx->regs + offset);
|
||||
__raw_writeb(*(u8 *)val, ctx->regs + offset);
|
||||
break;
|
||||
case 2:
|
||||
writew(*(u16 *)val, ctx->regs + offset);
|
||||
__raw_writew(*(u16 *)val, ctx->regs + offset);
|
||||
break;
|
||||
case 4:
|
||||
writel(*(u32 *)val, ctx->regs + offset);
|
||||
__raw_writel(*(u32 *)val, ctx->regs + offset);
|
||||
break;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
writeq(*(u64 *)val, ctx->regs + offset);
|
||||
__raw_writeq(*(u64 *)val, ctx->regs + offset);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -166,17 +193,17 @@ static int regmap_mmio_read(void *context,
|
|||
while (val_size) {
|
||||
switch (ctx->val_bytes) {
|
||||
case 1:
|
||||
*(u8 *)val = readb(ctx->regs + offset);
|
||||
*(u8 *)val = __raw_readb(ctx->regs + offset);
|
||||
break;
|
||||
case 2:
|
||||
*(u16 *)val = readw(ctx->regs + offset);
|
||||
*(u16 *)val = __raw_readw(ctx->regs + offset);
|
||||
break;
|
||||
case 4:
|
||||
*(u32 *)val = readl(ctx->regs + offset);
|
||||
*(u32 *)val = __raw_readl(ctx->regs + offset);
|
||||
break;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
*(u64 *)val = readq(ctx->regs + offset);
|
||||
*(u64 *)val = __raw_readq(ctx->regs + offset);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -231,26 +258,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
|
|||
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);
|
||||
}
|
||||
min_stride = regmap_mmio_get_min_stride(config->val_bits);
|
||||
if (min_stride < 0)
|
||||
return ERR_PTR(min_stride);
|
||||
|
||||
if (config->reg_stride < min_stride)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
@ -245,6 +245,28 @@ static void regmap_format_32_native(void *buf, unsigned int val,
|
|||
*(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)
|
||||
{
|
||||
}
|
||||
|
@ -332,6 +354,41 @@ static unsigned int regmap_parse_32_native(const void *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)
|
||||
{
|
||||
struct regmap *map = __map;
|
||||
|
@ -712,6 +769,21 @@ struct regmap *__regmap_init(struct device *dev,
|
|||
}
|
||||
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:
|
||||
goto err_map;
|
||||
}
|
||||
|
@ -771,6 +843,28 @@ struct regmap *__regmap_init(struct device *dev,
|
|||
goto err_map;
|
||||
}
|
||||
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) {
|
||||
|
@ -1513,7 +1607,7 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (reg % map->reg_stride)
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
@ -1540,7 +1634,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (reg % map->reg_stride)
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
@ -1714,7 +1808,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
|||
|
||||
if (map->bus && !map->format.parse_inplace)
|
||||
return -EINVAL;
|
||||
if (reg % map->reg_stride)
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
|
@ -1983,7 +2077,7 @@ static int _regmap_multi_reg_write(struct regmap *map,
|
|||
int reg = regs[i].reg;
|
||||
if (!map->writeable_reg(map->dev, reg))
|
||||
return -EINVAL;
|
||||
if (reg % map->reg_stride)
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2133,7 +2227,7 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
|
|||
|
||||
if (val_len % map->format.val_bytes)
|
||||
return -EINVAL;
|
||||
if (reg % map->reg_stride)
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
@ -2260,7 +2354,7 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (reg % map->reg_stride)
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
@ -2296,7 +2390,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
|
|||
return -EINVAL;
|
||||
if (val_len % map->format.val_bytes)
|
||||
return -EINVAL;
|
||||
if (reg % map->reg_stride)
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
return -EINVAL;
|
||||
if (val_count == 0)
|
||||
return -EINVAL;
|
||||
|
@ -2414,7 +2508,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
|
|||
size_t val_bytes = map->format.val_bytes;
|
||||
bool vol = regmap_volatile_range(map, reg, val_count);
|
||||
|
||||
if (reg % map->reg_stride)
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
return -EINVAL;
|
||||
|
||||
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,
|
|||
* we assume that the values are native
|
||||
* endian.
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
u64 *u64 = val;
|
||||
#endif
|
||||
u32 *u32 = val;
|
||||
u16 *u16 = val;
|
||||
u8 *u8 = val;
|
||||
|
||||
switch (map->format.val_bytes) {
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
u64[i] = ival;
|
||||
break;
|
||||
#endif
|
||||
case 4:
|
||||
u32[i] = ival;
|
||||
break;
|
||||
|
|
|
@ -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
|
||||
* @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 {
|
||||
unsigned int reg_offset;
|
||||
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) \
|
||||
|
@ -811,18 +817,23 @@ struct regmap_irq {
|
|||
* @ack_base: Base ack address. If zero then the chip is clear on read.
|
||||
* Using zero value is possible with @use_ack bit.
|
||||
* @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.
|
||||
* @init_ack_masked: Ack all masked interrupts once during initalization.
|
||||
* @mask_invert: Inverted mask register: cleared bits are masked out.
|
||||
* @use_ack: Use @ack register even if it is zero.
|
||||
* @ack_invert: Inverted ack register: cleared bits for ack.
|
||||
* @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.
|
||||
*
|
||||
* @num_regs: Number of registers in each control bank.
|
||||
* @irqs: Descriptors for individual IRQs. Interrupt numbers are
|
||||
* assigned based on the index in the array of the interrupt.
|
||||
* @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 {
|
||||
const char *name;
|
||||
|
@ -832,6 +843,7 @@ struct regmap_irq_chip {
|
|||
unsigned int unmask_base;
|
||||
unsigned int ack_base;
|
||||
unsigned int wake_base;
|
||||
unsigned int type_base;
|
||||
unsigned int irq_reg_stride;
|
||||
bool init_ack_masked:1;
|
||||
bool mask_invert:1;
|
||||
|
@ -839,11 +851,15 @@ struct regmap_irq_chip {
|
|||
bool ack_invert:1;
|
||||
bool wake_invert:1;
|
||||
bool runtime_pm:1;
|
||||
bool type_invert:1;
|
||||
|
||||
int num_regs;
|
||||
|
||||
const struct regmap_irq *irqs;
|
||||
int num_irqs;
|
||||
|
||||
int num_type_reg;
|
||||
unsigned int type_reg_stride;
|
||||
};
|
||||
|
||||
struct regmap_irq_chip_data;
|
||||
|
@ -1021,7 +1037,7 @@ static inline void regmap_async_complete(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)
|
||||
{
|
||||
WARN_ONCE(1, "regmap API is disabled");
|
||||
|
|
Loading…
Reference in New Issue