diff options
Diffstat (limited to 'sound/soc/soc-cache.c')
-rw-r--r-- | sound/soc/soc-cache.c | 386 |
1 files changed, 188 insertions, 198 deletions
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 8c2a21a978ac..5d76da43b14c 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/bitmap.h> | 18 | #include <linux/bitmap.h> |
19 | #include <linux/rbtree.h> | 19 | #include <linux/rbtree.h> |
20 | 20 | ||
21 | #include <trace/events/asoc.h> | ||
22 | |||
21 | static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, | 23 | static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, |
22 | unsigned int reg) | 24 | unsigned int reg) |
23 | { | 25 | { |
@@ -25,7 +27,8 @@ static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, | |||
25 | unsigned int val; | 27 | unsigned int val; |
26 | 28 | ||
27 | if (reg >= codec->driver->reg_cache_size || | 29 | if (reg >= codec->driver->reg_cache_size || |
28 | snd_soc_codec_volatile_register(codec, reg)) { | 30 | snd_soc_codec_volatile_register(codec, reg) || |
31 | codec->cache_bypass) { | ||
29 | if (codec->cache_only) | 32 | if (codec->cache_only) |
30 | return -1; | 33 | return -1; |
31 | 34 | ||
@@ -49,7 +52,8 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, | |||
49 | data[1] = value & 0x00ff; | 52 | data[1] = value & 0x00ff; |
50 | 53 | ||
51 | if (!snd_soc_codec_volatile_register(codec, reg) && | 54 | if (!snd_soc_codec_volatile_register(codec, reg) && |
52 | reg < codec->driver->reg_cache_size) { | 55 | reg < codec->driver->reg_cache_size && |
56 | !codec->cache_bypass) { | ||
53 | ret = snd_soc_cache_write(codec, reg, value); | 57 | ret = snd_soc_cache_write(codec, reg, value); |
54 | if (ret < 0) | 58 | if (ret < 0) |
55 | return -1; | 59 | return -1; |
@@ -106,7 +110,8 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, | |||
106 | unsigned int val; | 110 | unsigned int val; |
107 | 111 | ||
108 | if (reg >= codec->driver->reg_cache_size || | 112 | if (reg >= codec->driver->reg_cache_size || |
109 | snd_soc_codec_volatile_register(codec, reg)) { | 113 | snd_soc_codec_volatile_register(codec, reg) || |
114 | codec->cache_bypass) { | ||
110 | if (codec->cache_only) | 115 | if (codec->cache_only) |
111 | return -1; | 116 | return -1; |
112 | 117 | ||
@@ -130,7 +135,8 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, | |||
130 | data[1] = value & 0x00ff; | 135 | data[1] = value & 0x00ff; |
131 | 136 | ||
132 | if (!snd_soc_codec_volatile_register(codec, reg) && | 137 | if (!snd_soc_codec_volatile_register(codec, reg) && |
133 | reg < codec->driver->reg_cache_size) { | 138 | reg < codec->driver->reg_cache_size && |
139 | !codec->cache_bypass) { | ||
134 | ret = snd_soc_cache_write(codec, reg, value); | 140 | ret = snd_soc_cache_write(codec, reg, value); |
135 | if (ret < 0) | 141 | if (ret < 0) |
136 | return -1; | 142 | return -1; |
@@ -191,7 +197,8 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, | |||
191 | data[1] = value & 0xff; | 197 | data[1] = value & 0xff; |
192 | 198 | ||
193 | if (!snd_soc_codec_volatile_register(codec, reg) && | 199 | if (!snd_soc_codec_volatile_register(codec, reg) && |
194 | reg < codec->driver->reg_cache_size) { | 200 | reg < codec->driver->reg_cache_size && |
201 | !codec->cache_bypass) { | ||
195 | ret = snd_soc_cache_write(codec, reg, value); | 202 | ret = snd_soc_cache_write(codec, reg, value); |
196 | if (ret < 0) | 203 | if (ret < 0) |
197 | return -1; | 204 | return -1; |
@@ -216,7 +223,8 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, | |||
216 | 223 | ||
217 | reg &= 0xff; | 224 | reg &= 0xff; |
218 | if (reg >= codec->driver->reg_cache_size || | 225 | if (reg >= codec->driver->reg_cache_size || |
219 | snd_soc_codec_volatile_register(codec, reg)) { | 226 | snd_soc_codec_volatile_register(codec, reg) || |
227 | codec->cache_bypass) { | ||
220 | if (codec->cache_only) | 228 | if (codec->cache_only) |
221 | return -1; | 229 | return -1; |
222 | 230 | ||
@@ -271,7 +279,8 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, | |||
271 | data[2] = value & 0xff; | 279 | data[2] = value & 0xff; |
272 | 280 | ||
273 | if (!snd_soc_codec_volatile_register(codec, reg) && | 281 | if (!snd_soc_codec_volatile_register(codec, reg) && |
274 | reg < codec->driver->reg_cache_size) { | 282 | reg < codec->driver->reg_cache_size && |
283 | !codec->cache_bypass) { | ||
275 | ret = snd_soc_cache_write(codec, reg, value); | 284 | ret = snd_soc_cache_write(codec, reg, value); |
276 | if (ret < 0) | 285 | if (ret < 0) |
277 | return -1; | 286 | return -1; |
@@ -295,7 +304,8 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, | |||
295 | unsigned int val; | 304 | unsigned int val; |
296 | 305 | ||
297 | if (reg >= codec->driver->reg_cache_size || | 306 | if (reg >= codec->driver->reg_cache_size || |
298 | snd_soc_codec_volatile_register(codec, reg)) { | 307 | snd_soc_codec_volatile_register(codec, reg) || |
308 | codec->cache_bypass) { | ||
299 | if (codec->cache_only) | 309 | if (codec->cache_only) |
300 | return -1; | 310 | return -1; |
301 | 311 | ||
@@ -450,7 +460,8 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, | |||
450 | 460 | ||
451 | reg &= 0xff; | 461 | reg &= 0xff; |
452 | if (reg >= codec->driver->reg_cache_size || | 462 | if (reg >= codec->driver->reg_cache_size || |
453 | snd_soc_codec_volatile_register(codec, reg)) { | 463 | snd_soc_codec_volatile_register(codec, reg) || |
464 | codec->cache_bypass) { | ||
454 | if (codec->cache_only) | 465 | if (codec->cache_only) |
455 | return -1; | 466 | return -1; |
456 | 467 | ||
@@ -476,7 +487,8 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, | |||
476 | 487 | ||
477 | reg &= 0xff; | 488 | reg &= 0xff; |
478 | if (!snd_soc_codec_volatile_register(codec, reg) && | 489 | if (!snd_soc_codec_volatile_register(codec, reg) && |
479 | reg < codec->driver->reg_cache_size) { | 490 | reg < codec->driver->reg_cache_size && |
491 | !codec->cache_bypass) { | ||
480 | ret = snd_soc_cache_write(codec, reg, value); | 492 | ret = snd_soc_cache_write(codec, reg, value); |
481 | if (ret < 0) | 493 | if (ret < 0) |
482 | return -1; | 494 | return -1; |
@@ -568,7 +580,8 @@ static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, | |||
568 | unsigned int val; | 580 | unsigned int val; |
569 | 581 | ||
570 | if (reg >= codec->driver->reg_cache_size || | 582 | if (reg >= codec->driver->reg_cache_size || |
571 | snd_soc_codec_volatile_register(codec, reg)) { | 583 | snd_soc_codec_volatile_register(codec, reg) || |
584 | codec->cache_bypass) { | ||
572 | if (codec->cache_only) | 585 | if (codec->cache_only) |
573 | return -1; | 586 | return -1; |
574 | 587 | ||
@@ -595,7 +608,8 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, | |||
595 | data[3] = value & 0xff; | 608 | data[3] = value & 0xff; |
596 | 609 | ||
597 | if (!snd_soc_codec_volatile_register(codec, reg) && | 610 | if (!snd_soc_codec_volatile_register(codec, reg) && |
598 | reg < codec->driver->reg_cache_size) { | 611 | reg < codec->driver->reg_cache_size && |
612 | !codec->cache_bypass) { | ||
599 | ret = snd_soc_cache_write(codec, reg, value); | 613 | ret = snd_soc_cache_write(codec, reg, value); |
600 | if (ret < 0) | 614 | if (ret < 0) |
601 | return -1; | 615 | return -1; |
@@ -761,6 +775,49 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, | |||
761 | } | 775 | } |
762 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); | 776 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); |
763 | 777 | ||
778 | static bool snd_soc_set_cache_val(void *base, unsigned int idx, | ||
779 | unsigned int val, unsigned int word_size) | ||
780 | { | ||
781 | switch (word_size) { | ||
782 | case 1: { | ||
783 | u8 *cache = base; | ||
784 | if (cache[idx] == val) | ||
785 | return true; | ||
786 | cache[idx] = val; | ||
787 | break; | ||
788 | } | ||
789 | case 2: { | ||
790 | u16 *cache = base; | ||
791 | if (cache[idx] == val) | ||
792 | return true; | ||
793 | cache[idx] = val; | ||
794 | break; | ||
795 | } | ||
796 | default: | ||
797 | BUG(); | ||
798 | } | ||
799 | return false; | ||
800 | } | ||
801 | |||
802 | static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, | ||
803 | unsigned int word_size) | ||
804 | { | ||
805 | switch (word_size) { | ||
806 | case 1: { | ||
807 | const u8 *cache = base; | ||
808 | return cache[idx]; | ||
809 | } | ||
810 | case 2: { | ||
811 | const u16 *cache = base; | ||
812 | return cache[idx]; | ||
813 | } | ||
814 | default: | ||
815 | BUG(); | ||
816 | } | ||
817 | /* unreachable */ | ||
818 | return -1; | ||
819 | } | ||
820 | |||
764 | struct snd_soc_rbtree_node { | 821 | struct snd_soc_rbtree_node { |
765 | struct rb_node node; | 822 | struct rb_node node; |
766 | unsigned int reg; | 823 | unsigned int reg; |
@@ -835,7 +892,9 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec) | |||
835 | ret = snd_soc_cache_read(codec, rbnode->reg, &val); | 892 | ret = snd_soc_cache_read(codec, rbnode->reg, &val); |
836 | if (ret) | 893 | if (ret) |
837 | return ret; | 894 | return ret; |
895 | codec->cache_bypass = 1; | ||
838 | ret = snd_soc_write(codec, rbnode->reg, val); | 896 | ret = snd_soc_write(codec, rbnode->reg, val); |
897 | codec->cache_bypass = 0; | ||
839 | if (ret) | 898 | if (ret) |
840 | return ret; | 899 | return ret; |
841 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", | 900 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", |
@@ -924,7 +983,12 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec) | |||
924 | 983 | ||
925 | static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) | 984 | static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) |
926 | { | 985 | { |
986 | struct snd_soc_rbtree_node *rbtree_node; | ||
927 | struct snd_soc_rbtree_ctx *rbtree_ctx; | 987 | struct snd_soc_rbtree_ctx *rbtree_ctx; |
988 | unsigned int val; | ||
989 | unsigned int word_size; | ||
990 | int i; | ||
991 | int ret; | ||
928 | 992 | ||
929 | codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL); | 993 | codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL); |
930 | if (!codec->reg_cache) | 994 | if (!codec->reg_cache) |
@@ -936,53 +1000,25 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) | |||
936 | if (!codec->reg_def_copy) | 1000 | if (!codec->reg_def_copy) |
937 | return 0; | 1001 | return 0; |
938 | 1002 | ||
939 | /* | 1003 | /* |
940 | * populate the rbtree with the initialized registers. All other | 1004 | * populate the rbtree with the initialized registers. All other |
941 | * registers will be inserted into the tree when they are first written. | 1005 | * registers will be inserted when they are first modified. |
942 | * | 1006 | */ |
943 | * The reasoning behind this, is that we need to step through and | 1007 | word_size = codec->driver->reg_word_size; |
944 | * dereference the cache in u8/u16 increments without sacrificing | 1008 | for (i = 0; i < codec->driver->reg_cache_size; ++i) { |
945 | * portability. This could also be done using memcpy() but that would | 1009 | val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size); |
946 | * be slightly more cryptic. | 1010 | if (!val) |
947 | */ | 1011 | continue; |
948 | #define snd_soc_rbtree_populate(cache) \ | 1012 | rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); |
949 | ({ \ | 1013 | if (!rbtree_node) { |
950 | int ret, i; \ | 1014 | ret = -ENOMEM; |
951 | struct snd_soc_rbtree_node *rbtree_node; \ | 1015 | snd_soc_cache_exit(codec); |
952 | \ | 1016 | break; |
953 | ret = 0; \ | 1017 | } |
954 | cache = codec->reg_def_copy; \ | 1018 | rbtree_node->reg = i; |
955 | for (i = 0; i < codec->driver->reg_cache_size; ++i) { \ | 1019 | rbtree_node->value = val; |
956 | if (!cache[i]) \ | 1020 | rbtree_node->defval = val; |
957 | continue; \ | 1021 | snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node); |
958 | rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); \ | ||
959 | if (!rbtree_node) { \ | ||
960 | ret = -ENOMEM; \ | ||
961 | snd_soc_cache_exit(codec); \ | ||
962 | break; \ | ||
963 | } \ | ||
964 | rbtree_node->reg = i; \ | ||
965 | rbtree_node->value = cache[i]; \ | ||
966 | rbtree_node->defval = cache[i]; \ | ||
967 | snd_soc_rbtree_insert(&rbtree_ctx->root, \ | ||
968 | rbtree_node); \ | ||
969 | } \ | ||
970 | ret; \ | ||
971 | }) | ||
972 | |||
973 | switch (codec->driver->reg_word_size) { | ||
974 | case 1: { | ||
975 | const u8 *cache; | ||
976 | |||
977 | return snd_soc_rbtree_populate(cache); | ||
978 | } | ||
979 | case 2: { | ||
980 | const u16 *cache; | ||
981 | |||
982 | return snd_soc_rbtree_populate(cache); | ||
983 | } | ||
984 | default: | ||
985 | BUG(); | ||
986 | } | 1022 | } |
987 | 1023 | ||
988 | return 0; | 1024 | return 0; |
@@ -1080,34 +1116,28 @@ static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec, | |||
1080 | unsigned int reg) | 1116 | unsigned int reg) |
1081 | { | 1117 | { |
1082 | const struct snd_soc_codec_driver *codec_drv; | 1118 | const struct snd_soc_codec_driver *codec_drv; |
1083 | size_t reg_size; | ||
1084 | 1119 | ||
1085 | codec_drv = codec->driver; | 1120 | codec_drv = codec->driver; |
1086 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | ||
1087 | return (reg * codec_drv->reg_word_size) / | 1121 | return (reg * codec_drv->reg_word_size) / |
1088 | DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count()); | 1122 | DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()); |
1089 | } | 1123 | } |
1090 | 1124 | ||
1091 | static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec, | 1125 | static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec, |
1092 | unsigned int reg) | 1126 | unsigned int reg) |
1093 | { | 1127 | { |
1094 | const struct snd_soc_codec_driver *codec_drv; | 1128 | const struct snd_soc_codec_driver *codec_drv; |
1095 | size_t reg_size; | ||
1096 | 1129 | ||
1097 | codec_drv = codec->driver; | 1130 | codec_drv = codec->driver; |
1098 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | 1131 | return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) / |
1099 | return reg % (DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count()) / | ||
1100 | codec_drv->reg_word_size); | 1132 | codec_drv->reg_word_size); |
1101 | } | 1133 | } |
1102 | 1134 | ||
1103 | static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec) | 1135 | static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec) |
1104 | { | 1136 | { |
1105 | const struct snd_soc_codec_driver *codec_drv; | 1137 | const struct snd_soc_codec_driver *codec_drv; |
1106 | size_t reg_size; | ||
1107 | 1138 | ||
1108 | codec_drv = codec->driver; | 1139 | codec_drv = codec->driver; |
1109 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | 1140 | return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()); |
1110 | return DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count()); | ||
1111 | } | 1141 | } |
1112 | 1142 | ||
1113 | static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) | 1143 | static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) |
@@ -1122,7 +1152,9 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) | |||
1122 | ret = snd_soc_cache_read(codec, i, &val); | 1152 | ret = snd_soc_cache_read(codec, i, &val); |
1123 | if (ret) | 1153 | if (ret) |
1124 | return ret; | 1154 | return ret; |
1155 | codec->cache_bypass = 1; | ||
1125 | ret = snd_soc_write(codec, i, val); | 1156 | ret = snd_soc_write(codec, i, val); |
1157 | codec->cache_bypass = 0; | ||
1126 | if (ret) | 1158 | if (ret) |
1127 | return ret; | 1159 | return ret; |
1128 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", | 1160 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", |
@@ -1165,29 +1197,10 @@ static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec, | |||
1165 | } | 1197 | } |
1166 | 1198 | ||
1167 | /* write the new value to the cache */ | 1199 | /* write the new value to the cache */ |
1168 | switch (codec->driver->reg_word_size) { | 1200 | if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value, |
1169 | case 1: { | 1201 | codec->driver->reg_word_size)) { |
1170 | u8 *cache; | 1202 | kfree(lzo_block->dst); |
1171 | cache = lzo_block->dst; | 1203 | goto out; |
1172 | if (cache[blkpos] == value) { | ||
1173 | kfree(lzo_block->dst); | ||
1174 | goto out; | ||
1175 | } | ||
1176 | cache[blkpos] = value; | ||
1177 | } | ||
1178 | break; | ||
1179 | case 2: { | ||
1180 | u16 *cache; | ||
1181 | cache = lzo_block->dst; | ||
1182 | if (cache[blkpos] == value) { | ||
1183 | kfree(lzo_block->dst); | ||
1184 | goto out; | ||
1185 | } | ||
1186 | cache[blkpos] = value; | ||
1187 | } | ||
1188 | break; | ||
1189 | default: | ||
1190 | BUG(); | ||
1191 | } | 1204 | } |
1192 | 1205 | ||
1193 | /* prepare the source to be the decompressed block */ | 1206 | /* prepare the source to be the decompressed block */ |
@@ -1241,25 +1254,10 @@ static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec, | |||
1241 | 1254 | ||
1242 | /* decompress the block */ | 1255 | /* decompress the block */ |
1243 | ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block); | 1256 | ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block); |
1244 | if (ret >= 0) { | 1257 | if (ret >= 0) |
1245 | /* fetch the value from the cache */ | 1258 | /* fetch the value from the cache */ |
1246 | switch (codec->driver->reg_word_size) { | 1259 | *value = snd_soc_get_cache_val(lzo_block->dst, blkpos, |
1247 | case 1: { | 1260 | codec->driver->reg_word_size); |
1248 | u8 *cache; | ||
1249 | cache = lzo_block->dst; | ||
1250 | *value = cache[blkpos]; | ||
1251 | } | ||
1252 | break; | ||
1253 | case 2: { | ||
1254 | u16 *cache; | ||
1255 | cache = lzo_block->dst; | ||
1256 | *value = cache[blkpos]; | ||
1257 | } | ||
1258 | break; | ||
1259 | default: | ||
1260 | BUG(); | ||
1261 | } | ||
1262 | } | ||
1263 | 1261 | ||
1264 | kfree(lzo_block->dst); | 1262 | kfree(lzo_block->dst); |
1265 | /* restore the pointer and length of the compressed block */ | 1263 | /* restore the pointer and length of the compressed block */ |
@@ -1301,7 +1299,7 @@ static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec) | |||
1301 | static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) | 1299 | static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) |
1302 | { | 1300 | { |
1303 | struct snd_soc_lzo_ctx **lzo_blocks; | 1301 | struct snd_soc_lzo_ctx **lzo_blocks; |
1304 | size_t reg_size, bmp_size; | 1302 | size_t bmp_size; |
1305 | const struct snd_soc_codec_driver *codec_drv; | 1303 | const struct snd_soc_codec_driver *codec_drv; |
1306 | int ret, tofree, i, blksize, blkcount; | 1304 | int ret, tofree, i, blksize, blkcount; |
1307 | const char *p, *end; | 1305 | const char *p, *end; |
@@ -1309,7 +1307,6 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) | |||
1309 | 1307 | ||
1310 | ret = 0; | 1308 | ret = 0; |
1311 | codec_drv = codec->driver; | 1309 | codec_drv = codec->driver; |
1312 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | ||
1313 | 1310 | ||
1314 | /* | 1311 | /* |
1315 | * If we have not been given a default register cache | 1312 | * If we have not been given a default register cache |
@@ -1321,8 +1318,7 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) | |||
1321 | tofree = 1; | 1318 | tofree = 1; |
1322 | 1319 | ||
1323 | if (!codec->reg_def_copy) { | 1320 | if (!codec->reg_def_copy) { |
1324 | codec->reg_def_copy = kzalloc(reg_size, | 1321 | codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL); |
1325 | GFP_KERNEL); | ||
1326 | if (!codec->reg_def_copy) | 1322 | if (!codec->reg_def_copy) |
1327 | return -ENOMEM; | 1323 | return -ENOMEM; |
1328 | } | 1324 | } |
@@ -1370,7 +1366,7 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) | |||
1370 | 1366 | ||
1371 | blksize = snd_soc_lzo_get_blksize(codec); | 1367 | blksize = snd_soc_lzo_get_blksize(codec); |
1372 | p = codec->reg_def_copy; | 1368 | p = codec->reg_def_copy; |
1373 | end = codec->reg_def_copy + reg_size; | 1369 | end = codec->reg_def_copy + codec->reg_size; |
1374 | /* compress the register map and fill the lzo blocks */ | 1370 | /* compress the register map and fill the lzo blocks */ |
1375 | for (i = 0; i < blkcount; ++i, p += blksize) { | 1371 | for (i = 0; i < blkcount; ++i, p += blksize) { |
1376 | lzo_blocks[i]->src = p; | 1372 | lzo_blocks[i]->src = p; |
@@ -1414,28 +1410,10 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) | |||
1414 | ret = snd_soc_cache_read(codec, i, &val); | 1410 | ret = snd_soc_cache_read(codec, i, &val); |
1415 | if (ret) | 1411 | if (ret) |
1416 | return ret; | 1412 | return ret; |
1417 | if (codec_drv->reg_cache_default) { | 1413 | if (codec->reg_def_copy) |
1418 | switch (codec_drv->reg_word_size) { | 1414 | if (snd_soc_get_cache_val(codec->reg_def_copy, |
1419 | case 1: { | 1415 | i, codec_drv->reg_word_size) == val) |
1420 | const u8 *cache; | 1416 | continue; |
1421 | |||
1422 | cache = codec_drv->reg_cache_default; | ||
1423 | if (cache[i] == val) | ||
1424 | continue; | ||
1425 | } | ||
1426 | break; | ||
1427 | case 2: { | ||
1428 | const u16 *cache; | ||
1429 | |||
1430 | cache = codec_drv->reg_cache_default; | ||
1431 | if (cache[i] == val) | ||
1432 | continue; | ||
1433 | } | ||
1434 | break; | ||
1435 | default: | ||
1436 | BUG(); | ||
1437 | } | ||
1438 | } | ||
1439 | ret = snd_soc_write(codec, i, val); | 1417 | ret = snd_soc_write(codec, i, val); |
1440 | if (ret) | 1418 | if (ret) |
1441 | return ret; | 1419 | return ret; |
@@ -1448,50 +1426,16 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) | |||
1448 | static int snd_soc_flat_cache_write(struct snd_soc_codec *codec, | 1426 | static int snd_soc_flat_cache_write(struct snd_soc_codec *codec, |
1449 | unsigned int reg, unsigned int value) | 1427 | unsigned int reg, unsigned int value) |
1450 | { | 1428 | { |
1451 | switch (codec->driver->reg_word_size) { | 1429 | snd_soc_set_cache_val(codec->reg_cache, reg, value, |
1452 | case 1: { | 1430 | codec->driver->reg_word_size); |
1453 | u8 *cache; | ||
1454 | |||
1455 | cache = codec->reg_cache; | ||
1456 | cache[reg] = value; | ||
1457 | } | ||
1458 | break; | ||
1459 | case 2: { | ||
1460 | u16 *cache; | ||
1461 | |||
1462 | cache = codec->reg_cache; | ||
1463 | cache[reg] = value; | ||
1464 | } | ||
1465 | break; | ||
1466 | default: | ||
1467 | BUG(); | ||
1468 | } | ||
1469 | |||
1470 | return 0; | 1431 | return 0; |
1471 | } | 1432 | } |
1472 | 1433 | ||
1473 | static int snd_soc_flat_cache_read(struct snd_soc_codec *codec, | 1434 | static int snd_soc_flat_cache_read(struct snd_soc_codec *codec, |
1474 | unsigned int reg, unsigned int *value) | 1435 | unsigned int reg, unsigned int *value) |
1475 | { | 1436 | { |
1476 | switch (codec->driver->reg_word_size) { | 1437 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, |
1477 | case 1: { | 1438 | codec->driver->reg_word_size); |
1478 | u8 *cache; | ||
1479 | |||
1480 | cache = codec->reg_cache; | ||
1481 | *value = cache[reg]; | ||
1482 | } | ||
1483 | break; | ||
1484 | case 2: { | ||
1485 | u16 *cache; | ||
1486 | |||
1487 | cache = codec->reg_cache; | ||
1488 | *value = cache[reg]; | ||
1489 | } | ||
1490 | break; | ||
1491 | default: | ||
1492 | BUG(); | ||
1493 | } | ||
1494 | |||
1495 | return 0; | 1439 | return 0; |
1496 | } | 1440 | } |
1497 | 1441 | ||
@@ -1507,24 +1451,14 @@ static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec) | |||
1507 | static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) | 1451 | static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) |
1508 | { | 1452 | { |
1509 | const struct snd_soc_codec_driver *codec_drv; | 1453 | const struct snd_soc_codec_driver *codec_drv; |
1510 | size_t reg_size; | ||
1511 | 1454 | ||
1512 | codec_drv = codec->driver; | 1455 | codec_drv = codec->driver; |
1513 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | ||
1514 | 1456 | ||
1515 | /* | 1457 | if (codec->reg_def_copy) |
1516 | * for flat compression, we don't need to keep a copy of the | 1458 | codec->reg_cache = kmemdup(codec->reg_def_copy, |
1517 | * original defaults register cache as it will definitely not | 1459 | codec->reg_size, GFP_KERNEL); |
1518 | * be marked as __devinitconst | ||
1519 | */ | ||
1520 | kfree(codec->reg_def_copy); | ||
1521 | codec->reg_def_copy = NULL; | ||
1522 | |||
1523 | if (codec_drv->reg_cache_default) | ||
1524 | codec->reg_cache = kmemdup(codec_drv->reg_cache_default, | ||
1525 | reg_size, GFP_KERNEL); | ||
1526 | else | 1460 | else |
1527 | codec->reg_cache = kzalloc(reg_size, GFP_KERNEL); | 1461 | codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL); |
1528 | if (!codec->reg_cache) | 1462 | if (!codec->reg_cache) |
1529 | return -ENOMEM; | 1463 | return -ENOMEM; |
1530 | 1464 | ||
@@ -1669,21 +1603,77 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_write); | |||
1669 | int snd_soc_cache_sync(struct snd_soc_codec *codec) | 1603 | int snd_soc_cache_sync(struct snd_soc_codec *codec) |
1670 | { | 1604 | { |
1671 | int ret; | 1605 | int ret; |
1606 | const char *name; | ||
1672 | 1607 | ||
1673 | if (!codec->cache_sync) { | 1608 | if (!codec->cache_sync) { |
1674 | return 0; | 1609 | return 0; |
1675 | } | 1610 | } |
1676 | 1611 | ||
1677 | if (codec->cache_ops && codec->cache_ops->sync) { | 1612 | if (!codec->cache_ops || !codec->cache_ops->sync) |
1678 | if (codec->cache_ops->name) | 1613 | return -EINVAL; |
1679 | dev_dbg(codec->dev, "Syncing %s cache for %s codec\n", | ||
1680 | codec->cache_ops->name, codec->name); | ||
1681 | ret = codec->cache_ops->sync(codec); | ||
1682 | if (!ret) | ||
1683 | codec->cache_sync = 0; | ||
1684 | return ret; | ||
1685 | } | ||
1686 | 1614 | ||
1687 | return -EINVAL; | 1615 | if (codec->cache_ops->name) |
1616 | name = codec->cache_ops->name; | ||
1617 | else | ||
1618 | name = "unknown"; | ||
1619 | |||
1620 | if (codec->cache_ops->name) | ||
1621 | dev_dbg(codec->dev, "Syncing %s cache for %s codec\n", | ||
1622 | codec->cache_ops->name, codec->name); | ||
1623 | trace_snd_soc_cache_sync(codec, name, "start"); | ||
1624 | ret = codec->cache_ops->sync(codec); | ||
1625 | if (!ret) | ||
1626 | codec->cache_sync = 0; | ||
1627 | trace_snd_soc_cache_sync(codec, name, "end"); | ||
1628 | return ret; | ||
1688 | } | 1629 | } |
1689 | EXPORT_SYMBOL_GPL(snd_soc_cache_sync); | 1630 | EXPORT_SYMBOL_GPL(snd_soc_cache_sync); |
1631 | |||
1632 | static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec, | ||
1633 | unsigned int reg) | ||
1634 | { | ||
1635 | const struct snd_soc_codec_driver *codec_drv; | ||
1636 | unsigned int min, max, index; | ||
1637 | |||
1638 | codec_drv = codec->driver; | ||
1639 | min = 0; | ||
1640 | max = codec_drv->reg_access_size - 1; | ||
1641 | do { | ||
1642 | index = (min + max) / 2; | ||
1643 | if (codec_drv->reg_access_default[index].reg == reg) | ||
1644 | return index; | ||
1645 | if (codec_drv->reg_access_default[index].reg < reg) | ||
1646 | min = index + 1; | ||
1647 | else | ||
1648 | max = index; | ||
1649 | } while (min <= max); | ||
1650 | return -1; | ||
1651 | } | ||
1652 | |||
1653 | int snd_soc_default_volatile_register(struct snd_soc_codec *codec, | ||
1654 | unsigned int reg) | ||
1655 | { | ||
1656 | int index; | ||
1657 | |||
1658 | if (reg >= codec->driver->reg_cache_size) | ||
1659 | return 1; | ||
1660 | index = snd_soc_get_reg_access_index(codec, reg); | ||
1661 | if (index < 0) | ||
1662 | return 0; | ||
1663 | return codec->driver->reg_access_default[index].vol; | ||
1664 | } | ||
1665 | EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register); | ||
1666 | |||
1667 | int snd_soc_default_readable_register(struct snd_soc_codec *codec, | ||
1668 | unsigned int reg) | ||
1669 | { | ||
1670 | int index; | ||
1671 | |||
1672 | if (reg >= codec->driver->reg_cache_size) | ||
1673 | return 1; | ||
1674 | index = snd_soc_get_reg_access_index(codec, reg); | ||
1675 | if (index < 0) | ||
1676 | return 0; | ||
1677 | return codec->driver->reg_access_default[index].read; | ||
1678 | } | ||
1679 | EXPORT_SYMBOL_GPL(snd_soc_default_readable_register); | ||