blob: 6c0589e3fefba887059ff1ea0a5631fbd943c0f7 [file] [log] [blame]
Mark Brown17a52fd2009-07-05 17:24:50 +01001/*
2 * soc-cache.c -- ASoC register cache helpers
3 *
4 * Copyright 2009 Wolfson Microelectronics PLC.
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
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.
12 */
13
Mark Brown7084a422009-07-10 22:24:27 +010014#include <linux/i2c.h>
Mark Brown27ded042009-07-10 23:28:16 +010015#include <linux/spi/spi.h>
Mark Brown17a52fd2009-07-05 17:24:50 +010016#include <sound/soc.h>
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +000017#include <linux/lzo.h>
18#include <linux/bitmap.h>
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +000019#include <linux/rbtree.h>
Mark Brown17a52fd2009-07-05 17:24:50 +010020
Barry Song63b62ab2010-01-27 11:46:17 +080021static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
22 unsigned int reg)
23{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000024 int ret;
25 unsigned int val;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010026
27 if (reg >= codec->driver->reg_cache_size ||
28 snd_soc_codec_volatile_register(codec, reg)) {
29 if (codec->cache_only)
30 return -1;
31
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +000032 BUG_ON(!codec->hw_read);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010033 return codec->hw_read(codec, reg);
34 }
35
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000036 ret = snd_soc_cache_read(codec, reg, &val);
37 if (ret < 0)
38 return -1;
39 return val;
Barry Song63b62ab2010-01-27 11:46:17 +080040}
41
42static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
43 unsigned int value)
44{
Barry Song63b62ab2010-01-27 11:46:17 +080045 u8 data[2];
46 int ret;
47
Barry Song63b62ab2010-01-27 11:46:17 +080048 data[0] = (reg << 4) | ((value >> 8) & 0x000f);
49 data[1] = value & 0x00ff;
50
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010051 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000052 reg < codec->driver->reg_cache_size) {
53 ret = snd_soc_cache_write(codec, reg, value);
54 if (ret < 0)
55 return -1;
56 }
Mark Brown8c961bc2010-02-01 18:46:10 +000057
Mark Browna3032b42010-02-01 18:48:03 +000058 if (codec->cache_only) {
59 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +000060 return 0;
Mark Browna3032b42010-02-01 18:48:03 +000061 }
Mark Brown8c961bc2010-02-01 18:46:10 +000062
Barry Song63b62ab2010-01-27 11:46:17 +080063 ret = codec->hw_write(codec->control_data, data, 2);
64 if (ret == 2)
65 return 0;
66 if (ret < 0)
67 return ret;
68 else
69 return -EIO;
70}
71
72#if defined(CONFIG_SPI_MASTER)
73static int snd_soc_4_12_spi_write(void *control_data, const char *data,
74 int len)
75{
76 struct spi_device *spi = control_data;
77 struct spi_transfer t;
78 struct spi_message m;
79 u8 msg[2];
80
81 if (len <= 0)
82 return 0;
83
84 msg[0] = data[1];
85 msg[1] = data[0];
86
87 spi_message_init(&m);
88 memset(&t, 0, (sizeof t));
89
90 t.tx_buf = &msg[0];
91 t.len = len;
92
93 spi_message_add_tail(&t, &m);
94 spi_sync(spi, &m);
95
96 return len;
97}
98#else
99#define snd_soc_4_12_spi_write NULL
100#endif
101
Mark Brown17a52fd2009-07-05 17:24:50 +0100102static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
103 unsigned int reg)
104{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000105 int ret;
106 unsigned int val;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100107
108 if (reg >= codec->driver->reg_cache_size ||
109 snd_soc_codec_volatile_register(codec, reg)) {
110 if (codec->cache_only)
111 return -1;
112
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +0000113 BUG_ON(!codec->hw_read);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100114 return codec->hw_read(codec, reg);
115 }
116
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000117 ret = snd_soc_cache_read(codec, reg, &val);
118 if (ret < 0)
119 return -1;
120 return val;
Mark Brown17a52fd2009-07-05 17:24:50 +0100121}
122
123static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
124 unsigned int value)
125{
Mark Brown17a52fd2009-07-05 17:24:50 +0100126 u8 data[2];
127 int ret;
128
Mark Brown17a52fd2009-07-05 17:24:50 +0100129 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
130 data[1] = value & 0x00ff;
131
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100132 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000133 reg < codec->driver->reg_cache_size) {
134 ret = snd_soc_cache_write(codec, reg, value);
135 if (ret < 0)
136 return -1;
137 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000138
Mark Browna3032b42010-02-01 18:48:03 +0000139 if (codec->cache_only) {
140 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000141 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000142 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000143
Mark Brown17a52fd2009-07-05 17:24:50 +0100144 ret = codec->hw_write(codec->control_data, data, 2);
145 if (ret == 2)
146 return 0;
147 if (ret < 0)
148 return ret;
149 else
150 return -EIO;
151}
152
Mark Brown27ded042009-07-10 23:28:16 +0100153#if defined(CONFIG_SPI_MASTER)
154static int snd_soc_7_9_spi_write(void *control_data, const char *data,
155 int len)
156{
157 struct spi_device *spi = control_data;
158 struct spi_transfer t;
159 struct spi_message m;
160 u8 msg[2];
161
162 if (len <= 0)
163 return 0;
164
165 msg[0] = data[0];
166 msg[1] = data[1];
167
168 spi_message_init(&m);
169 memset(&t, 0, (sizeof t));
170
171 t.tx_buf = &msg[0];
172 t.len = len;
173
174 spi_message_add_tail(&t, &m);
175 spi_sync(spi, &m);
176
177 return len;
178}
179#else
180#define snd_soc_7_9_spi_write NULL
181#endif
182
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900183static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
184 unsigned int value)
185{
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900186 u8 data[2];
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000187 int ret;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900188
Barry Songf4bee1b2010-03-18 16:17:01 +0800189 reg &= 0xff;
190 data[0] = reg;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900191 data[1] = value & 0xff;
192
Dimitris Papastamos005d65f2010-09-22 16:16:06 +0100193 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000194 reg < codec->driver->reg_cache_size) {
195 ret = snd_soc_cache_write(codec, reg, value);
196 if (ret < 0)
197 return -1;
198 }
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900199
Mark Browna3032b42010-02-01 18:48:03 +0000200 if (codec->cache_only) {
201 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000202 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000203 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000204
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900205 if (codec->hw_write(codec->control_data, data, 2) == 2)
206 return 0;
207 else
208 return -EIO;
209}
210
211static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
212 unsigned int reg)
213{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000214 int ret;
215 unsigned int val;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100216
Barry Songf4bee1b2010-03-18 16:17:01 +0800217 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100218 if (reg >= codec->driver->reg_cache_size ||
219 snd_soc_codec_volatile_register(codec, reg)) {
220 if (codec->cache_only)
221 return -1;
222
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +0000223 BUG_ON(!codec->hw_read);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100224 return codec->hw_read(codec, reg);
225 }
226
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000227 ret = snd_soc_cache_read(codec, reg, &val);
228 if (ret < 0)
229 return -1;
230 return val;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900231}
232
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100233#if defined(CONFIG_SPI_MASTER)
234static int snd_soc_8_8_spi_write(void *control_data, const char *data,
235 int len)
236{
237 struct spi_device *spi = control_data;
238 struct spi_transfer t;
239 struct spi_message m;
240 u8 msg[2];
241
242 if (len <= 0)
243 return 0;
244
245 msg[0] = data[0];
246 msg[1] = data[1];
247
248 spi_message_init(&m);
249 memset(&t, 0, (sizeof t));
250
251 t.tx_buf = &msg[0];
252 t.len = len;
253
254 spi_message_add_tail(&t, &m);
255 spi_sync(spi, &m);
256
257 return len;
258}
259#else
260#define snd_soc_8_8_spi_write NULL
261#endif
262
Mark Brownafa2f102009-07-10 23:11:24 +0100263static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
264 unsigned int value)
265{
Mark Brownafa2f102009-07-10 23:11:24 +0100266 u8 data[3];
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000267 int ret;
Mark Brownafa2f102009-07-10 23:11:24 +0100268
269 data[0] = reg;
270 data[1] = (value >> 8) & 0xff;
271 data[2] = value & 0xff;
272
Takashi Iwai3e13f652010-09-23 07:40:16 +0200273 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000274 reg < codec->driver->reg_cache_size) {
275 ret = snd_soc_cache_write(codec, reg, value);
276 if (ret < 0)
277 return -1;
278 }
Mark Brownafa2f102009-07-10 23:11:24 +0100279
Mark Browna3032b42010-02-01 18:48:03 +0000280 if (codec->cache_only) {
281 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000282 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000283 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000284
Mark Brownafa2f102009-07-10 23:11:24 +0100285 if (codec->hw_write(codec->control_data, data, 3) == 3)
286 return 0;
287 else
288 return -EIO;
289}
290
291static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
292 unsigned int reg)
293{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000294 int ret;
295 unsigned int val;
Mark Brownafa2f102009-07-10 23:11:24 +0100296
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000297 if (reg >= codec->driver->reg_cache_size ||
Mark Brown8c961bc2010-02-01 18:46:10 +0000298 snd_soc_codec_volatile_register(codec, reg)) {
299 if (codec->cache_only)
Dimitris Papastamos391d8a02010-09-21 17:04:07 +0100300 return -1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000301
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +0000302 BUG_ON(!codec->hw_read);
Mark Brownafa2f102009-07-10 23:11:24 +0100303 return codec->hw_read(codec, reg);
Mark Brown8c961bc2010-02-01 18:46:10 +0000304 }
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000305
306 ret = snd_soc_cache_read(codec, reg, &val);
307 if (ret < 0)
308 return -1;
309 return val;
Mark Brownafa2f102009-07-10 23:11:24 +0100310}
311
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100312#if defined(CONFIG_SPI_MASTER)
313static int snd_soc_8_16_spi_write(void *control_data, const char *data,
314 int len)
315{
316 struct spi_device *spi = control_data;
317 struct spi_transfer t;
318 struct spi_message m;
319 u8 msg[3];
320
321 if (len <= 0)
322 return 0;
323
324 msg[0] = data[0];
325 msg[1] = data[1];
326 msg[2] = data[2];
327
328 spi_message_init(&m);
329 memset(&t, 0, (sizeof t));
330
331 t.tx_buf = &msg[0];
332 t.len = len;
333
334 spi_message_add_tail(&t, &m);
335 spi_sync(spi, &m);
336
337 return len;
338}
339#else
340#define snd_soc_8_16_spi_write NULL
341#endif
342
Randy Dunlap17244c22009-08-10 16:04:39 -0700343#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800344static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
345 unsigned int r)
346{
347 struct i2c_msg xfer[2];
348 u8 reg = r;
349 u8 data;
350 int ret;
351 struct i2c_client *client = codec->control_data;
352
353 /* Write register */
354 xfer[0].addr = client->addr;
355 xfer[0].flags = 0;
356 xfer[0].len = 1;
357 xfer[0].buf = &reg;
358
359 /* Read data */
360 xfer[1].addr = client->addr;
361 xfer[1].flags = I2C_M_RD;
362 xfer[1].len = 1;
363 xfer[1].buf = &data;
364
365 ret = i2c_transfer(client->adapter, xfer, 2);
366 if (ret != 2) {
367 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
368 return 0;
369 }
370
371 return data;
372}
373#else
374#define snd_soc_8_8_read_i2c NULL
375#endif
376
377#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100378static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
379 unsigned int r)
380{
381 struct i2c_msg xfer[2];
382 u8 reg = r;
383 u16 data;
384 int ret;
385 struct i2c_client *client = codec->control_data;
386
387 /* Write register */
388 xfer[0].addr = client->addr;
389 xfer[0].flags = 0;
390 xfer[0].len = 1;
391 xfer[0].buf = &reg;
392
393 /* Read data */
394 xfer[1].addr = client->addr;
395 xfer[1].flags = I2C_M_RD;
396 xfer[1].len = 2;
397 xfer[1].buf = (u8 *)&data;
398
399 ret = i2c_transfer(client->adapter, xfer, 2);
400 if (ret != 2) {
401 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
402 return 0;
403 }
404
405 return (data >> 8) | ((data & 0xff) << 8);
406}
407#else
408#define snd_soc_8_16_read_i2c NULL
409#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100410
Barry Song994dc422010-01-27 11:46:18 +0800411#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
412static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
413 unsigned int r)
414{
415 struct i2c_msg xfer[2];
416 u16 reg = r;
417 u8 data;
418 int ret;
419 struct i2c_client *client = codec->control_data;
420
421 /* Write register */
422 xfer[0].addr = client->addr;
423 xfer[0].flags = 0;
424 xfer[0].len = 2;
425 xfer[0].buf = (u8 *)&reg;
426
427 /* Read data */
428 xfer[1].addr = client->addr;
429 xfer[1].flags = I2C_M_RD;
430 xfer[1].len = 1;
431 xfer[1].buf = &data;
432
433 ret = i2c_transfer(client->adapter, xfer, 2);
434 if (ret != 2) {
435 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
436 return 0;
437 }
438
439 return data;
440}
441#else
442#define snd_soc_16_8_read_i2c NULL
443#endif
444
445static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
446 unsigned int reg)
447{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000448 int ret;
449 unsigned int val;
Barry Song994dc422010-01-27 11:46:18 +0800450
451 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100452 if (reg >= codec->driver->reg_cache_size ||
453 snd_soc_codec_volatile_register(codec, reg)) {
454 if (codec->cache_only)
455 return -1;
456
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +0000457 BUG_ON(!codec->hw_read);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100458 return codec->hw_read(codec, reg);
459 }
460
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000461 ret = snd_soc_cache_read(codec, reg, &val);
462 if (ret < 0)
463 return -1;
464 return val;
Barry Song994dc422010-01-27 11:46:18 +0800465}
466
467static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
468 unsigned int value)
469{
Barry Song994dc422010-01-27 11:46:18 +0800470 u8 data[3];
471 int ret;
472
Barry Song994dc422010-01-27 11:46:18 +0800473 data[0] = (reg >> 8) & 0xff;
474 data[1] = reg & 0xff;
475 data[2] = value;
476
477 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100478 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000479 reg < codec->driver->reg_cache_size) {
480 ret = snd_soc_cache_write(codec, reg, value);
481 if (ret < 0)
482 return -1;
483 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000484
Mark Browna3032b42010-02-01 18:48:03 +0000485 if (codec->cache_only) {
486 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000487 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000488 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000489
Barry Song994dc422010-01-27 11:46:18 +0800490 ret = codec->hw_write(codec->control_data, data, 3);
491 if (ret == 3)
492 return 0;
493 if (ret < 0)
494 return ret;
495 else
496 return -EIO;
497}
498
499#if defined(CONFIG_SPI_MASTER)
500static int snd_soc_16_8_spi_write(void *control_data, const char *data,
501 int len)
502{
503 struct spi_device *spi = control_data;
504 struct spi_transfer t;
505 struct spi_message m;
506 u8 msg[3];
507
508 if (len <= 0)
509 return 0;
510
511 msg[0] = data[0];
512 msg[1] = data[1];
513 msg[2] = data[2];
514
515 spi_message_init(&m);
516 memset(&t, 0, (sizeof t));
517
518 t.tx_buf = &msg[0];
519 t.len = len;
520
521 spi_message_add_tail(&t, &m);
522 spi_sync(spi, &m);
523
524 return len;
525}
526#else
527#define snd_soc_16_8_spi_write NULL
528#endif
529
Mark Brownbc6552f2010-03-05 16:27:15 +0000530#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
531static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
532 unsigned int r)
533{
534 struct i2c_msg xfer[2];
535 u16 reg = cpu_to_be16(r);
536 u16 data;
537 int ret;
538 struct i2c_client *client = codec->control_data;
539
540 /* Write register */
541 xfer[0].addr = client->addr;
542 xfer[0].flags = 0;
543 xfer[0].len = 2;
544 xfer[0].buf = (u8 *)&reg;
545
546 /* Read data */
547 xfer[1].addr = client->addr;
548 xfer[1].flags = I2C_M_RD;
549 xfer[1].len = 2;
550 xfer[1].buf = (u8 *)&data;
551
552 ret = i2c_transfer(client->adapter, xfer, 2);
553 if (ret != 2) {
554 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
555 return 0;
556 }
557
558 return be16_to_cpu(data);
559}
560#else
561#define snd_soc_16_16_read_i2c NULL
562#endif
563
564static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
565 unsigned int reg)
566{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000567 int ret;
568 unsigned int val;
Mark Brownbc6552f2010-03-05 16:27:15 +0000569
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000570 if (reg >= codec->driver->reg_cache_size ||
Mark Brownbc6552f2010-03-05 16:27:15 +0000571 snd_soc_codec_volatile_register(codec, reg)) {
572 if (codec->cache_only)
Dimitris Papastamos391d8a02010-09-21 17:04:07 +0100573 return -1;
Mark Brownbc6552f2010-03-05 16:27:15 +0000574
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +0000575 BUG_ON(!codec->hw_read);
Mark Brownbc6552f2010-03-05 16:27:15 +0000576 return codec->hw_read(codec, reg);
577 }
578
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000579 ret = snd_soc_cache_read(codec, reg, &val);
580 if (ret < 0)
581 return -1;
582
583 return val;
Mark Brownbc6552f2010-03-05 16:27:15 +0000584}
585
586static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
587 unsigned int value)
588{
Mark Brownbc6552f2010-03-05 16:27:15 +0000589 u8 data[4];
590 int ret;
591
592 data[0] = (reg >> 8) & 0xff;
593 data[1] = reg & 0xff;
594 data[2] = (value >> 8) & 0xff;
595 data[3] = value & 0xff;
596
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100597 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000598 reg < codec->driver->reg_cache_size) {
599 ret = snd_soc_cache_write(codec, reg, value);
600 if (ret < 0)
601 return -1;
602 }
Mark Brownbc6552f2010-03-05 16:27:15 +0000603
604 if (codec->cache_only) {
605 codec->cache_sync = 1;
606 return 0;
607 }
608
609 ret = codec->hw_write(codec->control_data, data, 4);
610 if (ret == 4)
611 return 0;
612 if (ret < 0)
613 return ret;
614 else
615 return -EIO;
616}
Barry Song994dc422010-01-27 11:46:18 +0800617
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100618#if defined(CONFIG_SPI_MASTER)
619static int snd_soc_16_16_spi_write(void *control_data, const char *data,
620 int len)
621{
622 struct spi_device *spi = control_data;
623 struct spi_transfer t;
624 struct spi_message m;
625 u8 msg[4];
626
627 if (len <= 0)
628 return 0;
629
630 msg[0] = data[0];
631 msg[1] = data[1];
632 msg[2] = data[2];
633 msg[3] = data[3];
634
635 spi_message_init(&m);
636 memset(&t, 0, (sizeof t));
637
638 t.tx_buf = &msg[0];
639 t.len = len;
640
641 spi_message_add_tail(&t, &m);
642 spi_sync(spi, &m);
643
644 return len;
645}
646#else
647#define snd_soc_16_16_spi_write NULL
648#endif
649
Mark Brown17a52fd2009-07-05 17:24:50 +0100650static struct {
651 int addr_bits;
652 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100653 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown27ded042009-07-10 23:28:16 +0100654 int (*spi_write)(void *, const char *, int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100655 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100656 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100657} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700658 {
Barry Song63b62ab2010-01-27 11:46:17 +0800659 .addr_bits = 4, .data_bits = 12,
660 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
661 .spi_write = snd_soc_4_12_spi_write,
662 },
663 {
Mark Brownd62ab352009-09-21 04:21:47 -0700664 .addr_bits = 7, .data_bits = 9,
665 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Barry Song8998c892009-12-31 10:30:34 +0800666 .spi_write = snd_soc_7_9_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700667 },
668 {
669 .addr_bits = 8, .data_bits = 8,
670 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800671 .i2c_read = snd_soc_8_8_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100672 .spi_write = snd_soc_8_8_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700673 },
674 {
675 .addr_bits = 8, .data_bits = 16,
676 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
677 .i2c_read = snd_soc_8_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100678 .spi_write = snd_soc_8_16_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700679 },
Barry Song994dc422010-01-27 11:46:18 +0800680 {
681 .addr_bits = 16, .data_bits = 8,
682 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
683 .i2c_read = snd_soc_16_8_read_i2c,
684 .spi_write = snd_soc_16_8_spi_write,
685 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000686 {
687 .addr_bits = 16, .data_bits = 16,
688 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
689 .i2c_read = snd_soc_16_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100690 .spi_write = snd_soc_16_16_spi_write,
Mark Brownbc6552f2010-03-05 16:27:15 +0000691 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100692};
693
694/**
695 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
696 *
697 * @codec: CODEC to configure.
698 * @type: Type of cache.
699 * @addr_bits: Number of bits of register address data.
700 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100701 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100702 *
703 * Register formats are frequently shared between many I2C and SPI
704 * devices. In order to promote code reuse the ASoC core provides
705 * some standard implementations of CODEC read and write operations
706 * which can be set up using this function.
707 *
708 * The caller is responsible for allocating and initialising the
709 * actual cache.
710 *
711 * Note that at present this code cannot be used by CODECs with
712 * volatile registers.
713 */
714int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100715 int addr_bits, int data_bits,
716 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100717{
718 int i;
719
Mark Brown17a52fd2009-07-05 17:24:50 +0100720 for (i = 0; i < ARRAY_SIZE(io_types); i++)
721 if (io_types[i].addr_bits == addr_bits &&
722 io_types[i].data_bits == data_bits)
723 break;
724 if (i == ARRAY_SIZE(io_types)) {
725 printk(KERN_ERR
726 "No I/O functions for %d bit address %d bit data\n",
727 addr_bits, data_bits);
728 return -EINVAL;
729 }
730
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000731 codec->driver->write = io_types[i].write;
732 codec->driver->read = io_types[i].read;
Mark Brown17a52fd2009-07-05 17:24:50 +0100733
Mark Brown7084a422009-07-10 22:24:27 +0100734 switch (control) {
735 case SND_SOC_CUSTOM:
736 break;
737
738 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700739#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100740 codec->hw_write = (hw_write_t)i2c_master_send;
741#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100742 if (io_types[i].i2c_read)
743 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100744
745 codec->control_data = container_of(codec->dev,
746 struct i2c_client,
747 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100748 break;
749
750 case SND_SOC_SPI:
Mark Brown27ded042009-07-10 23:28:16 +0100751 if (io_types[i].spi_write)
752 codec->hw_write = io_types[i].spi_write;
Mark Browna6d14342010-08-12 10:59:15 +0100753
754 codec->control_data = container_of(codec->dev,
755 struct spi_device,
756 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100757 break;
758 }
759
Mark Brown17a52fd2009-07-05 17:24:50 +0100760 return 0;
761}
762EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000763
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000764struct snd_soc_rbtree_node {
765 struct rb_node node;
766 unsigned int reg;
767 unsigned int value;
768 unsigned int defval;
769} __attribute__ ((packed));
770
771struct snd_soc_rbtree_ctx {
772 struct rb_root root;
773};
774
775static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
776 struct rb_root *root, unsigned int reg)
777{
778 struct rb_node *node;
779 struct snd_soc_rbtree_node *rbnode;
780
781 node = root->rb_node;
782 while (node) {
783 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
784 if (rbnode->reg < reg)
785 node = node->rb_left;
786 else if (rbnode->reg > reg)
787 node = node->rb_right;
788 else
789 return rbnode;
790 }
791
792 return NULL;
793}
794
795
796static int snd_soc_rbtree_insert(struct rb_root *root,
797 struct snd_soc_rbtree_node *rbnode)
798{
799 struct rb_node **new, *parent;
800 struct snd_soc_rbtree_node *rbnode_tmp;
801
802 parent = NULL;
803 new = &root->rb_node;
804 while (*new) {
805 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
806 node);
807 parent = *new;
808 if (rbnode_tmp->reg < rbnode->reg)
809 new = &((*new)->rb_left);
810 else if (rbnode_tmp->reg > rbnode->reg)
811 new = &((*new)->rb_right);
812 else
813 return 0;
814 }
815
816 /* insert the node into the rbtree */
817 rb_link_node(&rbnode->node, parent, new);
818 rb_insert_color(&rbnode->node, root);
819
820 return 1;
821}
822
823static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
824{
825 struct snd_soc_rbtree_ctx *rbtree_ctx;
826 struct rb_node *node;
827 struct snd_soc_rbtree_node *rbnode;
828 unsigned int val;
829
830 rbtree_ctx = codec->reg_cache;
831 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
832 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
833 if (rbnode->value == rbnode->defval)
834 continue;
835 snd_soc_cache_read(codec, rbnode->reg, &val);
836 snd_soc_write(codec, rbnode->reg, val);
837 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
838 rbnode->reg, val);
839 }
840
841 return 0;
842}
843
844static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
845 unsigned int reg, unsigned int value)
846{
847 struct snd_soc_rbtree_ctx *rbtree_ctx;
848 struct snd_soc_rbtree_node *rbnode;
849
850 rbtree_ctx = codec->reg_cache;
851 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
852 if (rbnode) {
853 if (rbnode->value == value)
854 return 0;
855 rbnode->value = value;
856 } else {
857 /* bail out early, no need to create the rbnode yet */
858 if (!value)
859 return 0;
860 /*
861 * for uninitialized registers whose value is changed
862 * from the default zero, create an rbnode and insert
863 * it into the tree.
864 */
865 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
866 if (!rbnode)
867 return -ENOMEM;
868 rbnode->reg = reg;
869 rbnode->value = value;
870 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
871 }
872
873 return 0;
874}
875
876static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
877 unsigned int reg, unsigned int *value)
878{
879 struct snd_soc_rbtree_ctx *rbtree_ctx;
880 struct snd_soc_rbtree_node *rbnode;
881
882 rbtree_ctx = codec->reg_cache;
883 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
884 if (rbnode) {
885 *value = rbnode->value;
886 } else {
887 /* uninitialized registers default to 0 */
888 *value = 0;
889 }
890
891 return 0;
892}
893
894static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
895{
896 struct rb_node *next;
897 struct snd_soc_rbtree_ctx *rbtree_ctx;
898 struct snd_soc_rbtree_node *rbtree_node;
899
900 /* if we've already been called then just return */
901 rbtree_ctx = codec->reg_cache;
902 if (!rbtree_ctx)
903 return 0;
904
905 /* free up the rbtree */
906 next = rb_first(&rbtree_ctx->root);
907 while (next) {
908 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
909 next = rb_next(&rbtree_node->node);
910 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
911 kfree(rbtree_node);
912 }
913
914 /* release the resources */
915 kfree(codec->reg_cache);
916 codec->reg_cache = NULL;
917
918 return 0;
919}
920
921static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
922{
923 struct snd_soc_rbtree_ctx *rbtree_ctx;
924
925 codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
926 if (!codec->reg_cache)
927 return -ENOMEM;
928
929 rbtree_ctx = codec->reg_cache;
930 rbtree_ctx->root = RB_ROOT;
931
932 if (!codec->driver->reg_cache_default)
933 return 0;
934
935/*
936 * populate the rbtree with the initialized registers. All other
937 * registers will be inserted into the tree when they are first written.
938 *
939 * The reasoning behind this, is that we need to step through and
940 * dereference the cache in u8/u16 increments without sacrificing
941 * portability. This could also be done using memcpy() but that would
942 * be slightly more cryptic.
943 */
944#define snd_soc_rbtree_populate(cache) \
945({ \
946 int ret, i; \
947 struct snd_soc_rbtree_node *rbtree_node; \
948 \
949 ret = 0; \
950 cache = codec->driver->reg_cache_default; \
951 for (i = 0; i < codec->driver->reg_cache_size; ++i) { \
952 if (!cache[i]) \
953 continue; \
954 rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); \
955 if (!rbtree_node) { \
956 ret = -ENOMEM; \
957 snd_soc_cache_exit(codec); \
958 break; \
959 } \
960 rbtree_node->reg = i; \
961 rbtree_node->value = cache[i]; \
962 rbtree_node->defval = cache[i]; \
963 snd_soc_rbtree_insert(&rbtree_ctx->root, \
964 rbtree_node); \
965 } \
966 ret; \
967})
968
969 switch (codec->driver->reg_word_size) {
970 case 1: {
971 const u8 *cache;
972
973 return snd_soc_rbtree_populate(cache);
974 }
975 case 2: {
976 const u16 *cache;
977
978 return snd_soc_rbtree_populate(cache);
979 }
980 default:
981 BUG();
982 }
983
984 return 0;
985}
986
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000987struct snd_soc_lzo_ctx {
988 void *wmem;
989 void *dst;
990 const void *src;
991 size_t src_len;
992 size_t dst_len;
993 size_t decompressed_size;
994 unsigned long *sync_bmp;
995 int sync_bmp_nbits;
996};
997
998#define LZO_BLOCK_NUM 8
999static int snd_soc_lzo_block_count(void)
1000{
1001 return LZO_BLOCK_NUM;
1002}
1003
1004static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx)
1005{
1006 lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
1007 if (!lzo_ctx->wmem)
1008 return -ENOMEM;
1009 return 0;
1010}
1011
1012static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx)
1013{
1014 size_t compress_size;
1015 int ret;
1016
1017 ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
1018 lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
1019 if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
1020 return -EINVAL;
1021 lzo_ctx->dst_len = compress_size;
1022 return 0;
1023}
1024
1025static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx)
1026{
1027 size_t dst_len;
1028 int ret;
1029
1030 dst_len = lzo_ctx->dst_len;
1031 ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
1032 lzo_ctx->dst, &dst_len);
1033 if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
1034 return -EINVAL;
1035 return 0;
1036}
1037
1038static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec,
1039 struct snd_soc_lzo_ctx *lzo_ctx)
1040{
1041 int ret;
1042
1043 lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
1044 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
1045 if (!lzo_ctx->dst) {
1046 lzo_ctx->dst_len = 0;
1047 return -ENOMEM;
1048 }
1049
1050 ret = snd_soc_lzo_compress(lzo_ctx);
1051 if (ret < 0)
1052 return ret;
1053 return 0;
1054}
1055
1056static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec,
1057 struct snd_soc_lzo_ctx *lzo_ctx)
1058{
1059 int ret;
1060
1061 lzo_ctx->dst_len = lzo_ctx->decompressed_size;
1062 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
1063 if (!lzo_ctx->dst) {
1064 lzo_ctx->dst_len = 0;
1065 return -ENOMEM;
1066 }
1067
1068 ret = snd_soc_lzo_decompress(lzo_ctx);
1069 if (ret < 0)
1070 return ret;
1071 return 0;
1072}
1073
1074static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
1075 unsigned int reg)
1076{
1077 struct snd_soc_codec_driver *codec_drv;
1078 size_t reg_size;
1079
1080 codec_drv = codec->driver;
1081 reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
1082 return (reg * codec_drv->reg_word_size) /
1083 DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count());
1084}
1085
1086static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
1087 unsigned int reg)
1088{
1089 struct snd_soc_codec_driver *codec_drv;
1090 size_t reg_size;
1091
1092 codec_drv = codec->driver;
1093 reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
1094 return reg % (DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count()) /
1095 codec_drv->reg_word_size);
1096}
1097
1098static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
1099{
1100 struct snd_soc_codec_driver *codec_drv;
1101 size_t reg_size;
1102
1103 codec_drv = codec->driver;
1104 reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
1105 return DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count());
1106}
1107
1108static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
1109{
1110 struct snd_soc_lzo_ctx **lzo_blocks;
1111 unsigned int val;
1112 int i;
1113
1114 lzo_blocks = codec->reg_cache;
1115 for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
1116 snd_soc_cache_read(codec, i, &val);
1117 snd_soc_write(codec, i, val);
1118 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1119 i, val);
1120 }
1121
1122 return 0;
1123}
1124
1125static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
1126 unsigned int reg, unsigned int value)
1127{
1128 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1129 int ret, blkindex, blkpos;
1130 size_t blksize, tmp_dst_len;
1131 void *tmp_dst;
1132
1133 /* index of the compressed lzo block */
1134 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1135 /* register index within the decompressed block */
1136 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1137 /* size of the compressed block */
1138 blksize = snd_soc_lzo_get_blksize(codec);
1139 lzo_blocks = codec->reg_cache;
1140 lzo_block = lzo_blocks[blkindex];
1141
1142 /* save the pointer and length of the compressed block */
1143 tmp_dst = lzo_block->dst;
1144 tmp_dst_len = lzo_block->dst_len;
1145
1146 /* prepare the source to be the compressed block */
1147 lzo_block->src = lzo_block->dst;
1148 lzo_block->src_len = lzo_block->dst_len;
1149
1150 /* decompress the block */
1151 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
1152 if (ret < 0) {
1153 kfree(lzo_block->dst);
1154 goto out;
1155 }
1156
1157 /* write the new value to the cache */
1158 switch (codec->driver->reg_word_size) {
1159 case 1: {
1160 u8 *cache;
1161 cache = lzo_block->dst;
1162 if (cache[blkpos] == value) {
1163 kfree(lzo_block->dst);
1164 goto out;
1165 }
1166 cache[blkpos] = value;
1167 }
1168 break;
1169 case 2: {
1170 u16 *cache;
1171 cache = lzo_block->dst;
1172 if (cache[blkpos] == value) {
1173 kfree(lzo_block->dst);
1174 goto out;
1175 }
1176 cache[blkpos] = value;
1177 }
1178 break;
1179 default:
1180 BUG();
1181 }
1182
1183 /* prepare the source to be the decompressed block */
1184 lzo_block->src = lzo_block->dst;
1185 lzo_block->src_len = lzo_block->dst_len;
1186
1187 /* compress the block */
1188 ret = snd_soc_lzo_compress_cache_block(codec, lzo_block);
1189 if (ret < 0) {
1190 kfree(lzo_block->dst);
1191 kfree(lzo_block->src);
1192 goto out;
1193 }
1194
1195 /* set the bit so we know we have to sync this register */
1196 set_bit(reg, lzo_block->sync_bmp);
1197 kfree(tmp_dst);
1198 kfree(lzo_block->src);
1199 return 0;
1200out:
1201 lzo_block->dst = tmp_dst;
1202 lzo_block->dst_len = tmp_dst_len;
1203 return ret;
1204}
1205
1206static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
1207 unsigned int reg, unsigned int *value)
1208{
1209 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1210 int ret, blkindex, blkpos;
1211 size_t blksize, tmp_dst_len;
1212 void *tmp_dst;
1213
1214 *value = 0;
1215 /* index of the compressed lzo block */
1216 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1217 /* register index within the decompressed block */
1218 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1219 /* size of the compressed block */
1220 blksize = snd_soc_lzo_get_blksize(codec);
1221 lzo_blocks = codec->reg_cache;
1222 lzo_block = lzo_blocks[blkindex];
1223
1224 /* save the pointer and length of the compressed block */
1225 tmp_dst = lzo_block->dst;
1226 tmp_dst_len = lzo_block->dst_len;
1227
1228 /* prepare the source to be the compressed block */
1229 lzo_block->src = lzo_block->dst;
1230 lzo_block->src_len = lzo_block->dst_len;
1231
1232 /* decompress the block */
1233 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
1234 if (ret >= 0) {
1235 /* fetch the value from the cache */
1236 switch (codec->driver->reg_word_size) {
1237 case 1: {
1238 u8 *cache;
1239 cache = lzo_block->dst;
1240 *value = cache[blkpos];
1241 }
1242 break;
1243 case 2: {
1244 u16 *cache;
1245 cache = lzo_block->dst;
1246 *value = cache[blkpos];
1247 }
1248 break;
1249 default:
1250 BUG();
1251 }
1252 }
1253
1254 kfree(lzo_block->dst);
1255 /* restore the pointer and length of the compressed block */
1256 lzo_block->dst = tmp_dst;
1257 lzo_block->dst_len = tmp_dst_len;
1258 return 0;
1259}
1260
1261static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
1262{
1263 struct snd_soc_lzo_ctx **lzo_blocks;
1264 int i, blkcount;
1265
1266 lzo_blocks = codec->reg_cache;
1267 if (!lzo_blocks)
1268 return 0;
1269
1270 blkcount = snd_soc_lzo_block_count();
1271 /*
1272 * the pointer to the bitmap used for syncing the cache
1273 * is shared amongst all lzo_blocks. Ensure it is freed
1274 * only once.
1275 */
1276 if (lzo_blocks[0])
1277 kfree(lzo_blocks[0]->sync_bmp);
1278 for (i = 0; i < blkcount; ++i) {
1279 if (lzo_blocks[i]) {
1280 kfree(lzo_blocks[i]->wmem);
1281 kfree(lzo_blocks[i]->dst);
1282 }
1283 /* each lzo_block is a pointer returned by kmalloc or NULL */
1284 kfree(lzo_blocks[i]);
1285 }
1286 kfree(lzo_blocks);
1287 codec->reg_cache = NULL;
1288 return 0;
1289}
1290
1291static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
1292{
1293 struct snd_soc_lzo_ctx **lzo_blocks;
1294 size_t reg_size, bmp_size;
1295 struct snd_soc_codec_driver *codec_drv;
1296 int ret, tofree, i, blksize, blkcount;
1297 const char *p, *end;
1298 unsigned long *sync_bmp;
1299
1300 ret = 0;
1301 codec_drv = codec->driver;
1302 reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
1303
1304 /*
1305 * If we have not been given a default register cache
1306 * then allocate a dummy zero-ed out region, compress it
1307 * and remember to free it afterwards.
1308 */
1309 tofree = 0;
1310 if (!codec_drv->reg_cache_default)
1311 tofree = 1;
1312
1313 if (!codec_drv->reg_cache_default) {
1314 codec_drv->reg_cache_default = kzalloc(reg_size,
1315 GFP_KERNEL);
1316 if (!codec_drv->reg_cache_default)
1317 return -ENOMEM;
1318 }
1319
1320 blkcount = snd_soc_lzo_block_count();
1321 codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks,
1322 GFP_KERNEL);
1323 if (!codec->reg_cache) {
1324 ret = -ENOMEM;
1325 goto err_tofree;
1326 }
1327 lzo_blocks = codec->reg_cache;
1328
1329 /*
1330 * allocate a bitmap to be used when syncing the cache with
1331 * the hardware. Each time a register is modified, the corresponding
1332 * bit is set in the bitmap, so we know that we have to sync
1333 * that register.
1334 */
1335 bmp_size = codec_drv->reg_cache_size;
1336 sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof (long),
1337 GFP_KERNEL);
1338 if (!sync_bmp) {
1339 ret = -ENOMEM;
1340 goto err;
1341 }
1342 bitmap_zero(sync_bmp, reg_size);
1343
1344 /* allocate the lzo blocks and initialize them */
1345 for (i = 0; i < blkcount; ++i) {
1346 lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
1347 GFP_KERNEL);
1348 if (!lzo_blocks[i]) {
1349 kfree(sync_bmp);
1350 ret = -ENOMEM;
1351 goto err;
1352 }
1353 lzo_blocks[i]->sync_bmp = sync_bmp;
1354 lzo_blocks[i]->sync_bmp_nbits = reg_size;
1355 /* alloc the working space for the compressed block */
1356 ret = snd_soc_lzo_prepare(lzo_blocks[i]);
1357 if (ret < 0)
1358 goto err;
1359 }
1360
1361 blksize = snd_soc_lzo_get_blksize(codec);
1362 p = codec_drv->reg_cache_default;
1363 end = codec_drv->reg_cache_default + reg_size;
1364 /* compress the register map and fill the lzo blocks */
1365 for (i = 0; i < blkcount; ++i, p += blksize) {
1366 lzo_blocks[i]->src = p;
1367 if (p + blksize > end)
1368 lzo_blocks[i]->src_len = end - p;
1369 else
1370 lzo_blocks[i]->src_len = blksize;
1371 ret = snd_soc_lzo_compress_cache_block(codec,
1372 lzo_blocks[i]);
1373 if (ret < 0)
1374 goto err;
1375 lzo_blocks[i]->decompressed_size =
1376 lzo_blocks[i]->src_len;
1377 }
1378
1379 if (tofree)
1380 kfree(codec_drv->reg_cache_default);
1381 return 0;
1382err:
1383 snd_soc_cache_exit(codec);
1384err_tofree:
1385 if (tofree)
1386 kfree(codec_drv->reg_cache_default);
1387 return ret;
1388}
1389
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001390static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
1391{
1392 int i;
1393 struct snd_soc_codec_driver *codec_drv;
1394 unsigned int val;
1395
1396 codec_drv = codec->driver;
1397 for (i = 0; i < codec_drv->reg_cache_size; ++i) {
1398 snd_soc_cache_read(codec, i, &val);
1399 if (codec_drv->reg_cache_default) {
1400 switch (codec_drv->reg_word_size) {
1401 case 1: {
1402 const u8 *cache;
1403
1404 cache = codec_drv->reg_cache_default;
1405 if (cache[i] == val)
1406 continue;
1407 }
1408 break;
1409 case 2: {
1410 const u16 *cache;
1411
1412 cache = codec_drv->reg_cache_default;
1413 if (cache[i] == val)
1414 continue;
1415 }
1416 break;
1417 default:
1418 BUG();
1419 }
1420 }
1421 snd_soc_write(codec, i, val);
1422 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1423 i, val);
1424 }
1425 return 0;
1426}
1427
1428static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
1429 unsigned int reg, unsigned int value)
1430{
1431 switch (codec->driver->reg_word_size) {
1432 case 1: {
1433 u8 *cache;
1434
1435 cache = codec->reg_cache;
1436 cache[reg] = value;
1437 }
1438 break;
1439 case 2: {
1440 u16 *cache;
1441
1442 cache = codec->reg_cache;
1443 cache[reg] = value;
1444 }
1445 break;
1446 default:
1447 BUG();
1448 }
1449
1450 return 0;
1451}
1452
1453static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
1454 unsigned int reg, unsigned int *value)
1455{
1456 switch (codec->driver->reg_word_size) {
1457 case 1: {
1458 u8 *cache;
1459
1460 cache = codec->reg_cache;
1461 *value = cache[reg];
1462 }
1463 break;
1464 case 2: {
1465 u16 *cache;
1466
1467 cache = codec->reg_cache;
1468 *value = cache[reg];
1469 }
1470 break;
1471 default:
1472 BUG();
1473 }
1474
1475 return 0;
1476}
1477
1478static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
1479{
1480 if (!codec->reg_cache)
1481 return 0;
1482 kfree(codec->reg_cache);
1483 codec->reg_cache = NULL;
1484 return 0;
1485}
1486
1487static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
1488{
1489 struct snd_soc_codec_driver *codec_drv;
1490 size_t reg_size;
1491
1492 codec_drv = codec->driver;
1493 reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
1494
1495 if (codec_drv->reg_cache_default)
1496 codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
1497 reg_size, GFP_KERNEL);
1498 else
1499 codec->reg_cache = kzalloc(reg_size, GFP_KERNEL);
1500 if (!codec->reg_cache)
1501 return -ENOMEM;
1502
1503 return 0;
1504}
1505
1506/* an array of all supported compression types */
1507static const struct snd_soc_cache_ops cache_types[] = {
1508 {
1509 .id = SND_SOC_NO_COMPRESSION,
1510 .init = snd_soc_flat_cache_init,
1511 .exit = snd_soc_flat_cache_exit,
1512 .read = snd_soc_flat_cache_read,
1513 .write = snd_soc_flat_cache_write,
1514 .sync = snd_soc_flat_cache_sync
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001515 },
1516 {
1517 .id = SND_SOC_LZO_COMPRESSION,
1518 .init = snd_soc_lzo_cache_init,
1519 .exit = snd_soc_lzo_cache_exit,
1520 .read = snd_soc_lzo_cache_read,
1521 .write = snd_soc_lzo_cache_write,
1522 .sync = snd_soc_lzo_cache_sync
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001523 },
1524 {
1525 .id = SND_SOC_RBTREE_COMPRESSION,
1526 .init = snd_soc_rbtree_cache_init,
1527 .exit = snd_soc_rbtree_cache_exit,
1528 .read = snd_soc_rbtree_cache_read,
1529 .write = snd_soc_rbtree_cache_write,
1530 .sync = snd_soc_rbtree_cache_sync
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001531 }
1532};
1533
1534int snd_soc_cache_init(struct snd_soc_codec *codec)
1535{
1536 int i;
1537
1538 for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
1539 if (cache_types[i].id == codec->driver->compress_type)
1540 break;
1541 if (i == ARRAY_SIZE(cache_types)) {
1542 dev_err(codec->dev, "Could not match compress type: %d\n",
1543 codec->driver->compress_type);
1544 return -EINVAL;
1545 }
1546
1547 mutex_init(&codec->cache_rw_mutex);
1548 codec->cache_ops = &cache_types[i];
1549
1550 if (codec->cache_ops->init)
1551 return codec->cache_ops->init(codec);
1552 return -EINVAL;
1553}
1554
1555/*
1556 * NOTE: keep in mind that this function might be called
1557 * multiple times.
1558 */
1559int snd_soc_cache_exit(struct snd_soc_codec *codec)
1560{
1561 if (codec->cache_ops && codec->cache_ops->exit)
1562 return codec->cache_ops->exit(codec);
1563 return -EINVAL;
1564}
1565
1566/**
1567 * snd_soc_cache_read: Fetch the value of a given register from the cache.
1568 *
1569 * @codec: CODEC to configure.
1570 * @reg: The register index.
1571 * @value: The value to be returned.
1572 */
1573int snd_soc_cache_read(struct snd_soc_codec *codec,
1574 unsigned int reg, unsigned int *value)
1575{
1576 int ret;
1577
1578 mutex_lock(&codec->cache_rw_mutex);
1579
1580 if (value && codec->cache_ops && codec->cache_ops->read) {
1581 ret = codec->cache_ops->read(codec, reg, value);
1582 mutex_unlock(&codec->cache_rw_mutex);
1583 return ret;
1584 }
1585
1586 mutex_unlock(&codec->cache_rw_mutex);
1587 return -EINVAL;
1588}
1589EXPORT_SYMBOL_GPL(snd_soc_cache_read);
1590
1591/**
1592 * snd_soc_cache_write: Set the value of a given register in the cache.
1593 *
1594 * @codec: CODEC to configure.
1595 * @reg: The register index.
1596 * @value: The new register value.
1597 */
1598int snd_soc_cache_write(struct snd_soc_codec *codec,
1599 unsigned int reg, unsigned int value)
1600{
1601 int ret;
1602
1603 mutex_lock(&codec->cache_rw_mutex);
1604
1605 if (codec->cache_ops && codec->cache_ops->write) {
1606 ret = codec->cache_ops->write(codec, reg, value);
1607 mutex_unlock(&codec->cache_rw_mutex);
1608 return ret;
1609 }
1610
1611 mutex_unlock(&codec->cache_rw_mutex);
1612 return -EINVAL;
1613}
1614EXPORT_SYMBOL_GPL(snd_soc_cache_write);
1615
1616/**
1617 * snd_soc_cache_sync: Sync the register cache with the hardware.
1618 *
1619 * @codec: CODEC to configure.
1620 *
1621 * Any registers that should not be synced should be marked as
1622 * volatile. In general drivers can choose not to use the provided
1623 * syncing functionality if they so require.
1624 */
1625int snd_soc_cache_sync(struct snd_soc_codec *codec)
1626{
1627 int ret;
1628
1629 if (!codec->cache_sync) {
1630 return 0;
1631 }
1632
1633 if (codec->cache_ops && codec->cache_ops->sync) {
1634 ret = codec->cache_ops->sync(codec);
1635 if (!ret)
1636 codec->cache_sync = 0;
1637 return ret;
1638 }
1639
1640 return -EINVAL;
1641}
1642EXPORT_SYMBOL_GPL(snd_soc_cache_sync);