diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-04-06 18:38:49 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-04-06 18:38:49 +0200 |
commit | 8239a38f5039a28c41065012efa40c8f8d5fa556 (patch) | |
tree | 9c2b60844beabfad9f33610f54a3edf1edcf517e | |
parent | 2fef2d590a80efa3b685ca3e506a582e0d9e478e (diff) | |
download | hda-emu-8239a38f5039a28c41065012efa40c8f8d5fa556.tar.gz |
Add regmap support code
Now we support regmap in the upstream, so follows the hda-emu, too.
The regmap support codes are added without checks in configure.
If you need to build the pre 4.1-rc1 version, use the previous git
checkout.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | include/linux/regmap.h | 56 | ||||
-rw-r--r-- | include/sound/hda_regmap.h | 3 | ||||
-rw-r--r-- | lib/Makefile.am | 3 | ||||
-rw-r--r-- | lib/array.c | 1 | ||||
-rw-r--r-- | lib/hdac_regmap.c | 183 |
5 files changed, 245 insertions, 1 deletions
diff --git a/include/linux/regmap.h b/include/linux/regmap.h new file mode 100644 index 0000000..67551c7 --- /dev/null +++ b/include/linux/regmap.h @@ -0,0 +1,56 @@ +/* stripped version of regmap implementation for hda-emu */ + +#ifndef __LINUX_REGMAP_H +#define __LINUX_REGMAP_H + +#include <linux/err.h> + +enum regcache_type { + REGCACHE_NONE, + REGCACHE_RBTREE, + REGCACHE_COMPRESSED, + REGCACHE_FLAT, +}; + +enum regmap_endian { + /* Unspecified -> 0 -> Backwards compatible default */ + REGMAP_ENDIAN_DEFAULT = 0, + REGMAP_ENDIAN_BIG, + REGMAP_ENDIAN_LITTLE, + REGMAP_ENDIAN_NATIVE, +}; + +struct remgap; +struct regmap_bus; + +struct regmap_config { + const char *name; + int reg_bits; + int val_bits; + bool (*writeable_reg)(struct device *dev, unsigned int reg); + bool (*readable_reg)(struct device *dev, unsigned int reg); + bool (*volatile_reg)(struct device *dev, unsigned int reg); + int (*reg_read)(void *context, unsigned int reg, unsigned int *val); + int (*reg_write)(void *context, unsigned int reg, unsigned int val); + unsigned int max_register; + enum regcache_type cache_type; + bool use_single_rw; +}; + +struct regmap *regmap_init(struct device *dev, + const struct regmap_bus *bus, + void *bus_context, + const struct regmap_config *config); + +void regmap_exit(struct regmap *map); +int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); +int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); + +int regcache_sync(struct regmap *map); +int regcache_sync_region(struct regmap *map, unsigned int min, + unsigned int max); +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); + +#endif /* __LINUX_REGMAP_H */ diff --git a/include/sound/hda_regmap.h b/include/sound/hda_regmap.h new file mode 100644 index 0000000..62668c3 --- /dev/null +++ b/include/sound/hda_regmap.h @@ -0,0 +1,3 @@ +#include <wrapper.h> +#include <sound/core.h> +#include "../../dist/include/sound/hda_regmap.h" diff --git a/lib/Makefile.am b/lib/Makefile.am index 09ebe85..738af69 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,3 +1,4 @@ noinst_LIBRARIES = libhdacore.a -libhdacore_a_SOURCES = hda_bus_type.c hdac_bus.c hdac_device.c hdac_sysfs.c +libhdacore_a_SOURCES = hda_bus_type.c hdac_bus.c hdac_device.c hdac_sysfs.c \ + hdac_regmap.c array.c INCLUDES = -I$(top_srcdir)/include diff --git a/lib/array.c b/lib/array.c new file mode 100644 index 0000000..3c7ca6a --- /dev/null +++ b/lib/array.c @@ -0,0 +1 @@ +#include "../dist/sound/hda/array.c" diff --git a/lib/hdac_regmap.c b/lib/hdac_regmap.c new file mode 100644 index 0000000..b3d71b6 --- /dev/null +++ b/lib/hdac_regmap.c @@ -0,0 +1,183 @@ +#include "../dist/sound/hda/hdac_regmap.c" + +/* + * regmap wrapper implementations + */ + +/* dumb value management by linked list */ +struct regmap_val; + +struct regmap_val { + int reg; + int val; + struct regmap_val *next; +}; + +struct regmap { + struct device *dev; + const struct regmap_bus *bus; + void *bus_context; + const struct regmap_config *config; + bool cache_dirty; + bool cache_only; + bool cache_bypass; + struct regmap_val *val; + struct regmap_val *val_last; +}; + +struct regmap *regmap_init(struct device *dev, + const struct regmap_bus *bus, + void *bus_context, + const struct regmap_config *config) +{ + struct regmap *map; + + map = calloc(1, sizeof(*map)); + if (!map) + exit(1); + map->dev = dev; + map->bus = bus; + map->bus_context = bus_context; + map->config = config; + return map; +} + +void regmap_exit(struct regmap *map) +{ + struct regmap_val *vp, *next; + + for (vp = map->val; vp; vp = next) { + next = vp->next; + free(vp); + } + + free(map); +} + +static struct regmap_val *cache_find_reg(struct regmap *map, unsigned int reg) +{ + struct regmap_val *vp; + + for (vp = map->val; vp; vp = vp->next) { + if (vp->reg == reg) + return vp; + } + return NULL; +} + +static bool cache_read_reg(struct regmap *map, unsigned int reg, unsigned int *val) +{ + struct regmap_val *vp = cache_find_reg(map, reg); + + if (!vp) + return false; + *val = vp->val; + return true; +} + +static void cache_write_reg(struct regmap *map, unsigned int reg, unsigned int val) +{ + struct regmap_val *vp = cache_find_reg(map, reg); + + if (vp) { + vp->val = val; + return; + } + + vp = malloc(sizeof(*vp)); + if (!vp) + exit(1); + vp->reg = reg; + vp->val = val; + vp->next = NULL; + if (!map->val) + map->val = vp; + else + map->val_last->next = vp; + map->val_last = vp; +} + +int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) +{ + int err; + + if (!map->config->writeable_reg(map->dev, reg)) + return -EINVAL; + if (map->cache_only) + err = 0; + else + err = map->config->reg_write(map->bus_context, reg, val); + if (!err && !map->cache_bypass && + !map->config->volatile_reg(map->dev, reg)) + cache_write_reg(map, reg, val); + return err; +} + +int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) +{ + int err; + + if (!map->config->readable_reg(map->dev, reg)) + return -EINVAL; + if (!map->cache_bypass && cache_read_reg(map, reg, val)) + return 0; + err = map->config->reg_read(map->bus_context, reg, val); + if (!err && !map->cache_bypass && + !map->config->volatile_reg(map->dev, reg)) + cache_write_reg(map, reg, *val); + return err; +} + +int regcache_sync(struct regmap *map) +{ + struct regmap_val *vp; + int err; + + if (!map->cache_dirty) + return 0; + for (vp = map->val; vp; vp = vp->next) { + if (!map->config->writeable_reg(map->dev, vp->reg)) + continue; + err = map->config->reg_write(map->bus_context, vp->reg, vp->val); + if (err < 0) + return err; + } + map->cache_dirty = false; + return 0; +} + +int regcache_sync_region(struct regmap *map, unsigned int min, + unsigned int max) +{ + struct regmap_val *vp; + int err; + + if (!map->cache_dirty) + return 0; + for (vp = map->val; vp; vp = vp->next) { + if (vp->reg < min || vp->reg > max) + continue; + if (!map->config->writeable_reg(map->dev, vp->reg)) + continue; + err = map->config->reg_write(map->bus_context, vp->reg, vp->val); + if (err < 0) + return err; + } + return 0; +} + +void regcache_cache_only(struct regmap *map, bool enable) +{ + map->cache_only = enable; +} + +void regcache_cache_bypass(struct regmap *map, bool enable) +{ + map->cache_bypass = enable; +} + +void regcache_mark_dirty(struct regmap *map) +{ + map->cache_dirty = true; +} + |