From: Mark Brown Date: Mon, 5 Dec 2011 13:18:50 +0000 (+0000) Subject: Merge branch 'topic/cache' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie... X-Git-Tag: v3.3-rc1~163^2~6 X-Git-Url: http://pileus.org/git/?a=commitdiff_plain;h=8569d023a0db699c462337d471f7e92163142e37;hp=-c;p=~andy%2Flinux Merge branch 'topic/cache' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap into regmap-next --- 8569d023a0db699c462337d471f7e92163142e37 diff --combined drivers/base/regmap/regmap.c index add5da6d9c0,579e85b8a68..be10a4ff660 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@@ -64,18 -64,6 +64,18 @@@ bool regmap_precious(struct regmap *map return false; } +static bool regmap_volatile_range(struct regmap *map, unsigned int reg, + unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) + if (!regmap_volatile(map, reg + i)) + return false; + + return true; +} + static void regmap_format_4_12_write(struct regmap *map, unsigned int reg, unsigned int val) { @@@ -90,16 -78,6 +90,16 @@@ static void regmap_format_7_9_write(str *out = cpu_to_be16((reg << 9) | val); } +static void regmap_format_10_14_write(struct regmap *map, + unsigned int reg, unsigned int val) +{ + u8 *out = map->work_buf; + + out[2] = val; + out[1] = (val >> 8) | (reg << 6); + out[0] = reg >> 2; +} + static void regmap_format_8(void *buf, unsigned int val) { u8 *b = buf; @@@ -149,7 -127,7 +149,7 @@@ struct regmap *regmap_init(struct devic int ret = -EINVAL; if (!bus || !config) - return NULL; + goto err; map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) { @@@ -169,6 -147,12 +169,6 @@@ map->volatile_reg = config->volatile_reg; map->precious_reg = config->precious_reg; map->cache_type = config->cache_type; - map->reg_defaults = config->reg_defaults; - map->num_reg_defaults = config->num_reg_defaults; - map->num_reg_defaults_raw = config->num_reg_defaults_raw; - map->reg_defaults_raw = config->reg_defaults_raw; - map->cache_size_raw = (config->val_bits / 8) * config->num_reg_defaults_raw; - map->cache_word_size = config->val_bits / 8; if (config->read_flag_mask || config->write_flag_mask) { map->read_flag_mask = config->read_flag_mask; @@@ -198,16 -182,6 +198,16 @@@ } break; + case 10: + switch (config->val_bits) { + case 14: + map->format.format_write = regmap_format_10_14_write; + break; + default: + goto err_map; + } + break; + case 8: map->format.format_reg = regmap_format_8; break; @@@ -241,16 -215,14 +241,16 @@@ goto err_map; } - ret = regcache_init(map); - if (ret < 0) - goto err_map; - regmap_debugfs_init(map); + ret = regcache_init(map, config); + if (ret < 0) + goto err_free_workbuf; + return map; +err_free_workbuf: + kfree(map->work_buf); err_map: kfree(map); err: @@@ -258,6 -230,39 +258,39 @@@ } EXPORT_SYMBOL_GPL(regmap_init); + /** + * regmap_reinit_cache(): Reinitialise the current register cache + * + * @map: Register map to operate on. + * @config: New configuration. Only the cache data will be used. + * + * Discard any existing register cache for the map and initialize a + * new cache. This can be used to restore the cache to defaults or to + * update the cache configuration to reflect runtime discovery of the + * hardware. + */ + int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) + { + int ret; + + mutex_lock(&map->lock); + + regcache_exit(map); + + map->max_register = config->max_register; + map->writeable_reg = config->writeable_reg; + map->readable_reg = config->readable_reg; + map->volatile_reg = config->volatile_reg; + map->precious_reg = config->precious_reg; + map->cache_type = config->cache_type; + + ret = regcache_init(map, config); + + mutex_unlock(&map->lock); + + return ret; + } + /** * regmap_exit(): Free a previously allocated register map */ @@@ -405,11 -410,9 +438,11 @@@ EXPORT_SYMBOL_GPL(regmap_write) int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len) { + size_t val_count = val_len / map->format.val_bytes; int ret; - WARN_ON(map->cache_type != REGCACHE_NONE); + WARN_ON(!regmap_volatile_range(map, reg, val_count) && + map->cache_type != REGCACHE_NONE); mutex_lock(&map->lock); @@@ -454,15 -457,15 +487,15 @@@ static int _regmap_read(struct regmap * { int ret; - if (!map->format.parse_val) - return -EINVAL; - if (!map->cache_bypass) { ret = regcache_read(map, reg, val); if (ret == 0) return 0; } + if (!map->format.parse_val) + return -EINVAL; + if (map->cache_only) return -EBUSY; @@@ -513,11 -516,15 +546,11 @@@ EXPORT_SYMBOL_GPL(regmap_read) int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, size_t val_len) { + size_t val_count = val_len / map->format.val_bytes; int ret; - int i; - bool vol = true; - for (i = 0; i < val_len / map->format.val_bytes; i++) - if (!regmap_volatile(map, reg + i)) - vol = false; - - WARN_ON(!vol && map->cache_type != REGCACHE_NONE); + WARN_ON(!regmap_volatile_range(map, reg, val_count) && + map->cache_type != REGCACHE_NONE); mutex_lock(&map->lock); @@@ -545,11 -552,16 +578,11 @@@ int regmap_bulk_read(struct regmap *map { int ret, i; size_t val_bytes = map->format.val_bytes; - bool vol = true; + bool vol = regmap_volatile_range(map, reg, val_count); if (!map->format.parse_val) return -EINVAL; - /* Is this a block of volatile registers? */ - for (i = 0; i < val_count; i++) - if (!regmap_volatile(map, reg + i)) - vol = false; - if (vol || map->cache_type == REGCACHE_NONE) { ret = regmap_raw_read(map, reg, val, val_bytes * val_count); if (ret != 0) @@@ -569,73 -581,40 +602,73 @@@ } EXPORT_SYMBOL_GPL(regmap_bulk_read); -/** - * remap_update_bits: Perform a read/modify/write cycle on the register map - * - * @map: Register map to update - * @reg: Register to update - * @mask: Bitmask to change - * @val: New value for bitmask - * - * Returns zero for success, a negative number on error. - */ -int regmap_update_bits(struct regmap *map, unsigned int reg, - unsigned int mask, unsigned int val) +static int _regmap_update_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val, + bool *change) { int ret; - unsigned int tmp; + unsigned int tmp, orig; mutex_lock(&map->lock); - ret = _regmap_read(map, reg, &tmp); + ret = _regmap_read(map, reg, &orig); if (ret != 0) goto out; - tmp &= ~mask; + tmp = orig & ~mask; tmp |= val & mask; - ret = _regmap_write(map, reg, tmp); + if (tmp != orig) { + ret = _regmap_write(map, reg, tmp); + *change = true; + } else { + *change = false; + } out: mutex_unlock(&map->lock); return ret; } + +/** + * regmap_update_bits: Perform a read/modify/write cycle on the register map + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * + * Returns zero for success, a negative number on error. + */ +int regmap_update_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + bool change; + return _regmap_update_bits(map, reg, mask, val, &change); +} EXPORT_SYMBOL_GPL(regmap_update_bits); +/** + * regmap_update_bits_check: Perform a read/modify/write cycle on the + * register map and report if updated + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * @change: Boolean indicating if a write was done + * + * Returns zero for success, a negative number on error. + */ +int regmap_update_bits_check(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val, + bool *change) +{ + return _regmap_update_bits(map, reg, mask, val, change); +} +EXPORT_SYMBOL_GPL(regmap_update_bits_check); + static int __init regmap_initcall(void) { regmap_debugfs_initcall(); diff --combined include/linux/regmap.h index a83e4a097ab,86923a98a76..cfce3a358fb --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@@ -23,6 -23,7 +23,6 @@@ struct spi_device /* An enum of all the supported cache types */ enum regcache_type { REGCACHE_NONE, - REGCACHE_INDEXED, REGCACHE_RBTREE, REGCACHE_COMPRESSED }; @@@ -82,7 -83,7 +82,7 @@@ struct regmap_config bool (*precious_reg)(struct device *dev, unsigned int reg); unsigned int max_register; - struct reg_default *reg_defaults; + const struct reg_default *reg_defaults; unsigned int num_reg_defaults; enum regcache_type cache_type; const void *reg_defaults_raw; @@@ -128,6 -129,8 +128,8 @@@ struct regmap *regmap_init_spi(struct s const struct regmap_config *config); void regmap_exit(struct regmap *map); + int regmap_reinit_cache(struct regmap *map, + const struct regmap_config *config); int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len); @@@ -138,60 -141,10 +140,60 @@@ int regmap_bulk_read(struct regmap *map size_t val_count); int regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); +int regmap_update_bits_check(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val, + bool *change); int regcache_sync(struct regmap *map); void regcache_cache_only(struct regmap *map, bool enable); void regcache_cache_bypass(struct regmap *map, bool enable); void regcache_mark_dirty(struct regmap *map); +/** + * Description of an IRQ for the generic regmap irq_chip. + * + * @reg_offset: Offset of the status/mask register within the bank + * @mask: Mask used to flag/control the register. + */ +struct regmap_irq { + unsigned int reg_offset; + unsigned int mask; +}; + +/** + * Description of a generic regmap irq_chip. This is not intended to + * handle every possible interrupt controller, but it should handle a + * substantial proportion of those that are found in the wild. + * + * @name: Descriptive name for IRQ controller. + * + * @status_base: Base status register address. + * @mask_base: Base mask register address. + * @ack_base: Base ack address. If zero then the chip is clear on read. + * + * @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. + */ +struct regmap_irq_chip { + const char *name; + + unsigned int status_base; + unsigned int mask_base; + unsigned int ack_base; + + int num_regs; + + const struct regmap_irq *irqs; + int num_irqs; +}; + +struct regmap_irq_chip_data; + +int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, + int irq_base, struct regmap_irq_chip *chip, + struct regmap_irq_chip_data **data); +void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data); + #endif