From: Mark Brown Date: Tue, 5 Jan 2016 19:07:17 +0000 (+0000) Subject: Merge remote-tracking branches 'regmap/topic/64bit' and 'regmap/topic/irq-type' into... X-Git-Tag: v4.5-rc1~153^2~1 X-Git-Url: https://repo.jachan.dev/linux.git/commitdiff_plain/a8d99344c9ebc2f12232473f92beac2f894b6ea5?hp=-c Merge remote-tracking branches 'regmap/topic/64bit' and 'regmap/topic/irq-type' into regmap-next --- a8d99344c9ebc2f12232473f92beac2f894b6ea5 diff --combined drivers/base/regmap/regcache.c index 60aeaad7fb69,1c0210aa2573,4c07802986b2..348be3a35410 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@@@ -100,25 -100,15 -100,15 +100,25 @@@@ int regcache_init(struct regmap *map, c 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; @@@@ -148,6 -138,8 -138,8 +148,6 @@@@ * 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) @@@@ -543,19 -535,30 -535,19 +543,30 @@@@ bool regcache_set_val(struct regmap *ma 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(); } @@@@ -576,16 -579,26 -568,16 +587,26 @@@@ unsigned int regcache_get_val(struct re 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(); } diff --combined drivers/base/regmap/regmap-irq.c index 4d2cb21254aa,8d16db533527,dbe7a0d15a26..9b0d202414d0 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@@@ -39,8 -39,8 -39,11 +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 -144,6 -147,22 +147,22 @@@@ static void regmap_irq_sync_unlock(stru } } ++ 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 -178,6 -197,38 +197,38 @@@@ static void regmap_irq_disable(struct i 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 -204,6 -255,7 +255,7 @@@@ static const struct irq_chip regmap_irq .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 -386,28 -438,40 +438,40 @@@@ int regmap_add_irq_chip(struct regmap * 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,11 -420,10 -484,15 +484,16 @@@@ 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; } @@@@ -512,6 -511,6 -580,33 +581,33 @@@@ } } ++ 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, @@@@ -542,6 -541,6 -637,8 +638,8 @@@@ 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); @@@@ -565,6 -564,6 -662,8 +663,8 @@@@ void regmap_del_irq_chip(int irq, struc 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); diff --combined drivers/base/regmap/regmap.c index a8f6dd9457be,d27fe2f0182e,4ac63c0e50c7..ee54e841de4a --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@@@ -245,6 -245,28 -245,6 +245,28 @@@@ static void regmap_format_32_native(voi *(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 -332,6 +354,41 @@@@ static unsigned int regmap_parse_32_nat 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 -712,6 +769,21 @@@@ struct regmap *__regmap_init(struct 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 -771,6 +843,28 @@@@ 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 -1513,7 +1607,7 @@@@ int regmap_write(struct regmap *map, un { 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 -1540,7 +1634,7 @@@@ int regmap_write_async(struct regmap *m { 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 -1714,7 +1808,7 @@@@ int regmap_bulk_write(struct regmap *ma 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 -1983,7 +2077,7 @@@@ static int _regmap_multi_reg_write(stru 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 -2133,7 +2227,7 @@@@ int regmap_raw_write_async(struct regma 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 -2260,7 +2354,7 @@@@ int regmap_read(struct regmap *map, uns { 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 -2296,7 +2390,7 @@@@ int regmap_raw_read(struct regmap *map 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 -2414,7 +2508,7 @@@@ int regmap_bulk_read(struct regmap *map 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 -2488,11 +2582,19 @@@@ * 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; diff --combined include/linux/regmap.h index 4d9a1a04647b,d68bb402120e,95b6636d3a59..18394343f489 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@@@ -788,10 -788,10 -788,16 +788,16 @@@@ int regmap_fields_update_bits(struct re * * @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 -811,18 -817,23 +817,23 @@@@ * @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 -832,6 -843,7 +843,7 @@@@ 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 -839,11 -851,15 +851,15 @@@@ 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 -1021,7 -1037,7 +1037,7 @@@@ static inline void regmap_async_complet } 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");