blob: abb0243f3adff5d51c67220269c276931f215b65 [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
Dimitris Papastamosc358e642011-01-21 15:29:02 +000021#include <trace/events/asoc.h>
22
Dimitris Papastamos26e99842011-03-22 10:36:58 +000023static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
24 unsigned int value, const void *data, int len)
25{
26 int ret;
27
28 if (!snd_soc_codec_volatile_register(codec, reg) &&
29 reg < codec->driver->reg_cache_size &&
30 !codec->cache_bypass) {
31 ret = snd_soc_cache_write(codec, reg, value);
32 if (ret < 0)
33 return -1;
34 }
35
36 if (codec->cache_only) {
37 codec->cache_sync = 1;
38 return 0;
39 }
40
41 ret = codec->hw_write(codec->control_data, data, len);
42 if (ret == len)
43 return 0;
44 if (ret < 0)
45 return ret;
46 else
47 return -EIO;
48}
49
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000050static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg)
Barry Song63b62ab2010-01-27 11:46:17 +080051{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000052 int ret;
53 unsigned int val;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010054
55 if (reg >= codec->driver->reg_cache_size ||
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000056 snd_soc_codec_volatile_register(codec, reg) ||
57 codec->cache_bypass) {
58 if (codec->cache_only)
59 return -1;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010060
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000061 BUG_ON(!codec->hw_read);
62 return codec->hw_read(codec, reg);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010063 }
64
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000065 ret = snd_soc_cache_read(codec, reg, &val);
66 if (ret < 0)
67 return -1;
68 return val;
Barry Song63b62ab2010-01-27 11:46:17 +080069}
70
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000071static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
72 unsigned int reg)
73{
74 return do_hw_read(codec, reg);
75}
76
Barry Song63b62ab2010-01-27 11:46:17 +080077static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
78 unsigned int value)
79{
Barry Song63b62ab2010-01-27 11:46:17 +080080 u8 data[2];
Barry Song63b62ab2010-01-27 11:46:17 +080081
Barry Song63b62ab2010-01-27 11:46:17 +080082 data[0] = (reg << 4) | ((value >> 8) & 0x000f);
83 data[1] = value & 0x00ff;
84
Dimitris Papastamos26e99842011-03-22 10:36:58 +000085 return do_hw_write(codec, reg, value, data, 2);
Barry Song63b62ab2010-01-27 11:46:17 +080086}
87
88#if defined(CONFIG_SPI_MASTER)
89static int snd_soc_4_12_spi_write(void *control_data, const char *data,
90 int len)
91{
92 struct spi_device *spi = control_data;
93 struct spi_transfer t;
94 struct spi_message m;
95 u8 msg[2];
96
97 if (len <= 0)
98 return 0;
99
100 msg[0] = data[1];
101 msg[1] = data[0];
102
103 spi_message_init(&m);
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +0000104 memset(&t, 0, sizeof t);
Barry Song63b62ab2010-01-27 11:46:17 +0800105
106 t.tx_buf = &msg[0];
107 t.len = len;
108
109 spi_message_add_tail(&t, &m);
110 spi_sync(spi, &m);
111
112 return len;
113}
114#else
115#define snd_soc_4_12_spi_write NULL
116#endif
117
Mark Brown17a52fd2009-07-05 17:24:50 +0100118static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
119 unsigned int reg)
120{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000121 return do_hw_read(codec, reg);
Mark Brown17a52fd2009-07-05 17:24:50 +0100122}
123
124static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
125 unsigned int value)
126{
Mark Brown17a52fd2009-07-05 17:24:50 +0100127 u8 data[2];
Mark Brown17a52fd2009-07-05 17:24:50 +0100128
Mark Brown17a52fd2009-07-05 17:24:50 +0100129 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
130 data[1] = value & 0x00ff;
131
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000132 return do_hw_write(codec, reg, value, data, 2);
Mark Brown17a52fd2009-07-05 17:24:50 +0100133}
134
Mark Brown27ded042009-07-10 23:28:16 +0100135#if defined(CONFIG_SPI_MASTER)
136static int snd_soc_7_9_spi_write(void *control_data, const char *data,
137 int len)
138{
139 struct spi_device *spi = control_data;
140 struct spi_transfer t;
141 struct spi_message m;
142 u8 msg[2];
143
144 if (len <= 0)
145 return 0;
146
147 msg[0] = data[0];
148 msg[1] = data[1];
149
150 spi_message_init(&m);
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +0000151 memset(&t, 0, sizeof t);
Mark Brown27ded042009-07-10 23:28:16 +0100152
153 t.tx_buf = &msg[0];
154 t.len = len;
155
156 spi_message_add_tail(&t, &m);
157 spi_sync(spi, &m);
158
159 return len;
160}
161#else
162#define snd_soc_7_9_spi_write NULL
163#endif
164
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900165static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
166 unsigned int value)
167{
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900168 u8 data[2];
169
Barry Songf4bee1b2010-03-18 16:17:01 +0800170 reg &= 0xff;
171 data[0] = reg;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900172 data[1] = value & 0xff;
173
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000174 return do_hw_write(codec, reg, value, data, 2);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900175}
176
177static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
178 unsigned int reg)
179{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000180 return do_hw_read(codec, reg);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900181}
182
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100183#if defined(CONFIG_SPI_MASTER)
184static int snd_soc_8_8_spi_write(void *control_data, const char *data,
185 int len)
186{
187 struct spi_device *spi = control_data;
188 struct spi_transfer t;
189 struct spi_message m;
190 u8 msg[2];
191
192 if (len <= 0)
193 return 0;
194
195 msg[0] = data[0];
196 msg[1] = data[1];
197
198 spi_message_init(&m);
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +0000199 memset(&t, 0, sizeof t);
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100200
201 t.tx_buf = &msg[0];
202 t.len = len;
203
204 spi_message_add_tail(&t, &m);
205 spi_sync(spi, &m);
206
207 return len;
208}
209#else
210#define snd_soc_8_8_spi_write NULL
211#endif
212
Mark Brownafa2f102009-07-10 23:11:24 +0100213static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
214 unsigned int value)
215{
Mark Brownafa2f102009-07-10 23:11:24 +0100216 u8 data[3];
217
218 data[0] = reg;
219 data[1] = (value >> 8) & 0xff;
220 data[2] = value & 0xff;
221
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000222 return do_hw_write(codec, reg, value, data, 3);
Mark Brownafa2f102009-07-10 23:11:24 +0100223}
224
225static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
226 unsigned int reg)
227{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000228 return do_hw_read(codec, reg);
Mark Brownafa2f102009-07-10 23:11:24 +0100229}
230
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100231#if defined(CONFIG_SPI_MASTER)
232static int snd_soc_8_16_spi_write(void *control_data, const char *data,
233 int len)
234{
235 struct spi_device *spi = control_data;
236 struct spi_transfer t;
237 struct spi_message m;
238 u8 msg[3];
239
240 if (len <= 0)
241 return 0;
242
243 msg[0] = data[0];
244 msg[1] = data[1];
245 msg[2] = data[2];
246
247 spi_message_init(&m);
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +0000248 memset(&t, 0, sizeof t);
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100249
250 t.tx_buf = &msg[0];
251 t.len = len;
252
253 spi_message_add_tail(&t, &m);
254 spi_sync(spi, &m);
255
256 return len;
257}
258#else
259#define snd_soc_8_16_spi_write NULL
260#endif
261
Randy Dunlap17244c22009-08-10 16:04:39 -0700262#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000263static unsigned int do_i2c_read(struct snd_soc_codec *codec,
264 void *reg, int reglen,
265 void *data, int datalen)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800266{
267 struct i2c_msg xfer[2];
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800268 int ret;
269 struct i2c_client *client = codec->control_data;
270
271 /* Write register */
272 xfer[0].addr = client->addr;
273 xfer[0].flags = 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000274 xfer[0].len = reglen;
275 xfer[0].buf = reg;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800276
277 /* Read data */
278 xfer[1].addr = client->addr;
279 xfer[1].flags = I2C_M_RD;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000280 xfer[1].len = datalen;
281 xfer[1].buf = data;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800282
283 ret = i2c_transfer(client->adapter, xfer, 2);
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000284 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
285 if (ret == 2)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800286 return 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000287 else if (ret < 0)
288 return ret;
289 else
290 return -EIO;
291}
292#endif
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800293
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000294#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
295static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
296 unsigned int r)
297{
298 u8 reg = r;
299 u8 data;
300 int ret;
301
302 ret = do_i2c_read(codec, &reg, 1, &data, 1);
303 if (ret < 0)
304 return 0;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800305 return data;
306}
307#else
308#define snd_soc_8_8_read_i2c NULL
309#endif
310
311#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100312static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
313 unsigned int r)
314{
Mark Brownafa2f102009-07-10 23:11:24 +0100315 u8 reg = r;
316 u16 data;
317 int ret;
Mark Brownafa2f102009-07-10 23:11:24 +0100318
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000319 ret = do_i2c_read(codec, &reg, 1, &data, 2);
320 if (ret < 0)
Mark Brownafa2f102009-07-10 23:11:24 +0100321 return 0;
Mark Brownafa2f102009-07-10 23:11:24 +0100322 return (data >> 8) | ((data & 0xff) << 8);
323}
324#else
325#define snd_soc_8_16_read_i2c NULL
326#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100327
Barry Song994dc422010-01-27 11:46:18 +0800328#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
329static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
330 unsigned int r)
331{
Barry Song994dc422010-01-27 11:46:18 +0800332 u16 reg = r;
333 u8 data;
334 int ret;
Barry Song994dc422010-01-27 11:46:18 +0800335
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000336 ret = do_i2c_read(codec, &reg, 2, &data, 1);
337 if (ret < 0)
Barry Song994dc422010-01-27 11:46:18 +0800338 return 0;
Barry Song994dc422010-01-27 11:46:18 +0800339 return data;
340}
341#else
342#define snd_soc_16_8_read_i2c NULL
343#endif
344
345static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
346 unsigned int reg)
347{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000348 return do_hw_read(codec, reg);
Barry Song994dc422010-01-27 11:46:18 +0800349}
350
351static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
352 unsigned int value)
353{
Barry Song994dc422010-01-27 11:46:18 +0800354 u8 data[3];
Barry Song994dc422010-01-27 11:46:18 +0800355
Barry Song994dc422010-01-27 11:46:18 +0800356 data[0] = (reg >> 8) & 0xff;
357 data[1] = reg & 0xff;
358 data[2] = value;
Barry Song994dc422010-01-27 11:46:18 +0800359 reg &= 0xff;
Mark Brown8c961bc2010-02-01 18:46:10 +0000360
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000361 return do_hw_write(codec, reg, value, data, 3);
Barry Song994dc422010-01-27 11:46:18 +0800362}
363
364#if defined(CONFIG_SPI_MASTER)
365static int snd_soc_16_8_spi_write(void *control_data, const char *data,
366 int len)
367{
368 struct spi_device *spi = control_data;
369 struct spi_transfer t;
370 struct spi_message m;
371 u8 msg[3];
372
373 if (len <= 0)
374 return 0;
375
376 msg[0] = data[0];
377 msg[1] = data[1];
378 msg[2] = data[2];
379
380 spi_message_init(&m);
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +0000381 memset(&t, 0, sizeof t);
Barry Song994dc422010-01-27 11:46:18 +0800382
383 t.tx_buf = &msg[0];
384 t.len = len;
385
386 spi_message_add_tail(&t, &m);
387 spi_sync(spi, &m);
388
389 return len;
390}
391#else
392#define snd_soc_16_8_spi_write NULL
393#endif
394
Mark Brownbc6552f2010-03-05 16:27:15 +0000395#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
396static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
397 unsigned int r)
398{
Mark Brownbc6552f2010-03-05 16:27:15 +0000399 u16 reg = cpu_to_be16(r);
400 u16 data;
401 int ret;
Mark Brownbc6552f2010-03-05 16:27:15 +0000402
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000403 ret = do_i2c_read(codec, &reg, 2, &data, 2);
404 if (ret < 0)
Mark Brownbc6552f2010-03-05 16:27:15 +0000405 return 0;
Mark Brownbc6552f2010-03-05 16:27:15 +0000406 return be16_to_cpu(data);
407}
408#else
409#define snd_soc_16_16_read_i2c NULL
410#endif
411
412static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
413 unsigned int reg)
414{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000415 return do_hw_read(codec, reg);
Mark Brownbc6552f2010-03-05 16:27:15 +0000416}
417
418static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
419 unsigned int value)
420{
Mark Brownbc6552f2010-03-05 16:27:15 +0000421 u8 data[4];
Mark Brownbc6552f2010-03-05 16:27:15 +0000422
423 data[0] = (reg >> 8) & 0xff;
424 data[1] = reg & 0xff;
425 data[2] = (value >> 8) & 0xff;
426 data[3] = value & 0xff;
427
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000428 return do_hw_write(codec, reg, value, data, 4);
Mark Brownbc6552f2010-03-05 16:27:15 +0000429}
Barry Song994dc422010-01-27 11:46:18 +0800430
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100431#if defined(CONFIG_SPI_MASTER)
432static int snd_soc_16_16_spi_write(void *control_data, const char *data,
433 int len)
434{
435 struct spi_device *spi = control_data;
436 struct spi_transfer t;
437 struct spi_message m;
438 u8 msg[4];
439
440 if (len <= 0)
441 return 0;
442
443 msg[0] = data[0];
444 msg[1] = data[1];
445 msg[2] = data[2];
446 msg[3] = data[3];
447
448 spi_message_init(&m);
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +0000449 memset(&t, 0, sizeof t);
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100450
451 t.tx_buf = &msg[0];
452 t.len = len;
453
454 spi_message_add_tail(&t, &m);
455 spi_sync(spi, &m);
456
457 return len;
458}
459#else
460#define snd_soc_16_16_spi_write NULL
461#endif
462
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000463/* Primitive bulk write support for soc-cache. The data pointed to by `data' needs
464 * to already be in the form the hardware expects including any leading register specific
465 * data. Any data written through this function will not go through the cache as it
466 * only handles writing to volatile or out of bounds registers.
467 */
468static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
469 const void *data, size_t len)
470{
471 int ret;
472
473 /* Ensure that the base register is volatile. Subsequently
474 * any other register that is touched by this routine should be
475 * volatile as well to ensure that we don't get out of sync with
476 * the cache.
477 */
478 if (!snd_soc_codec_volatile_register(codec, reg)
479 && reg < codec->driver->reg_cache_size)
480 return -EINVAL;
481
482 switch (codec->control_type) {
483 case SND_SOC_I2C:
484 ret = i2c_master_send(codec->control_data, data, len);
485 break;
486 case SND_SOC_SPI:
487 ret = do_spi_write(codec->control_data, data, len);
488 break;
489 default:
490 BUG();
491 }
492
493 if (ret == len)
494 return 0;
495 if (ret < 0)
496 return ret;
497 else
498 return -EIO;
499}
500
Mark Brown17a52fd2009-07-05 17:24:50 +0100501static struct {
502 int addr_bits;
503 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100504 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown27ded042009-07-10 23:28:16 +0100505 int (*spi_write)(void *, const char *, int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100506 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100507 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100508} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700509 {
Barry Song63b62ab2010-01-27 11:46:17 +0800510 .addr_bits = 4, .data_bits = 12,
511 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
512 .spi_write = snd_soc_4_12_spi_write,
513 },
514 {
Mark Brownd62ab352009-09-21 04:21:47 -0700515 .addr_bits = 7, .data_bits = 9,
516 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Barry Song8998c892009-12-31 10:30:34 +0800517 .spi_write = snd_soc_7_9_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700518 },
519 {
520 .addr_bits = 8, .data_bits = 8,
521 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800522 .i2c_read = snd_soc_8_8_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100523 .spi_write = snd_soc_8_8_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700524 },
525 {
526 .addr_bits = 8, .data_bits = 16,
527 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
528 .i2c_read = snd_soc_8_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100529 .spi_write = snd_soc_8_16_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700530 },
Barry Song994dc422010-01-27 11:46:18 +0800531 {
532 .addr_bits = 16, .data_bits = 8,
533 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
534 .i2c_read = snd_soc_16_8_read_i2c,
535 .spi_write = snd_soc_16_8_spi_write,
536 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000537 {
538 .addr_bits = 16, .data_bits = 16,
539 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
540 .i2c_read = snd_soc_16_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100541 .spi_write = snd_soc_16_16_spi_write,
Mark Brownbc6552f2010-03-05 16:27:15 +0000542 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100543};
544
545/**
546 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
547 *
548 * @codec: CODEC to configure.
549 * @type: Type of cache.
550 * @addr_bits: Number of bits of register address data.
551 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100552 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100553 *
554 * Register formats are frequently shared between many I2C and SPI
555 * devices. In order to promote code reuse the ASoC core provides
556 * some standard implementations of CODEC read and write operations
557 * which can be set up using this function.
558 *
559 * The caller is responsible for allocating and initialising the
560 * actual cache.
561 *
562 * Note that at present this code cannot be used by CODECs with
563 * volatile registers.
564 */
565int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100566 int addr_bits, int data_bits,
567 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100568{
569 int i;
570
Mark Brown17a52fd2009-07-05 17:24:50 +0100571 for (i = 0; i < ARRAY_SIZE(io_types); i++)
572 if (io_types[i].addr_bits == addr_bits &&
573 io_types[i].data_bits == data_bits)
574 break;
575 if (i == ARRAY_SIZE(io_types)) {
576 printk(KERN_ERR
577 "No I/O functions for %d bit address %d bit data\n",
578 addr_bits, data_bits);
579 return -EINVAL;
580 }
581
Mark Brownc3acec22010-12-02 16:15:29 +0000582 codec->write = io_types[i].write;
583 codec->read = io_types[i].read;
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000584 codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
Mark Brown17a52fd2009-07-05 17:24:50 +0100585
Mark Brown7084a422009-07-10 22:24:27 +0100586 switch (control) {
587 case SND_SOC_CUSTOM:
588 break;
589
590 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700591#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100592 codec->hw_write = (hw_write_t)i2c_master_send;
593#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100594 if (io_types[i].i2c_read)
595 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100596
597 codec->control_data = container_of(codec->dev,
598 struct i2c_client,
599 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100600 break;
601
602 case SND_SOC_SPI:
Mark Brown27ded042009-07-10 23:28:16 +0100603 if (io_types[i].spi_write)
604 codec->hw_write = io_types[i].spi_write;
Mark Browna6d14342010-08-12 10:59:15 +0100605
606 codec->control_data = container_of(codec->dev,
607 struct spi_device,
608 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100609 break;
610 }
611
Mark Brown17a52fd2009-07-05 17:24:50 +0100612 return 0;
613}
614EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000615
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000616static bool snd_soc_set_cache_val(void *base, unsigned int idx,
617 unsigned int val, unsigned int word_size)
618{
619 switch (word_size) {
620 case 1: {
621 u8 *cache = base;
622 if (cache[idx] == val)
623 return true;
624 cache[idx] = val;
625 break;
626 }
627 case 2: {
628 u16 *cache = base;
629 if (cache[idx] == val)
630 return true;
631 cache[idx] = val;
632 break;
633 }
634 default:
635 BUG();
636 }
637 return false;
638}
639
640static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
641 unsigned int word_size)
642{
643 switch (word_size) {
644 case 1: {
645 const u8 *cache = base;
646 return cache[idx];
647 }
648 case 2: {
649 const u16 *cache = base;
650 return cache[idx];
651 }
652 default:
653 BUG();
654 }
655 /* unreachable */
656 return -1;
657}
658
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000659struct snd_soc_rbtree_node {
660 struct rb_node node;
661 unsigned int reg;
662 unsigned int value;
663 unsigned int defval;
664} __attribute__ ((packed));
665
666struct snd_soc_rbtree_ctx {
667 struct rb_root root;
668};
669
670static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
671 struct rb_root *root, unsigned int reg)
672{
673 struct rb_node *node;
674 struct snd_soc_rbtree_node *rbnode;
675
676 node = root->rb_node;
677 while (node) {
678 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
679 if (rbnode->reg < reg)
680 node = node->rb_left;
681 else if (rbnode->reg > reg)
682 node = node->rb_right;
683 else
684 return rbnode;
685 }
686
687 return NULL;
688}
689
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000690static int snd_soc_rbtree_insert(struct rb_root *root,
691 struct snd_soc_rbtree_node *rbnode)
692{
693 struct rb_node **new, *parent;
694 struct snd_soc_rbtree_node *rbnode_tmp;
695
696 parent = NULL;
697 new = &root->rb_node;
698 while (*new) {
699 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
700 node);
701 parent = *new;
702 if (rbnode_tmp->reg < rbnode->reg)
703 new = &((*new)->rb_left);
704 else if (rbnode_tmp->reg > rbnode->reg)
705 new = &((*new)->rb_right);
706 else
707 return 0;
708 }
709
710 /* insert the node into the rbtree */
711 rb_link_node(&rbnode->node, parent, new);
712 rb_insert_color(&rbnode->node, root);
713
714 return 1;
715}
716
717static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
718{
719 struct snd_soc_rbtree_ctx *rbtree_ctx;
720 struct rb_node *node;
721 struct snd_soc_rbtree_node *rbnode;
722 unsigned int val;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000723 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000724
725 rbtree_ctx = codec->reg_cache;
726 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
727 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
728 if (rbnode->value == rbnode->defval)
729 continue;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000730 ret = snd_soc_cache_read(codec, rbnode->reg, &val);
731 if (ret)
732 return ret;
Dimitris Papastamos99780072011-01-19 14:53:37 +0000733 codec->cache_bypass = 1;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000734 ret = snd_soc_write(codec, rbnode->reg, val);
Dimitris Papastamos99780072011-01-19 14:53:37 +0000735 codec->cache_bypass = 0;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000736 if (ret)
737 return ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000738 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
739 rbnode->reg, val);
740 }
741
742 return 0;
743}
744
745static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
746 unsigned int reg, unsigned int value)
747{
748 struct snd_soc_rbtree_ctx *rbtree_ctx;
749 struct snd_soc_rbtree_node *rbnode;
750
751 rbtree_ctx = codec->reg_cache;
752 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
753 if (rbnode) {
754 if (rbnode->value == value)
755 return 0;
756 rbnode->value = value;
757 } else {
758 /* bail out early, no need to create the rbnode yet */
759 if (!value)
760 return 0;
761 /*
762 * for uninitialized registers whose value is changed
763 * from the default zero, create an rbnode and insert
764 * it into the tree.
765 */
766 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
767 if (!rbnode)
768 return -ENOMEM;
769 rbnode->reg = reg;
770 rbnode->value = value;
771 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
772 }
773
774 return 0;
775}
776
777static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
778 unsigned int reg, unsigned int *value)
779{
780 struct snd_soc_rbtree_ctx *rbtree_ctx;
781 struct snd_soc_rbtree_node *rbnode;
782
783 rbtree_ctx = codec->reg_cache;
784 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
785 if (rbnode) {
786 *value = rbnode->value;
787 } else {
788 /* uninitialized registers default to 0 */
789 *value = 0;
790 }
791
792 return 0;
793}
794
795static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
796{
797 struct rb_node *next;
798 struct snd_soc_rbtree_ctx *rbtree_ctx;
799 struct snd_soc_rbtree_node *rbtree_node;
800
801 /* if we've already been called then just return */
802 rbtree_ctx = codec->reg_cache;
803 if (!rbtree_ctx)
804 return 0;
805
806 /* free up the rbtree */
807 next = rb_first(&rbtree_ctx->root);
808 while (next) {
809 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
810 next = rb_next(&rbtree_node->node);
811 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
812 kfree(rbtree_node);
813 }
814
815 /* release the resources */
816 kfree(codec->reg_cache);
817 codec->reg_cache = NULL;
818
819 return 0;
820}
821
822static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
823{
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000824 struct snd_soc_rbtree_node *rbtree_node;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000825 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000826 unsigned int val;
827 unsigned int word_size;
828 int i;
829 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000830
831 codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
832 if (!codec->reg_cache)
833 return -ENOMEM;
834
835 rbtree_ctx = codec->reg_cache;
836 rbtree_ctx->root = RB_ROOT;
837
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000838 if (!codec->reg_def_copy)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000839 return 0;
840
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000841 /*
842 * populate the rbtree with the initialized registers. All other
843 * registers will be inserted when they are first modified.
844 */
845 word_size = codec->driver->reg_word_size;
846 for (i = 0; i < codec->driver->reg_cache_size; ++i) {
847 val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size);
848 if (!val)
849 continue;
850 rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL);
851 if (!rbtree_node) {
852 ret = -ENOMEM;
853 snd_soc_cache_exit(codec);
854 break;
855 }
856 rbtree_node->reg = i;
857 rbtree_node->value = val;
858 rbtree_node->defval = val;
859 snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000860 }
861
862 return 0;
863}
864
Mark Brown68d44ee2010-12-21 17:19:56 +0000865#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000866struct snd_soc_lzo_ctx {
867 void *wmem;
868 void *dst;
869 const void *src;
870 size_t src_len;
871 size_t dst_len;
872 size_t decompressed_size;
873 unsigned long *sync_bmp;
874 int sync_bmp_nbits;
875};
876
877#define LZO_BLOCK_NUM 8
878static int snd_soc_lzo_block_count(void)
879{
880 return LZO_BLOCK_NUM;
881}
882
883static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx)
884{
885 lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
886 if (!lzo_ctx->wmem)
887 return -ENOMEM;
888 return 0;
889}
890
891static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx)
892{
893 size_t compress_size;
894 int ret;
895
896 ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
897 lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
898 if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
899 return -EINVAL;
900 lzo_ctx->dst_len = compress_size;
901 return 0;
902}
903
904static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx)
905{
906 size_t dst_len;
907 int ret;
908
909 dst_len = lzo_ctx->dst_len;
910 ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
911 lzo_ctx->dst, &dst_len);
912 if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
913 return -EINVAL;
914 return 0;
915}
916
917static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec,
918 struct snd_soc_lzo_ctx *lzo_ctx)
919{
920 int ret;
921
922 lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
923 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
924 if (!lzo_ctx->dst) {
925 lzo_ctx->dst_len = 0;
926 return -ENOMEM;
927 }
928
929 ret = snd_soc_lzo_compress(lzo_ctx);
930 if (ret < 0)
931 return ret;
932 return 0;
933}
934
935static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec,
936 struct snd_soc_lzo_ctx *lzo_ctx)
937{
938 int ret;
939
940 lzo_ctx->dst_len = lzo_ctx->decompressed_size;
941 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
942 if (!lzo_ctx->dst) {
943 lzo_ctx->dst_len = 0;
944 return -ENOMEM;
945 }
946
947 ret = snd_soc_lzo_decompress(lzo_ctx);
948 if (ret < 0)
949 return ret;
950 return 0;
951}
952
953static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
954 unsigned int reg)
955{
Mark Brown001ae4c2010-12-02 16:21:08 +0000956 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000957
958 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000959 return (reg * codec_drv->reg_word_size) /
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000960 DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000961}
962
963static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
964 unsigned int reg)
965{
Mark Brown001ae4c2010-12-02 16:21:08 +0000966 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000967
968 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000969 return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) /
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000970 codec_drv->reg_word_size);
971}
972
973static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
974{
Mark Brown001ae4c2010-12-02 16:21:08 +0000975 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000976
977 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000978 return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000979}
980
981static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
982{
983 struct snd_soc_lzo_ctx **lzo_blocks;
984 unsigned int val;
985 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000986 int ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000987
988 lzo_blocks = codec->reg_cache;
989 for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000990 ret = snd_soc_cache_read(codec, i, &val);
991 if (ret)
992 return ret;
Dimitris Papastamos99780072011-01-19 14:53:37 +0000993 codec->cache_bypass = 1;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000994 ret = snd_soc_write(codec, i, val);
Dimitris Papastamos99780072011-01-19 14:53:37 +0000995 codec->cache_bypass = 0;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000996 if (ret)
997 return ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000998 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
999 i, val);
1000 }
1001
1002 return 0;
1003}
1004
1005static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
1006 unsigned int reg, unsigned int value)
1007{
1008 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1009 int ret, blkindex, blkpos;
1010 size_t blksize, tmp_dst_len;
1011 void *tmp_dst;
1012
1013 /* index of the compressed lzo block */
1014 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1015 /* register index within the decompressed block */
1016 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1017 /* size of the compressed block */
1018 blksize = snd_soc_lzo_get_blksize(codec);
1019 lzo_blocks = codec->reg_cache;
1020 lzo_block = lzo_blocks[blkindex];
1021
1022 /* save the pointer and length of the compressed block */
1023 tmp_dst = lzo_block->dst;
1024 tmp_dst_len = lzo_block->dst_len;
1025
1026 /* prepare the source to be the compressed block */
1027 lzo_block->src = lzo_block->dst;
1028 lzo_block->src_len = lzo_block->dst_len;
1029
1030 /* decompress the block */
1031 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
1032 if (ret < 0) {
1033 kfree(lzo_block->dst);
1034 goto out;
1035 }
1036
1037 /* write the new value to the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001038 if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value,
1039 codec->driver->reg_word_size)) {
1040 kfree(lzo_block->dst);
1041 goto out;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001042 }
1043
1044 /* prepare the source to be the decompressed block */
1045 lzo_block->src = lzo_block->dst;
1046 lzo_block->src_len = lzo_block->dst_len;
1047
1048 /* compress the block */
1049 ret = snd_soc_lzo_compress_cache_block(codec, lzo_block);
1050 if (ret < 0) {
1051 kfree(lzo_block->dst);
1052 kfree(lzo_block->src);
1053 goto out;
1054 }
1055
1056 /* set the bit so we know we have to sync this register */
1057 set_bit(reg, lzo_block->sync_bmp);
1058 kfree(tmp_dst);
1059 kfree(lzo_block->src);
1060 return 0;
1061out:
1062 lzo_block->dst = tmp_dst;
1063 lzo_block->dst_len = tmp_dst_len;
1064 return ret;
1065}
1066
1067static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
1068 unsigned int reg, unsigned int *value)
1069{
1070 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1071 int ret, blkindex, blkpos;
1072 size_t blksize, tmp_dst_len;
1073 void *tmp_dst;
1074
1075 *value = 0;
1076 /* index of the compressed lzo block */
1077 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1078 /* register index within the decompressed block */
1079 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1080 /* size of the compressed block */
1081 blksize = snd_soc_lzo_get_blksize(codec);
1082 lzo_blocks = codec->reg_cache;
1083 lzo_block = lzo_blocks[blkindex];
1084
1085 /* save the pointer and length of the compressed block */
1086 tmp_dst = lzo_block->dst;
1087 tmp_dst_len = lzo_block->dst_len;
1088
1089 /* prepare the source to be the compressed block */
1090 lzo_block->src = lzo_block->dst;
1091 lzo_block->src_len = lzo_block->dst_len;
1092
1093 /* decompress the block */
1094 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001095 if (ret >= 0)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001096 /* fetch the value from the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001097 *value = snd_soc_get_cache_val(lzo_block->dst, blkpos,
1098 codec->driver->reg_word_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001099
1100 kfree(lzo_block->dst);
1101 /* restore the pointer and length of the compressed block */
1102 lzo_block->dst = tmp_dst;
1103 lzo_block->dst_len = tmp_dst_len;
1104 return 0;
1105}
1106
1107static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
1108{
1109 struct snd_soc_lzo_ctx **lzo_blocks;
1110 int i, blkcount;
1111
1112 lzo_blocks = codec->reg_cache;
1113 if (!lzo_blocks)
1114 return 0;
1115
1116 blkcount = snd_soc_lzo_block_count();
1117 /*
1118 * the pointer to the bitmap used for syncing the cache
1119 * is shared amongst all lzo_blocks. Ensure it is freed
1120 * only once.
1121 */
1122 if (lzo_blocks[0])
1123 kfree(lzo_blocks[0]->sync_bmp);
1124 for (i = 0; i < blkcount; ++i) {
1125 if (lzo_blocks[i]) {
1126 kfree(lzo_blocks[i]->wmem);
1127 kfree(lzo_blocks[i]->dst);
1128 }
1129 /* each lzo_block is a pointer returned by kmalloc or NULL */
1130 kfree(lzo_blocks[i]);
1131 }
1132 kfree(lzo_blocks);
1133 codec->reg_cache = NULL;
1134 return 0;
1135}
1136
1137static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
1138{
1139 struct snd_soc_lzo_ctx **lzo_blocks;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001140 size_t bmp_size;
Mark Brown001ae4c2010-12-02 16:21:08 +00001141 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001142 int ret, tofree, i, blksize, blkcount;
1143 const char *p, *end;
1144 unsigned long *sync_bmp;
1145
1146 ret = 0;
1147 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001148
1149 /*
1150 * If we have not been given a default register cache
1151 * then allocate a dummy zero-ed out region, compress it
1152 * and remember to free it afterwards.
1153 */
1154 tofree = 0;
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001155 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001156 tofree = 1;
1157
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001158 if (!codec->reg_def_copy) {
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001159 codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001160 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001161 return -ENOMEM;
1162 }
1163
1164 blkcount = snd_soc_lzo_block_count();
1165 codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks,
1166 GFP_KERNEL);
1167 if (!codec->reg_cache) {
1168 ret = -ENOMEM;
1169 goto err_tofree;
1170 }
1171 lzo_blocks = codec->reg_cache;
1172
1173 /*
1174 * allocate a bitmap to be used when syncing the cache with
1175 * the hardware. Each time a register is modified, the corresponding
1176 * bit is set in the bitmap, so we know that we have to sync
1177 * that register.
1178 */
1179 bmp_size = codec_drv->reg_cache_size;
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +00001180 sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001181 GFP_KERNEL);
1182 if (!sync_bmp) {
1183 ret = -ENOMEM;
1184 goto err;
1185 }
Dimitris Papastamos09c74a92010-11-29 11:43:33 +00001186 bitmap_zero(sync_bmp, bmp_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001187
1188 /* allocate the lzo blocks and initialize them */
1189 for (i = 0; i < blkcount; ++i) {
1190 lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
1191 GFP_KERNEL);
1192 if (!lzo_blocks[i]) {
1193 kfree(sync_bmp);
1194 ret = -ENOMEM;
1195 goto err;
1196 }
1197 lzo_blocks[i]->sync_bmp = sync_bmp;
Dimitris Papastamos04f8fd12011-01-11 11:24:02 +00001198 lzo_blocks[i]->sync_bmp_nbits = bmp_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001199 /* alloc the working space for the compressed block */
1200 ret = snd_soc_lzo_prepare(lzo_blocks[i]);
1201 if (ret < 0)
1202 goto err;
1203 }
1204
1205 blksize = snd_soc_lzo_get_blksize(codec);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001206 p = codec->reg_def_copy;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001207 end = codec->reg_def_copy + codec->reg_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001208 /* compress the register map and fill the lzo blocks */
1209 for (i = 0; i < blkcount; ++i, p += blksize) {
1210 lzo_blocks[i]->src = p;
1211 if (p + blksize > end)
1212 lzo_blocks[i]->src_len = end - p;
1213 else
1214 lzo_blocks[i]->src_len = blksize;
1215 ret = snd_soc_lzo_compress_cache_block(codec,
1216 lzo_blocks[i]);
1217 if (ret < 0)
1218 goto err;
1219 lzo_blocks[i]->decompressed_size =
1220 lzo_blocks[i]->src_len;
1221 }
1222
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001223 if (tofree) {
1224 kfree(codec->reg_def_copy);
1225 codec->reg_def_copy = NULL;
1226 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001227 return 0;
1228err:
1229 snd_soc_cache_exit(codec);
1230err_tofree:
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001231 if (tofree) {
1232 kfree(codec->reg_def_copy);
1233 codec->reg_def_copy = NULL;
1234 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001235 return ret;
1236}
Mark Brown68d44ee2010-12-21 17:19:56 +00001237#endif
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001238
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001239static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
1240{
1241 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001242 int ret;
Mark Brown001ae4c2010-12-02 16:21:08 +00001243 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001244 unsigned int val;
1245
1246 codec_drv = codec->driver;
1247 for (i = 0; i < codec_drv->reg_cache_size; ++i) {
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001248 ret = snd_soc_cache_read(codec, i, &val);
1249 if (ret)
1250 return ret;
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001251 if (codec->reg_def_copy)
1252 if (snd_soc_get_cache_val(codec->reg_def_copy,
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001253 i, codec_drv->reg_word_size) == val)
1254 continue;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001255 ret = snd_soc_write(codec, i, val);
1256 if (ret)
1257 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001258 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1259 i, val);
1260 }
1261 return 0;
1262}
1263
1264static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
1265 unsigned int reg, unsigned int value)
1266{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001267 snd_soc_set_cache_val(codec->reg_cache, reg, value,
1268 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001269 return 0;
1270}
1271
1272static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
1273 unsigned int reg, unsigned int *value)
1274{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001275 *value = snd_soc_get_cache_val(codec->reg_cache, reg,
1276 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001277 return 0;
1278}
1279
1280static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
1281{
1282 if (!codec->reg_cache)
1283 return 0;
1284 kfree(codec->reg_cache);
1285 codec->reg_cache = NULL;
1286 return 0;
1287}
1288
1289static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
1290{
Mark Brown001ae4c2010-12-02 16:21:08 +00001291 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001292
1293 codec_drv = codec->driver;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001294
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001295 if (codec->reg_def_copy)
1296 codec->reg_cache = kmemdup(codec->reg_def_copy,
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001297 codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001298 else
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001299 codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001300 if (!codec->reg_cache)
1301 return -ENOMEM;
1302
1303 return 0;
1304}
1305
1306/* an array of all supported compression types */
1307static const struct snd_soc_cache_ops cache_types[] = {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001308 /* Flat *must* be the first entry for fallback */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001309 {
Dimitris Papastamosdf0701b2010-11-29 10:54:28 +00001310 .id = SND_SOC_FLAT_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001311 .name = "flat",
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001312 .init = snd_soc_flat_cache_init,
1313 .exit = snd_soc_flat_cache_exit,
1314 .read = snd_soc_flat_cache_read,
1315 .write = snd_soc_flat_cache_write,
1316 .sync = snd_soc_flat_cache_sync
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001317 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001318#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001319 {
1320 .id = SND_SOC_LZO_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001321 .name = "LZO",
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001322 .init = snd_soc_lzo_cache_init,
1323 .exit = snd_soc_lzo_cache_exit,
1324 .read = snd_soc_lzo_cache_read,
1325 .write = snd_soc_lzo_cache_write,
1326 .sync = snd_soc_lzo_cache_sync
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001327 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001328#endif
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001329 {
1330 .id = SND_SOC_RBTREE_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001331 .name = "rbtree",
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001332 .init = snd_soc_rbtree_cache_init,
1333 .exit = snd_soc_rbtree_cache_exit,
1334 .read = snd_soc_rbtree_cache_read,
1335 .write = snd_soc_rbtree_cache_write,
1336 .sync = snd_soc_rbtree_cache_sync
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001337 }
1338};
1339
1340int snd_soc_cache_init(struct snd_soc_codec *codec)
1341{
1342 int i;
1343
1344 for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
Dimitris Papastamos23bbce32010-12-02 14:53:01 +00001345 if (cache_types[i].id == codec->compress_type)
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001346 break;
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001347
1348 /* Fall back to flat compression */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001349 if (i == ARRAY_SIZE(cache_types)) {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001350 dev_warn(codec->dev, "Could not match compress type: %d\n",
1351 codec->compress_type);
1352 i = 0;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001353 }
1354
1355 mutex_init(&codec->cache_rw_mutex);
1356 codec->cache_ops = &cache_types[i];
1357
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001358 if (codec->cache_ops->init) {
1359 if (codec->cache_ops->name)
1360 dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
1361 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001362 return codec->cache_ops->init(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001363 }
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001364 return -EINVAL;
1365}
1366
1367/*
1368 * NOTE: keep in mind that this function might be called
1369 * multiple times.
1370 */
1371int snd_soc_cache_exit(struct snd_soc_codec *codec)
1372{
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001373 if (codec->cache_ops && codec->cache_ops->exit) {
1374 if (codec->cache_ops->name)
1375 dev_dbg(codec->dev, "Destroying %s cache for %s codec\n",
1376 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001377 return codec->cache_ops->exit(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001378 }
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001379 return -EINVAL;
1380}
1381
1382/**
1383 * snd_soc_cache_read: Fetch the value of a given register from the cache.
1384 *
1385 * @codec: CODEC to configure.
1386 * @reg: The register index.
1387 * @value: The value to be returned.
1388 */
1389int snd_soc_cache_read(struct snd_soc_codec *codec,
1390 unsigned int reg, unsigned int *value)
1391{
1392 int ret;
1393
1394 mutex_lock(&codec->cache_rw_mutex);
1395
1396 if (value && codec->cache_ops && codec->cache_ops->read) {
1397 ret = codec->cache_ops->read(codec, reg, value);
1398 mutex_unlock(&codec->cache_rw_mutex);
1399 return ret;
1400 }
1401
1402 mutex_unlock(&codec->cache_rw_mutex);
1403 return -EINVAL;
1404}
1405EXPORT_SYMBOL_GPL(snd_soc_cache_read);
1406
1407/**
1408 * snd_soc_cache_write: Set the value of a given register in the cache.
1409 *
1410 * @codec: CODEC to configure.
1411 * @reg: The register index.
1412 * @value: The new register value.
1413 */
1414int snd_soc_cache_write(struct snd_soc_codec *codec,
1415 unsigned int reg, unsigned int value)
1416{
1417 int ret;
1418
1419 mutex_lock(&codec->cache_rw_mutex);
1420
1421 if (codec->cache_ops && codec->cache_ops->write) {
1422 ret = codec->cache_ops->write(codec, reg, value);
1423 mutex_unlock(&codec->cache_rw_mutex);
1424 return ret;
1425 }
1426
1427 mutex_unlock(&codec->cache_rw_mutex);
1428 return -EINVAL;
1429}
1430EXPORT_SYMBOL_GPL(snd_soc_cache_write);
1431
1432/**
1433 * snd_soc_cache_sync: Sync the register cache with the hardware.
1434 *
1435 * @codec: CODEC to configure.
1436 *
1437 * Any registers that should not be synced should be marked as
1438 * volatile. In general drivers can choose not to use the provided
1439 * syncing functionality if they so require.
1440 */
1441int snd_soc_cache_sync(struct snd_soc_codec *codec)
1442{
1443 int ret;
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001444 const char *name;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001445
1446 if (!codec->cache_sync) {
1447 return 0;
1448 }
1449
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001450 if (!codec->cache_ops || !codec->cache_ops->sync)
1451 return -EINVAL;
1452
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001453 if (codec->cache_ops->name)
1454 name = codec->cache_ops->name;
1455 else
1456 name = "unknown";
1457
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001458 if (codec->cache_ops->name)
1459 dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
1460 codec->cache_ops->name, codec->name);
1461 trace_snd_soc_cache_sync(codec, name, "start");
1462 ret = codec->cache_ops->sync(codec);
1463 if (!ret)
1464 codec->cache_sync = 0;
1465 trace_snd_soc_cache_sync(codec, name, "end");
1466 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001467}
1468EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
Dimitris Papastamos066d16c2011-01-13 12:20:36 +00001469
1470static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec,
1471 unsigned int reg)
1472{
1473 const struct snd_soc_codec_driver *codec_drv;
1474 unsigned int min, max, index;
1475
1476 codec_drv = codec->driver;
1477 min = 0;
1478 max = codec_drv->reg_access_size - 1;
1479 do {
1480 index = (min + max) / 2;
1481 if (codec_drv->reg_access_default[index].reg == reg)
1482 return index;
1483 if (codec_drv->reg_access_default[index].reg < reg)
1484 min = index + 1;
1485 else
1486 max = index;
1487 } while (min <= max);
1488 return -1;
1489}
1490
1491int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
1492 unsigned int reg)
1493{
1494 int index;
1495
1496 if (reg >= codec->driver->reg_cache_size)
1497 return 1;
1498 index = snd_soc_get_reg_access_index(codec, reg);
1499 if (index < 0)
1500 return 0;
1501 return codec->driver->reg_access_default[index].vol;
1502}
1503EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register);
1504
1505int snd_soc_default_readable_register(struct snd_soc_codec *codec,
1506 unsigned int reg)
1507{
1508 int index;
1509
1510 if (reg >= codec->driver->reg_cache_size)
1511 return 1;
1512 index = snd_soc_get_reg_access_index(codec, reg);
1513 if (index < 0)
1514 return 0;
1515 return codec->driver->reg_access_default[index].read;
1516}
1517EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);