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",
81 codec
->component
.name
);
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",
101 codec
->component
.name
);
102 kfree(codec
->reg_cache
);
103 codec
->reg_cache
= NULL
;
108 * snd_soc_cache_read: Fetch the value of a given register from the cache.
110 * @codec: CODEC to configure.
111 * @reg: The register index.
112 * @value: The value to be returned.
114 int snd_soc_cache_read(struct snd_soc_codec
*codec
,
115 unsigned int reg
, unsigned int *value
)
120 mutex_lock(&codec
->cache_rw_mutex
);
121 if (!ZERO_OR_NULL_PTR(codec
->reg_cache
))
122 *value
= snd_soc_get_cache_val(codec
->reg_cache
, reg
,
123 codec
->driver
->reg_word_size
);
124 mutex_unlock(&codec
->cache_rw_mutex
);
128 EXPORT_SYMBOL_GPL(snd_soc_cache_read
);
131 * snd_soc_cache_write: Set the value of a given register in the cache.
133 * @codec: CODEC to configure.
134 * @reg: The register index.
135 * @value: The new register value.
137 int snd_soc_cache_write(struct snd_soc_codec
*codec
,
138 unsigned int reg
, unsigned int value
)
140 mutex_lock(&codec
->cache_rw_mutex
);
141 if (!ZERO_OR_NULL_PTR(codec
->reg_cache
))
142 snd_soc_set_cache_val(codec
->reg_cache
, reg
, value
,
143 codec
->driver
->reg_word_size
);
144 mutex_unlock(&codec
->cache_rw_mutex
);
148 EXPORT_SYMBOL_GPL(snd_soc_cache_write
);
150 static int snd_soc_flat_cache_sync(struct snd_soc_codec
*codec
)
154 const struct snd_soc_codec_driver
*codec_drv
;
157 codec_drv
= codec
->driver
;
158 for (i
= 0; i
< codec_drv
->reg_cache_size
; ++i
) {
159 ret
= snd_soc_cache_read(codec
, i
, &val
);
162 if (codec_drv
->reg_cache_default
)
163 if (snd_soc_get_cache_val(codec_drv
->reg_cache_default
,
164 i
, codec_drv
->reg_word_size
) == val
)
167 ret
= snd_soc_write(codec
, i
, val
);
170 dev_dbg(codec
->dev
, "ASoC: Synced register %#x, value = %#x\n",
177 * snd_soc_cache_sync: Sync the register cache with the hardware.
179 * @codec: CODEC to configure.
181 * Any registers that should not be synced should be marked as
182 * volatile. In general drivers can choose not to use the provided
183 * syncing functionality if they so require.
185 int snd_soc_cache_sync(struct snd_soc_codec
*codec
)
187 const char *name
= "flat";
190 if (!codec
->cache_sync
)
193 dev_dbg(codec
->dev
, "ASoC: Syncing cache for %s codec\n",
194 codec
->component
.name
);
195 trace_snd_soc_cache_sync(codec
, name
, "start");
196 ret
= snd_soc_flat_cache_sync(codec
);
198 codec
->cache_sync
= 0;
199 trace_snd_soc_cache_sync(codec
, name
, "end");
202 EXPORT_SYMBOL_GPL(snd_soc_cache_sync
);