2 * soc-cache.c -- ASoC register cache helpers
4 * Copyright 2009 Wolfson Microelectronics PLC.
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
14 #include <sound/soc.h>
15 #include <linux/export.h>
16 #include <linux/slab.h>
18 #include <trace/events/asoc.h>
20 static bool snd_soc_set_cache_val(void *base
, unsigned int idx
,
21 unsigned int val
, unsigned int word_size
)
26 if (cache
[idx
] == val
)
33 if (cache
[idx
] == val
)
39 WARN(1, "Invalid word_size %d\n", word_size
);
45 static unsigned int snd_soc_get_cache_val(const void *base
, unsigned int idx
,
46 unsigned int word_size
)
53 const u8
*cache
= base
;
57 const u16
*cache
= base
;
61 WARN(1, "Invalid word_size %d\n", word_size
);
68 int snd_soc_cache_init(struct snd_soc_codec
*codec
)
70 const struct snd_soc_codec_driver
*codec_drv
= codec
->driver
;
73 reg_size
= codec_drv
->reg_cache_size
* codec_drv
->reg_word_size
;
78 mutex_init(&codec
->cache_rw_mutex
);
80 dev_dbg(codec
->dev
, "ASoC: Initializing cache for %s codec\n",
83 if (codec_drv
->reg_cache_default
)
84 codec
->reg_cache
= kmemdup(codec_drv
->reg_cache_default
,
85 reg_size
, GFP_KERNEL
);
87 codec
->reg_cache
= kzalloc(reg_size
, GFP_KERNEL
);
88 if (!codec
->reg_cache
)
95 * NOTE: keep in mind that this function might be called
98 int snd_soc_cache_exit(struct snd_soc_codec
*codec
)
100 dev_dbg(codec
->dev
, "ASoC: Destroying cache for %s codec\n",
103 kfree(codec
->reg_cache
);
104 codec
->reg_cache
= NULL
;
109 * snd_soc_cache_read: Fetch the value of a given register from the cache.
111 * @codec: CODEC to configure.
112 * @reg: The register index.
113 * @value: The value to be returned.
115 int snd_soc_cache_read(struct snd_soc_codec
*codec
,
116 unsigned int reg
, unsigned int *value
)
121 mutex_lock(&codec
->cache_rw_mutex
);
122 if (!ZERO_OR_NULL_PTR(codec
->reg_cache
))
123 *value
= snd_soc_get_cache_val(codec
->reg_cache
, reg
,
124 codec
->driver
->reg_word_size
);
125 mutex_unlock(&codec
->cache_rw_mutex
);
129 EXPORT_SYMBOL_GPL(snd_soc_cache_read
);
132 * snd_soc_cache_write: Set the value of a given register in the cache.
134 * @codec: CODEC to configure.
135 * @reg: The register index.
136 * @value: The new register value.
138 int snd_soc_cache_write(struct snd_soc_codec
*codec
,
139 unsigned int reg
, unsigned int value
)
141 mutex_lock(&codec
->cache_rw_mutex
);
142 if (!ZERO_OR_NULL_PTR(codec
->reg_cache
))
143 snd_soc_set_cache_val(codec
->reg_cache
, reg
, value
,
144 codec
->driver
->reg_word_size
);
145 mutex_unlock(&codec
->cache_rw_mutex
);
149 EXPORT_SYMBOL_GPL(snd_soc_cache_write
);
151 static int snd_soc_flat_cache_sync(struct snd_soc_codec
*codec
)
155 const struct snd_soc_codec_driver
*codec_drv
;
158 codec_drv
= codec
->driver
;
159 for (i
= 0; i
< codec_drv
->reg_cache_size
; ++i
) {
160 ret
= snd_soc_cache_read(codec
, i
, &val
);
163 if (codec_drv
->reg_cache_default
)
164 if (snd_soc_get_cache_val(codec_drv
->reg_cache_default
,
165 i
, codec_drv
->reg_word_size
) == val
)
168 ret
= snd_soc_write(codec
, i
, val
);
171 dev_dbg(codec
->dev
, "ASoC: Synced register %#x, value = %#x\n",
178 * snd_soc_cache_sync: Sync the register cache with the hardware.
180 * @codec: CODEC to configure.
182 * Any registers that should not be synced should be marked as
183 * volatile. In general drivers can choose not to use the provided
184 * syncing functionality if they so require.
186 int snd_soc_cache_sync(struct snd_soc_codec
*codec
)
188 const char *name
= "flat";
191 if (!codec
->cache_sync
)
194 dev_dbg(codec
->dev
, "ASoC: Syncing cache for %s codec\n",
196 trace_snd_soc_cache_sync(codec
, name
, "start");
197 ret
= snd_soc_flat_cache_sync(codec
);
199 codec
->cache_sync
= 0;
200 trace_snd_soc_cache_sync(codec
, name
, "end");
203 EXPORT_SYMBOL_GPL(snd_soc_cache_sync
);