Loading drivers/base/regmap/regcache.c +21 −0 Original line number Original line Diff line number Diff line Loading @@ -543,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(); } } Loading @@ -576,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(); } } Loading drivers/base/regmap/regmap-irq.c +100 −0 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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); Loading @@ -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, }; }; Loading Loading @@ -408,6 +460,18 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, 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; Loading @@ -420,6 +484,11 @@ 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_array(chip->num_regs, d->status_reg_buf = kmalloc_array(chip->num_regs, Loading Loading @@ -512,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, Loading Loading @@ -542,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); Loading @@ -565,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); Loading drivers/base/regmap/regmap.c +102 −0 Original line number Original line Diff line number Diff line Loading @@ -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) { { } } Loading Loading @@ -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; Loading Loading @@ -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; } } Loading Loading @@ -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) { Loading Loading @@ -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; Loading include/linux/regmap.h +16 −0 Original line number Original line Diff line number Diff line Loading @@ -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) \ Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading
drivers/base/regmap/regcache.c +21 −0 Original line number Original line Diff line number Diff line Loading @@ -543,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(); } } Loading @@ -576,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(); } } Loading
drivers/base/regmap/regmap-irq.c +100 −0 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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); Loading @@ -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, }; }; Loading Loading @@ -408,6 +460,18 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, 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; Loading @@ -420,6 +484,11 @@ 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_array(chip->num_regs, d->status_reg_buf = kmalloc_array(chip->num_regs, Loading Loading @@ -512,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, Loading Loading @@ -542,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); Loading @@ -565,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); Loading
drivers/base/regmap/regmap.c +102 −0 Original line number Original line Diff line number Diff line Loading @@ -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) { { } } Loading Loading @@ -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; Loading Loading @@ -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; } } Loading Loading @@ -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) { Loading Loading @@ -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; Loading
include/linux/regmap.h +16 −0 Original line number Original line Diff line number Diff line Loading @@ -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) \ Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading