blob: d1d4059be04e654b7f349807536d4ff11a786c5b [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 Papastamos30539a12011-03-22 10:37:00 +000023#if defined(CONFIG_SPI_MASTER)
24static int do_spi_write(void *control_data, const void *msg,
25 int len)
26{
27 struct spi_device *spi = control_data;
28 struct spi_transfer t;
29 struct spi_message m;
30
31 if (len <= 0)
32 return 0;
33
34 spi_message_init(&m);
35 memset(&t, 0, sizeof t);
36
37 t.tx_buf = msg;
38 t.len = len;
39
40 spi_message_add_tail(&t, &m);
41 spi_sync(spi, &m);
42
43 return len;
44}
45#endif
46
Dimitris Papastamos26e99842011-03-22 10:36:58 +000047static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
48 unsigned int value, const void *data, int len)
49{
50 int ret;
51
52 if (!snd_soc_codec_volatile_register(codec, reg) &&
53 reg < codec->driver->reg_cache_size &&
54 !codec->cache_bypass) {
55 ret = snd_soc_cache_write(codec, reg, value);
56 if (ret < 0)
57 return -1;
58 }
59
60 if (codec->cache_only) {
61 codec->cache_sync = 1;
62 return 0;
63 }
64
65 ret = codec->hw_write(codec->control_data, data, len);
66 if (ret == len)
67 return 0;
68 if (ret < 0)
69 return ret;
70 else
71 return -EIO;
72}
73
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000074static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg)
Barry Song63b62ab2010-01-27 11:46:17 +080075{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000076 int ret;
77 unsigned int val;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010078
79 if (reg >= codec->driver->reg_cache_size ||
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000080 snd_soc_codec_volatile_register(codec, reg) ||
81 codec->cache_bypass) {
82 if (codec->cache_only)
83 return -1;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010084
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000085 BUG_ON(!codec->hw_read);
86 return codec->hw_read(codec, reg);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010087 }
88
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000089 ret = snd_soc_cache_read(codec, reg, &val);
90 if (ret < 0)
91 return -1;
92 return val;
Barry Song63b62ab2010-01-27 11:46:17 +080093}
94
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000095static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +010096 unsigned int reg)
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000097{
98 return do_hw_read(codec, reg);
99}
100
Barry Song63b62ab2010-01-27 11:46:17 +0800101static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100102 unsigned int value)
Barry Song63b62ab2010-01-27 11:46:17 +0800103{
Barry Song63b62ab2010-01-27 11:46:17 +0800104 u8 data[2];
Barry Song63b62ab2010-01-27 11:46:17 +0800105
Barry Song63b62ab2010-01-27 11:46:17 +0800106 data[0] = (reg << 4) | ((value >> 8) & 0x000f);
107 data[1] = value & 0x00ff;
108
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000109 return do_hw_write(codec, reg, value, data, 2);
Barry Song63b62ab2010-01-27 11:46:17 +0800110}
111
112#if defined(CONFIG_SPI_MASTER)
113static int snd_soc_4_12_spi_write(void *control_data, const char *data,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100114 int len)
Barry Song63b62ab2010-01-27 11:46:17 +0800115{
Barry Song63b62ab2010-01-27 11:46:17 +0800116 u8 msg[2];
117
Barry Song63b62ab2010-01-27 11:46:17 +0800118 msg[0] = data[1];
119 msg[1] = data[0];
120
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000121 return do_spi_write(control_data, msg, len);
Barry Song63b62ab2010-01-27 11:46:17 +0800122}
123#else
124#define snd_soc_4_12_spi_write NULL
125#endif
126
Mark Brown17a52fd2009-07-05 17:24:50 +0100127static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
128 unsigned int reg)
129{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000130 return do_hw_read(codec, reg);
Mark Brown17a52fd2009-07-05 17:24:50 +0100131}
132
133static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
134 unsigned int value)
135{
Mark Brownf06f1362011-05-11 00:56:13 +0200136 u16 data;
Mark Brown17a52fd2009-07-05 17:24:50 +0100137
Mark Brownf06f1362011-05-11 00:56:13 +0200138 data = cpu_to_be16((reg << 9) | (value & 0x1ff));
Mark Brown17a52fd2009-07-05 17:24:50 +0100139
Mark Brownf06f1362011-05-11 00:56:13 +0200140 return do_hw_write(codec, reg, value, &data, 2);
Mark Brown17a52fd2009-07-05 17:24:50 +0100141}
142
Mark Brown27ded042009-07-10 23:28:16 +0100143#if defined(CONFIG_SPI_MASTER)
144static int snd_soc_7_9_spi_write(void *control_data, const char *data,
145 int len)
146{
Mark Brown27ded042009-07-10 23:28:16 +0100147 u8 msg[2];
148
Mark Brown27ded042009-07-10 23:28:16 +0100149 msg[0] = data[0];
150 msg[1] = data[1];
151
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000152 return do_spi_write(control_data, msg, len);
Mark Brown27ded042009-07-10 23:28:16 +0100153}
154#else
155#define snd_soc_7_9_spi_write NULL
156#endif
157
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900158static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
159 unsigned int value)
160{
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900161 u8 data[2];
162
Barry Songf4bee1b2010-03-18 16:17:01 +0800163 reg &= 0xff;
164 data[0] = reg;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900165 data[1] = value & 0xff;
166
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000167 return do_hw_write(codec, reg, value, data, 2);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900168}
169
170static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
171 unsigned int reg)
172{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000173 return do_hw_read(codec, reg);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900174}
175
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100176#if defined(CONFIG_SPI_MASTER)
177static int snd_soc_8_8_spi_write(void *control_data, const char *data,
178 int len)
179{
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100180 u8 msg[2];
181
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100182 msg[0] = data[0];
183 msg[1] = data[1];
184
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000185 return do_spi_write(control_data, msg, len);
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100186}
187#else
188#define snd_soc_8_8_spi_write NULL
189#endif
190
Mark Brownafa2f102009-07-10 23:11:24 +0100191static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
192 unsigned int value)
193{
Mark Brownafa2f102009-07-10 23:11:24 +0100194 u8 data[3];
Mark Brown94228bcf2011-05-11 11:18:00 +0200195 u16 val = cpu_to_be16(value);
Mark Brownafa2f102009-07-10 23:11:24 +0100196
197 data[0] = reg;
Mark Brown94228bcf2011-05-11 11:18:00 +0200198 memcpy(&data[1], &val, sizeof(val));
Mark Brownafa2f102009-07-10 23:11:24 +0100199
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000200 return do_hw_write(codec, reg, value, data, 3);
Mark Brownafa2f102009-07-10 23:11:24 +0100201}
202
203static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
204 unsigned int reg)
205{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000206 return do_hw_read(codec, reg);
Mark Brownafa2f102009-07-10 23:11:24 +0100207}
208
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100209#if defined(CONFIG_SPI_MASTER)
210static int snd_soc_8_16_spi_write(void *control_data, const char *data,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100211 int len)
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100212{
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100213 u8 msg[3];
214
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100215 msg[0] = data[0];
216 msg[1] = data[1];
217 msg[2] = data[2];
218
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000219 return do_spi_write(control_data, msg, len);
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100220}
221#else
222#define snd_soc_8_16_spi_write NULL
223#endif
224
Randy Dunlap17244c22009-08-10 16:04:39 -0700225#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000226static unsigned int do_i2c_read(struct snd_soc_codec *codec,
227 void *reg, int reglen,
228 void *data, int datalen)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800229{
230 struct i2c_msg xfer[2];
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800231 int ret;
232 struct i2c_client *client = codec->control_data;
233
234 /* Write register */
235 xfer[0].addr = client->addr;
236 xfer[0].flags = 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000237 xfer[0].len = reglen;
238 xfer[0].buf = reg;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800239
240 /* Read data */
241 xfer[1].addr = client->addr;
242 xfer[1].flags = I2C_M_RD;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000243 xfer[1].len = datalen;
244 xfer[1].buf = data;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800245
246 ret = i2c_transfer(client->adapter, xfer, 2);
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000247 if (ret == 2)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800248 return 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000249 else if (ret < 0)
250 return ret;
251 else
252 return -EIO;
253}
254#endif
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800255
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000256#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
257static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100258 unsigned int r)
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000259{
260 u8 reg = r;
261 u8 data;
262 int ret;
263
264 ret = do_i2c_read(codec, &reg, 1, &data, 1);
265 if (ret < 0)
266 return 0;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800267 return data;
268}
269#else
270#define snd_soc_8_8_read_i2c NULL
271#endif
272
273#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100274static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
275 unsigned int r)
276{
Mark Brownafa2f102009-07-10 23:11:24 +0100277 u8 reg = r;
278 u16 data;
279 int ret;
Mark Brownafa2f102009-07-10 23:11:24 +0100280
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000281 ret = do_i2c_read(codec, &reg, 1, &data, 2);
282 if (ret < 0)
Mark Brownafa2f102009-07-10 23:11:24 +0100283 return 0;
Mark Brownafa2f102009-07-10 23:11:24 +0100284 return (data >> 8) | ((data & 0xff) << 8);
285}
286#else
287#define snd_soc_8_16_read_i2c NULL
288#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100289
Barry Song994dc422010-01-27 11:46:18 +0800290#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
291static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
292 unsigned int r)
293{
Barry Song994dc422010-01-27 11:46:18 +0800294 u16 reg = r;
295 u8 data;
296 int ret;
Barry Song994dc422010-01-27 11:46:18 +0800297
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000298 ret = do_i2c_read(codec, &reg, 2, &data, 1);
299 if (ret < 0)
Barry Song994dc422010-01-27 11:46:18 +0800300 return 0;
Barry Song994dc422010-01-27 11:46:18 +0800301 return data;
302}
303#else
304#define snd_soc_16_8_read_i2c NULL
305#endif
306
307static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100308 unsigned int reg)
Barry Song994dc422010-01-27 11:46:18 +0800309{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000310 return do_hw_read(codec, reg);
Barry Song994dc422010-01-27 11:46:18 +0800311}
312
313static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100314 unsigned int value)
Barry Song994dc422010-01-27 11:46:18 +0800315{
Barry Song994dc422010-01-27 11:46:18 +0800316 u8 data[3];
Mark Brown2ac8b6f2011-05-11 15:15:56 +0200317 u16 rval = cpu_to_be16(reg);
Barry Song994dc422010-01-27 11:46:18 +0800318
Mark Brown2ac8b6f2011-05-11 15:15:56 +0200319 memcpy(data, &rval, sizeof(rval));
Barry Song994dc422010-01-27 11:46:18 +0800320 data[2] = value;
Barry Song994dc422010-01-27 11:46:18 +0800321 reg &= 0xff;
Mark Brown8c961bc2010-02-01 18:46:10 +0000322
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000323 return do_hw_write(codec, reg, value, data, 3);
Barry Song994dc422010-01-27 11:46:18 +0800324}
325
326#if defined(CONFIG_SPI_MASTER)
327static int snd_soc_16_8_spi_write(void *control_data, const char *data,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100328 int len)
Barry Song994dc422010-01-27 11:46:18 +0800329{
Barry Song994dc422010-01-27 11:46:18 +0800330 u8 msg[3];
331
Barry Song994dc422010-01-27 11:46:18 +0800332 msg[0] = data[0];
333 msg[1] = data[1];
334 msg[2] = data[2];
335
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000336 return do_spi_write(control_data, msg, len);
Barry Song994dc422010-01-27 11:46:18 +0800337}
338#else
339#define snd_soc_16_8_spi_write NULL
340#endif
341
Mark Brownbc6552f2010-03-05 16:27:15 +0000342#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
343static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
344 unsigned int r)
345{
Mark Brownbc6552f2010-03-05 16:27:15 +0000346 u16 reg = cpu_to_be16(r);
347 u16 data;
348 int ret;
Mark Brownbc6552f2010-03-05 16:27:15 +0000349
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000350 ret = do_i2c_read(codec, &reg, 2, &data, 2);
351 if (ret < 0)
Mark Brownbc6552f2010-03-05 16:27:15 +0000352 return 0;
Mark Brownbc6552f2010-03-05 16:27:15 +0000353 return be16_to_cpu(data);
354}
355#else
356#define snd_soc_16_16_read_i2c NULL
357#endif
358
359static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
360 unsigned int reg)
361{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000362 return do_hw_read(codec, reg);
Mark Brownbc6552f2010-03-05 16:27:15 +0000363}
364
365static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
366 unsigned int value)
367{
Mark Brown60c655e2011-05-11 01:02:35 +0200368 u16 data[2];
Mark Brownbc6552f2010-03-05 16:27:15 +0000369
Mark Brown60c655e2011-05-11 01:02:35 +0200370 data[0] = cpu_to_be16(reg);
371 data[1] = cpu_to_be16(value);
Mark Brownbc6552f2010-03-05 16:27:15 +0000372
Mark Brown60c655e2011-05-11 01:02:35 +0200373 return do_hw_write(codec, reg, value, data, sizeof(data));
Mark Brownbc6552f2010-03-05 16:27:15 +0000374}
Barry Song994dc422010-01-27 11:46:18 +0800375
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100376#if defined(CONFIG_SPI_MASTER)
377static int snd_soc_16_16_spi_write(void *control_data, const char *data,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100378 int len)
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100379{
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100380 u8 msg[4];
381
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100382 msg[0] = data[0];
383 msg[1] = data[1];
384 msg[2] = data[2];
385 msg[3] = data[3];
386
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000387 return do_spi_write(control_data, msg, len);
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100388}
389#else
390#define snd_soc_16_16_spi_write NULL
391#endif
392
Mark Brown34bad692011-04-04 17:55:42 +0900393/* Primitive bulk write support for soc-cache. The data pointed to by
394 * `data' needs to already be in the form the hardware expects
395 * including any leading register specific data. Any data written
396 * through this function will not go through the cache as it only
397 * handles writing to volatile or out of bounds registers.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000398 */
399static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
400 const void *data, size_t len)
401{
402 int ret;
403
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100404 /* To ensure that we don't get out of sync with the cache, check
405 * whether the base register is volatile or if we've directly asked
406 * to bypass the cache. Out of bounds registers are considered
407 * volatile.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000408 */
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100409 if (!codec->cache_bypass
410 && !snd_soc_codec_volatile_register(codec, reg)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000411 && reg < codec->driver->reg_cache_size)
412 return -EINVAL;
413
414 switch (codec->control_type) {
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900415#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000416 case SND_SOC_I2C:
417 ret = i2c_master_send(codec->control_data, data, len);
418 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900419#endif
420#if defined(CONFIG_SPI_MASTER)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000421 case SND_SOC_SPI:
422 ret = do_spi_write(codec->control_data, data, len);
423 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900424#endif
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000425 default:
426 BUG();
427 }
428
429 if (ret == len)
430 return 0;
431 if (ret < 0)
432 return ret;
433 else
434 return -EIO;
435}
436
Mark Brown17a52fd2009-07-05 17:24:50 +0100437static struct {
438 int addr_bits;
439 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100440 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown27ded042009-07-10 23:28:16 +0100441 int (*spi_write)(void *, const char *, int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100442 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100443 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100444} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700445 {
Barry Song63b62ab2010-01-27 11:46:17 +0800446 .addr_bits = 4, .data_bits = 12,
447 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
448 .spi_write = snd_soc_4_12_spi_write,
449 },
450 {
Mark Brownd62ab352009-09-21 04:21:47 -0700451 .addr_bits = 7, .data_bits = 9,
452 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Barry Song8998c892009-12-31 10:30:34 +0800453 .spi_write = snd_soc_7_9_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700454 },
455 {
456 .addr_bits = 8, .data_bits = 8,
457 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800458 .i2c_read = snd_soc_8_8_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100459 .spi_write = snd_soc_8_8_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700460 },
461 {
462 .addr_bits = 8, .data_bits = 16,
463 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
464 .i2c_read = snd_soc_8_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100465 .spi_write = snd_soc_8_16_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700466 },
Barry Song994dc422010-01-27 11:46:18 +0800467 {
468 .addr_bits = 16, .data_bits = 8,
469 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
470 .i2c_read = snd_soc_16_8_read_i2c,
471 .spi_write = snd_soc_16_8_spi_write,
472 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000473 {
474 .addr_bits = 16, .data_bits = 16,
475 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
476 .i2c_read = snd_soc_16_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100477 .spi_write = snd_soc_16_16_spi_write,
Mark Brownbc6552f2010-03-05 16:27:15 +0000478 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100479};
480
481/**
482 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
483 *
484 * @codec: CODEC to configure.
Mark Brown17a52fd2009-07-05 17:24:50 +0100485 * @addr_bits: Number of bits of register address data.
486 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100487 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100488 *
489 * Register formats are frequently shared between many I2C and SPI
490 * devices. In order to promote code reuse the ASoC core provides
491 * some standard implementations of CODEC read and write operations
492 * which can be set up using this function.
493 *
494 * The caller is responsible for allocating and initialising the
495 * actual cache.
496 *
497 * Note that at present this code cannot be used by CODECs with
498 * volatile registers.
499 */
500int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100501 int addr_bits, int data_bits,
502 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100503{
504 int i;
505
Mark Brown17a52fd2009-07-05 17:24:50 +0100506 for (i = 0; i < ARRAY_SIZE(io_types); i++)
507 if (io_types[i].addr_bits == addr_bits &&
508 io_types[i].data_bits == data_bits)
509 break;
510 if (i == ARRAY_SIZE(io_types)) {
511 printk(KERN_ERR
512 "No I/O functions for %d bit address %d bit data\n",
513 addr_bits, data_bits);
514 return -EINVAL;
515 }
516
Mark Brownc3acec22010-12-02 16:15:29 +0000517 codec->write = io_types[i].write;
518 codec->read = io_types[i].read;
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000519 codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
Mark Brown17a52fd2009-07-05 17:24:50 +0100520
Mark Brown7084a422009-07-10 22:24:27 +0100521 switch (control) {
522 case SND_SOC_CUSTOM:
523 break;
524
525 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700526#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100527 codec->hw_write = (hw_write_t)i2c_master_send;
528#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100529 if (io_types[i].i2c_read)
530 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100531
532 codec->control_data = container_of(codec->dev,
533 struct i2c_client,
534 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100535 break;
536
537 case SND_SOC_SPI:
Mark Brown27ded042009-07-10 23:28:16 +0100538 if (io_types[i].spi_write)
539 codec->hw_write = io_types[i].spi_write;
Mark Browna6d14342010-08-12 10:59:15 +0100540
541 codec->control_data = container_of(codec->dev,
542 struct spi_device,
543 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100544 break;
545 }
546
Mark Brown17a52fd2009-07-05 17:24:50 +0100547 return 0;
548}
549EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000550
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000551static bool snd_soc_set_cache_val(void *base, unsigned int idx,
552 unsigned int val, unsigned int word_size)
553{
554 switch (word_size) {
555 case 1: {
556 u8 *cache = base;
557 if (cache[idx] == val)
558 return true;
559 cache[idx] = val;
560 break;
561 }
562 case 2: {
563 u16 *cache = base;
564 if (cache[idx] == val)
565 return true;
566 cache[idx] = val;
567 break;
568 }
569 default:
570 BUG();
571 }
572 return false;
573}
574
575static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
576 unsigned int word_size)
577{
578 switch (word_size) {
579 case 1: {
580 const u8 *cache = base;
581 return cache[idx];
582 }
583 case 2: {
584 const u16 *cache = base;
585 return cache[idx];
586 }
587 default:
588 BUG();
589 }
590 /* unreachable */
591 return -1;
592}
593
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000594struct snd_soc_rbtree_node {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100595 struct rb_node node; /* the actual rbtree node holding this block */
596 unsigned int base_reg; /* base register handled by this block */
597 unsigned int word_size; /* number of bytes needed to represent the register index */
598 void *block; /* block of adjacent registers */
599 unsigned int blklen; /* number of registers available in the block */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000600} __attribute__ ((packed));
601
602struct snd_soc_rbtree_ctx {
603 struct rb_root root;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100604 struct snd_soc_rbtree_node *cached_rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000605};
606
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100607static inline void snd_soc_rbtree_get_base_top_reg(
608 struct snd_soc_rbtree_node *rbnode,
609 unsigned int *base, unsigned int *top)
610{
611 *base = rbnode->base_reg;
612 *top = rbnode->base_reg + rbnode->blklen - 1;
613}
614
615static unsigned int snd_soc_rbtree_get_register(
616 struct snd_soc_rbtree_node *rbnode, unsigned int idx)
617{
618 unsigned int val;
619
620 switch (rbnode->word_size) {
621 case 1: {
622 u8 *p = rbnode->block;
623 val = p[idx];
624 return val;
625 }
626 case 2: {
627 u16 *p = rbnode->block;
628 val = p[idx];
629 return val;
630 }
631 default:
632 BUG();
633 break;
634 }
635 return -1;
636}
637
638static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
639 unsigned int idx, unsigned int val)
640{
641 switch (rbnode->word_size) {
642 case 1: {
643 u8 *p = rbnode->block;
644 p[idx] = val;
645 break;
646 }
647 case 2: {
648 u16 *p = rbnode->block;
649 p[idx] = val;
650 break;
651 }
652 default:
653 BUG();
654 break;
655 }
656}
657
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000658static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
659 struct rb_root *root, unsigned int reg)
660{
661 struct rb_node *node;
662 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100663 unsigned int base_reg, top_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000664
665 node = root->rb_node;
666 while (node) {
667 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100668 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
669 if (reg >= base_reg && reg <= top_reg)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000670 return rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100671 else if (reg > top_reg)
672 node = node->rb_right;
673 else if (reg < base_reg)
674 node = node->rb_left;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000675 }
676
677 return NULL;
678}
679
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000680static int snd_soc_rbtree_insert(struct rb_root *root,
681 struct snd_soc_rbtree_node *rbnode)
682{
683 struct rb_node **new, *parent;
684 struct snd_soc_rbtree_node *rbnode_tmp;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100685 unsigned int base_reg_tmp, top_reg_tmp;
686 unsigned int base_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000687
688 parent = NULL;
689 new = &root->rb_node;
690 while (*new) {
691 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
692 node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100693 /* base and top registers of the current rbnode */
694 snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
695 &top_reg_tmp);
696 /* base register of the rbnode to be added */
697 base_reg = rbnode->base_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000698 parent = *new;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100699 /* if this register has already been inserted, just return */
700 if (base_reg >= base_reg_tmp &&
701 base_reg <= top_reg_tmp)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000702 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100703 else if (base_reg > top_reg_tmp)
704 new = &((*new)->rb_right);
705 else if (base_reg < base_reg_tmp)
706 new = &((*new)->rb_left);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000707 }
708
709 /* insert the node into the rbtree */
710 rb_link_node(&rbnode->node, parent, new);
711 rb_insert_color(&rbnode->node, root);
712
713 return 1;
714}
715
716static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
717{
718 struct snd_soc_rbtree_ctx *rbtree_ctx;
719 struct rb_node *node;
720 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100721 unsigned int regtmp;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000722 unsigned int val;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000723 int ret;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100724 int i;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000725
726 rbtree_ctx = codec->reg_cache;
727 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
728 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100729 for (i = 0; i < rbnode->blklen; ++i) {
730 regtmp = rbnode->base_reg + i;
731 WARN_ON(codec->writable_register &&
732 codec->writable_register(codec, regtmp));
733 val = snd_soc_rbtree_get_register(rbnode, i);
734 codec->cache_bypass = 1;
735 ret = snd_soc_write(codec, regtmp, val);
736 codec->cache_bypass = 0;
737 if (ret)
738 return ret;
739 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
740 regtmp, val);
741 }
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000742 }
743
744 return 0;
745}
746
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100747static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
748 unsigned int pos, unsigned int reg,
749 unsigned int value)
750{
751 u8 *blk;
752
753 blk = krealloc(rbnode->block,
754 (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
755 if (!blk)
756 return -ENOMEM;
757
758 /* insert the register value in the correct place in the rbnode block */
759 memmove(blk + (pos + 1) * rbnode->word_size,
760 blk + pos * rbnode->word_size,
761 (rbnode->blklen - pos) * rbnode->word_size);
762
763 /* update the rbnode block, its size and the base register */
764 rbnode->block = blk;
765 rbnode->blklen++;
766 if (!pos)
767 rbnode->base_reg = reg;
768
769 snd_soc_rbtree_set_register(rbnode, pos, value);
770 return 0;
771}
772
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000773static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
774 unsigned int reg, unsigned int value)
775{
776 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100777 struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
778 struct rb_node *node;
779 unsigned int val;
780 unsigned int reg_tmp;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100781 unsigned int base_reg, top_reg;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100782 unsigned int pos;
783 int i;
784 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000785
786 rbtree_ctx = codec->reg_cache;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100787 /* look up the required register in the cached rbnode */
788 rbnode = rbtree_ctx->cached_rbnode;
789 if (rbnode) {
790 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
791 if (reg >= base_reg && reg <= top_reg) {
792 reg_tmp = reg - base_reg;
793 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
794 if (val == value)
795 return 0;
796 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
797 return 0;
798 }
799 }
800 /* if we can't locate it in the cached rbnode we'll have
801 * to traverse the rbtree looking for it.
802 */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000803 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
804 if (rbnode) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100805 reg_tmp = reg - rbnode->base_reg;
806 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
807 if (val == value)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000808 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100809 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100810 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000811 } else {
812 /* bail out early, no need to create the rbnode yet */
813 if (!value)
814 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100815 /* look for an adjacent register to the one we are about to add */
816 for (node = rb_first(&rbtree_ctx->root); node;
817 node = rb_next(node)) {
818 rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
819 for (i = 0; i < rbnode_tmp->blklen; ++i) {
820 reg_tmp = rbnode_tmp->base_reg + i;
821 if (abs(reg_tmp - reg) != 1)
822 continue;
823 /* decide where in the block to place our register */
824 if (reg_tmp + 1 == reg)
825 pos = i + 1;
826 else
827 pos = i;
828 ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
829 reg, value);
830 if (ret)
831 return ret;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100832 rbtree_ctx->cached_rbnode = rbnode_tmp;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100833 return 0;
834 }
835 }
836 /* we did not manage to find a place to insert it in an existing
837 * block so create a new rbnode with a single register in its block.
838 * This block will get populated further if any other adjacent
839 * registers get modified in the future.
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000840 */
841 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
842 if (!rbnode)
843 return -ENOMEM;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100844 rbnode->blklen = 1;
845 rbnode->base_reg = reg;
846 rbnode->word_size = codec->driver->reg_word_size;
847 rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
848 GFP_KERNEL);
849 if (!rbnode->block) {
850 kfree(rbnode);
851 return -ENOMEM;
852 }
853 snd_soc_rbtree_set_register(rbnode, 0, value);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000854 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100855 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000856 }
857
858 return 0;
859}
860
861static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
862 unsigned int reg, unsigned int *value)
863{
864 struct snd_soc_rbtree_ctx *rbtree_ctx;
865 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100866 unsigned int base_reg, top_reg;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100867 unsigned int reg_tmp;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000868
869 rbtree_ctx = codec->reg_cache;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100870 /* look up the required register in the cached rbnode */
871 rbnode = rbtree_ctx->cached_rbnode;
872 if (rbnode) {
873 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
874 if (reg >= base_reg && reg <= top_reg) {
875 reg_tmp = reg - base_reg;
876 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
877 return 0;
878 }
879 }
880 /* if we can't locate it in the cached rbnode we'll have
881 * to traverse the rbtree looking for it.
882 */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000883 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
884 if (rbnode) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100885 reg_tmp = reg - rbnode->base_reg;
886 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100887 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000888 } else {
889 /* uninitialized registers default to 0 */
890 *value = 0;
891 }
892
893 return 0;
894}
895
896static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
897{
898 struct rb_node *next;
899 struct snd_soc_rbtree_ctx *rbtree_ctx;
900 struct snd_soc_rbtree_node *rbtree_node;
901
902 /* if we've already been called then just return */
903 rbtree_ctx = codec->reg_cache;
904 if (!rbtree_ctx)
905 return 0;
906
907 /* free up the rbtree */
908 next = rb_first(&rbtree_ctx->root);
909 while (next) {
910 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
911 next = rb_next(&rbtree_node->node);
912 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100913 kfree(rbtree_node->block);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000914 kfree(rbtree_node);
915 }
916
917 /* release the resources */
918 kfree(codec->reg_cache);
919 codec->reg_cache = NULL;
920
921 return 0;
922}
923
924static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
925{
926 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000927 unsigned int word_size;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100928 unsigned int val;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000929 int i;
930 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000931
932 codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
933 if (!codec->reg_cache)
934 return -ENOMEM;
935
936 rbtree_ctx = codec->reg_cache;
937 rbtree_ctx->root = RB_ROOT;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100938 rbtree_ctx->cached_rbnode = NULL;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000939
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000940 if (!codec->reg_def_copy)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000941 return 0;
942
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000943 word_size = codec->driver->reg_word_size;
944 for (i = 0; i < codec->driver->reg_cache_size; ++i) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100945 val = snd_soc_get_cache_val(codec->reg_def_copy, i,
946 word_size);
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000947 if (!val)
948 continue;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100949 ret = snd_soc_rbtree_cache_write(codec, i, val);
950 if (ret)
951 goto err;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000952 }
953
954 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100955
956err:
957 snd_soc_cache_exit(codec);
958 return ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000959}
960
Mark Brown68d44ee2010-12-21 17:19:56 +0000961#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000962struct snd_soc_lzo_ctx {
963 void *wmem;
964 void *dst;
965 const void *src;
966 size_t src_len;
967 size_t dst_len;
968 size_t decompressed_size;
969 unsigned long *sync_bmp;
970 int sync_bmp_nbits;
971};
972
973#define LZO_BLOCK_NUM 8
974static int snd_soc_lzo_block_count(void)
975{
976 return LZO_BLOCK_NUM;
977}
978
979static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx)
980{
981 lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
982 if (!lzo_ctx->wmem)
983 return -ENOMEM;
984 return 0;
985}
986
987static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx)
988{
989 size_t compress_size;
990 int ret;
991
992 ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
993 lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
994 if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
995 return -EINVAL;
996 lzo_ctx->dst_len = compress_size;
997 return 0;
998}
999
1000static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx)
1001{
1002 size_t dst_len;
1003 int ret;
1004
1005 dst_len = lzo_ctx->dst_len;
1006 ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
1007 lzo_ctx->dst, &dst_len);
1008 if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
1009 return -EINVAL;
1010 return 0;
1011}
1012
1013static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec,
1014 struct snd_soc_lzo_ctx *lzo_ctx)
1015{
1016 int ret;
1017
1018 lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
1019 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
1020 if (!lzo_ctx->dst) {
1021 lzo_ctx->dst_len = 0;
1022 return -ENOMEM;
1023 }
1024
1025 ret = snd_soc_lzo_compress(lzo_ctx);
1026 if (ret < 0)
1027 return ret;
1028 return 0;
1029}
1030
1031static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec,
1032 struct snd_soc_lzo_ctx *lzo_ctx)
1033{
1034 int ret;
1035
1036 lzo_ctx->dst_len = lzo_ctx->decompressed_size;
1037 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
1038 if (!lzo_ctx->dst) {
1039 lzo_ctx->dst_len = 0;
1040 return -ENOMEM;
1041 }
1042
1043 ret = snd_soc_lzo_decompress(lzo_ctx);
1044 if (ret < 0)
1045 return ret;
1046 return 0;
1047}
1048
1049static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
1050 unsigned int reg)
1051{
Mark Brown001ae4c2010-12-02 16:21:08 +00001052 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001053
1054 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001055 return (reg * codec_drv->reg_word_size) /
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001056 DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001057}
1058
1059static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
1060 unsigned int reg)
1061{
Mark Brown001ae4c2010-12-02 16:21:08 +00001062 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001063
1064 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001065 return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) /
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001066 codec_drv->reg_word_size);
1067}
1068
1069static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
1070{
Mark Brown001ae4c2010-12-02 16:21:08 +00001071 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001072
1073 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001074 return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001075}
1076
1077static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
1078{
1079 struct snd_soc_lzo_ctx **lzo_blocks;
1080 unsigned int val;
1081 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001082 int ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001083
1084 lzo_blocks = codec->reg_cache;
1085 for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +01001086 WARN_ON(codec->writable_register &&
1087 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001088 ret = snd_soc_cache_read(codec, i, &val);
1089 if (ret)
1090 return ret;
Dimitris Papastamos99780072011-01-19 14:53:37 +00001091 codec->cache_bypass = 1;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001092 ret = snd_soc_write(codec, i, val);
Dimitris Papastamos99780072011-01-19 14:53:37 +00001093 codec->cache_bypass = 0;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001094 if (ret)
1095 return ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001096 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1097 i, val);
1098 }
1099
1100 return 0;
1101}
1102
1103static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
1104 unsigned int reg, unsigned int value)
1105{
1106 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1107 int ret, blkindex, blkpos;
1108 size_t blksize, tmp_dst_len;
1109 void *tmp_dst;
1110
1111 /* index of the compressed lzo block */
1112 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1113 /* register index within the decompressed block */
1114 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1115 /* size of the compressed block */
1116 blksize = snd_soc_lzo_get_blksize(codec);
1117 lzo_blocks = codec->reg_cache;
1118 lzo_block = lzo_blocks[blkindex];
1119
1120 /* save the pointer and length of the compressed block */
1121 tmp_dst = lzo_block->dst;
1122 tmp_dst_len = lzo_block->dst_len;
1123
1124 /* prepare the source to be the compressed block */
1125 lzo_block->src = lzo_block->dst;
1126 lzo_block->src_len = lzo_block->dst_len;
1127
1128 /* decompress the block */
1129 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
1130 if (ret < 0) {
1131 kfree(lzo_block->dst);
1132 goto out;
1133 }
1134
1135 /* write the new value to the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001136 if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value,
1137 codec->driver->reg_word_size)) {
1138 kfree(lzo_block->dst);
1139 goto out;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001140 }
1141
1142 /* prepare the source to be the decompressed block */
1143 lzo_block->src = lzo_block->dst;
1144 lzo_block->src_len = lzo_block->dst_len;
1145
1146 /* compress the block */
1147 ret = snd_soc_lzo_compress_cache_block(codec, lzo_block);
1148 if (ret < 0) {
1149 kfree(lzo_block->dst);
1150 kfree(lzo_block->src);
1151 goto out;
1152 }
1153
1154 /* set the bit so we know we have to sync this register */
1155 set_bit(reg, lzo_block->sync_bmp);
1156 kfree(tmp_dst);
1157 kfree(lzo_block->src);
1158 return 0;
1159out:
1160 lzo_block->dst = tmp_dst;
1161 lzo_block->dst_len = tmp_dst_len;
1162 return ret;
1163}
1164
1165static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
1166 unsigned int reg, unsigned int *value)
1167{
1168 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1169 int ret, blkindex, blkpos;
1170 size_t blksize, tmp_dst_len;
1171 void *tmp_dst;
1172
1173 *value = 0;
1174 /* index of the compressed lzo block */
1175 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1176 /* register index within the decompressed block */
1177 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1178 /* size of the compressed block */
1179 blksize = snd_soc_lzo_get_blksize(codec);
1180 lzo_blocks = codec->reg_cache;
1181 lzo_block = lzo_blocks[blkindex];
1182
1183 /* save the pointer and length of the compressed block */
1184 tmp_dst = lzo_block->dst;
1185 tmp_dst_len = lzo_block->dst_len;
1186
1187 /* prepare the source to be the compressed block */
1188 lzo_block->src = lzo_block->dst;
1189 lzo_block->src_len = lzo_block->dst_len;
1190
1191 /* decompress the block */
1192 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001193 if (ret >= 0)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001194 /* fetch the value from the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001195 *value = snd_soc_get_cache_val(lzo_block->dst, blkpos,
1196 codec->driver->reg_word_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001197
1198 kfree(lzo_block->dst);
1199 /* restore the pointer and length of the compressed block */
1200 lzo_block->dst = tmp_dst;
1201 lzo_block->dst_len = tmp_dst_len;
1202 return 0;
1203}
1204
1205static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
1206{
1207 struct snd_soc_lzo_ctx **lzo_blocks;
1208 int i, blkcount;
1209
1210 lzo_blocks = codec->reg_cache;
1211 if (!lzo_blocks)
1212 return 0;
1213
1214 blkcount = snd_soc_lzo_block_count();
1215 /*
1216 * the pointer to the bitmap used for syncing the cache
1217 * is shared amongst all lzo_blocks. Ensure it is freed
1218 * only once.
1219 */
1220 if (lzo_blocks[0])
1221 kfree(lzo_blocks[0]->sync_bmp);
1222 for (i = 0; i < blkcount; ++i) {
1223 if (lzo_blocks[i]) {
1224 kfree(lzo_blocks[i]->wmem);
1225 kfree(lzo_blocks[i]->dst);
1226 }
1227 /* each lzo_block is a pointer returned by kmalloc or NULL */
1228 kfree(lzo_blocks[i]);
1229 }
1230 kfree(lzo_blocks);
1231 codec->reg_cache = NULL;
1232 return 0;
1233}
1234
1235static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
1236{
1237 struct snd_soc_lzo_ctx **lzo_blocks;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001238 size_t bmp_size;
Mark Brown001ae4c2010-12-02 16:21:08 +00001239 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001240 int ret, tofree, i, blksize, blkcount;
1241 const char *p, *end;
1242 unsigned long *sync_bmp;
1243
1244 ret = 0;
1245 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001246
1247 /*
1248 * If we have not been given a default register cache
1249 * then allocate a dummy zero-ed out region, compress it
1250 * and remember to free it afterwards.
1251 */
1252 tofree = 0;
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001253 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001254 tofree = 1;
1255
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001256 if (!codec->reg_def_copy) {
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001257 codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001258 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001259 return -ENOMEM;
1260 }
1261
1262 blkcount = snd_soc_lzo_block_count();
1263 codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks,
1264 GFP_KERNEL);
1265 if (!codec->reg_cache) {
1266 ret = -ENOMEM;
1267 goto err_tofree;
1268 }
1269 lzo_blocks = codec->reg_cache;
1270
1271 /*
1272 * allocate a bitmap to be used when syncing the cache with
1273 * the hardware. Each time a register is modified, the corresponding
1274 * bit is set in the bitmap, so we know that we have to sync
1275 * that register.
1276 */
1277 bmp_size = codec_drv->reg_cache_size;
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +00001278 sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001279 GFP_KERNEL);
1280 if (!sync_bmp) {
1281 ret = -ENOMEM;
1282 goto err;
1283 }
Dimitris Papastamos09c74a92010-11-29 11:43:33 +00001284 bitmap_zero(sync_bmp, bmp_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001285
1286 /* allocate the lzo blocks and initialize them */
1287 for (i = 0; i < blkcount; ++i) {
1288 lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
1289 GFP_KERNEL);
1290 if (!lzo_blocks[i]) {
1291 kfree(sync_bmp);
1292 ret = -ENOMEM;
1293 goto err;
1294 }
1295 lzo_blocks[i]->sync_bmp = sync_bmp;
Dimitris Papastamos04f8fd12011-01-11 11:24:02 +00001296 lzo_blocks[i]->sync_bmp_nbits = bmp_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001297 /* alloc the working space for the compressed block */
1298 ret = snd_soc_lzo_prepare(lzo_blocks[i]);
1299 if (ret < 0)
1300 goto err;
1301 }
1302
1303 blksize = snd_soc_lzo_get_blksize(codec);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001304 p = codec->reg_def_copy;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001305 end = codec->reg_def_copy + codec->reg_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001306 /* compress the register map and fill the lzo blocks */
1307 for (i = 0; i < blkcount; ++i, p += blksize) {
1308 lzo_blocks[i]->src = p;
1309 if (p + blksize > end)
1310 lzo_blocks[i]->src_len = end - p;
1311 else
1312 lzo_blocks[i]->src_len = blksize;
1313 ret = snd_soc_lzo_compress_cache_block(codec,
1314 lzo_blocks[i]);
1315 if (ret < 0)
1316 goto err;
1317 lzo_blocks[i]->decompressed_size =
1318 lzo_blocks[i]->src_len;
1319 }
1320
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001321 if (tofree) {
1322 kfree(codec->reg_def_copy);
1323 codec->reg_def_copy = NULL;
1324 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001325 return 0;
1326err:
1327 snd_soc_cache_exit(codec);
1328err_tofree:
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001329 if (tofree) {
1330 kfree(codec->reg_def_copy);
1331 codec->reg_def_copy = NULL;
1332 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001333 return ret;
1334}
Mark Brown68d44ee2010-12-21 17:19:56 +00001335#endif
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001336
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001337static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
1338{
1339 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001340 int ret;
Mark Brown001ae4c2010-12-02 16:21:08 +00001341 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001342 unsigned int val;
1343
1344 codec_drv = codec->driver;
1345 for (i = 0; i < codec_drv->reg_cache_size; ++i) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +01001346 WARN_ON(codec->writable_register &&
1347 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001348 ret = snd_soc_cache_read(codec, i, &val);
1349 if (ret)
1350 return ret;
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001351 if (codec->reg_def_copy)
1352 if (snd_soc_get_cache_val(codec->reg_def_copy,
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001353 i, codec_drv->reg_word_size) == val)
1354 continue;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001355 ret = snd_soc_write(codec, i, val);
1356 if (ret)
1357 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001358 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1359 i, val);
1360 }
1361 return 0;
1362}
1363
1364static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
1365 unsigned int reg, unsigned int value)
1366{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001367 snd_soc_set_cache_val(codec->reg_cache, reg, value,
1368 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001369 return 0;
1370}
1371
1372static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
1373 unsigned int reg, unsigned int *value)
1374{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001375 *value = snd_soc_get_cache_val(codec->reg_cache, reg,
1376 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001377 return 0;
1378}
1379
1380static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
1381{
1382 if (!codec->reg_cache)
1383 return 0;
1384 kfree(codec->reg_cache);
1385 codec->reg_cache = NULL;
1386 return 0;
1387}
1388
1389static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
1390{
Mark Brown001ae4c2010-12-02 16:21:08 +00001391 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001392
1393 codec_drv = codec->driver;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001394
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001395 if (codec->reg_def_copy)
1396 codec->reg_cache = kmemdup(codec->reg_def_copy,
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001397 codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001398 else
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001399 codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001400 if (!codec->reg_cache)
1401 return -ENOMEM;
1402
1403 return 0;
1404}
1405
1406/* an array of all supported compression types */
1407static const struct snd_soc_cache_ops cache_types[] = {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001408 /* Flat *must* be the first entry for fallback */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001409 {
Dimitris Papastamosdf0701b2010-11-29 10:54:28 +00001410 .id = SND_SOC_FLAT_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001411 .name = "flat",
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001412 .init = snd_soc_flat_cache_init,
1413 .exit = snd_soc_flat_cache_exit,
1414 .read = snd_soc_flat_cache_read,
1415 .write = snd_soc_flat_cache_write,
1416 .sync = snd_soc_flat_cache_sync
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001417 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001418#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001419 {
1420 .id = SND_SOC_LZO_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001421 .name = "LZO",
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001422 .init = snd_soc_lzo_cache_init,
1423 .exit = snd_soc_lzo_cache_exit,
1424 .read = snd_soc_lzo_cache_read,
1425 .write = snd_soc_lzo_cache_write,
1426 .sync = snd_soc_lzo_cache_sync
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001427 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001428#endif
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001429 {
1430 .id = SND_SOC_RBTREE_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001431 .name = "rbtree",
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001432 .init = snd_soc_rbtree_cache_init,
1433 .exit = snd_soc_rbtree_cache_exit,
1434 .read = snd_soc_rbtree_cache_read,
1435 .write = snd_soc_rbtree_cache_write,
1436 .sync = snd_soc_rbtree_cache_sync
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001437 }
1438};
1439
1440int snd_soc_cache_init(struct snd_soc_codec *codec)
1441{
1442 int i;
1443
1444 for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
Dimitris Papastamos23bbce32010-12-02 14:53:01 +00001445 if (cache_types[i].id == codec->compress_type)
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001446 break;
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001447
1448 /* Fall back to flat compression */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001449 if (i == ARRAY_SIZE(cache_types)) {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001450 dev_warn(codec->dev, "Could not match compress type: %d\n",
1451 codec->compress_type);
1452 i = 0;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001453 }
1454
1455 mutex_init(&codec->cache_rw_mutex);
1456 codec->cache_ops = &cache_types[i];
1457
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001458 if (codec->cache_ops->init) {
1459 if (codec->cache_ops->name)
1460 dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
1461 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001462 return codec->cache_ops->init(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001463 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001464 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001465}
1466
1467/*
1468 * NOTE: keep in mind that this function might be called
1469 * multiple times.
1470 */
1471int snd_soc_cache_exit(struct snd_soc_codec *codec)
1472{
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001473 if (codec->cache_ops && codec->cache_ops->exit) {
1474 if (codec->cache_ops->name)
1475 dev_dbg(codec->dev, "Destroying %s cache for %s codec\n",
1476 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001477 return codec->cache_ops->exit(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001478 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001479 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001480}
1481
1482/**
1483 * snd_soc_cache_read: Fetch the value of a given register from the cache.
1484 *
1485 * @codec: CODEC to configure.
1486 * @reg: The register index.
1487 * @value: The value to be returned.
1488 */
1489int snd_soc_cache_read(struct snd_soc_codec *codec,
1490 unsigned int reg, unsigned int *value)
1491{
1492 int ret;
1493
1494 mutex_lock(&codec->cache_rw_mutex);
1495
1496 if (value && codec->cache_ops && codec->cache_ops->read) {
1497 ret = codec->cache_ops->read(codec, reg, value);
1498 mutex_unlock(&codec->cache_rw_mutex);
1499 return ret;
1500 }
1501
1502 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001503 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001504}
1505EXPORT_SYMBOL_GPL(snd_soc_cache_read);
1506
1507/**
1508 * snd_soc_cache_write: Set the value of a given register in the cache.
1509 *
1510 * @codec: CODEC to configure.
1511 * @reg: The register index.
1512 * @value: The new register value.
1513 */
1514int snd_soc_cache_write(struct snd_soc_codec *codec,
1515 unsigned int reg, unsigned int value)
1516{
1517 int ret;
1518
1519 mutex_lock(&codec->cache_rw_mutex);
1520
1521 if (codec->cache_ops && codec->cache_ops->write) {
1522 ret = codec->cache_ops->write(codec, reg, value);
1523 mutex_unlock(&codec->cache_rw_mutex);
1524 return ret;
1525 }
1526
1527 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001528 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001529}
1530EXPORT_SYMBOL_GPL(snd_soc_cache_write);
1531
1532/**
1533 * snd_soc_cache_sync: Sync the register cache with the hardware.
1534 *
1535 * @codec: CODEC to configure.
1536 *
1537 * Any registers that should not be synced should be marked as
1538 * volatile. In general drivers can choose not to use the provided
1539 * syncing functionality if they so require.
1540 */
1541int snd_soc_cache_sync(struct snd_soc_codec *codec)
1542{
1543 int ret;
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001544 const char *name;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001545
1546 if (!codec->cache_sync) {
1547 return 0;
1548 }
1549
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001550 if (!codec->cache_ops || !codec->cache_ops->sync)
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001551 return -ENOSYS;
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001552
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001553 if (codec->cache_ops->name)
1554 name = codec->cache_ops->name;
1555 else
1556 name = "unknown";
1557
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001558 if (codec->cache_ops->name)
1559 dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
1560 codec->cache_ops->name, codec->name);
1561 trace_snd_soc_cache_sync(codec, name, "start");
1562 ret = codec->cache_ops->sync(codec);
1563 if (!ret)
1564 codec->cache_sync = 0;
1565 trace_snd_soc_cache_sync(codec, name, "end");
1566 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001567}
1568EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
Dimitris Papastamos066d16c2011-01-13 12:20:36 +00001569
1570static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec,
1571 unsigned int reg)
1572{
1573 const struct snd_soc_codec_driver *codec_drv;
1574 unsigned int min, max, index;
1575
1576 codec_drv = codec->driver;
1577 min = 0;
1578 max = codec_drv->reg_access_size - 1;
1579 do {
1580 index = (min + max) / 2;
1581 if (codec_drv->reg_access_default[index].reg == reg)
1582 return index;
1583 if (codec_drv->reg_access_default[index].reg < reg)
1584 min = index + 1;
1585 else
1586 max = index;
1587 } while (min <= max);
1588 return -1;
1589}
1590
1591int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
1592 unsigned int reg)
1593{
1594 int index;
1595
1596 if (reg >= codec->driver->reg_cache_size)
1597 return 1;
1598 index = snd_soc_get_reg_access_index(codec, reg);
1599 if (index < 0)
1600 return 0;
1601 return codec->driver->reg_access_default[index].vol;
1602}
1603EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register);
1604
1605int snd_soc_default_readable_register(struct snd_soc_codec *codec,
1606 unsigned int reg)
1607{
1608 int index;
1609
1610 if (reg >= codec->driver->reg_cache_size)
1611 return 1;
1612 index = snd_soc_get_reg_access_index(codec, reg);
1613 if (index < 0)
1614 return 0;
1615 return codec->driver->reg_access_default[index].read;
1616}
1617EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
Dimitris Papastamos80204542011-03-24 13:45:17 +00001618
1619int snd_soc_default_writable_register(struct snd_soc_codec *codec,
1620 unsigned int reg)
1621{
1622 int index;
1623
1624 if (reg >= codec->driver->reg_cache_size)
1625 return 1;
1626 index = snd_soc_get_reg_access_index(codec, reg);
1627 if (index < 0)
1628 return 0;
1629 return codec->driver->reg_access_default[index].write;
1630}
1631EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);