Loading drivers/base/regmap/internal.h +16 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,7 @@ struct regmap { /* number of bits to (left) shift the reg value when formatting*/ int reg_shift; int reg_stride; int reg_stride_order; /* regcache specific members */ const struct regcache_ops *cache_ops; Loading Loading @@ -263,4 +264,19 @@ static inline const char *regmap_name(const struct regmap *map) return map->name; } static inline unsigned int regmap_get_offset(const struct regmap *map, unsigned int index) { if (map->reg_stride_order >= 0) return index << map->reg_stride_order; else return index * map->reg_stride; } static inline unsigned int regcache_get_index_by_order(const struct regmap *map, unsigned int reg) { return reg >> map->reg_stride_order; } #endif drivers/base/regmap/regcache-flat.c +15 −5 Original line number Diff line number Diff line Loading @@ -16,20 +16,30 @@ #include "internal.h" static inline unsigned int regcache_flat_get_index(const struct regmap *map, unsigned int reg) { return regcache_get_index_by_order(map, reg); } static int regcache_flat_init(struct regmap *map) { int i; unsigned int *cache; map->cache = kcalloc(map->max_register + 1, sizeof(unsigned int), GFP_KERNEL); if (!map || map->reg_stride_order < 0) return -EINVAL; map->cache = kcalloc(regcache_flat_get_index(map, map->max_register) + 1, sizeof(unsigned int), GFP_KERNEL); if (!map->cache) return -ENOMEM; cache = map->cache; for (i = 0; i < map->num_reg_defaults; i++) cache[map->reg_defaults[i].reg] = map->reg_defaults[i].def; cache[regcache_flat_get_index(map, map->reg_defaults[i].reg)] = map->reg_defaults[i].def; return 0; } Loading @@ -47,7 +57,7 @@ static int regcache_flat_read(struct regmap *map, { unsigned int *cache = map->cache; *value = cache[reg]; *value = cache[regcache_flat_get_index(map, reg)]; return 0; } Loading @@ -57,7 +67,7 @@ static int regcache_flat_write(struct regmap *map, unsigned int reg, { unsigned int *cache = map->cache; cache[reg] = value; cache[regcache_flat_get_index(map, reg)] = value; return 0; } Loading drivers/base/regmap/regmap-irq.c +104 −0 Original line number Diff line number Diff line Loading @@ -379,6 +379,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, data); irq_set_chip(virq, &data->irq_chip); irq_set_nested_thread(virq, 1); irq_set_parent(virq, data->irq); irq_set_noprobe(virq); return 0; Loading Loading @@ -655,13 +656,34 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip); * * @irq: Primary IRQ for the device * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() * * This function also dispose all mapped irq on chip. */ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) { unsigned int virq; int hwirq; if (!d) return; free_irq(irq, d); /* Dispose all virtual irq from irq domain before removing it */ for (hwirq = 0; hwirq < d->chip->num_irqs; hwirq++) { /* Ignore hwirq if holes in the IRQ list */ if (!d->chip->irqs[hwirq].mask) continue; /* * Find the virtual irq of hwirq on chip and if it is * there then dispose it */ virq = irq_find_mapping(d->domain, hwirq); if (virq) irq_dispose_mapping(virq); } irq_domain_remove(d->domain); kfree(d->type_buf); kfree(d->type_buf_def); Loading @@ -674,6 +696,88 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) } EXPORT_SYMBOL_GPL(regmap_del_irq_chip); static void devm_regmap_irq_chip_release(struct device *dev, void *res) { struct regmap_irq_chip_data *d = *(struct regmap_irq_chip_data **)res; regmap_del_irq_chip(d->irq, d); } static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data) { struct regmap_irq_chip_data **r = res; if (!r || !*r) { WARN_ON(!r || !*r); return 0; } return *r == data; } /** * devm_regmap_add_irq_chip(): Resource manager regmap_add_irq_chip() * * @dev: The device pointer on which irq_chip belongs to. * @map: The regmap for the device. * @irq: The IRQ the device uses to signal interrupts * @irq_flags: The IRQF_ flags to use for the primary interrupt. * @chip: Configuration for the interrupt controller. * @data: Runtime data structure for the controller, allocated on success * * Returns 0 on success or an errno on failure. * * The regmap_irq_chip data automatically be released when the device is * unbound. */ int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq, int irq_flags, int irq_base, const struct regmap_irq_chip *chip, struct regmap_irq_chip_data **data) { struct regmap_irq_chip_data **ptr, *d; int ret; ptr = devres_alloc(devm_regmap_irq_chip_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return -ENOMEM; ret = regmap_add_irq_chip(map, irq, irq_flags, irq_base, chip, &d); if (ret < 0) { devres_free(ptr); return ret; } *ptr = d; devres_add(dev, ptr); *data = d; return 0; } EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip); /** * devm_regmap_del_irq_chip(): Resource managed regmap_del_irq_chip() * * @dev: Device for which which resource was allocated. * @irq: Primary IRQ for the device * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() */ void devm_regmap_del_irq_chip(struct device *dev, int irq, struct regmap_irq_chip_data *data) { int rc; WARN_ON(irq != data->irq); rc = devres_release(dev, devm_regmap_irq_chip_release, devm_regmap_irq_chip_match, data); if (rc != 0) WARN_ON(rc); } EXPORT_SYMBOL_GPL(devm_regmap_del_irq_chip); /** * regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip * Loading drivers/base/regmap/regmap.c +13 −6 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <linux/rbtree.h> #include <linux/sched.h> #include <linux/delay.h> #include <linux/log2.h> #define CREATE_TRACE_POINTS #include "trace.h" Loading Loading @@ -640,6 +641,10 @@ struct regmap *__regmap_init(struct device *dev, map->reg_stride = config->reg_stride; else map->reg_stride = 1; if (is_power_of_2(map->reg_stride)) map->reg_stride_order = ilog2(map->reg_stride); else map->reg_stride_order = -1; map->use_single_read = config->use_single_rw || !bus || !bus->read; map->use_single_write = config->use_single_rw || !bus || !bus->write; map->can_multi_write = config->can_multi_write && bus && bus->write; Loading Loading @@ -1310,7 +1315,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, if (map->writeable_reg) for (i = 0; i < val_len / map->format.val_bytes; i++) if (!map->writeable_reg(map->dev, reg + (i * map->reg_stride))) reg + regmap_get_offset(map, i))) return -EINVAL; if (!map->cache_bypass && map->format.parse_val) { Loading @@ -1318,7 +1323,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, int val_bytes = map->format.val_bytes; for (i = 0; i < val_len / val_bytes; i++) { ival = map->format.parse_val(val + (i * val_bytes)); ret = regcache_write(map, reg + (i * map->reg_stride), ret = regcache_write(map, reg + regmap_get_offset(map, i), ival); if (ret) { dev_err(map->dev, Loading Loading @@ -1848,7 +1854,8 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, goto out; } ret = _regmap_write(map, reg + (i * map->reg_stride), ret = _regmap_write(map, reg + regmap_get_offset(map, i), ival); if (ret != 0) goto out; Loading Loading @@ -2421,7 +2428,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, * cost as we expect to hit the cache. */ for (i = 0; i < val_count; i++) { ret = _regmap_read(map, reg + (i * map->reg_stride), ret = _regmap_read(map, reg + regmap_get_offset(map, i), &v); if (ret != 0) goto out; Loading Loading @@ -2573,7 +2580,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, } else { for (i = 0; i < val_count; i++) { unsigned int ival; ret = regmap_read(map, reg + (i * map->reg_stride), ret = regmap_read(map, reg + regmap_get_offset(map, i), &ival); if (ret != 0) return ret; Loading include/linux/regmap.h +9 −1 Original line number Diff line number Diff line Loading @@ -162,7 +162,7 @@ typedef void (*regmap_unlock)(void *); * This field is a duplicate of a similar file in * 'struct regmap_bus' and serves exact same purpose. * Use it only for "no-bus" cases. * @max_register: Optional, specifies the maximum valid register index. * @max_register: Optional, specifies the maximum valid register address. * @wr_table: Optional, points to a struct regmap_access_table specifying * valid ranges for write access. * @rd_table: As above, for read access. Loading Loading @@ -868,6 +868,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, int irq_base, const struct regmap_irq_chip *chip, struct regmap_irq_chip_data **data); void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data); int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq, int irq_flags, int irq_base, const struct regmap_irq_chip *chip, struct regmap_irq_chip_data **data); void devm_regmap_del_irq_chip(struct device *dev, int irq, struct regmap_irq_chip_data *data); int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data); int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq); struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data); Loading Loading
drivers/base/regmap/internal.h +16 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,7 @@ struct regmap { /* number of bits to (left) shift the reg value when formatting*/ int reg_shift; int reg_stride; int reg_stride_order; /* regcache specific members */ const struct regcache_ops *cache_ops; Loading Loading @@ -263,4 +264,19 @@ static inline const char *regmap_name(const struct regmap *map) return map->name; } static inline unsigned int regmap_get_offset(const struct regmap *map, unsigned int index) { if (map->reg_stride_order >= 0) return index << map->reg_stride_order; else return index * map->reg_stride; } static inline unsigned int regcache_get_index_by_order(const struct regmap *map, unsigned int reg) { return reg >> map->reg_stride_order; } #endif
drivers/base/regmap/regcache-flat.c +15 −5 Original line number Diff line number Diff line Loading @@ -16,20 +16,30 @@ #include "internal.h" static inline unsigned int regcache_flat_get_index(const struct regmap *map, unsigned int reg) { return regcache_get_index_by_order(map, reg); } static int regcache_flat_init(struct regmap *map) { int i; unsigned int *cache; map->cache = kcalloc(map->max_register + 1, sizeof(unsigned int), GFP_KERNEL); if (!map || map->reg_stride_order < 0) return -EINVAL; map->cache = kcalloc(regcache_flat_get_index(map, map->max_register) + 1, sizeof(unsigned int), GFP_KERNEL); if (!map->cache) return -ENOMEM; cache = map->cache; for (i = 0; i < map->num_reg_defaults; i++) cache[map->reg_defaults[i].reg] = map->reg_defaults[i].def; cache[regcache_flat_get_index(map, map->reg_defaults[i].reg)] = map->reg_defaults[i].def; return 0; } Loading @@ -47,7 +57,7 @@ static int regcache_flat_read(struct regmap *map, { unsigned int *cache = map->cache; *value = cache[reg]; *value = cache[regcache_flat_get_index(map, reg)]; return 0; } Loading @@ -57,7 +67,7 @@ static int regcache_flat_write(struct regmap *map, unsigned int reg, { unsigned int *cache = map->cache; cache[reg] = value; cache[regcache_flat_get_index(map, reg)] = value; return 0; } Loading
drivers/base/regmap/regmap-irq.c +104 −0 Original line number Diff line number Diff line Loading @@ -379,6 +379,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, data); irq_set_chip(virq, &data->irq_chip); irq_set_nested_thread(virq, 1); irq_set_parent(virq, data->irq); irq_set_noprobe(virq); return 0; Loading Loading @@ -655,13 +656,34 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip); * * @irq: Primary IRQ for the device * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() * * This function also dispose all mapped irq on chip. */ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) { unsigned int virq; int hwirq; if (!d) return; free_irq(irq, d); /* Dispose all virtual irq from irq domain before removing it */ for (hwirq = 0; hwirq < d->chip->num_irqs; hwirq++) { /* Ignore hwirq if holes in the IRQ list */ if (!d->chip->irqs[hwirq].mask) continue; /* * Find the virtual irq of hwirq on chip and if it is * there then dispose it */ virq = irq_find_mapping(d->domain, hwirq); if (virq) irq_dispose_mapping(virq); } irq_domain_remove(d->domain); kfree(d->type_buf); kfree(d->type_buf_def); Loading @@ -674,6 +696,88 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) } EXPORT_SYMBOL_GPL(regmap_del_irq_chip); static void devm_regmap_irq_chip_release(struct device *dev, void *res) { struct regmap_irq_chip_data *d = *(struct regmap_irq_chip_data **)res; regmap_del_irq_chip(d->irq, d); } static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data) { struct regmap_irq_chip_data **r = res; if (!r || !*r) { WARN_ON(!r || !*r); return 0; } return *r == data; } /** * devm_regmap_add_irq_chip(): Resource manager regmap_add_irq_chip() * * @dev: The device pointer on which irq_chip belongs to. * @map: The regmap for the device. * @irq: The IRQ the device uses to signal interrupts * @irq_flags: The IRQF_ flags to use for the primary interrupt. * @chip: Configuration for the interrupt controller. * @data: Runtime data structure for the controller, allocated on success * * Returns 0 on success or an errno on failure. * * The regmap_irq_chip data automatically be released when the device is * unbound. */ int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq, int irq_flags, int irq_base, const struct regmap_irq_chip *chip, struct regmap_irq_chip_data **data) { struct regmap_irq_chip_data **ptr, *d; int ret; ptr = devres_alloc(devm_regmap_irq_chip_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return -ENOMEM; ret = regmap_add_irq_chip(map, irq, irq_flags, irq_base, chip, &d); if (ret < 0) { devres_free(ptr); return ret; } *ptr = d; devres_add(dev, ptr); *data = d; return 0; } EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip); /** * devm_regmap_del_irq_chip(): Resource managed regmap_del_irq_chip() * * @dev: Device for which which resource was allocated. * @irq: Primary IRQ for the device * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() */ void devm_regmap_del_irq_chip(struct device *dev, int irq, struct regmap_irq_chip_data *data) { int rc; WARN_ON(irq != data->irq); rc = devres_release(dev, devm_regmap_irq_chip_release, devm_regmap_irq_chip_match, data); if (rc != 0) WARN_ON(rc); } EXPORT_SYMBOL_GPL(devm_regmap_del_irq_chip); /** * regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip * Loading
drivers/base/regmap/regmap.c +13 −6 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <linux/rbtree.h> #include <linux/sched.h> #include <linux/delay.h> #include <linux/log2.h> #define CREATE_TRACE_POINTS #include "trace.h" Loading Loading @@ -640,6 +641,10 @@ struct regmap *__regmap_init(struct device *dev, map->reg_stride = config->reg_stride; else map->reg_stride = 1; if (is_power_of_2(map->reg_stride)) map->reg_stride_order = ilog2(map->reg_stride); else map->reg_stride_order = -1; map->use_single_read = config->use_single_rw || !bus || !bus->read; map->use_single_write = config->use_single_rw || !bus || !bus->write; map->can_multi_write = config->can_multi_write && bus && bus->write; Loading Loading @@ -1310,7 +1315,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, if (map->writeable_reg) for (i = 0; i < val_len / map->format.val_bytes; i++) if (!map->writeable_reg(map->dev, reg + (i * map->reg_stride))) reg + regmap_get_offset(map, i))) return -EINVAL; if (!map->cache_bypass && map->format.parse_val) { Loading @@ -1318,7 +1323,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, int val_bytes = map->format.val_bytes; for (i = 0; i < val_len / val_bytes; i++) { ival = map->format.parse_val(val + (i * val_bytes)); ret = regcache_write(map, reg + (i * map->reg_stride), ret = regcache_write(map, reg + regmap_get_offset(map, i), ival); if (ret) { dev_err(map->dev, Loading Loading @@ -1848,7 +1854,8 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, goto out; } ret = _regmap_write(map, reg + (i * map->reg_stride), ret = _regmap_write(map, reg + regmap_get_offset(map, i), ival); if (ret != 0) goto out; Loading Loading @@ -2421,7 +2428,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, * cost as we expect to hit the cache. */ for (i = 0; i < val_count; i++) { ret = _regmap_read(map, reg + (i * map->reg_stride), ret = _regmap_read(map, reg + regmap_get_offset(map, i), &v); if (ret != 0) goto out; Loading Loading @@ -2573,7 +2580,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, } else { for (i = 0; i < val_count; i++) { unsigned int ival; ret = regmap_read(map, reg + (i * map->reg_stride), ret = regmap_read(map, reg + regmap_get_offset(map, i), &ival); if (ret != 0) return ret; Loading
include/linux/regmap.h +9 −1 Original line number Diff line number Diff line Loading @@ -162,7 +162,7 @@ typedef void (*regmap_unlock)(void *); * This field is a duplicate of a similar file in * 'struct regmap_bus' and serves exact same purpose. * Use it only for "no-bus" cases. * @max_register: Optional, specifies the maximum valid register index. * @max_register: Optional, specifies the maximum valid register address. * @wr_table: Optional, points to a struct regmap_access_table specifying * valid ranges for write access. * @rd_table: As above, for read access. Loading Loading @@ -868,6 +868,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, int irq_base, const struct regmap_irq_chip *chip, struct regmap_irq_chip_data **data); void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data); int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq, int irq_flags, int irq_base, const struct regmap_irq_chip *chip, struct regmap_irq_chip_data **data); void devm_regmap_del_irq_chip(struct device *dev, int irq, struct regmap_irq_chip_data *data); int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data); int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq); struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data); Loading