diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/soc/soc-cache.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'sound/soc/soc-cache.c')
-rw-r--r-- | sound/soc/soc-cache.c | 1379 |
1 files changed, 1072 insertions, 307 deletions
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index f6b0d2829ea9..039b9532b270 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -14,40 +14,46 @@ | |||
14 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
15 | #include <linux/spi/spi.h> | 15 | #include <linux/spi/spi.h> |
16 | #include <sound/soc.h> | 16 | #include <sound/soc.h> |
17 | #include <linux/lzo.h> | ||
18 | #include <linux/bitmap.h> | ||
19 | #include <linux/rbtree.h> | ||
17 | 20 | ||
18 | static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, | 21 | #include <trace/events/asoc.h> |
19 | unsigned int reg) | ||
20 | { | ||
21 | u16 *cache = codec->reg_cache; | ||
22 | if (reg >= codec->reg_cache_size) | ||
23 | return -1; | ||
24 | return cache[reg]; | ||
25 | } | ||
26 | 22 | ||
27 | static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, | 23 | #ifdef CONFIG_SPI_MASTER |
28 | unsigned int value) | 24 | static int do_spi_write(void *control, const char *data, int len) |
29 | { | 25 | { |
30 | u16 *cache = codec->reg_cache; | 26 | struct spi_device *spi = control; |
31 | u8 data[2]; | ||
32 | int ret; | 27 | int ret; |
33 | 28 | ||
34 | BUG_ON(codec->volatile_register); | 29 | ret = spi_write(spi, data, len); |
30 | if (ret < 0) | ||
31 | return ret; | ||
35 | 32 | ||
36 | data[0] = (reg << 4) | ((value >> 8) & 0x000f); | 33 | return len; |
37 | data[1] = value & 0x00ff; | 34 | } |
35 | #endif | ||
38 | 36 | ||
39 | if (reg < codec->reg_cache_size) | 37 | static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, |
40 | cache[reg] = value; | 38 | unsigned int value, const void *data, int len) |
39 | { | ||
40 | int ret; | ||
41 | |||
42 | if (!snd_soc_codec_volatile_register(codec, reg) && | ||
43 | reg < codec->driver->reg_cache_size && | ||
44 | !codec->cache_bypass) { | ||
45 | ret = snd_soc_cache_write(codec, reg, value); | ||
46 | if (ret < 0) | ||
47 | return -1; | ||
48 | } | ||
41 | 49 | ||
42 | if (codec->cache_only) { | 50 | if (codec->cache_only) { |
43 | codec->cache_sync = 1; | 51 | codec->cache_sync = 1; |
44 | return 0; | 52 | return 0; |
45 | } | 53 | } |
46 | 54 | ||
47 | dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | 55 | ret = codec->hw_write(codec->control_data, data, len); |
48 | 56 | if (ret == len) | |
49 | ret = codec->hw_write(codec->control_data, data, 2); | ||
50 | if (ret == 2) | ||
51 | return 0; | 57 | return 0; |
52 | if (ret < 0) | 58 | if (ret < 0) |
53 | return ret; | 59 | return ret; |
@@ -55,215 +61,138 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, | |||
55 | return -EIO; | 61 | return -EIO; |
56 | } | 62 | } |
57 | 63 | ||
58 | #if defined(CONFIG_SPI_MASTER) | 64 | static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg) |
59 | static int snd_soc_4_12_spi_write(void *control_data, const char *data, | ||
60 | int len) | ||
61 | { | 65 | { |
62 | struct spi_device *spi = control_data; | 66 | int ret; |
63 | struct spi_transfer t; | 67 | unsigned int val; |
64 | struct spi_message m; | ||
65 | u8 msg[2]; | ||
66 | 68 | ||
67 | if (len <= 0) | 69 | if (reg >= codec->driver->reg_cache_size || |
68 | return 0; | 70 | snd_soc_codec_volatile_register(codec, reg) || |
71 | codec->cache_bypass) { | ||
72 | if (codec->cache_only) | ||
73 | return -1; | ||
74 | |||
75 | BUG_ON(!codec->hw_read); | ||
76 | return codec->hw_read(codec, reg); | ||
77 | } | ||
69 | 78 | ||
70 | msg[0] = data[1]; | 79 | ret = snd_soc_cache_read(codec, reg, &val); |
71 | msg[1] = data[0]; | 80 | if (ret < 0) |
81 | return -1; | ||
82 | return val; | ||
83 | } | ||
72 | 84 | ||
73 | spi_message_init(&m); | 85 | static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, |
74 | memset(&t, 0, (sizeof t)); | 86 | unsigned int reg) |
87 | { | ||
88 | return do_hw_read(codec, reg); | ||
89 | } | ||
75 | 90 | ||
76 | t.tx_buf = &msg[0]; | 91 | static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, |
77 | t.len = len; | 92 | unsigned int value) |
93 | { | ||
94 | u16 data; | ||
78 | 95 | ||
79 | spi_message_add_tail(&t, &m); | 96 | data = cpu_to_be16((reg << 12) | (value & 0xffffff)); |
80 | spi_sync(spi, &m); | ||
81 | 97 | ||
82 | return len; | 98 | return do_hw_write(codec, reg, value, &data, 2); |
83 | } | 99 | } |
84 | #else | ||
85 | #define snd_soc_4_12_spi_write NULL | ||
86 | #endif | ||
87 | 100 | ||
88 | static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, | 101 | static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, |
89 | unsigned int reg) | 102 | unsigned int reg) |
90 | { | 103 | { |
91 | u16 *cache = codec->reg_cache; | 104 | return do_hw_read(codec, reg); |
92 | if (reg >= codec->reg_cache_size) | ||
93 | return -1; | ||
94 | return cache[reg]; | ||
95 | } | 105 | } |
96 | 106 | ||
97 | static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, | 107 | static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, |
98 | unsigned int value) | 108 | unsigned int value) |
99 | { | 109 | { |
100 | u16 *cache = codec->reg_cache; | ||
101 | u8 data[2]; | 110 | u8 data[2]; |
102 | int ret; | ||
103 | |||
104 | BUG_ON(codec->volatile_register); | ||
105 | 111 | ||
106 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | 112 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); |
107 | data[1] = value & 0x00ff; | 113 | data[1] = value & 0x00ff; |
108 | 114 | ||
109 | if (reg < codec->reg_cache_size) | 115 | return do_hw_write(codec, reg, value, data, 2); |
110 | cache[reg] = value; | ||
111 | |||
112 | if (codec->cache_only) { | ||
113 | codec->cache_sync = 1; | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | ||
118 | |||
119 | ret = codec->hw_write(codec->control_data, data, 2); | ||
120 | if (ret == 2) | ||
121 | return 0; | ||
122 | if (ret < 0) | ||
123 | return ret; | ||
124 | else | ||
125 | return -EIO; | ||
126 | } | 116 | } |
127 | 117 | ||
128 | #if defined(CONFIG_SPI_MASTER) | ||
129 | static int snd_soc_7_9_spi_write(void *control_data, const char *data, | ||
130 | int len) | ||
131 | { | ||
132 | struct spi_device *spi = control_data; | ||
133 | struct spi_transfer t; | ||
134 | struct spi_message m; | ||
135 | u8 msg[2]; | ||
136 | |||
137 | if (len <= 0) | ||
138 | return 0; | ||
139 | |||
140 | msg[0] = data[0]; | ||
141 | msg[1] = data[1]; | ||
142 | |||
143 | spi_message_init(&m); | ||
144 | memset(&t, 0, (sizeof t)); | ||
145 | |||
146 | t.tx_buf = &msg[0]; | ||
147 | t.len = len; | ||
148 | |||
149 | spi_message_add_tail(&t, &m); | ||
150 | spi_sync(spi, &m); | ||
151 | |||
152 | return len; | ||
153 | } | ||
154 | #else | ||
155 | #define snd_soc_7_9_spi_write NULL | ||
156 | #endif | ||
157 | |||
158 | static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, | 118 | static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, |
159 | unsigned int value) | 119 | unsigned int value) |
160 | { | 120 | { |
161 | u8 *cache = codec->reg_cache; | ||
162 | u8 data[2]; | 121 | u8 data[2]; |
163 | 122 | ||
164 | BUG_ON(codec->volatile_register); | ||
165 | |||
166 | reg &= 0xff; | 123 | reg &= 0xff; |
167 | data[0] = reg; | 124 | data[0] = reg; |
168 | data[1] = value & 0xff; | 125 | data[1] = value & 0xff; |
169 | 126 | ||
170 | if (reg < codec->reg_cache_size) | 127 | return do_hw_write(codec, reg, value, data, 2); |
171 | cache[reg] = value; | ||
172 | |||
173 | if (codec->cache_only) { | ||
174 | codec->cache_sync = 1; | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | ||
179 | |||
180 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
181 | return 0; | ||
182 | else | ||
183 | return -EIO; | ||
184 | } | 128 | } |
185 | 129 | ||
186 | static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, | 130 | static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, |
187 | unsigned int reg) | 131 | unsigned int reg) |
188 | { | 132 | { |
189 | u8 *cache = codec->reg_cache; | 133 | return do_hw_read(codec, reg); |
190 | reg &= 0xff; | ||
191 | if (reg >= codec->reg_cache_size) | ||
192 | return -1; | ||
193 | return cache[reg]; | ||
194 | } | 134 | } |
195 | 135 | ||
196 | static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, | 136 | static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, |
197 | unsigned int value) | 137 | unsigned int value) |
198 | { | 138 | { |
199 | u16 *reg_cache = codec->reg_cache; | ||
200 | u8 data[3]; | 139 | u8 data[3]; |
201 | 140 | ||
202 | data[0] = reg; | 141 | data[0] = reg; |
203 | data[1] = (value >> 8) & 0xff; | 142 | data[1] = (value >> 8) & 0xff; |
204 | data[2] = value & 0xff; | 143 | data[2] = value & 0xff; |
205 | 144 | ||
206 | if (!snd_soc_codec_volatile_register(codec, reg) | 145 | return do_hw_write(codec, reg, value, data, 3); |
207 | && reg < codec->reg_cache_size) | ||
208 | reg_cache[reg] = value; | ||
209 | |||
210 | if (codec->cache_only) { | ||
211 | codec->cache_sync = 1; | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | ||
216 | |||
217 | if (codec->hw_write(codec->control_data, data, 3) == 3) | ||
218 | return 0; | ||
219 | else | ||
220 | return -EIO; | ||
221 | } | 146 | } |
222 | 147 | ||
223 | static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, | 148 | static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, |
224 | unsigned int reg) | 149 | unsigned int reg) |
225 | { | 150 | { |
226 | u16 *cache = codec->reg_cache; | 151 | return do_hw_read(codec, reg); |
227 | |||
228 | if (reg >= codec->reg_cache_size || | ||
229 | snd_soc_codec_volatile_register(codec, reg)) { | ||
230 | if (codec->cache_only) | ||
231 | return -EINVAL; | ||
232 | |||
233 | return codec->hw_read(codec, reg); | ||
234 | } else { | ||
235 | return cache[reg]; | ||
236 | } | ||
237 | } | 152 | } |
238 | 153 | ||
239 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | 154 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) |
240 | static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, | 155 | static unsigned int do_i2c_read(struct snd_soc_codec *codec, |
241 | unsigned int r) | 156 | void *reg, int reglen, |
157 | void *data, int datalen) | ||
242 | { | 158 | { |
243 | struct i2c_msg xfer[2]; | 159 | struct i2c_msg xfer[2]; |
244 | u8 reg = r; | ||
245 | u8 data; | ||
246 | int ret; | 160 | int ret; |
247 | struct i2c_client *client = codec->control_data; | 161 | struct i2c_client *client = codec->control_data; |
248 | 162 | ||
249 | /* Write register */ | 163 | /* Write register */ |
250 | xfer[0].addr = client->addr; | 164 | xfer[0].addr = client->addr; |
251 | xfer[0].flags = 0; | 165 | xfer[0].flags = 0; |
252 | xfer[0].len = 1; | 166 | xfer[0].len = reglen; |
253 | xfer[0].buf = ® | 167 | xfer[0].buf = reg; |
254 | 168 | ||
255 | /* Read data */ | 169 | /* Read data */ |
256 | xfer[1].addr = client->addr; | 170 | xfer[1].addr = client->addr; |
257 | xfer[1].flags = I2C_M_RD; | 171 | xfer[1].flags = I2C_M_RD; |
258 | xfer[1].len = 1; | 172 | xfer[1].len = datalen; |
259 | xfer[1].buf = &data; | 173 | xfer[1].buf = data; |
260 | 174 | ||
261 | ret = i2c_transfer(client->adapter, xfer, 2); | 175 | ret = i2c_transfer(client->adapter, xfer, 2); |
262 | if (ret != 2) { | 176 | if (ret == 2) |
263 | dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); | ||
264 | return 0; | 177 | return 0; |
265 | } | 178 | else if (ret < 0) |
179 | return ret; | ||
180 | else | ||
181 | return -EIO; | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
186 | static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, | ||
187 | unsigned int r) | ||
188 | { | ||
189 | u8 reg = r; | ||
190 | u8 data; | ||
191 | int ret; | ||
266 | 192 | ||
193 | ret = do_i2c_read(codec, ®, 1, &data, 1); | ||
194 | if (ret < 0) | ||
195 | return 0; | ||
267 | return data; | 196 | return data; |
268 | } | 197 | } |
269 | #else | 198 | #else |
@@ -274,30 +203,13 @@ static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, | |||
274 | static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, | 203 | static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, |
275 | unsigned int r) | 204 | unsigned int r) |
276 | { | 205 | { |
277 | struct i2c_msg xfer[2]; | ||
278 | u8 reg = r; | 206 | u8 reg = r; |
279 | u16 data; | 207 | u16 data; |
280 | int ret; | 208 | int ret; |
281 | struct i2c_client *client = codec->control_data; | ||
282 | |||
283 | /* Write register */ | ||
284 | xfer[0].addr = client->addr; | ||
285 | xfer[0].flags = 0; | ||
286 | xfer[0].len = 1; | ||
287 | xfer[0].buf = ® | ||
288 | |||
289 | /* Read data */ | ||
290 | xfer[1].addr = client->addr; | ||
291 | xfer[1].flags = I2C_M_RD; | ||
292 | xfer[1].len = 2; | ||
293 | xfer[1].buf = (u8 *)&data; | ||
294 | 209 | ||
295 | ret = i2c_transfer(client->adapter, xfer, 2); | 210 | ret = do_i2c_read(codec, ®, 1, &data, 2); |
296 | if (ret != 2) { | 211 | if (ret < 0) |
297 | dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); | ||
298 | return 0; | 212 | return 0; |
299 | } | ||
300 | |||
301 | return (data >> 8) | ((data & 0xff) << 8); | 213 | return (data >> 8) | ((data & 0xff) << 8); |
302 | } | 214 | } |
303 | #else | 215 | #else |
@@ -308,30 +220,13 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, | |||
308 | static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, | 220 | static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, |
309 | unsigned int r) | 221 | unsigned int r) |
310 | { | 222 | { |
311 | struct i2c_msg xfer[2]; | ||
312 | u16 reg = r; | 223 | u16 reg = r; |
313 | u8 data; | 224 | u8 data; |
314 | int ret; | 225 | int ret; |
315 | struct i2c_client *client = codec->control_data; | ||
316 | |||
317 | /* Write register */ | ||
318 | xfer[0].addr = client->addr; | ||
319 | xfer[0].flags = 0; | ||
320 | xfer[0].len = 2; | ||
321 | xfer[0].buf = (u8 *)® | ||
322 | 226 | ||
323 | /* Read data */ | 227 | ret = do_i2c_read(codec, ®, 2, &data, 1); |
324 | xfer[1].addr = client->addr; | 228 | if (ret < 0) |
325 | xfer[1].flags = I2C_M_RD; | ||
326 | xfer[1].len = 1; | ||
327 | xfer[1].buf = &data; | ||
328 | |||
329 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
330 | if (ret != 2) { | ||
331 | dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); | ||
332 | return 0; | 229 | return 0; |
333 | } | ||
334 | |||
335 | return data; | 230 | return data; |
336 | } | 231 | } |
337 | #else | 232 | #else |
@@ -339,108 +234,34 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, | |||
339 | #endif | 234 | #endif |
340 | 235 | ||
341 | static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, | 236 | static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, |
342 | unsigned int reg) | 237 | unsigned int reg) |
343 | { | 238 | { |
344 | u8 *cache = codec->reg_cache; | 239 | return do_hw_read(codec, reg); |
345 | |||
346 | reg &= 0xff; | ||
347 | if (reg >= codec->reg_cache_size) | ||
348 | return -1; | ||
349 | return cache[reg]; | ||
350 | } | 240 | } |
351 | 241 | ||
352 | static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, | 242 | static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, |
353 | unsigned int value) | 243 | unsigned int value) |
354 | { | 244 | { |
355 | u8 *cache = codec->reg_cache; | ||
356 | u8 data[3]; | 245 | u8 data[3]; |
357 | int ret; | ||
358 | |||
359 | BUG_ON(codec->volatile_register); | ||
360 | 246 | ||
361 | data[0] = (reg >> 8) & 0xff; | 247 | data[0] = (reg >> 8) & 0xff; |
362 | data[1] = reg & 0xff; | 248 | data[1] = reg & 0xff; |
363 | data[2] = value; | 249 | data[2] = value; |
364 | 250 | ||
365 | reg &= 0xff; | 251 | return do_hw_write(codec, reg, value, data, 3); |
366 | if (reg < codec->reg_cache_size) | ||
367 | cache[reg] = value; | ||
368 | |||
369 | if (codec->cache_only) { | ||
370 | codec->cache_sync = 1; | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | ||
375 | |||
376 | ret = codec->hw_write(codec->control_data, data, 3); | ||
377 | if (ret == 3) | ||
378 | return 0; | ||
379 | if (ret < 0) | ||
380 | return ret; | ||
381 | else | ||
382 | return -EIO; | ||
383 | } | 252 | } |
384 | 253 | ||
385 | #if defined(CONFIG_SPI_MASTER) | ||
386 | static int snd_soc_16_8_spi_write(void *control_data, const char *data, | ||
387 | int len) | ||
388 | { | ||
389 | struct spi_device *spi = control_data; | ||
390 | struct spi_transfer t; | ||
391 | struct spi_message m; | ||
392 | u8 msg[3]; | ||
393 | |||
394 | if (len <= 0) | ||
395 | return 0; | ||
396 | |||
397 | msg[0] = data[0]; | ||
398 | msg[1] = data[1]; | ||
399 | msg[2] = data[2]; | ||
400 | |||
401 | spi_message_init(&m); | ||
402 | memset(&t, 0, (sizeof t)); | ||
403 | |||
404 | t.tx_buf = &msg[0]; | ||
405 | t.len = len; | ||
406 | |||
407 | spi_message_add_tail(&t, &m); | ||
408 | spi_sync(spi, &m); | ||
409 | |||
410 | return len; | ||
411 | } | ||
412 | #else | ||
413 | #define snd_soc_16_8_spi_write NULL | ||
414 | #endif | ||
415 | |||
416 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | 254 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) |
417 | static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, | 255 | static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, |
418 | unsigned int r) | 256 | unsigned int r) |
419 | { | 257 | { |
420 | struct i2c_msg xfer[2]; | ||
421 | u16 reg = cpu_to_be16(r); | 258 | u16 reg = cpu_to_be16(r); |
422 | u16 data; | 259 | u16 data; |
423 | int ret; | 260 | int ret; |
424 | struct i2c_client *client = codec->control_data; | ||
425 | |||
426 | /* Write register */ | ||
427 | xfer[0].addr = client->addr; | ||
428 | xfer[0].flags = 0; | ||
429 | xfer[0].len = 2; | ||
430 | xfer[0].buf = (u8 *)® | ||
431 | |||
432 | /* Read data */ | ||
433 | xfer[1].addr = client->addr; | ||
434 | xfer[1].flags = I2C_M_RD; | ||
435 | xfer[1].len = 2; | ||
436 | xfer[1].buf = (u8 *)&data; | ||
437 | 261 | ||
438 | ret = i2c_transfer(client->adapter, xfer, 2); | 262 | ret = do_i2c_read(codec, ®, 2, &data, 2); |
439 | if (ret != 2) { | 263 | if (ret < 0) |
440 | dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); | ||
441 | return 0; | 264 | return 0; |
442 | } | ||
443 | |||
444 | return be16_to_cpu(data); | 265 | return be16_to_cpu(data); |
445 | } | 266 | } |
446 | #else | 267 | #else |
@@ -450,43 +271,59 @@ static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, | |||
450 | static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, | 271 | static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, |
451 | unsigned int reg) | 272 | unsigned int reg) |
452 | { | 273 | { |
453 | u16 *cache = codec->reg_cache; | 274 | return do_hw_read(codec, reg); |
454 | |||
455 | if (reg >= codec->reg_cache_size || | ||
456 | snd_soc_codec_volatile_register(codec, reg)) { | ||
457 | if (codec->cache_only) | ||
458 | return -EINVAL; | ||
459 | |||
460 | return codec->hw_read(codec, reg); | ||
461 | } | ||
462 | |||
463 | return cache[reg]; | ||
464 | } | 275 | } |
465 | 276 | ||
466 | static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, | 277 | static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, |
467 | unsigned int value) | 278 | unsigned int value) |
468 | { | 279 | { |
469 | u16 *cache = codec->reg_cache; | ||
470 | u8 data[4]; | 280 | u8 data[4]; |
471 | int ret; | ||
472 | 281 | ||
473 | data[0] = (reg >> 8) & 0xff; | 282 | data[0] = (reg >> 8) & 0xff; |
474 | data[1] = reg & 0xff; | 283 | data[1] = reg & 0xff; |
475 | data[2] = (value >> 8) & 0xff; | 284 | data[2] = (value >> 8) & 0xff; |
476 | data[3] = value & 0xff; | 285 | data[3] = value & 0xff; |
477 | 286 | ||
478 | if (reg < codec->reg_cache_size) | 287 | return do_hw_write(codec, reg, value, data, 4); |
479 | cache[reg] = value; | 288 | } |
480 | 289 | ||
481 | if (codec->cache_only) { | 290 | /* Primitive bulk write support for soc-cache. The data pointed to by |
482 | codec->cache_sync = 1; | 291 | * `data' needs to already be in the form the hardware expects |
483 | return 0; | 292 | * including any leading register specific data. Any data written |
484 | } | 293 | * through this function will not go through the cache as it only |
294 | * handles writing to volatile or out of bounds registers. | ||
295 | */ | ||
296 | static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg, | ||
297 | const void *data, size_t len) | ||
298 | { | ||
299 | int ret; | ||
485 | 300 | ||
486 | dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | 301 | /* To ensure that we don't get out of sync with the cache, check |
302 | * whether the base register is volatile or if we've directly asked | ||
303 | * to bypass the cache. Out of bounds registers are considered | ||
304 | * volatile. | ||
305 | */ | ||
306 | if (!codec->cache_bypass | ||
307 | && !snd_soc_codec_volatile_register(codec, reg) | ||
308 | && reg < codec->driver->reg_cache_size) | ||
309 | return -EINVAL; | ||
487 | 310 | ||
488 | ret = codec->hw_write(codec->control_data, data, 4); | 311 | switch (codec->control_type) { |
489 | if (ret == 4) | 312 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) |
313 | case SND_SOC_I2C: | ||
314 | ret = i2c_master_send(codec->control_data, data, len); | ||
315 | break; | ||
316 | #endif | ||
317 | #if defined(CONFIG_SPI_MASTER) | ||
318 | case SND_SOC_SPI: | ||
319 | ret = spi_write(codec->control_data, data, len); | ||
320 | break; | ||
321 | #endif | ||
322 | default: | ||
323 | BUG(); | ||
324 | } | ||
325 | |||
326 | if (ret == len) | ||
490 | return 0; | 327 | return 0; |
491 | if (ret < 0) | 328 | if (ret < 0) |
492 | return ret; | 329 | return ret; |
@@ -498,19 +335,16 @@ static struct { | |||
498 | int addr_bits; | 335 | int addr_bits; |
499 | int data_bits; | 336 | int data_bits; |
500 | int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); | 337 | int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); |
501 | int (*spi_write)(void *, const char *, int); | ||
502 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | 338 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); |
503 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); | 339 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); |
504 | } io_types[] = { | 340 | } io_types[] = { |
505 | { | 341 | { |
506 | .addr_bits = 4, .data_bits = 12, | 342 | .addr_bits = 4, .data_bits = 12, |
507 | .write = snd_soc_4_12_write, .read = snd_soc_4_12_read, | 343 | .write = snd_soc_4_12_write, .read = snd_soc_4_12_read, |
508 | .spi_write = snd_soc_4_12_spi_write, | ||
509 | }, | 344 | }, |
510 | { | 345 | { |
511 | .addr_bits = 7, .data_bits = 9, | 346 | .addr_bits = 7, .data_bits = 9, |
512 | .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, | 347 | .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, |
513 | .spi_write = snd_soc_7_9_spi_write, | ||
514 | }, | 348 | }, |
515 | { | 349 | { |
516 | .addr_bits = 8, .data_bits = 8, | 350 | .addr_bits = 8, .data_bits = 8, |
@@ -526,7 +360,6 @@ static struct { | |||
526 | .addr_bits = 16, .data_bits = 8, | 360 | .addr_bits = 16, .data_bits = 8, |
527 | .write = snd_soc_16_8_write, .read = snd_soc_16_8_read, | 361 | .write = snd_soc_16_8_write, .read = snd_soc_16_8_read, |
528 | .i2c_read = snd_soc_16_8_read_i2c, | 362 | .i2c_read = snd_soc_16_8_read_i2c, |
529 | .spi_write = snd_soc_16_8_spi_write, | ||
530 | }, | 363 | }, |
531 | { | 364 | { |
532 | .addr_bits = 16, .data_bits = 16, | 365 | .addr_bits = 16, .data_bits = 16, |
@@ -539,7 +372,6 @@ static struct { | |||
539 | * snd_soc_codec_set_cache_io: Set up standard I/O functions. | 372 | * snd_soc_codec_set_cache_io: Set up standard I/O functions. |
540 | * | 373 | * |
541 | * @codec: CODEC to configure. | 374 | * @codec: CODEC to configure. |
542 | * @type: Type of cache. | ||
543 | * @addr_bits: Number of bits of register address data. | 375 | * @addr_bits: Number of bits of register address data. |
544 | * @data_bits: Number of bits of data per register. | 376 | * @data_bits: Number of bits of data per register. |
545 | * @control: Control bus used. | 377 | * @control: Control bus used. |
@@ -574,25 +406,958 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, | |||
574 | 406 | ||
575 | codec->write = io_types[i].write; | 407 | codec->write = io_types[i].write; |
576 | codec->read = io_types[i].read; | 408 | codec->read = io_types[i].read; |
409 | codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; | ||
577 | 410 | ||
578 | switch (control) { | 411 | switch (control) { |
579 | case SND_SOC_CUSTOM: | ||
580 | break; | ||
581 | |||
582 | case SND_SOC_I2C: | 412 | case SND_SOC_I2C: |
583 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | 413 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) |
584 | codec->hw_write = (hw_write_t)i2c_master_send; | 414 | codec->hw_write = (hw_write_t)i2c_master_send; |
585 | #endif | 415 | #endif |
586 | if (io_types[i].i2c_read) | 416 | if (io_types[i].i2c_read) |
587 | codec->hw_read = io_types[i].i2c_read; | 417 | codec->hw_read = io_types[i].i2c_read; |
418 | |||
419 | codec->control_data = container_of(codec->dev, | ||
420 | struct i2c_client, | ||
421 | dev); | ||
588 | break; | 422 | break; |
589 | 423 | ||
590 | case SND_SOC_SPI: | 424 | case SND_SOC_SPI: |
591 | if (io_types[i].spi_write) | 425 | #ifdef CONFIG_SPI_MASTER |
592 | codec->hw_write = io_types[i].spi_write; | 426 | codec->hw_write = do_spi_write; |
427 | #endif | ||
428 | |||
429 | codec->control_data = container_of(codec->dev, | ||
430 | struct spi_device, | ||
431 | dev); | ||
593 | break; | 432 | break; |
594 | } | 433 | } |
595 | 434 | ||
596 | return 0; | 435 | return 0; |
597 | } | 436 | } |
598 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); | 437 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); |
438 | |||
439 | static bool snd_soc_set_cache_val(void *base, unsigned int idx, | ||
440 | unsigned int val, unsigned int word_size) | ||
441 | { | ||
442 | switch (word_size) { | ||
443 | case 1: { | ||
444 | u8 *cache = base; | ||
445 | if (cache[idx] == val) | ||
446 | return true; | ||
447 | cache[idx] = val; | ||
448 | break; | ||
449 | } | ||
450 | case 2: { | ||
451 | u16 *cache = base; | ||
452 | if (cache[idx] == val) | ||
453 | return true; | ||
454 | cache[idx] = val; | ||
455 | break; | ||
456 | } | ||
457 | default: | ||
458 | BUG(); | ||
459 | } | ||
460 | return false; | ||
461 | } | ||
462 | |||
463 | static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, | ||
464 | unsigned int word_size) | ||
465 | { | ||
466 | if (!base) | ||
467 | return -1; | ||
468 | |||
469 | switch (word_size) { | ||
470 | case 1: { | ||
471 | const u8 *cache = base; | ||
472 | return cache[idx]; | ||
473 | } | ||
474 | case 2: { | ||
475 | const u16 *cache = base; | ||
476 | return cache[idx]; | ||
477 | } | ||
478 | default: | ||
479 | BUG(); | ||
480 | } | ||
481 | /* unreachable */ | ||
482 | return -1; | ||
483 | } | ||
484 | |||
485 | struct snd_soc_rbtree_node { | ||
486 | struct rb_node node; | ||
487 | unsigned int reg; | ||
488 | unsigned int value; | ||
489 | unsigned int defval; | ||
490 | } __attribute__ ((packed)); | ||
491 | |||
492 | struct snd_soc_rbtree_ctx { | ||
493 | struct rb_root root; | ||
494 | }; | ||
495 | |||
496 | static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup( | ||
497 | struct rb_root *root, unsigned int reg) | ||
498 | { | ||
499 | struct rb_node *node; | ||
500 | struct snd_soc_rbtree_node *rbnode; | ||
501 | |||
502 | node = root->rb_node; | ||
503 | while (node) { | ||
504 | rbnode = container_of(node, struct snd_soc_rbtree_node, node); | ||
505 | if (rbnode->reg < reg) | ||
506 | node = node->rb_left; | ||
507 | else if (rbnode->reg > reg) | ||
508 | node = node->rb_right; | ||
509 | else | ||
510 | return rbnode; | ||
511 | } | ||
512 | |||
513 | return NULL; | ||
514 | } | ||
515 | |||
516 | static int snd_soc_rbtree_insert(struct rb_root *root, | ||
517 | struct snd_soc_rbtree_node *rbnode) | ||
518 | { | ||
519 | struct rb_node **new, *parent; | ||
520 | struct snd_soc_rbtree_node *rbnode_tmp; | ||
521 | |||
522 | parent = NULL; | ||
523 | new = &root->rb_node; | ||
524 | while (*new) { | ||
525 | rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node, | ||
526 | node); | ||
527 | parent = *new; | ||
528 | if (rbnode_tmp->reg < rbnode->reg) | ||
529 | new = &((*new)->rb_left); | ||
530 | else if (rbnode_tmp->reg > rbnode->reg) | ||
531 | new = &((*new)->rb_right); | ||
532 | else | ||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | /* insert the node into the rbtree */ | ||
537 | rb_link_node(&rbnode->node, parent, new); | ||
538 | rb_insert_color(&rbnode->node, root); | ||
539 | |||
540 | return 1; | ||
541 | } | ||
542 | |||
543 | static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec) | ||
544 | { | ||
545 | struct snd_soc_rbtree_ctx *rbtree_ctx; | ||
546 | struct rb_node *node; | ||
547 | struct snd_soc_rbtree_node *rbnode; | ||
548 | unsigned int val; | ||
549 | int ret; | ||
550 | |||
551 | rbtree_ctx = codec->reg_cache; | ||
552 | for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { | ||
553 | rbnode = rb_entry(node, struct snd_soc_rbtree_node, node); | ||
554 | if (rbnode->value == rbnode->defval) | ||
555 | continue; | ||
556 | WARN_ON(codec->writable_register && | ||
557 | codec->writable_register(codec, rbnode->reg)); | ||
558 | ret = snd_soc_cache_read(codec, rbnode->reg, &val); | ||
559 | if (ret) | ||
560 | return ret; | ||
561 | codec->cache_bypass = 1; | ||
562 | ret = snd_soc_write(codec, rbnode->reg, val); | ||
563 | codec->cache_bypass = 0; | ||
564 | if (ret) | ||
565 | return ret; | ||
566 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", | ||
567 | rbnode->reg, val); | ||
568 | } | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, | ||
574 | unsigned int reg, unsigned int value) | ||
575 | { | ||
576 | struct snd_soc_rbtree_ctx *rbtree_ctx; | ||
577 | struct snd_soc_rbtree_node *rbnode; | ||
578 | |||
579 | rbtree_ctx = codec->reg_cache; | ||
580 | rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); | ||
581 | if (rbnode) { | ||
582 | if (rbnode->value == value) | ||
583 | return 0; | ||
584 | rbnode->value = value; | ||
585 | } else { | ||
586 | /* bail out early, no need to create the rbnode yet */ | ||
587 | if (!value) | ||
588 | return 0; | ||
589 | /* | ||
590 | * for uninitialized registers whose value is changed | ||
591 | * from the default zero, create an rbnode and insert | ||
592 | * it into the tree. | ||
593 | */ | ||
594 | rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); | ||
595 | if (!rbnode) | ||
596 | return -ENOMEM; | ||
597 | rbnode->reg = reg; | ||
598 | rbnode->value = value; | ||
599 | snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode); | ||
600 | } | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec, | ||
606 | unsigned int reg, unsigned int *value) | ||
607 | { | ||
608 | struct snd_soc_rbtree_ctx *rbtree_ctx; | ||
609 | struct snd_soc_rbtree_node *rbnode; | ||
610 | |||
611 | rbtree_ctx = codec->reg_cache; | ||
612 | rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); | ||
613 | if (rbnode) { | ||
614 | *value = rbnode->value; | ||
615 | } else { | ||
616 | /* uninitialized registers default to 0 */ | ||
617 | *value = 0; | ||
618 | } | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec) | ||
624 | { | ||
625 | struct rb_node *next; | ||
626 | struct snd_soc_rbtree_ctx *rbtree_ctx; | ||
627 | struct snd_soc_rbtree_node *rbtree_node; | ||
628 | |||
629 | /* if we've already been called then just return */ | ||
630 | rbtree_ctx = codec->reg_cache; | ||
631 | if (!rbtree_ctx) | ||
632 | return 0; | ||
633 | |||
634 | /* free up the rbtree */ | ||
635 | next = rb_first(&rbtree_ctx->root); | ||
636 | while (next) { | ||
637 | rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node); | ||
638 | next = rb_next(&rbtree_node->node); | ||
639 | rb_erase(&rbtree_node->node, &rbtree_ctx->root); | ||
640 | kfree(rbtree_node); | ||
641 | } | ||
642 | |||
643 | /* release the resources */ | ||
644 | kfree(codec->reg_cache); | ||
645 | codec->reg_cache = NULL; | ||
646 | |||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) | ||
651 | { | ||
652 | struct snd_soc_rbtree_node *rbtree_node; | ||
653 | struct snd_soc_rbtree_ctx *rbtree_ctx; | ||
654 | unsigned int val; | ||
655 | unsigned int word_size; | ||
656 | int i; | ||
657 | int ret; | ||
658 | |||
659 | codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL); | ||
660 | if (!codec->reg_cache) | ||
661 | return -ENOMEM; | ||
662 | |||
663 | rbtree_ctx = codec->reg_cache; | ||
664 | rbtree_ctx->root = RB_ROOT; | ||
665 | |||
666 | if (!codec->reg_def_copy) | ||
667 | return 0; | ||
668 | |||
669 | /* | ||
670 | * populate the rbtree with the initialized registers. All other | ||
671 | * registers will be inserted when they are first modified. | ||
672 | */ | ||
673 | word_size = codec->driver->reg_word_size; | ||
674 | for (i = 0; i < codec->driver->reg_cache_size; ++i) { | ||
675 | val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size); | ||
676 | if (!val) | ||
677 | continue; | ||
678 | rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); | ||
679 | if (!rbtree_node) { | ||
680 | ret = -ENOMEM; | ||
681 | snd_soc_cache_exit(codec); | ||
682 | break; | ||
683 | } | ||
684 | rbtree_node->reg = i; | ||
685 | rbtree_node->value = val; | ||
686 | rbtree_node->defval = val; | ||
687 | snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node); | ||
688 | } | ||
689 | |||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | #ifdef CONFIG_SND_SOC_CACHE_LZO | ||
694 | struct snd_soc_lzo_ctx { | ||
695 | void *wmem; | ||
696 | void *dst; | ||
697 | const void *src; | ||
698 | size_t src_len; | ||
699 | size_t dst_len; | ||
700 | size_t decompressed_size; | ||
701 | unsigned long *sync_bmp; | ||
702 | int sync_bmp_nbits; | ||
703 | }; | ||
704 | |||
705 | #define LZO_BLOCK_NUM 8 | ||
706 | static int snd_soc_lzo_block_count(void) | ||
707 | { | ||
708 | return LZO_BLOCK_NUM; | ||
709 | } | ||
710 | |||
711 | static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx) | ||
712 | { | ||
713 | lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); | ||
714 | if (!lzo_ctx->wmem) | ||
715 | return -ENOMEM; | ||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx) | ||
720 | { | ||
721 | size_t compress_size; | ||
722 | int ret; | ||
723 | |||
724 | ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len, | ||
725 | lzo_ctx->dst, &compress_size, lzo_ctx->wmem); | ||
726 | if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len) | ||
727 | return -EINVAL; | ||
728 | lzo_ctx->dst_len = compress_size; | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx) | ||
733 | { | ||
734 | size_t dst_len; | ||
735 | int ret; | ||
736 | |||
737 | dst_len = lzo_ctx->dst_len; | ||
738 | ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len, | ||
739 | lzo_ctx->dst, &dst_len); | ||
740 | if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len) | ||
741 | return -EINVAL; | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec, | ||
746 | struct snd_soc_lzo_ctx *lzo_ctx) | ||
747 | { | ||
748 | int ret; | ||
749 | |||
750 | lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE); | ||
751 | lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL); | ||
752 | if (!lzo_ctx->dst) { | ||
753 | lzo_ctx->dst_len = 0; | ||
754 | return -ENOMEM; | ||
755 | } | ||
756 | |||
757 | ret = snd_soc_lzo_compress(lzo_ctx); | ||
758 | if (ret < 0) | ||
759 | return ret; | ||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec, | ||
764 | struct snd_soc_lzo_ctx *lzo_ctx) | ||
765 | { | ||
766 | int ret; | ||
767 | |||
768 | lzo_ctx->dst_len = lzo_ctx->decompressed_size; | ||
769 | lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL); | ||
770 | if (!lzo_ctx->dst) { | ||
771 | lzo_ctx->dst_len = 0; | ||
772 | return -ENOMEM; | ||
773 | } | ||
774 | |||
775 | ret = snd_soc_lzo_decompress(lzo_ctx); | ||
776 | if (ret < 0) | ||
777 | return ret; | ||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec, | ||
782 | unsigned int reg) | ||
783 | { | ||
784 | const struct snd_soc_codec_driver *codec_drv; | ||
785 | |||
786 | codec_drv = codec->driver; | ||
787 | return (reg * codec_drv->reg_word_size) / | ||
788 | DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()); | ||
789 | } | ||
790 | |||
791 | static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec, | ||
792 | unsigned int reg) | ||
793 | { | ||
794 | const struct snd_soc_codec_driver *codec_drv; | ||
795 | |||
796 | codec_drv = codec->driver; | ||
797 | return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) / | ||
798 | codec_drv->reg_word_size); | ||
799 | } | ||
800 | |||
801 | static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec) | ||
802 | { | ||
803 | const struct snd_soc_codec_driver *codec_drv; | ||
804 | |||
805 | codec_drv = codec->driver; | ||
806 | return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()); | ||
807 | } | ||
808 | |||
809 | static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) | ||
810 | { | ||
811 | struct snd_soc_lzo_ctx **lzo_blocks; | ||
812 | unsigned int val; | ||
813 | int i; | ||
814 | int ret; | ||
815 | |||
816 | lzo_blocks = codec->reg_cache; | ||
817 | for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) { | ||
818 | WARN_ON(codec->writable_register && | ||
819 | codec->writable_register(codec, i)); | ||
820 | ret = snd_soc_cache_read(codec, i, &val); | ||
821 | if (ret) | ||
822 | return ret; | ||
823 | codec->cache_bypass = 1; | ||
824 | ret = snd_soc_write(codec, i, val); | ||
825 | codec->cache_bypass = 0; | ||
826 | if (ret) | ||
827 | return ret; | ||
828 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", | ||
829 | i, val); | ||
830 | } | ||
831 | |||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec, | ||
836 | unsigned int reg, unsigned int value) | ||
837 | { | ||
838 | struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks; | ||
839 | int ret, blkindex, blkpos; | ||
840 | size_t blksize, tmp_dst_len; | ||
841 | void *tmp_dst; | ||
842 | |||
843 | /* index of the compressed lzo block */ | ||
844 | blkindex = snd_soc_lzo_get_blkindex(codec, reg); | ||
845 | /* register index within the decompressed block */ | ||
846 | blkpos = snd_soc_lzo_get_blkpos(codec, reg); | ||
847 | /* size of the compressed block */ | ||
848 | blksize = snd_soc_lzo_get_blksize(codec); | ||
849 | lzo_blocks = codec->reg_cache; | ||
850 | lzo_block = lzo_blocks[blkindex]; | ||
851 | |||
852 | /* save the pointer and length of the compressed block */ | ||
853 | tmp_dst = lzo_block->dst; | ||
854 | tmp_dst_len = lzo_block->dst_len; | ||
855 | |||
856 | /* prepare the source to be the compressed block */ | ||
857 | lzo_block->src = lzo_block->dst; | ||
858 | lzo_block->src_len = lzo_block->dst_len; | ||
859 | |||
860 | /* decompress the block */ | ||
861 | ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block); | ||
862 | if (ret < 0) { | ||
863 | kfree(lzo_block->dst); | ||
864 | goto out; | ||
865 | } | ||
866 | |||
867 | /* write the new value to the cache */ | ||
868 | if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value, | ||
869 | codec->driver->reg_word_size)) { | ||
870 | kfree(lzo_block->dst); | ||
871 | goto out; | ||
872 | } | ||
873 | |||
874 | /* prepare the source to be the decompressed block */ | ||
875 | lzo_block->src = lzo_block->dst; | ||
876 | lzo_block->src_len = lzo_block->dst_len; | ||
877 | |||
878 | /* compress the block */ | ||
879 | ret = snd_soc_lzo_compress_cache_block(codec, lzo_block); | ||
880 | if (ret < 0) { | ||
881 | kfree(lzo_block->dst); | ||
882 | kfree(lzo_block->src); | ||
883 | goto out; | ||
884 | } | ||
885 | |||
886 | /* set the bit so we know we have to sync this register */ | ||
887 | set_bit(reg, lzo_block->sync_bmp); | ||
888 | kfree(tmp_dst); | ||
889 | kfree(lzo_block->src); | ||
890 | return 0; | ||
891 | out: | ||
892 | lzo_block->dst = tmp_dst; | ||
893 | lzo_block->dst_len = tmp_dst_len; | ||
894 | return ret; | ||
895 | } | ||
896 | |||
897 | static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec, | ||
898 | unsigned int reg, unsigned int *value) | ||
899 | { | ||
900 | struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks; | ||
901 | int ret, blkindex, blkpos; | ||
902 | size_t blksize, tmp_dst_len; | ||
903 | void *tmp_dst; | ||
904 | |||
905 | *value = 0; | ||
906 | /* index of the compressed lzo block */ | ||
907 | blkindex = snd_soc_lzo_get_blkindex(codec, reg); | ||
908 | /* register index within the decompressed block */ | ||
909 | blkpos = snd_soc_lzo_get_blkpos(codec, reg); | ||
910 | /* size of the compressed block */ | ||
911 | blksize = snd_soc_lzo_get_blksize(codec); | ||
912 | lzo_blocks = codec->reg_cache; | ||
913 | lzo_block = lzo_blocks[blkindex]; | ||
914 | |||
915 | /* save the pointer and length of the compressed block */ | ||
916 | tmp_dst = lzo_block->dst; | ||
917 | tmp_dst_len = lzo_block->dst_len; | ||
918 | |||
919 | /* prepare the source to be the compressed block */ | ||
920 | lzo_block->src = lzo_block->dst; | ||
921 | lzo_block->src_len = lzo_block->dst_len; | ||
922 | |||
923 | /* decompress the block */ | ||
924 | ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block); | ||
925 | if (ret >= 0) | ||
926 | /* fetch the value from the cache */ | ||
927 | *value = snd_soc_get_cache_val(lzo_block->dst, blkpos, | ||
928 | codec->driver->reg_word_size); | ||
929 | |||
930 | kfree(lzo_block->dst); | ||
931 | /* restore the pointer and length of the compressed block */ | ||
932 | lzo_block->dst = tmp_dst; | ||
933 | lzo_block->dst_len = tmp_dst_len; | ||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec) | ||
938 | { | ||
939 | struct snd_soc_lzo_ctx **lzo_blocks; | ||
940 | int i, blkcount; | ||
941 | |||
942 | lzo_blocks = codec->reg_cache; | ||
943 | if (!lzo_blocks) | ||
944 | return 0; | ||
945 | |||
946 | blkcount = snd_soc_lzo_block_count(); | ||
947 | /* | ||
948 | * the pointer to the bitmap used for syncing the cache | ||
949 | * is shared amongst all lzo_blocks. Ensure it is freed | ||
950 | * only once. | ||
951 | */ | ||
952 | if (lzo_blocks[0]) | ||
953 | kfree(lzo_blocks[0]->sync_bmp); | ||
954 | for (i = 0; i < blkcount; ++i) { | ||
955 | if (lzo_blocks[i]) { | ||
956 | kfree(lzo_blocks[i]->wmem); | ||
957 | kfree(lzo_blocks[i]->dst); | ||
958 | } | ||
959 | /* each lzo_block is a pointer returned by kmalloc or NULL */ | ||
960 | kfree(lzo_blocks[i]); | ||
961 | } | ||
962 | kfree(lzo_blocks); | ||
963 | codec->reg_cache = NULL; | ||
964 | return 0; | ||
965 | } | ||
966 | |||
967 | static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) | ||
968 | { | ||
969 | struct snd_soc_lzo_ctx **lzo_blocks; | ||
970 | size_t bmp_size; | ||
971 | const struct snd_soc_codec_driver *codec_drv; | ||
972 | int ret, tofree, i, blksize, blkcount; | ||
973 | const char *p, *end; | ||
974 | unsigned long *sync_bmp; | ||
975 | |||
976 | ret = 0; | ||
977 | codec_drv = codec->driver; | ||
978 | |||
979 | /* | ||
980 | * If we have not been given a default register cache | ||
981 | * then allocate a dummy zero-ed out region, compress it | ||
982 | * and remember to free it afterwards. | ||
983 | */ | ||
984 | tofree = 0; | ||
985 | if (!codec->reg_def_copy) | ||
986 | tofree = 1; | ||
987 | |||
988 | if (!codec->reg_def_copy) { | ||
989 | codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL); | ||
990 | if (!codec->reg_def_copy) | ||
991 | return -ENOMEM; | ||
992 | } | ||
993 | |||
994 | blkcount = snd_soc_lzo_block_count(); | ||
995 | codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks, | ||
996 | GFP_KERNEL); | ||
997 | if (!codec->reg_cache) { | ||
998 | ret = -ENOMEM; | ||
999 | goto err_tofree; | ||
1000 | } | ||
1001 | lzo_blocks = codec->reg_cache; | ||
1002 | |||
1003 | /* | ||
1004 | * allocate a bitmap to be used when syncing the cache with | ||
1005 | * the hardware. Each time a register is modified, the corresponding | ||
1006 | * bit is set in the bitmap, so we know that we have to sync | ||
1007 | * that register. | ||
1008 | */ | ||
1009 | bmp_size = codec_drv->reg_cache_size; | ||
1010 | sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long), | ||
1011 | GFP_KERNEL); | ||
1012 | if (!sync_bmp) { | ||
1013 | ret = -ENOMEM; | ||
1014 | goto err; | ||
1015 | } | ||
1016 | bitmap_zero(sync_bmp, bmp_size); | ||
1017 | |||
1018 | /* allocate the lzo blocks and initialize them */ | ||
1019 | for (i = 0; i < blkcount; ++i) { | ||
1020 | lzo_blocks[i] = kzalloc(sizeof **lzo_blocks, | ||
1021 | GFP_KERNEL); | ||
1022 | if (!lzo_blocks[i]) { | ||
1023 | kfree(sync_bmp); | ||
1024 | ret = -ENOMEM; | ||
1025 | goto err; | ||
1026 | } | ||
1027 | lzo_blocks[i]->sync_bmp = sync_bmp; | ||
1028 | lzo_blocks[i]->sync_bmp_nbits = bmp_size; | ||
1029 | /* alloc the working space for the compressed block */ | ||
1030 | ret = snd_soc_lzo_prepare(lzo_blocks[i]); | ||
1031 | if (ret < 0) | ||
1032 | goto err; | ||
1033 | } | ||
1034 | |||
1035 | blksize = snd_soc_lzo_get_blksize(codec); | ||
1036 | p = codec->reg_def_copy; | ||
1037 | end = codec->reg_def_copy + codec->reg_size; | ||
1038 | /* compress the register map and fill the lzo blocks */ | ||
1039 | for (i = 0; i < blkcount; ++i, p += blksize) { | ||
1040 | lzo_blocks[i]->src = p; | ||
1041 | if (p + blksize > end) | ||
1042 | lzo_blocks[i]->src_len = end - p; | ||
1043 | else | ||
1044 | lzo_blocks[i]->src_len = blksize; | ||
1045 | ret = snd_soc_lzo_compress_cache_block(codec, | ||
1046 | lzo_blocks[i]); | ||
1047 | if (ret < 0) | ||
1048 | goto err; | ||
1049 | lzo_blocks[i]->decompressed_size = | ||
1050 | lzo_blocks[i]->src_len; | ||
1051 | } | ||
1052 | |||
1053 | if (tofree) { | ||
1054 | kfree(codec->reg_def_copy); | ||
1055 | codec->reg_def_copy = NULL; | ||
1056 | } | ||
1057 | return 0; | ||
1058 | err: | ||
1059 | snd_soc_cache_exit(codec); | ||
1060 | err_tofree: | ||
1061 | if (tofree) { | ||
1062 | kfree(codec->reg_def_copy); | ||
1063 | codec->reg_def_copy = NULL; | ||
1064 | } | ||
1065 | return ret; | ||
1066 | } | ||
1067 | #endif | ||
1068 | |||
1069 | static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) | ||
1070 | { | ||
1071 | int i; | ||
1072 | int ret; | ||
1073 | const struct snd_soc_codec_driver *codec_drv; | ||
1074 | unsigned int val; | ||
1075 | |||
1076 | codec_drv = codec->driver; | ||
1077 | for (i = 0; i < codec_drv->reg_cache_size; ++i) { | ||
1078 | WARN_ON(codec->writable_register && | ||
1079 | codec->writable_register(codec, i)); | ||
1080 | ret = snd_soc_cache_read(codec, i, &val); | ||
1081 | if (ret) | ||
1082 | return ret; | ||
1083 | if (codec->reg_def_copy) | ||
1084 | if (snd_soc_get_cache_val(codec->reg_def_copy, | ||
1085 | i, codec_drv->reg_word_size) == val) | ||
1086 | continue; | ||
1087 | ret = snd_soc_write(codec, i, val); | ||
1088 | if (ret) | ||
1089 | return ret; | ||
1090 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", | ||
1091 | i, val); | ||
1092 | } | ||
1093 | return 0; | ||
1094 | } | ||
1095 | |||
1096 | static int snd_soc_flat_cache_write(struct snd_soc_codec *codec, | ||
1097 | unsigned int reg, unsigned int value) | ||
1098 | { | ||
1099 | snd_soc_set_cache_val(codec->reg_cache, reg, value, | ||
1100 | codec->driver->reg_word_size); | ||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | static int snd_soc_flat_cache_read(struct snd_soc_codec *codec, | ||
1105 | unsigned int reg, unsigned int *value) | ||
1106 | { | ||
1107 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, | ||
1108 | codec->driver->reg_word_size); | ||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1112 | static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec) | ||
1113 | { | ||
1114 | if (!codec->reg_cache) | ||
1115 | return 0; | ||
1116 | kfree(codec->reg_cache); | ||
1117 | codec->reg_cache = NULL; | ||
1118 | return 0; | ||
1119 | } | ||
1120 | |||
1121 | static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) | ||
1122 | { | ||
1123 | const struct snd_soc_codec_driver *codec_drv; | ||
1124 | |||
1125 | codec_drv = codec->driver; | ||
1126 | |||
1127 | if (codec->reg_def_copy) | ||
1128 | codec->reg_cache = kmemdup(codec->reg_def_copy, | ||
1129 | codec->reg_size, GFP_KERNEL); | ||
1130 | else | ||
1131 | codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL); | ||
1132 | if (!codec->reg_cache) | ||
1133 | return -ENOMEM; | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | /* an array of all supported compression types */ | ||
1139 | static const struct snd_soc_cache_ops cache_types[] = { | ||
1140 | /* Flat *must* be the first entry for fallback */ | ||
1141 | { | ||
1142 | .id = SND_SOC_FLAT_COMPRESSION, | ||
1143 | .name = "flat", | ||
1144 | .init = snd_soc_flat_cache_init, | ||
1145 | .exit = snd_soc_flat_cache_exit, | ||
1146 | .read = snd_soc_flat_cache_read, | ||
1147 | .write = snd_soc_flat_cache_write, | ||
1148 | .sync = snd_soc_flat_cache_sync | ||
1149 | }, | ||
1150 | #ifdef CONFIG_SND_SOC_CACHE_LZO | ||
1151 | { | ||
1152 | .id = SND_SOC_LZO_COMPRESSION, | ||
1153 | .name = "LZO", | ||
1154 | .init = snd_soc_lzo_cache_init, | ||
1155 | .exit = snd_soc_lzo_cache_exit, | ||
1156 | .read = snd_soc_lzo_cache_read, | ||
1157 | .write = snd_soc_lzo_cache_write, | ||
1158 | .sync = snd_soc_lzo_cache_sync | ||
1159 | }, | ||
1160 | #endif | ||
1161 | { | ||
1162 | .id = SND_SOC_RBTREE_COMPRESSION, | ||
1163 | .name = "rbtree", | ||
1164 | .init = snd_soc_rbtree_cache_init, | ||
1165 | .exit = snd_soc_rbtree_cache_exit, | ||
1166 | .read = snd_soc_rbtree_cache_read, | ||
1167 | .write = snd_soc_rbtree_cache_write, | ||
1168 | .sync = snd_soc_rbtree_cache_sync | ||
1169 | } | ||
1170 | }; | ||
1171 | |||
1172 | int snd_soc_cache_init(struct snd_soc_codec *codec) | ||
1173 | { | ||
1174 | int i; | ||
1175 | |||
1176 | for (i = 0; i < ARRAY_SIZE(cache_types); ++i) | ||
1177 | if (cache_types[i].id == codec->compress_type) | ||
1178 | break; | ||
1179 | |||
1180 | /* Fall back to flat compression */ | ||
1181 | if (i == ARRAY_SIZE(cache_types)) { | ||
1182 | dev_warn(codec->dev, "Could not match compress type: %d\n", | ||
1183 | codec->compress_type); | ||
1184 | i = 0; | ||
1185 | } | ||
1186 | |||
1187 | mutex_init(&codec->cache_rw_mutex); | ||
1188 | codec->cache_ops = &cache_types[i]; | ||
1189 | |||
1190 | if (codec->cache_ops->init) { | ||
1191 | if (codec->cache_ops->name) | ||
1192 | dev_dbg(codec->dev, "Initializing %s cache for %s codec\n", | ||
1193 | codec->cache_ops->name, codec->name); | ||
1194 | return codec->cache_ops->init(codec); | ||
1195 | } | ||
1196 | return -ENOSYS; | ||
1197 | } | ||
1198 | |||
1199 | /* | ||
1200 | * NOTE: keep in mind that this function might be called | ||
1201 | * multiple times. | ||
1202 | */ | ||
1203 | int snd_soc_cache_exit(struct snd_soc_codec *codec) | ||
1204 | { | ||
1205 | if (codec->cache_ops && codec->cache_ops->exit) { | ||
1206 | if (codec->cache_ops->name) | ||
1207 | dev_dbg(codec->dev, "Destroying %s cache for %s codec\n", | ||
1208 | codec->cache_ops->name, codec->name); | ||
1209 | return codec->cache_ops->exit(codec); | ||
1210 | } | ||
1211 | return -ENOSYS; | ||
1212 | } | ||
1213 | |||
1214 | /** | ||
1215 | * snd_soc_cache_read: Fetch the value of a given register from the cache. | ||
1216 | * | ||
1217 | * @codec: CODEC to configure. | ||
1218 | * @reg: The register index. | ||
1219 | * @value: The value to be returned. | ||
1220 | */ | ||
1221 | int snd_soc_cache_read(struct snd_soc_codec *codec, | ||
1222 | unsigned int reg, unsigned int *value) | ||
1223 | { | ||
1224 | int ret; | ||
1225 | |||
1226 | mutex_lock(&codec->cache_rw_mutex); | ||
1227 | |||
1228 | if (value && codec->cache_ops && codec->cache_ops->read) { | ||
1229 | ret = codec->cache_ops->read(codec, reg, value); | ||
1230 | mutex_unlock(&codec->cache_rw_mutex); | ||
1231 | return ret; | ||
1232 | } | ||
1233 | |||
1234 | mutex_unlock(&codec->cache_rw_mutex); | ||
1235 | return -ENOSYS; | ||
1236 | } | ||
1237 | EXPORT_SYMBOL_GPL(snd_soc_cache_read); | ||
1238 | |||
1239 | /** | ||
1240 | * snd_soc_cache_write: Set the value of a given register in the cache. | ||
1241 | * | ||
1242 | * @codec: CODEC to configure. | ||
1243 | * @reg: The register index. | ||
1244 | * @value: The new register value. | ||
1245 | */ | ||
1246 | int snd_soc_cache_write(struct snd_soc_codec *codec, | ||
1247 | unsigned int reg, unsigned int value) | ||
1248 | { | ||
1249 | int ret; | ||
1250 | |||
1251 | mutex_lock(&codec->cache_rw_mutex); | ||
1252 | |||
1253 | if (codec->cache_ops && codec->cache_ops->write) { | ||
1254 | ret = codec->cache_ops->write(codec, reg, value); | ||
1255 | mutex_unlock(&codec->cache_rw_mutex); | ||
1256 | return ret; | ||
1257 | } | ||
1258 | |||
1259 | mutex_unlock(&codec->cache_rw_mutex); | ||
1260 | return -ENOSYS; | ||
1261 | } | ||
1262 | EXPORT_SYMBOL_GPL(snd_soc_cache_write); | ||
1263 | |||
1264 | /** | ||
1265 | * snd_soc_cache_sync: Sync the register cache with the hardware. | ||
1266 | * | ||
1267 | * @codec: CODEC to configure. | ||
1268 | * | ||
1269 | * Any registers that should not be synced should be marked as | ||
1270 | * volatile. In general drivers can choose not to use the provided | ||
1271 | * syncing functionality if they so require. | ||
1272 | */ | ||
1273 | int snd_soc_cache_sync(struct snd_soc_codec *codec) | ||
1274 | { | ||
1275 | int ret; | ||
1276 | const char *name; | ||
1277 | |||
1278 | if (!codec->cache_sync) { | ||
1279 | return 0; | ||
1280 | } | ||
1281 | |||
1282 | if (!codec->cache_ops || !codec->cache_ops->sync) | ||
1283 | return -ENOSYS; | ||
1284 | |||
1285 | if (codec->cache_ops->name) | ||
1286 | name = codec->cache_ops->name; | ||
1287 | else | ||
1288 | name = "unknown"; | ||
1289 | |||
1290 | if (codec->cache_ops->name) | ||
1291 | dev_dbg(codec->dev, "Syncing %s cache for %s codec\n", | ||
1292 | codec->cache_ops->name, codec->name); | ||
1293 | trace_snd_soc_cache_sync(codec, name, "start"); | ||
1294 | ret = codec->cache_ops->sync(codec); | ||
1295 | if (!ret) | ||
1296 | codec->cache_sync = 0; | ||
1297 | trace_snd_soc_cache_sync(codec, name, "end"); | ||
1298 | return ret; | ||
1299 | } | ||
1300 | EXPORT_SYMBOL_GPL(snd_soc_cache_sync); | ||
1301 | |||
1302 | static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec, | ||
1303 | unsigned int reg) | ||
1304 | { | ||
1305 | const struct snd_soc_codec_driver *codec_drv; | ||
1306 | unsigned int min, max, index; | ||
1307 | |||
1308 | codec_drv = codec->driver; | ||
1309 | min = 0; | ||
1310 | max = codec_drv->reg_access_size - 1; | ||
1311 | do { | ||
1312 | index = (min + max) / 2; | ||
1313 | if (codec_drv->reg_access_default[index].reg == reg) | ||
1314 | return index; | ||
1315 | if (codec_drv->reg_access_default[index].reg < reg) | ||
1316 | min = index + 1; | ||
1317 | else | ||
1318 | max = index; | ||
1319 | } while (min <= max); | ||
1320 | return -1; | ||
1321 | } | ||
1322 | |||
1323 | int snd_soc_default_volatile_register(struct snd_soc_codec *codec, | ||
1324 | unsigned int reg) | ||
1325 | { | ||
1326 | int index; | ||
1327 | |||
1328 | if (reg >= codec->driver->reg_cache_size) | ||
1329 | return 1; | ||
1330 | index = snd_soc_get_reg_access_index(codec, reg); | ||
1331 | if (index < 0) | ||
1332 | return 0; | ||
1333 | return codec->driver->reg_access_default[index].vol; | ||
1334 | } | ||
1335 | EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register); | ||
1336 | |||
1337 | int snd_soc_default_readable_register(struct snd_soc_codec *codec, | ||
1338 | unsigned int reg) | ||
1339 | { | ||
1340 | int index; | ||
1341 | |||
1342 | if (reg >= codec->driver->reg_cache_size) | ||
1343 | return 1; | ||
1344 | index = snd_soc_get_reg_access_index(codec, reg); | ||
1345 | if (index < 0) | ||
1346 | return 0; | ||
1347 | return codec->driver->reg_access_default[index].read; | ||
1348 | } | ||
1349 | EXPORT_SYMBOL_GPL(snd_soc_default_readable_register); | ||
1350 | |||
1351 | int snd_soc_default_writable_register(struct snd_soc_codec *codec, | ||
1352 | unsigned int reg) | ||
1353 | { | ||
1354 | int index; | ||
1355 | |||
1356 | if (reg >= codec->driver->reg_cache_size) | ||
1357 | return 1; | ||
1358 | index = snd_soc_get_reg_access_index(codec, reg); | ||
1359 | if (index < 0) | ||
1360 | return 0; | ||
1361 | return codec->driver->reg_access_default[index].write; | ||
1362 | } | ||
1363 | EXPORT_SYMBOL_GPL(snd_soc_default_writable_register); | ||