aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-cache.c
diff options
context:
space:
mode:
authorDimitris Papastamos <dp@opensource.wolfsonmicro.com>2010-11-11 05:04:57 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-11-11 10:58:41 -0500
commit7a30a3db34cc7b2180a1a6c4a51d19d93c8a8b80 (patch)
tree0a5effd9cc63055d49f837ba4751573f2cb70ef7 /sound/soc/soc-cache.c
parent84e909303dbd3c8d882f152c17d1319f2873e147 (diff)
ASoC: soc-cache: Add support for flat register caching
This patch introduces the new caching API and migrates the old caching interface into the new one. The flat register caching technique does not use compression at all and it is equivalent to the old caching technique. One can still access codec->reg_cache directly but this is not advised as that will not be portable across different caching strategies. None of the existing drivers need to be changed to adapt to this caching technique. There should be no noticeable overhead associated with using the new caching API. Signed-off-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/soc-cache.c')
-rw-r--r--sound/soc/soc-cache.c339
1 files changed, 308 insertions, 31 deletions
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index e7479988deca..cbf9694097b2 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -18,7 +18,8 @@
18static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, 18static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
19 unsigned int reg) 19 unsigned int reg)
20{ 20{
21 u16 *cache = codec->reg_cache; 21 int ret;
22 unsigned int val;
22 23
23 if (reg >= codec->driver->reg_cache_size || 24 if (reg >= codec->driver->reg_cache_size ||
24 snd_soc_codec_volatile_register(codec, reg)) { 25 snd_soc_codec_volatile_register(codec, reg)) {
@@ -29,13 +30,15 @@ static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
29 return codec->hw_read(codec, reg); 30 return codec->hw_read(codec, reg);
30 } 31 }
31 32
32 return cache[reg]; 33 ret = snd_soc_cache_read(codec, reg, &val);
34 if (ret < 0)
35 return -1;
36 return val;
33} 37}
34 38
35static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, 39static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
36 unsigned int value) 40 unsigned int value)
37{ 41{
38 u16 *cache = codec->reg_cache;
39 u8 data[2]; 42 u8 data[2];
40 int ret; 43 int ret;
41 44
@@ -43,8 +46,11 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
43 data[1] = value & 0x00ff; 46 data[1] = value & 0x00ff;
44 47
45 if (!snd_soc_codec_volatile_register(codec, reg) && 48 if (!snd_soc_codec_volatile_register(codec, reg) &&
46 reg < codec->driver->reg_cache_size) 49 reg < codec->driver->reg_cache_size) {
47 cache[reg] = value; 50 ret = snd_soc_cache_write(codec, reg, value);
51 if (ret < 0)
52 return -1;
53 }
48 54
49 if (codec->cache_only) { 55 if (codec->cache_only) {
50 codec->cache_sync = 1; 56 codec->cache_sync = 1;
@@ -93,7 +99,8 @@ static int snd_soc_4_12_spi_write(void *control_data, const char *data,
93static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, 99static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
94 unsigned int reg) 100 unsigned int reg)
95{ 101{
96 u16 *cache = codec->reg_cache; 102 int ret;
103 unsigned int val;
97 104
98 if (reg >= codec->driver->reg_cache_size || 105 if (reg >= codec->driver->reg_cache_size ||
99 snd_soc_codec_volatile_register(codec, reg)) { 106 snd_soc_codec_volatile_register(codec, reg)) {
@@ -104,13 +111,15 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
104 return codec->hw_read(codec, reg); 111 return codec->hw_read(codec, reg);
105 } 112 }
106 113
107 return cache[reg]; 114 ret = snd_soc_cache_read(codec, reg, &val);
115 if (ret < 0)
116 return -1;
117 return val;
108} 118}
109 119
110static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, 120static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
111 unsigned int value) 121 unsigned int value)
112{ 122{
113 u16 *cache = codec->reg_cache;
114 u8 data[2]; 123 u8 data[2];
115 int ret; 124 int ret;
116 125
@@ -118,8 +127,11 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
118 data[1] = value & 0x00ff; 127 data[1] = value & 0x00ff;
119 128
120 if (!snd_soc_codec_volatile_register(codec, reg) && 129 if (!snd_soc_codec_volatile_register(codec, reg) &&
121 reg < codec->driver->reg_cache_size) 130 reg < codec->driver->reg_cache_size) {
122 cache[reg] = value; 131 ret = snd_soc_cache_write(codec, reg, value);
132 if (ret < 0)
133 return -1;
134 }
123 135
124 if (codec->cache_only) { 136 if (codec->cache_only) {
125 codec->cache_sync = 1; 137 codec->cache_sync = 1;
@@ -168,16 +180,19 @@ static int snd_soc_7_9_spi_write(void *control_data, const char *data,
168static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, 180static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
169 unsigned int value) 181 unsigned int value)
170{ 182{
171 u8 *cache = codec->reg_cache;
172 u8 data[2]; 183 u8 data[2];
184 int ret;
173 185
174 reg &= 0xff; 186 reg &= 0xff;
175 data[0] = reg; 187 data[0] = reg;
176 data[1] = value & 0xff; 188 data[1] = value & 0xff;
177 189
178 if (!snd_soc_codec_volatile_register(codec, reg) && 190 if (!snd_soc_codec_volatile_register(codec, reg) &&
179 reg < codec->driver->reg_cache_size) 191 reg < codec->driver->reg_cache_size) {
180 cache[reg] = value; 192 ret = snd_soc_cache_write(codec, reg, value);
193 if (ret < 0)
194 return -1;
195 }
181 196
182 if (codec->cache_only) { 197 if (codec->cache_only) {
183 codec->cache_sync = 1; 198 codec->cache_sync = 1;
@@ -193,7 +208,8 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
193static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, 208static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
194 unsigned int reg) 209 unsigned int reg)
195{ 210{
196 u8 *cache = codec->reg_cache; 211 int ret;
212 unsigned int val;
197 213
198 reg &= 0xff; 214 reg &= 0xff;
199 if (reg >= codec->driver->reg_cache_size || 215 if (reg >= codec->driver->reg_cache_size ||
@@ -205,7 +221,10 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
205 return codec->hw_read(codec, reg); 221 return codec->hw_read(codec, reg);
206 } 222 }
207 223
208 return cache[reg]; 224 ret = snd_soc_cache_read(codec, reg, &val);
225 if (ret < 0)
226 return -1;
227 return val;
209} 228}
210 229
211#if defined(CONFIG_SPI_MASTER) 230#if defined(CONFIG_SPI_MASTER)
@@ -241,16 +260,19 @@ static int snd_soc_8_8_spi_write(void *control_data, const char *data,
241static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, 260static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
242 unsigned int value) 261 unsigned int value)
243{ 262{
244 u16 *reg_cache = codec->reg_cache;
245 u8 data[3]; 263 u8 data[3];
264 int ret;
246 265
247 data[0] = reg; 266 data[0] = reg;
248 data[1] = (value >> 8) & 0xff; 267 data[1] = (value >> 8) & 0xff;
249 data[2] = value & 0xff; 268 data[2] = value & 0xff;
250 269
251 if (!snd_soc_codec_volatile_register(codec, reg) && 270 if (!snd_soc_codec_volatile_register(codec, reg) &&
252 reg < codec->driver->reg_cache_size) 271 reg < codec->driver->reg_cache_size) {
253 reg_cache[reg] = value; 272 ret = snd_soc_cache_write(codec, reg, value);
273 if (ret < 0)
274 return -1;
275 }
254 276
255 if (codec->cache_only) { 277 if (codec->cache_only) {
256 codec->cache_sync = 1; 278 codec->cache_sync = 1;
@@ -266,7 +288,8 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
266static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, 288static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
267 unsigned int reg) 289 unsigned int reg)
268{ 290{
269 u16 *cache = codec->reg_cache; 291 int ret;
292 unsigned int val;
270 293
271 if (reg >= codec->driver->reg_cache_size || 294 if (reg >= codec->driver->reg_cache_size ||
272 snd_soc_codec_volatile_register(codec, reg)) { 295 snd_soc_codec_volatile_register(codec, reg)) {
@@ -275,9 +298,12 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
275 298
276 BUG_ON(!codec->hw_read); 299 BUG_ON(!codec->hw_read);
277 return codec->hw_read(codec, reg); 300 return codec->hw_read(codec, reg);
278 } else {
279 return cache[reg];
280 } 301 }
302
303 ret = snd_soc_cache_read(codec, reg, &val);
304 if (ret < 0)
305 return -1;
306 return val;
281} 307}
282 308
283#if defined(CONFIG_SPI_MASTER) 309#if defined(CONFIG_SPI_MASTER)
@@ -416,7 +442,8 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
416static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, 442static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
417 unsigned int reg) 443 unsigned int reg)
418{ 444{
419 u8 *cache = codec->reg_cache; 445 int ret;
446 unsigned int val;
420 447
421 reg &= 0xff; 448 reg &= 0xff;
422 if (reg >= codec->driver->reg_cache_size || 449 if (reg >= codec->driver->reg_cache_size ||
@@ -428,13 +455,15 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
428 return codec->hw_read(codec, reg); 455 return codec->hw_read(codec, reg);
429 } 456 }
430 457
431 return cache[reg]; 458 ret = snd_soc_cache_read(codec, reg, &val);
459 if (ret < 0)
460 return -1;
461 return val;
432} 462}
433 463
434static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, 464static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
435 unsigned int value) 465 unsigned int value)
436{ 466{
437 u8 *cache = codec->reg_cache;
438 u8 data[3]; 467 u8 data[3];
439 int ret; 468 int ret;
440 469
@@ -444,8 +473,11 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
444 473
445 reg &= 0xff; 474 reg &= 0xff;
446 if (!snd_soc_codec_volatile_register(codec, reg) && 475 if (!snd_soc_codec_volatile_register(codec, reg) &&
447 reg < codec->driver->reg_cache_size) 476 reg < codec->driver->reg_cache_size) {
448 cache[reg] = value; 477 ret = snd_soc_cache_write(codec, reg, value);
478 if (ret < 0)
479 return -1;
480 }
449 481
450 if (codec->cache_only) { 482 if (codec->cache_only) {
451 codec->cache_sync = 1; 483 codec->cache_sync = 1;
@@ -529,7 +561,8 @@ static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
529static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, 561static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
530 unsigned int reg) 562 unsigned int reg)
531{ 563{
532 u16 *cache = codec->reg_cache; 564 int ret;
565 unsigned int val;
533 566
534 if (reg >= codec->driver->reg_cache_size || 567 if (reg >= codec->driver->reg_cache_size ||
535 snd_soc_codec_volatile_register(codec, reg)) { 568 snd_soc_codec_volatile_register(codec, reg)) {
@@ -540,13 +573,16 @@ static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
540 return codec->hw_read(codec, reg); 573 return codec->hw_read(codec, reg);
541 } 574 }
542 575
543 return cache[reg]; 576 ret = snd_soc_cache_read(codec, reg, &val);
577 if (ret < 0)
578 return -1;
579
580 return val;
544} 581}
545 582
546static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, 583static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
547 unsigned int value) 584 unsigned int value)
548{ 585{
549 u16 *cache = codec->reg_cache;
550 u8 data[4]; 586 u8 data[4];
551 int ret; 587 int ret;
552 588
@@ -556,8 +592,11 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
556 data[3] = value & 0xff; 592 data[3] = value & 0xff;
557 593
558 if (!snd_soc_codec_volatile_register(codec, reg) && 594 if (!snd_soc_codec_volatile_register(codec, reg) &&
559 reg < codec->driver->reg_cache_size) 595 reg < codec->driver->reg_cache_size) {
560 cache[reg] = value; 596 ret = snd_soc_cache_write(codec, reg, value);
597 if (ret < 0)
598 return -1;
599 }
561 600
562 if (codec->cache_only) { 601 if (codec->cache_only) {
563 codec->cache_sync = 1; 602 codec->cache_sync = 1;
@@ -718,3 +757,241 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
718 return 0; 757 return 0;
719} 758}
720EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); 759EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
760
761static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
762{
763 int i;
764 struct snd_soc_codec_driver *codec_drv;
765 unsigned int val;
766
767 codec_drv = codec->driver;
768 for (i = 0; i < codec_drv->reg_cache_size; ++i) {
769 snd_soc_cache_read(codec, i, &val);
770 if (codec_drv->reg_cache_default) {
771 switch (codec_drv->reg_word_size) {
772 case 1: {
773 const u8 *cache;
774
775 cache = codec_drv->reg_cache_default;
776 if (cache[i] == val)
777 continue;
778 }
779 break;
780 case 2: {
781 const u16 *cache;
782
783 cache = codec_drv->reg_cache_default;
784 if (cache[i] == val)
785 continue;
786 }
787 break;
788 default:
789 BUG();
790 }
791 }
792 snd_soc_write(codec, i, val);
793 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
794 i, val);
795 }
796 return 0;
797}
798
799static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
800 unsigned int reg, unsigned int value)
801{
802 switch (codec->driver->reg_word_size) {
803 case 1: {
804 u8 *cache;
805
806 cache = codec->reg_cache;
807 cache[reg] = value;
808 }
809 break;
810 case 2: {
811 u16 *cache;
812
813 cache = codec->reg_cache;
814 cache[reg] = value;
815 }
816 break;
817 default:
818 BUG();
819 }
820
821 return 0;
822}
823
824static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
825 unsigned int reg, unsigned int *value)
826{
827 switch (codec->driver->reg_word_size) {
828 case 1: {
829 u8 *cache;
830
831 cache = codec->reg_cache;
832 *value = cache[reg];
833 }
834 break;
835 case 2: {
836 u16 *cache;
837
838 cache = codec->reg_cache;
839 *value = cache[reg];
840 }
841 break;
842 default:
843 BUG();
844 }
845
846 return 0;
847}
848
849static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
850{
851 if (!codec->reg_cache)
852 return 0;
853 kfree(codec->reg_cache);
854 codec->reg_cache = NULL;
855 return 0;
856}
857
858static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
859{
860 struct snd_soc_codec_driver *codec_drv;
861 size_t reg_size;
862
863 codec_drv = codec->driver;
864 reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
865
866 if (codec_drv->reg_cache_default)
867 codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
868 reg_size, GFP_KERNEL);
869 else
870 codec->reg_cache = kzalloc(reg_size, GFP_KERNEL);
871 if (!codec->reg_cache)
872 return -ENOMEM;
873
874 return 0;
875}
876
877/* an array of all supported compression types */
878static const struct snd_soc_cache_ops cache_types[] = {
879 {
880 .id = SND_SOC_NO_COMPRESSION,
881 .init = snd_soc_flat_cache_init,
882 .exit = snd_soc_flat_cache_exit,
883 .read = snd_soc_flat_cache_read,
884 .write = snd_soc_flat_cache_write,
885 .sync = snd_soc_flat_cache_sync
886 }
887};
888
889int snd_soc_cache_init(struct snd_soc_codec *codec)
890{
891 int i;
892
893 for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
894 if (cache_types[i].id == codec->driver->compress_type)
895 break;
896 if (i == ARRAY_SIZE(cache_types)) {
897 dev_err(codec->dev, "Could not match compress type: %d\n",
898 codec->driver->compress_type);
899 return -EINVAL;
900 }
901
902 mutex_init(&codec->cache_rw_mutex);
903 codec->cache_ops = &cache_types[i];
904
905 if (codec->cache_ops->init)
906 return codec->cache_ops->init(codec);
907 return -EINVAL;
908}
909
910/*
911 * NOTE: keep in mind that this function might be called
912 * multiple times.
913 */
914int snd_soc_cache_exit(struct snd_soc_codec *codec)
915{
916 if (codec->cache_ops && codec->cache_ops->exit)
917 return codec->cache_ops->exit(codec);
918 return -EINVAL;
919}
920
921/**
922 * snd_soc_cache_read: Fetch the value of a given register from the cache.
923 *
924 * @codec: CODEC to configure.
925 * @reg: The register index.
926 * @value: The value to be returned.
927 */
928int snd_soc_cache_read(struct snd_soc_codec *codec,
929 unsigned int reg, unsigned int *value)
930{
931 int ret;
932
933 mutex_lock(&codec->cache_rw_mutex);
934
935 if (value && codec->cache_ops && codec->cache_ops->read) {
936 ret = codec->cache_ops->read(codec, reg, value);
937 mutex_unlock(&codec->cache_rw_mutex);
938 return ret;
939 }
940
941 mutex_unlock(&codec->cache_rw_mutex);
942 return -EINVAL;
943}
944EXPORT_SYMBOL_GPL(snd_soc_cache_read);
945
946/**
947 * snd_soc_cache_write: Set the value of a given register in the cache.
948 *
949 * @codec: CODEC to configure.
950 * @reg: The register index.
951 * @value: The new register value.
952 */
953int snd_soc_cache_write(struct snd_soc_codec *codec,
954 unsigned int reg, unsigned int value)
955{
956 int ret;
957
958 mutex_lock(&codec->cache_rw_mutex);
959
960 if (codec->cache_ops && codec->cache_ops->write) {
961 ret = codec->cache_ops->write(codec, reg, value);
962 mutex_unlock(&codec->cache_rw_mutex);
963 return ret;
964 }
965
966 mutex_unlock(&codec->cache_rw_mutex);
967 return -EINVAL;
968}
969EXPORT_SYMBOL_GPL(snd_soc_cache_write);
970
971/**
972 * snd_soc_cache_sync: Sync the register cache with the hardware.
973 *
974 * @codec: CODEC to configure.
975 *
976 * Any registers that should not be synced should be marked as
977 * volatile. In general drivers can choose not to use the provided
978 * syncing functionality if they so require.
979 */
980int snd_soc_cache_sync(struct snd_soc_codec *codec)
981{
982 int ret;
983
984 if (!codec->cache_sync) {
985 return 0;
986 }
987
988 if (codec->cache_ops && codec->cache_ops->sync) {
989 ret = codec->cache_ops->sync(codec);
990 if (!ret)
991 codec->cache_sync = 0;
992 return ret;
993 }
994
995 return -EINVAL;
996}
997EXPORT_SYMBOL_GPL(snd_soc_cache_sync);