/* * Register map access API * * Copyright 2011 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/device.h>#include <linux/slab.h>#include <linux/export.h>#include <linux/mutex.h>#include <linux/err.h> #define CREATE_TRACE_POINTS#include <trace/events/regmap.h> #include "internal.h" bool regmap_writeable(struct regmap *map, unsigned int reg){ if (map->max_register && reg > map->max_register) return false; if (map->writeable_reg) return map->writeable_reg(map->dev, reg); return true;} bool regmap_readable(struct regmap *map, unsigned int reg){ if (map->max_register && reg > map->max_register) return false; if (map->format.format_write) return false; if (map->readable_reg) return map->readable_reg(map->dev, reg); return true;} bool regmap_volatile(struct regmap *map, unsigned int reg){ if (!regmap_readable(map, reg)) return false; if (map->volatile_reg) return map->volatile_reg(map->dev, reg); return true;} bool regmap_precious(struct regmap *map, unsigned int reg){ if (!regmap_readable(map, reg)) return false; if (map->precious_reg) return map->precious_reg(map->dev, reg); 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_2_6_write(struct regmap *map, unsigned int reg, unsigned int val){ u8 *out = map->work_buf; *out = (reg << 6) | val;} static void regmap_format_4_12_write(struct regmap *map, unsigned int reg, unsigned int val){ __be16 *out = map->work_buf; *out = cpu_to_be16((reg << 12) | val);} static void regmap_format_7_9_write(struct regmap *map, unsigned int reg, unsigned int val){ __be16 *out = map->work_buf; *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, unsigned int shift){ u8 *b = buf; b[0] = val << shift;} static void regmap_format_16(void *buf, unsigned int val, unsigned int shift){ __be16 *b = buf; b[0] = cpu_to_be16(val << shift);} static void regmap_format_24(void *buf, unsigned int val, unsigned int shift){ u8 *b = buf; val <<= shift; b[0] = val >> 16; b[1] = val >> 8; b[2] = val;} static void regmap_format_32(void *buf, unsigned int val, unsigned int shift){ __be32 *b = buf; b[0] = cpu_to_be32(val << shift);} static unsigned int regmap_parse_8(void *buf){ u8 *b = buf; return b[0];} static unsigned int regmap_parse_16(void *buf){ __be16 *b = buf; b[0] = be16_to_cpu(b[0]); return b[0];} static unsigned int regmap_parse_24(void *buf){ u8 *b = buf; unsigned int ret = b[2]; ret |= ((unsigned int)b[1]) << 8; ret |= ((unsigned int)b[0]) << 16; return ret;} static unsigned int regmap_parse_32(void *buf){ __be32 *b = buf; b[0] = be32_to_cpu(b[0]); return b[0];} static void regmap_lock_mutex(struct regmap *map){ mutex_lock(&map->mutex);} static void regmap_unlock_mutex(struct regmap *map){ mutex_unlock(&map->mutex);} static void regmap_lock_spinlock(struct regmap *map){ spin_lock(&map->spinlock);} static void regmap_unlock_spinlock(struct regmap *map){ spin_unlock(&map->spinlock);} static void dev_get_regmap_release(struct device *dev, void *res){ /* * We don't actually have anything to do here; the goal here * is not to manage the regmap but to provide a simple way to * get the regmap back given a struct device. */} /** * regmap_init(): Initialise register map * * @dev: Device that will be interacted with * @bus: Bus-specific callbacks to use with device * @bus_context: Data passed to bus-specific callbacks * @config: Configuration for register map * * The return value will be an ERR_PTR() on error or a valid pointer to * a struct regmap. This function should generally not be called * directly, it should be called by bus-specific init functions. */struct regmap *regmap_init(struct device *dev, const struct regmap_bus *bus, void *bus_context, const struct regmap_config *config){ struct regmap *map, **m; int ret = -EINVAL; if (!bus || !config) goto err; map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) { ret = -ENOMEM; goto err; } if (bus->fast_io) { spin_lock_init(&map->spinlock); map->lock = regmap_lock_spinlock; map->unlock = regmap_unlock_spinlock; } else { mutex_init(&map->mutex); map->lock = regmap_lock_mutex; map->unlock = regmap_unlock_mutex; } map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); map->format.pad_bytes = config->pad_bits / 8; map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); map->format.buf_size = DIV_ROUND_UP(config->reg_bits + config->val_bits + config->pad_bits, 8); map->reg_shift = config->pad_bits % 8; if (config->reg_stride) map->reg_stride = config->reg_stride; else map->reg_stride = 1; map->use_single_rw = config->use_single_rw; map->dev = dev; map->bus = bus; map->bus_context = bus_context; 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; map->name = config->name; if (config->read_flag_mask || config->write_flag_mask) { map->read_flag_mask = config->read_flag_mask; map->write_flag_mask = config->write_flag_mask; } else { map->read_flag_mask = bus->read_flag_mask; } switch (config->reg_bits + map->reg_shift) { case 2: switch (config->val_bits) { case 6: map->format.format_write = regmap_format_2_6_write; break; default: goto err_map; } break; case 4: switch (config->val_bits) { case 12: map->format.format_write = regmap_format_4_12_write; break; default: goto err_map; } break; case 7: switch (config->val_bits) { case 9: map->format.format_write = regmap_format_7_9_write; break; default: goto err_map; } 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; case 16: map->format.format_reg = regmap_format_16; break; case 32: map->format.format_reg = regmap_format_32; break; default: goto err_map; } switch (config->val_bits) { case 8: map->format.format_val = regmap_format_8; map->format.parse_val = regmap_parse_8; break; case 16: map->format.format_val = regmap_format_16; map->format.parse_val = regmap_parse_16; break; case 24: map->format.format_val = regmap_format_24; map->format.parse_val = regmap_parse_24; break; case 32: map->format.format_val = regmap_format_32; map->format.parse_val = regmap_parse_32; break; } if (map->format.format_write) map->use_single_rw = true; if (!map->format.format_write && !(map->format.format_reg && map->format.format_val)) goto err_map; map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL); if (map->work_buf == NULL) { ret = -ENOMEM; goto err_map; } regmap_debugfs_init(map, config->name); ret = regcache_init(map, config); if (ret < 0) goto err_debugfs; /* Add a devres resource for dev_get_regmap() */ m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL); if (!m) { ret = -ENOMEM; goto err_cache; } *m = map; devres_add(dev, m); return map; err_cache: regcache_exit(map);err_debugfs: regmap_debugfs_exit(map); kfree(map->work_buf);err_map: kfree(map);err: return ERR_PTR(ret);}EXPORT_SYMBOL_GPL(regmap_init); static void devm_regmap_release(struct device *dev, void *res){ regmap_exit(*(struct regmap **)res);} /** * devm_regmap_init(): Initialise managed register map * * @dev: Device that will be interacted with * @bus: Bus-specific callbacks to use with device * @bus_context: Data passed to bus-specific callbacks * @config: Configuration for register map * * The return value will be an ERR_PTR() on error or a valid pointer * to a struct regmap. This function should generally not be called * directly, it should be called by bus-specific init functions. The * map will be automatically freed by the device management code. */struct regmap *devm_regmap_init(struct device *dev, const struct regmap_bus *bus, void *bus_context, const struct regmap_config *config){ struct regmap **ptr, *regmap; ptr = devres_alloc(devm_regmap_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); regmap = regmap_init(dev, bus, bus_context, config); if (!IS_ERR(regmap)) { *ptr = regmap; devres_add(dev, ptr); } else { devres_free(ptr); } return regmap;}EXPORT_SYMBOL_GPL(devm_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; map->lock(map); regcache_exit(map); regmap_debugfs_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; regmap_debugfs_init(map, config->name); map->cache_bypass = false; map->cache_only = false; ret = regcache_init(map, config); map->unlock(map); return ret;}EXPORT_SYMBOL_GPL(regmap_reinit_cache); /** * regmap_exit(): Free a previously allocated register map */void regmap_exit(struct regmap *map){ regcache_exit(map); regmap_debugfs_exit(map); if (map->bus->free_context) map->bus->free_context(map->bus_context); kfree(map->work_buf); kfree(map);}EXPORT_SYMBOL_GPL(regmap_exit); static int dev_get_regmap_match(struct device *dev, void *res, void *data){ struct regmap **r = res; if (!r || !*r) { WARN_ON(!r || !*r); return 0; } /* If the user didn't specify a name match any */ if (data)Lines 1–500 of 1124. Load more
/* * Register map access API * * Copyright 2011 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/device.h> #include <linux/slab.h> #include <linux/export.h> #include <linux/mutex.h> #include <linux/err.h> #define CREATE_TRACE_POINTS #include <trace/events/regmap.h> #include "internal.h" bool regmap_writeable(struct regmap *map, unsigned int reg) { if (map->max_register && reg > map->max_register) return false; if (map->writeable_reg) return map->writeable_reg(map->dev, reg); return true; } bool regmap_readable(struct regmap *map, unsigned int reg) { if (map->max_register && reg > map->max_register) return false; if (map->format.format_write) return false; if (map->readable_reg) return map->readable_reg(map->dev, reg); return true; } bool regmap_volatile(struct regmap *map, unsigned int reg) { if (!regmap_readable(map, reg)) return false; if (map->volatile_reg) return map->volatile_reg(map->dev, reg); return true; } bool regmap_precious(struct regmap *map, unsigned int reg) { if (!regmap_readable(map, reg)) return false; if (map->precious_reg) return map->precious_reg(map->dev, reg); 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_2_6_write(struct regmap *map, unsigned int reg, unsigned int val) { u8 *out = map->work_buf; *out = (reg << 6) | val; } static void regmap_format_4_12_write(struct regmap *map, unsigned int reg, unsigned int val) { __be16 *out = map->work_buf; *out = cpu_to_be16((reg << 12) | val); } static void regmap_format_7_9_write(struct regmap *map, unsigned int reg, unsigned int val) { __be16 *out = map->work_buf; *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, unsigned int shift) { u8 *b = buf; b[0] = val << shift; } static void regmap_format_16(void *buf, unsigned int val, unsigned int shift) { __be16 *b = buf; b[0] = cpu_to_be16(val << shift); } static void regmap_format_24(void *buf, unsigned int val, unsigned int shift) { u8 *b = buf; val <<= shift; b[0] = val >> 16; b[1] = val >> 8; b[2] = val; } static void regmap_format_32(void *buf, unsigned int val, unsigned int shift) { __be32 *b = buf; b[0] = cpu_to_be32(val << shift); } static unsigned int regmap_parse_8(void *buf) { u8 *b = buf; return b[0]; } static unsigned int regmap_parse_16(void *buf) { __be16 *b = buf; b[0] = be16_to_cpu(b[0]); return b[0]; } static unsigned int regmap_parse_24(void *buf) { u8 *b = buf; unsigned int ret = b[2]; ret |= ((unsigned int)b[1]) << 8; ret |= ((unsigned int)b[0]) << 16; return ret; } static unsigned int regmap_parse_32(void *buf) { __be32 *b = buf; b[0] = be32_to_cpu(b[0]); return b[0]; } static void regmap_lock_mutex(struct regmap *map) { mutex_lock(&map->mutex); } static void regmap_unlock_mutex(struct regmap *map) { mutex_unlock(&map->mutex); } static void regmap_lock_spinlock(struct regmap *map) { spin_lock(&map->spinlock); } static void regmap_unlock_spinlock(struct regmap *map) { spin_unlock(&map->spinlock); } static void dev_get_regmap_release(struct device *dev, void *res) { /* * We don't actually have anything to do here; the goal here * is not to manage the regmap but to provide a simple way to * get the regmap back given a struct device. */ } /** * regmap_init(): Initialise register map * * @dev: Device that will be interacted with * @bus: Bus-specific callbacks to use with device * @bus_context: Data passed to bus-specific callbacks * @config: Configuration for register map * * The return value will be an ERR_PTR() on error or a valid pointer to * a struct regmap. This function should generally not be called * directly, it should be called by bus-specific init functions. */ struct regmap *regmap_init(struct device *dev, const struct regmap_bus *bus, void *bus_context, const struct regmap_config *config) { struct regmap *map, **m; int ret = -EINVAL; if (!bus || !config) goto err; map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) { ret = -ENOMEM; goto err; } if (bus->fast_io) { spin_lock_init(&map->spinlock); map->lock = regmap_lock_spinlock; map->unlock = regmap_unlock_spinlock; } else { mutex_init(&map->mutex); map->lock = regmap_lock_mutex; map->unlock = regmap_unlock_mutex; } map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); map->format.pad_bytes = config->pad_bits / 8; map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); map->format.buf_size = DIV_ROUND_UP(config->reg_bits + config->val_bits + config->pad_bits, 8); map->reg_shift = config->pad_bits % 8; if (config->reg_stride) map->reg_stride = config->reg_stride; else map->reg_stride = 1; map->use_single_rw = config->use_single_rw; map->dev = dev; map->bus = bus; map->bus_context = bus_context; 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; map->name = config->name; if (config->read_flag_mask || config->write_flag_mask) { map->read_flag_mask = config->read_flag_mask; map->write_flag_mask = config->write_flag_mask; } else { map->read_flag_mask = bus->read_flag_mask; } switch (config->reg_bits + map->reg_shift) { case 2: switch (config->val_bits) { case 6: map->format.format_write = regmap_format_2_6_write; break; default: goto err_map; } break; case 4: switch (config->val_bits) { case 12: map->format.format_write = regmap_format_4_12_write; break; default: goto err_map; } break; case 7: switch (config->val_bits) { case 9: map->format.format_write = regmap_format_7_9_write; break; default: goto err_map; } 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; case 16: map->format.format_reg = regmap_format_16; break; case 32: map->format.format_reg = regmap_format_32; break; default: goto err_map; } switch (config->val_bits) { case 8: map->format.format_val = regmap_format_8; map->format.parse_val = regmap_parse_8; break; case 16: map->format.format_val = regmap_format_16; map->format.parse_val = regmap_parse_16; break; case 24: map->format.format_val = regmap_format_24; map->format.parse_val = regmap_parse_24; break; case 32: map->format.format_val = regmap_format_32; map->format.parse_val = regmap_parse_32; break; } if (map->format.format_write) map->use_single_rw = true; if (!map->format.format_write && !(map->format.format_reg && map->format.format_val)) goto err_map; map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL); if (map->work_buf == NULL) { ret = -ENOMEM; goto err_map; } regmap_debugfs_init(map, config->name); ret = regcache_init(map, config); if (ret < 0) goto err_debugfs; /* Add a devres resource for dev_get_regmap() */ m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL); if (!m) { ret = -ENOMEM; goto err_cache; } *m = map; devres_add(dev, m); return map; err_cache: regcache_exit(map); err_debugfs: regmap_debugfs_exit(map); kfree(map->work_buf); err_map: kfree(map); err: return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(regmap_init); static void devm_regmap_release(struct device *dev, void *res) { regmap_exit(*(struct regmap **)res); } /** * devm_regmap_init(): Initialise managed register map * * @dev: Device that will be interacted with * @bus: Bus-specific callbacks to use with device * @bus_context: Data passed to bus-specific callbacks * @config: Configuration for register map * * The return value will be an ERR_PTR() on error or a valid pointer * to a struct regmap. This function should generally not be called * directly, it should be called by bus-specific init functions. The * map will be automatically freed by the device management code. */ struct regmap *devm_regmap_init(struct device *dev, const struct regmap_bus *bus, void *bus_context, const struct regmap_config *config) { struct regmap **ptr, *regmap; ptr = devres_alloc(devm_regmap_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); regmap = regmap_init(dev, bus, bus_context, config); if (!IS_ERR(regmap)) { *ptr = regmap; devres_add(dev, ptr); } else { devres_free(ptr); } return regmap; } EXPORT_SYMBOL_GPL(devm_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; map->lock(map); regcache_exit(map); regmap_debugfs_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; regmap_debugfs_init(map, config->name); map->cache_bypass = false; map->cache_only = false; ret = regcache_init(map, config); map->unlock(map); return ret; } EXPORT_SYMBOL_GPL(regmap_reinit_cache); /** * regmap_exit(): Free a previously allocated register map */ void regmap_exit(struct regmap *map) { regcache_exit(map); regmap_debugfs_exit(map); if (map->bus->free_context) map->bus->free_context(map->bus_context); kfree(map->work_buf); kfree(map); } EXPORT_SYMBOL_GPL(regmap_exit); static int dev_get_regmap_match(struct device *dev, void *res, void *data) { struct regmap **r = res; if (!r || !*r) { WARN_ON(!r || !*r); return 0; } /* If the user didn't specify a name match any */ if (data)