blob: 5cd23daff4adbe0b81ab83976388d67e4ca73af5 [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 Brown17a52fd2009-07-05 17:24:50 +0100136 u8 data[2];
Mark Brown17a52fd2009-07-05 17:24:50 +0100137
Mark Brown17a52fd2009-07-05 17:24:50 +0100138 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
139 data[1] = value & 0x00ff;
140
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000141 return do_hw_write(codec, reg, value, data, 2);
Mark Brown17a52fd2009-07-05 17:24:50 +0100142}
143
Mark Brown27ded042009-07-10 23:28:16 +0100144#if defined(CONFIG_SPI_MASTER)
145static int snd_soc_7_9_spi_write(void *control_data, const char *data,
146 int len)
147{
Mark Brown27ded042009-07-10 23:28:16 +0100148 u8 msg[2];
149
Mark Brown27ded042009-07-10 23:28:16 +0100150 msg[0] = data[0];
151 msg[1] = data[1];
152
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000153 return do_spi_write(control_data, msg, len);
Mark Brown27ded042009-07-10 23:28:16 +0100154}
155#else
156#define snd_soc_7_9_spi_write NULL
157#endif
158
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900159static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
160 unsigned int value)
161{
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900162 u8 data[2];
163
Barry Songf4bee1b2010-03-18 16:17:01 +0800164 reg &= 0xff;
165 data[0] = reg;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900166 data[1] = value & 0xff;
167
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000168 return do_hw_write(codec, reg, value, data, 2);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900169}
170
171static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
172 unsigned int reg)
173{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000174 return do_hw_read(codec, reg);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900175}
176
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100177#if defined(CONFIG_SPI_MASTER)
178static int snd_soc_8_8_spi_write(void *control_data, const char *data,
179 int len)
180{
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100181 u8 msg[2];
182
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100183 msg[0] = data[0];
184 msg[1] = data[1];
185
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000186 return do_spi_write(control_data, msg, len);
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100187}
188#else
189#define snd_soc_8_8_spi_write NULL
190#endif
191
Mark Brownafa2f102009-07-10 23:11:24 +0100192static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
193 unsigned int value)
194{
Mark Brownafa2f102009-07-10 23:11:24 +0100195 u8 data[3];
196
197 data[0] = reg;
198 data[1] = (value >> 8) & 0xff;
199 data[2] = value & 0xff;
200
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000201 return do_hw_write(codec, reg, value, data, 3);
Mark Brownafa2f102009-07-10 23:11:24 +0100202}
203
204static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
205 unsigned int reg)
206{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000207 return do_hw_read(codec, reg);
Mark Brownafa2f102009-07-10 23:11:24 +0100208}
209
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100210#if defined(CONFIG_SPI_MASTER)
211static int snd_soc_8_16_spi_write(void *control_data, const char *data,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100212 int len)
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100213{
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100214 u8 msg[3];
215
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100216 msg[0] = data[0];
217 msg[1] = data[1];
218 msg[2] = data[2];
219
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000220 return do_spi_write(control_data, msg, len);
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100221}
222#else
223#define snd_soc_8_16_spi_write NULL
224#endif
225
Randy Dunlap17244c22009-08-10 16:04:39 -0700226#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000227static unsigned int do_i2c_read(struct snd_soc_codec *codec,
228 void *reg, int reglen,
229 void *data, int datalen)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800230{
231 struct i2c_msg xfer[2];
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800232 int ret;
233 struct i2c_client *client = codec->control_data;
234
235 /* Write register */
236 xfer[0].addr = client->addr;
237 xfer[0].flags = 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000238 xfer[0].len = reglen;
239 xfer[0].buf = reg;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800240
241 /* Read data */
242 xfer[1].addr = client->addr;
243 xfer[1].flags = I2C_M_RD;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000244 xfer[1].len = datalen;
245 xfer[1].buf = data;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800246
247 ret = i2c_transfer(client->adapter, xfer, 2);
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000248 if (ret == 2)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800249 return 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000250 else if (ret < 0)
251 return ret;
252 else
253 return -EIO;
254}
255#endif
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800256
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000257#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
258static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100259 unsigned int r)
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000260{
261 u8 reg = r;
262 u8 data;
263 int ret;
264
265 ret = do_i2c_read(codec, &reg, 1, &data, 1);
266 if (ret < 0)
267 return 0;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800268 return data;
269}
270#else
271#define snd_soc_8_8_read_i2c NULL
272#endif
273
274#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100275static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
276 unsigned int r)
277{
Mark Brownafa2f102009-07-10 23:11:24 +0100278 u8 reg = r;
279 u16 data;
280 int ret;
Mark Brownafa2f102009-07-10 23:11:24 +0100281
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000282 ret = do_i2c_read(codec, &reg, 1, &data, 2);
283 if (ret < 0)
Mark Brownafa2f102009-07-10 23:11:24 +0100284 return 0;
Mark Brownafa2f102009-07-10 23:11:24 +0100285 return (data >> 8) | ((data & 0xff) << 8);
286}
287#else
288#define snd_soc_8_16_read_i2c NULL
289#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100290
Barry Song994dc422010-01-27 11:46:18 +0800291#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
292static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
293 unsigned int r)
294{
Barry Song994dc422010-01-27 11:46:18 +0800295 u16 reg = r;
296 u8 data;
297 int ret;
Barry Song994dc422010-01-27 11:46:18 +0800298
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000299 ret = do_i2c_read(codec, &reg, 2, &data, 1);
300 if (ret < 0)
Barry Song994dc422010-01-27 11:46:18 +0800301 return 0;
Barry Song994dc422010-01-27 11:46:18 +0800302 return data;
303}
304#else
305#define snd_soc_16_8_read_i2c NULL
306#endif
307
308static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100309 unsigned int reg)
Barry Song994dc422010-01-27 11:46:18 +0800310{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000311 return do_hw_read(codec, reg);
Barry Song994dc422010-01-27 11:46:18 +0800312}
313
314static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100315 unsigned int value)
Barry Song994dc422010-01-27 11:46:18 +0800316{
Barry Song994dc422010-01-27 11:46:18 +0800317 u8 data[3];
Barry Song994dc422010-01-27 11:46:18 +0800318
Barry Song994dc422010-01-27 11:46:18 +0800319 data[0] = (reg >> 8) & 0xff;
320 data[1] = reg & 0xff;
321 data[2] = value;
Barry Song994dc422010-01-27 11:46:18 +0800322 reg &= 0xff;
Mark Brown8c961bc2010-02-01 18:46:10 +0000323
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000324 return do_hw_write(codec, reg, value, data, 3);
Barry Song994dc422010-01-27 11:46:18 +0800325}
326
327#if defined(CONFIG_SPI_MASTER)
328static int snd_soc_16_8_spi_write(void *control_data, const char *data,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100329 int len)
Barry Song994dc422010-01-27 11:46:18 +0800330{
Barry Song994dc422010-01-27 11:46:18 +0800331 u8 msg[3];
332
Barry Song994dc422010-01-27 11:46:18 +0800333 msg[0] = data[0];
334 msg[1] = data[1];
335 msg[2] = data[2];
336
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000337 return do_spi_write(control_data, msg, len);
Barry Song994dc422010-01-27 11:46:18 +0800338}
339#else
340#define snd_soc_16_8_spi_write NULL
341#endif
342
Mark Brownbc6552f2010-03-05 16:27:15 +0000343#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
344static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
345 unsigned int r)
346{
Mark Brownbc6552f2010-03-05 16:27:15 +0000347 u16 reg = cpu_to_be16(r);
348 u16 data;
349 int ret;
Mark Brownbc6552f2010-03-05 16:27:15 +0000350
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000351 ret = do_i2c_read(codec, &reg, 2, &data, 2);
352 if (ret < 0)
Mark Brownbc6552f2010-03-05 16:27:15 +0000353 return 0;
Mark Brownbc6552f2010-03-05 16:27:15 +0000354 return be16_to_cpu(data);
355}
356#else
357#define snd_soc_16_16_read_i2c NULL
358#endif
359
360static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
361 unsigned int reg)
362{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000363 return do_hw_read(codec, reg);
Mark Brownbc6552f2010-03-05 16:27:15 +0000364}
365
366static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
367 unsigned int value)
368{
Mark Brownbc6552f2010-03-05 16:27:15 +0000369 u8 data[4];
Mark Brownbc6552f2010-03-05 16:27:15 +0000370
371 data[0] = (reg >> 8) & 0xff;
372 data[1] = reg & 0xff;
373 data[2] = (value >> 8) & 0xff;
374 data[3] = value & 0xff;
375
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000376 return do_hw_write(codec, reg, value, data, 4);
Mark Brownbc6552f2010-03-05 16:27:15 +0000377}
Barry Song994dc422010-01-27 11:46:18 +0800378
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100379#if defined(CONFIG_SPI_MASTER)
380static int snd_soc_16_16_spi_write(void *control_data, const char *data,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100381 int len)
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100382{
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100383 u8 msg[4];
384
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100385 msg[0] = data[0];
386 msg[1] = data[1];
387 msg[2] = data[2];
388 msg[3] = data[3];
389
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000390 return do_spi_write(control_data, msg, len);
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100391}
392#else
393#define snd_soc_16_16_spi_write NULL
394#endif
395
Mark Brown34bad692011-04-04 17:55:42 +0900396/* Primitive bulk write support for soc-cache. The data pointed to by
397 * `data' needs to already be in the form the hardware expects
398 * including any leading register specific data. Any data written
399 * through this function will not go through the cache as it only
400 * handles writing to volatile or out of bounds registers.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000401 */
402static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
403 const void *data, size_t len)
404{
405 int ret;
406
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100407 /* To ensure that we don't get out of sync with the cache, check
408 * whether the base register is volatile or if we've directly asked
409 * to bypass the cache. Out of bounds registers are considered
410 * volatile.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000411 */
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100412 if (!codec->cache_bypass
413 && !snd_soc_codec_volatile_register(codec, reg)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000414 && reg < codec->driver->reg_cache_size)
415 return -EINVAL;
416
417 switch (codec->control_type) {
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900418#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000419 case SND_SOC_I2C:
420 ret = i2c_master_send(codec->control_data, data, len);
421 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900422#endif
423#if defined(CONFIG_SPI_MASTER)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000424 case SND_SOC_SPI:
425 ret = do_spi_write(codec->control_data, data, len);
426 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900427#endif
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000428 default:
429 BUG();
430 }
431
432 if (ret == len)
433 return 0;
434 if (ret < 0)
435 return ret;
436 else
437 return -EIO;
438}
439
Mark Brown17a52fd2009-07-05 17:24:50 +0100440static struct {
441 int addr_bits;
442 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100443 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown27ded042009-07-10 23:28:16 +0100444 int (*spi_write)(void *, const char *, int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100445 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100446 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100447} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700448 {
Barry Song63b62ab2010-01-27 11:46:17 +0800449 .addr_bits = 4, .data_bits = 12,
450 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
451 .spi_write = snd_soc_4_12_spi_write,
452 },
453 {
Mark Brownd62ab352009-09-21 04:21:47 -0700454 .addr_bits = 7, .data_bits = 9,
455 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Barry Song8998c892009-12-31 10:30:34 +0800456 .spi_write = snd_soc_7_9_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700457 },
458 {
459 .addr_bits = 8, .data_bits = 8,
460 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800461 .i2c_read = snd_soc_8_8_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100462 .spi_write = snd_soc_8_8_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700463 },
464 {
465 .addr_bits = 8, .data_bits = 16,
466 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
467 .i2c_read = snd_soc_8_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100468 .spi_write = snd_soc_8_16_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700469 },
Barry Song994dc422010-01-27 11:46:18 +0800470 {
471 .addr_bits = 16, .data_bits = 8,
472 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
473 .i2c_read = snd_soc_16_8_read_i2c,
474 .spi_write = snd_soc_16_8_spi_write,
475 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000476 {
477 .addr_bits = 16, .data_bits = 16,
478 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
479 .i2c_read = snd_soc_16_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100480 .spi_write = snd_soc_16_16_spi_write,
Mark Brownbc6552f2010-03-05 16:27:15 +0000481 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100482};
483
484/**
485 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
486 *
487 * @codec: CODEC to configure.
Mark Brown17a52fd2009-07-05 17:24:50 +0100488 * @addr_bits: Number of bits of register address data.
489 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100490 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100491 *
492 * Register formats are frequently shared between many I2C and SPI
493 * devices. In order to promote code reuse the ASoC core provides
494 * some standard implementations of CODEC read and write operations
495 * which can be set up using this function.
496 *
497 * The caller is responsible for allocating and initialising the
498 * actual cache.
499 *
500 * Note that at present this code cannot be used by CODECs with
501 * volatile registers.
502 */
503int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100504 int addr_bits, int data_bits,
505 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100506{
507 int i;
508
Mark Brown17a52fd2009-07-05 17:24:50 +0100509 for (i = 0; i < ARRAY_SIZE(io_types); i++)
510 if (io_types[i].addr_bits == addr_bits &&
511 io_types[i].data_bits == data_bits)
512 break;
513 if (i == ARRAY_SIZE(io_types)) {
514 printk(KERN_ERR
515 "No I/O functions for %d bit address %d bit data\n",
516 addr_bits, data_bits);
517 return -EINVAL;
518 }
519
Mark Brownc3acec22010-12-02 16:15:29 +0000520 codec->write = io_types[i].write;
521 codec->read = io_types[i].read;
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000522 codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
Mark Brown17a52fd2009-07-05 17:24:50 +0100523
Mark Brown7084a422009-07-10 22:24:27 +0100524 switch (control) {
525 case SND_SOC_CUSTOM:
526 break;
527
528 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700529#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100530 codec->hw_write = (hw_write_t)i2c_master_send;
531#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100532 if (io_types[i].i2c_read)
533 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100534
535 codec->control_data = container_of(codec->dev,
536 struct i2c_client,
537 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100538 break;
539
540 case SND_SOC_SPI:
Mark Brown27ded042009-07-10 23:28:16 +0100541 if (io_types[i].spi_write)
542 codec->hw_write = io_types[i].spi_write;
Mark Browna6d14342010-08-12 10:59:15 +0100543
544 codec->control_data = container_of(codec->dev,
545 struct spi_device,
546 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100547 break;
548 }
549
Mark Brown17a52fd2009-07-05 17:24:50 +0100550 return 0;
551}
552EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000553
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000554static bool snd_soc_set_cache_val(void *base, unsigned int idx,
555 unsigned int val, unsigned int word_size)
556{
557 switch (word_size) {
558 case 1: {
559 u8 *cache = base;
560 if (cache[idx] == val)
561 return true;
562 cache[idx] = val;
563 break;
564 }
565 case 2: {
566 u16 *cache = base;
567 if (cache[idx] == val)
568 return true;
569 cache[idx] = val;
570 break;
571 }
572 default:
573 BUG();
574 }
575 return false;
576}
577
578static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
579 unsigned int word_size)
580{
581 switch (word_size) {
582 case 1: {
583 const u8 *cache = base;
584 return cache[idx];
585 }
586 case 2: {
587 const u16 *cache = base;
588 return cache[idx];
589 }
590 default:
591 BUG();
592 }
593 /* unreachable */
594 return -1;
595}
596
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000597struct snd_soc_rbtree_node {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100598 struct rb_node node; /* the actual rbtree node holding this block */
599 unsigned int base_reg; /* base register handled by this block */
600 unsigned int word_size; /* number of bytes needed to represent the register index */
601 void *block; /* block of adjacent registers */
602 unsigned int blklen; /* number of registers available in the block */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000603} __attribute__ ((packed));
604
605struct snd_soc_rbtree_ctx {
606 struct rb_root root;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100607 struct snd_soc_rbtree_node *cached_rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000608};
609
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100610static inline void snd_soc_rbtree_get_base_top_reg(
611 struct snd_soc_rbtree_node *rbnode,
612 unsigned int *base, unsigned int *top)
613{
614 *base = rbnode->base_reg;
615 *top = rbnode->base_reg + rbnode->blklen - 1;
616}
617
618static unsigned int snd_soc_rbtree_get_register(
619 struct snd_soc_rbtree_node *rbnode, unsigned int idx)
620{
621 unsigned int val;
622
623 switch (rbnode->word_size) {
624 case 1: {
625 u8 *p = rbnode->block;
626 val = p[idx];
627 return val;
628 }
629 case 2: {
630 u16 *p = rbnode->block;
631 val = p[idx];
632 return val;
633 }
634 default:
635 BUG();
636 break;
637 }
638 return -1;
639}
640
641static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
642 unsigned int idx, unsigned int val)
643{
644 switch (rbnode->word_size) {
645 case 1: {
646 u8 *p = rbnode->block;
647 p[idx] = val;
648 break;
649 }
650 case 2: {
651 u16 *p = rbnode->block;
652 p[idx] = val;
653 break;
654 }
655 default:
656 BUG();
657 break;
658 }
659}
660
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000661static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
662 struct rb_root *root, unsigned int reg)
663{
664 struct rb_node *node;
665 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100666 unsigned int base_reg, top_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000667
668 node = root->rb_node;
669 while (node) {
670 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100671 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
672 if (reg >= base_reg && reg <= top_reg)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000673 return rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100674 else if (reg > top_reg)
675 node = node->rb_right;
676 else if (reg < base_reg)
677 node = node->rb_left;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000678 }
679
680 return NULL;
681}
682
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000683static int snd_soc_rbtree_insert(struct rb_root *root,
684 struct snd_soc_rbtree_node *rbnode)
685{
686 struct rb_node **new, *parent;
687 struct snd_soc_rbtree_node *rbnode_tmp;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100688 unsigned int base_reg_tmp, top_reg_tmp;
689 unsigned int base_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000690
691 parent = NULL;
692 new = &root->rb_node;
693 while (*new) {
694 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
695 node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100696 /* base and top registers of the current rbnode */
697 snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
698 &top_reg_tmp);
699 /* base register of the rbnode to be added */
700 base_reg = rbnode->base_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000701 parent = *new;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100702 /* if this register has already been inserted, just return */
703 if (base_reg >= base_reg_tmp &&
704 base_reg <= top_reg_tmp)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000705 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100706 else if (base_reg > top_reg_tmp)
707 new = &((*new)->rb_right);
708 else if (base_reg < base_reg_tmp)
709 new = &((*new)->rb_left);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000710 }
711
712 /* insert the node into the rbtree */
713 rb_link_node(&rbnode->node, parent, new);
714 rb_insert_color(&rbnode->node, root);
715
716 return 1;
717}
718
719static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
720{
721 struct snd_soc_rbtree_ctx *rbtree_ctx;
722 struct rb_node *node;
723 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100724 unsigned int regtmp;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000725 unsigned int val;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000726 int ret;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100727 int i;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000728
729 rbtree_ctx = codec->reg_cache;
730 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
731 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100732 for (i = 0; i < rbnode->blklen; ++i) {
733 regtmp = rbnode->base_reg + i;
734 WARN_ON(codec->writable_register &&
735 codec->writable_register(codec, regtmp));
736 val = snd_soc_rbtree_get_register(rbnode, i);
737 codec->cache_bypass = 1;
738 ret = snd_soc_write(codec, regtmp, val);
739 codec->cache_bypass = 0;
740 if (ret)
741 return ret;
742 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
743 regtmp, val);
744 }
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000745 }
746
747 return 0;
748}
749
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100750static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
751 unsigned int pos, unsigned int reg,
752 unsigned int value)
753{
754 u8 *blk;
755
756 blk = krealloc(rbnode->block,
757 (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
758 if (!blk)
759 return -ENOMEM;
760
761 /* insert the register value in the correct place in the rbnode block */
762 memmove(blk + (pos + 1) * rbnode->word_size,
763 blk + pos * rbnode->word_size,
764 (rbnode->blklen - pos) * rbnode->word_size);
765
766 /* update the rbnode block, its size and the base register */
767 rbnode->block = blk;
768 rbnode->blklen++;
769 if (!pos)
770 rbnode->base_reg = reg;
771
772 snd_soc_rbtree_set_register(rbnode, pos, value);
773 return 0;
774}
775
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000776static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
777 unsigned int reg, unsigned int value)
778{
779 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100780 struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
781 struct rb_node *node;
782 unsigned int val;
783 unsigned int reg_tmp;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100784 unsigned int base_reg, top_reg;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100785 unsigned int pos;
786 int i;
787 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000788
789 rbtree_ctx = codec->reg_cache;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100790 /* look up the required register in the cached rbnode */
791 rbnode = rbtree_ctx->cached_rbnode;
792 if (rbnode) {
793 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
794 if (reg >= base_reg && reg <= top_reg) {
795 reg_tmp = reg - base_reg;
796 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
797 if (val == value)
798 return 0;
799 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
800 return 0;
801 }
802 }
803 /* if we can't locate it in the cached rbnode we'll have
804 * to traverse the rbtree looking for it.
805 */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000806 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
807 if (rbnode) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100808 reg_tmp = reg - rbnode->base_reg;
809 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
810 if (val == value)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000811 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100812 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100813 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000814 } else {
815 /* bail out early, no need to create the rbnode yet */
816 if (!value)
817 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100818 /* look for an adjacent register to the one we are about to add */
819 for (node = rb_first(&rbtree_ctx->root); node;
820 node = rb_next(node)) {
821 rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
822 for (i = 0; i < rbnode_tmp->blklen; ++i) {
823 reg_tmp = rbnode_tmp->base_reg + i;
824 if (abs(reg_tmp - reg) != 1)
825 continue;
826 /* decide where in the block to place our register */
827 if (reg_tmp + 1 == reg)
828 pos = i + 1;
829 else
830 pos = i;
831 ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
832 reg, value);
833 if (ret)
834 return ret;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100835 rbtree_ctx->cached_rbnode = rbnode_tmp;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100836 return 0;
837 }
838 }
839 /* we did not manage to find a place to insert it in an existing
840 * block so create a new rbnode with a single register in its block.
841 * This block will get populated further if any other adjacent
842 * registers get modified in the future.
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000843 */
844 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
845 if (!rbnode)
846 return -ENOMEM;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100847 rbnode->blklen = 1;
848 rbnode->base_reg = reg;
849 rbnode->word_size = codec->driver->reg_word_size;
850 rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
851 GFP_KERNEL);
852 if (!rbnode->block) {
853 kfree(rbnode);
854 return -ENOMEM;
855 }
856 snd_soc_rbtree_set_register(rbnode, 0, value);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000857 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100858 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000859 }
860
861 return 0;
862}
863
864static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
865 unsigned int reg, unsigned int *value)
866{
867 struct snd_soc_rbtree_ctx *rbtree_ctx;
868 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100869 unsigned int base_reg, top_reg;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100870 unsigned int reg_tmp;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000871
872 rbtree_ctx = codec->reg_cache;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100873 /* look up the required register in the cached rbnode */
874 rbnode = rbtree_ctx->cached_rbnode;
875 if (rbnode) {
876 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
877 if (reg >= base_reg && reg <= top_reg) {
878 reg_tmp = reg - base_reg;
879 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
880 return 0;
881 }
882 }
883 /* if we can't locate it in the cached rbnode we'll have
884 * to traverse the rbtree looking for it.
885 */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000886 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
887 if (rbnode) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100888 reg_tmp = reg - rbnode->base_reg;
889 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100890 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000891 } else {
892 /* uninitialized registers default to 0 */
893 *value = 0;
894 }
895
896 return 0;
897}
898
899static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
900{
901 struct rb_node *next;
902 struct snd_soc_rbtree_ctx *rbtree_ctx;
903 struct snd_soc_rbtree_node *rbtree_node;
904
905 /* if we've already been called then just return */
906 rbtree_ctx = codec->reg_cache;
907 if (!rbtree_ctx)
908 return 0;
909
910 /* free up the rbtree */
911 next = rb_first(&rbtree_ctx->root);
912 while (next) {
913 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
914 next = rb_next(&rbtree_node->node);
915 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100916 kfree(rbtree_node->block);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000917 kfree(rbtree_node);
918 }
919
920 /* release the resources */
921 kfree(codec->reg_cache);
922 codec->reg_cache = NULL;
923
924 return 0;
925}
926
927static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
928{
929 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000930 unsigned int word_size;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100931 unsigned int val;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000932 int i;
933 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000934
935 codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
936 if (!codec->reg_cache)
937 return -ENOMEM;
938
939 rbtree_ctx = codec->reg_cache;
940 rbtree_ctx->root = RB_ROOT;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100941 rbtree_ctx->cached_rbnode = NULL;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000942
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000943 if (!codec->reg_def_copy)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000944 return 0;
945
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000946 word_size = codec->driver->reg_word_size;
947 for (i = 0; i < codec->driver->reg_cache_size; ++i) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100948 val = snd_soc_get_cache_val(codec->reg_def_copy, i,
949 word_size);
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000950 if (!val)
951 continue;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100952 ret = snd_soc_rbtree_cache_write(codec, i, val);
953 if (ret)
954 goto err;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000955 }
956
957 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100958
959err:
960 snd_soc_cache_exit(codec);
961 return ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000962}
963
Mark Brown68d44ee2010-12-21 17:19:56 +0000964#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000965struct snd_soc_lzo_ctx {
966 void *wmem;
967 void *dst;
968 const void *src;
969 size_t src_len;
970 size_t dst_len;
971 size_t decompressed_size;
972 unsigned long *sync_bmp;
973 int sync_bmp_nbits;
974};
975
976#define LZO_BLOCK_NUM 8
977static int snd_soc_lzo_block_count(void)
978{
979 return LZO_BLOCK_NUM;
980}
981
982static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx)
983{
984 lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
985 if (!lzo_ctx->wmem)
986 return -ENOMEM;
987 return 0;
988}
989
990static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx)
991{
992 size_t compress_size;
993 int ret;
994
995 ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
996 lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
997 if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
998 return -EINVAL;
999 lzo_ctx->dst_len = compress_size;
1000 return 0;
1001}
1002
1003static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx)
1004{
1005 size_t dst_len;
1006 int ret;
1007
1008 dst_len = lzo_ctx->dst_len;
1009 ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
1010 lzo_ctx->dst, &dst_len);
1011 if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
1012 return -EINVAL;
1013 return 0;
1014}
1015
1016static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec,
1017 struct snd_soc_lzo_ctx *lzo_ctx)
1018{
1019 int ret;
1020
1021 lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
1022 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
1023 if (!lzo_ctx->dst) {
1024 lzo_ctx->dst_len = 0;
1025 return -ENOMEM;
1026 }
1027
1028 ret = snd_soc_lzo_compress(lzo_ctx);
1029 if (ret < 0)
1030 return ret;
1031 return 0;
1032}
1033
1034static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec,
1035 struct snd_soc_lzo_ctx *lzo_ctx)
1036{
1037 int ret;
1038
1039 lzo_ctx->dst_len = lzo_ctx->decompressed_size;
1040 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
1041 if (!lzo_ctx->dst) {
1042 lzo_ctx->dst_len = 0;
1043 return -ENOMEM;
1044 }
1045
1046 ret = snd_soc_lzo_decompress(lzo_ctx);
1047 if (ret < 0)
1048 return ret;
1049 return 0;
1050}
1051
1052static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
1053 unsigned int reg)
1054{
Mark Brown001ae4c2010-12-02 16:21:08 +00001055 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001056
1057 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001058 return (reg * codec_drv->reg_word_size) /
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001059 DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001060}
1061
1062static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
1063 unsigned int reg)
1064{
Mark Brown001ae4c2010-12-02 16:21:08 +00001065 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001066
1067 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001068 return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) /
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001069 codec_drv->reg_word_size);
1070}
1071
1072static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
1073{
Mark Brown001ae4c2010-12-02 16:21:08 +00001074 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001075
1076 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001077 return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001078}
1079
1080static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
1081{
1082 struct snd_soc_lzo_ctx **lzo_blocks;
1083 unsigned int val;
1084 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001085 int ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001086
1087 lzo_blocks = codec->reg_cache;
1088 for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +01001089 WARN_ON(codec->writable_register &&
1090 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001091 ret = snd_soc_cache_read(codec, i, &val);
1092 if (ret)
1093 return ret;
Dimitris Papastamos99780072011-01-19 14:53:37 +00001094 codec->cache_bypass = 1;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001095 ret = snd_soc_write(codec, i, val);
Dimitris Papastamos99780072011-01-19 14:53:37 +00001096 codec->cache_bypass = 0;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001097 if (ret)
1098 return ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001099 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1100 i, val);
1101 }
1102
1103 return 0;
1104}
1105
1106static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
1107 unsigned int reg, unsigned int value)
1108{
1109 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1110 int ret, blkindex, blkpos;
1111 size_t blksize, tmp_dst_len;
1112 void *tmp_dst;
1113
1114 /* index of the compressed lzo block */
1115 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1116 /* register index within the decompressed block */
1117 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1118 /* size of the compressed block */
1119 blksize = snd_soc_lzo_get_blksize(codec);
1120 lzo_blocks = codec->reg_cache;
1121 lzo_block = lzo_blocks[blkindex];
1122
1123 /* save the pointer and length of the compressed block */
1124 tmp_dst = lzo_block->dst;
1125 tmp_dst_len = lzo_block->dst_len;
1126
1127 /* prepare the source to be the compressed block */
1128 lzo_block->src = lzo_block->dst;
1129 lzo_block->src_len = lzo_block->dst_len;
1130
1131 /* decompress the block */
1132 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
1133 if (ret < 0) {
1134 kfree(lzo_block->dst);
1135 goto out;
1136 }
1137
1138 /* write the new value to the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001139 if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value,
1140 codec->driver->reg_word_size)) {
1141 kfree(lzo_block->dst);
1142 goto out;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001143 }
1144
1145 /* prepare the source to be the decompressed block */
1146 lzo_block->src = lzo_block->dst;
1147 lzo_block->src_len = lzo_block->dst_len;
1148
1149 /* compress the block */
1150 ret = snd_soc_lzo_compress_cache_block(codec, lzo_block);
1151 if (ret < 0) {
1152 kfree(lzo_block->dst);
1153 kfree(lzo_block->src);
1154 goto out;
1155 }
1156
1157 /* set the bit so we know we have to sync this register */
1158 set_bit(reg, lzo_block->sync_bmp);
1159 kfree(tmp_dst);
1160 kfree(lzo_block->src);
1161 return 0;
1162out:
1163 lzo_block->dst = tmp_dst;
1164 lzo_block->dst_len = tmp_dst_len;
1165 return ret;
1166}
1167
1168static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
1169 unsigned int reg, unsigned int *value)
1170{
1171 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1172 int ret, blkindex, blkpos;
1173 size_t blksize, tmp_dst_len;
1174 void *tmp_dst;
1175
1176 *value = 0;
1177 /* index of the compressed lzo block */
1178 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1179 /* register index within the decompressed block */
1180 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1181 /* size of the compressed block */
1182 blksize = snd_soc_lzo_get_blksize(codec);
1183 lzo_blocks = codec->reg_cache;
1184 lzo_block = lzo_blocks[blkindex];
1185
1186 /* save the pointer and length of the compressed block */
1187 tmp_dst = lzo_block->dst;
1188 tmp_dst_len = lzo_block->dst_len;
1189
1190 /* prepare the source to be the compressed block */
1191 lzo_block->src = lzo_block->dst;
1192 lzo_block->src_len = lzo_block->dst_len;
1193
1194 /* decompress the block */
1195 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001196 if (ret >= 0)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001197 /* fetch the value from the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001198 *value = snd_soc_get_cache_val(lzo_block->dst, blkpos,
1199 codec->driver->reg_word_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001200
1201 kfree(lzo_block->dst);
1202 /* restore the pointer and length of the compressed block */
1203 lzo_block->dst = tmp_dst;
1204 lzo_block->dst_len = tmp_dst_len;
1205 return 0;
1206}
1207
1208static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
1209{
1210 struct snd_soc_lzo_ctx **lzo_blocks;
1211 int i, blkcount;
1212
1213 lzo_blocks = codec->reg_cache;
1214 if (!lzo_blocks)
1215 return 0;
1216
1217 blkcount = snd_soc_lzo_block_count();
1218 /*
1219 * the pointer to the bitmap used for syncing the cache
1220 * is shared amongst all lzo_blocks. Ensure it is freed
1221 * only once.
1222 */
1223 if (lzo_blocks[0])
1224 kfree(lzo_blocks[0]->sync_bmp);
1225 for (i = 0; i < blkcount; ++i) {
1226 if (lzo_blocks[i]) {
1227 kfree(lzo_blocks[i]->wmem);
1228 kfree(lzo_blocks[i]->dst);
1229 }
1230 /* each lzo_block is a pointer returned by kmalloc or NULL */
1231 kfree(lzo_blocks[i]);
1232 }
1233 kfree(lzo_blocks);
1234 codec->reg_cache = NULL;
1235 return 0;
1236}
1237
1238static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
1239{
1240 struct snd_soc_lzo_ctx **lzo_blocks;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001241 size_t bmp_size;
Mark Brown001ae4c2010-12-02 16:21:08 +00001242 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001243 int ret, tofree, i, blksize, blkcount;
1244 const char *p, *end;
1245 unsigned long *sync_bmp;
1246
1247 ret = 0;
1248 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001249
1250 /*
1251 * If we have not been given a default register cache
1252 * then allocate a dummy zero-ed out region, compress it
1253 * and remember to free it afterwards.
1254 */
1255 tofree = 0;
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001256 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001257 tofree = 1;
1258
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001259 if (!codec->reg_def_copy) {
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001260 codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001261 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001262 return -ENOMEM;
1263 }
1264
1265 blkcount = snd_soc_lzo_block_count();
1266 codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks,
1267 GFP_KERNEL);
1268 if (!codec->reg_cache) {
1269 ret = -ENOMEM;
1270 goto err_tofree;
1271 }
1272 lzo_blocks = codec->reg_cache;
1273
1274 /*
1275 * allocate a bitmap to be used when syncing the cache with
1276 * the hardware. Each time a register is modified, the corresponding
1277 * bit is set in the bitmap, so we know that we have to sync
1278 * that register.
1279 */
1280 bmp_size = codec_drv->reg_cache_size;
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +00001281 sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001282 GFP_KERNEL);
1283 if (!sync_bmp) {
1284 ret = -ENOMEM;
1285 goto err;
1286 }
Dimitris Papastamos09c74a92010-11-29 11:43:33 +00001287 bitmap_zero(sync_bmp, bmp_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001288
1289 /* allocate the lzo blocks and initialize them */
1290 for (i = 0; i < blkcount; ++i) {
1291 lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
1292 GFP_KERNEL);
1293 if (!lzo_blocks[i]) {
1294 kfree(sync_bmp);
1295 ret = -ENOMEM;
1296 goto err;
1297 }
1298 lzo_blocks[i]->sync_bmp = sync_bmp;
Dimitris Papastamos04f8fd12011-01-11 11:24:02 +00001299 lzo_blocks[i]->sync_bmp_nbits = bmp_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001300 /* alloc the working space for the compressed block */
1301 ret = snd_soc_lzo_prepare(lzo_blocks[i]);
1302 if (ret < 0)
1303 goto err;
1304 }
1305
1306 blksize = snd_soc_lzo_get_blksize(codec);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001307 p = codec->reg_def_copy;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001308 end = codec->reg_def_copy + codec->reg_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001309 /* compress the register map and fill the lzo blocks */
1310 for (i = 0; i < blkcount; ++i, p += blksize) {
1311 lzo_blocks[i]->src = p;
1312 if (p + blksize > end)
1313 lzo_blocks[i]->src_len = end - p;
1314 else
1315 lzo_blocks[i]->src_len = blksize;
1316 ret = snd_soc_lzo_compress_cache_block(codec,
1317 lzo_blocks[i]);
1318 if (ret < 0)
1319 goto err;
1320 lzo_blocks[i]->decompressed_size =
1321 lzo_blocks[i]->src_len;
1322 }
1323
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001324 if (tofree) {
1325 kfree(codec->reg_def_copy);
1326 codec->reg_def_copy = NULL;
1327 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001328 return 0;
1329err:
1330 snd_soc_cache_exit(codec);
1331err_tofree:
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001332 if (tofree) {
1333 kfree(codec->reg_def_copy);
1334 codec->reg_def_copy = NULL;
1335 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001336 return ret;
1337}
Mark Brown68d44ee2010-12-21 17:19:56 +00001338#endif
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001339
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001340static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
1341{
1342 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001343 int ret;
Mark Brown001ae4c2010-12-02 16:21:08 +00001344 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001345 unsigned int val;
1346
1347 codec_drv = codec->driver;
1348 for (i = 0; i < codec_drv->reg_cache_size; ++i) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +01001349 WARN_ON(codec->writable_register &&
1350 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001351 ret = snd_soc_cache_read(codec, i, &val);
1352 if (ret)
1353 return ret;
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001354 if (codec->reg_def_copy)
1355 if (snd_soc_get_cache_val(codec->reg_def_copy,
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001356 i, codec_drv->reg_word_size) == val)
1357 continue;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001358 ret = snd_soc_write(codec, i, val);
1359 if (ret)
1360 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001361 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1362 i, val);
1363 }
1364 return 0;
1365}
1366
1367static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
1368 unsigned int reg, unsigned int value)
1369{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001370 snd_soc_set_cache_val(codec->reg_cache, reg, value,
1371 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001372 return 0;
1373}
1374
1375static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
1376 unsigned int reg, unsigned int *value)
1377{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001378 *value = snd_soc_get_cache_val(codec->reg_cache, reg,
1379 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001380 return 0;
1381}
1382
1383static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
1384{
1385 if (!codec->reg_cache)
1386 return 0;
1387 kfree(codec->reg_cache);
1388 codec->reg_cache = NULL;
1389 return 0;
1390}
1391
1392static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
1393{
Mark Brown001ae4c2010-12-02 16:21:08 +00001394 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001395
1396 codec_drv = codec->driver;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001397
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001398 if (codec->reg_def_copy)
1399 codec->reg_cache = kmemdup(codec->reg_def_copy,
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001400 codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001401 else
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001402 codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001403 if (!codec->reg_cache)
1404 return -ENOMEM;
1405
1406 return 0;
1407}
1408
1409/* an array of all supported compression types */
1410static const struct snd_soc_cache_ops cache_types[] = {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001411 /* Flat *must* be the first entry for fallback */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001412 {
Dimitris Papastamosdf0701b2010-11-29 10:54:28 +00001413 .id = SND_SOC_FLAT_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001414 .name = "flat",
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001415 .init = snd_soc_flat_cache_init,
1416 .exit = snd_soc_flat_cache_exit,
1417 .read = snd_soc_flat_cache_read,
1418 .write = snd_soc_flat_cache_write,
1419 .sync = snd_soc_flat_cache_sync
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001420 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001421#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001422 {
1423 .id = SND_SOC_LZO_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001424 .name = "LZO",
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001425 .init = snd_soc_lzo_cache_init,
1426 .exit = snd_soc_lzo_cache_exit,
1427 .read = snd_soc_lzo_cache_read,
1428 .write = snd_soc_lzo_cache_write,
1429 .sync = snd_soc_lzo_cache_sync
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001430 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001431#endif
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001432 {
1433 .id = SND_SOC_RBTREE_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001434 .name = "rbtree",
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001435 .init = snd_soc_rbtree_cache_init,
1436 .exit = snd_soc_rbtree_cache_exit,
1437 .read = snd_soc_rbtree_cache_read,
1438 .write = snd_soc_rbtree_cache_write,
1439 .sync = snd_soc_rbtree_cache_sync
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001440 }
1441};
1442
1443int snd_soc_cache_init(struct snd_soc_codec *codec)
1444{
1445 int i;
1446
1447 for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
Dimitris Papastamos23bbce32010-12-02 14:53:01 +00001448 if (cache_types[i].id == codec->compress_type)
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001449 break;
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001450
1451 /* Fall back to flat compression */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001452 if (i == ARRAY_SIZE(cache_types)) {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001453 dev_warn(codec->dev, "Could not match compress type: %d\n",
1454 codec->compress_type);
1455 i = 0;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001456 }
1457
1458 mutex_init(&codec->cache_rw_mutex);
1459 codec->cache_ops = &cache_types[i];
1460
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001461 if (codec->cache_ops->init) {
1462 if (codec->cache_ops->name)
1463 dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
1464 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001465 return codec->cache_ops->init(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001466 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001467 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001468}
1469
1470/*
1471 * NOTE: keep in mind that this function might be called
1472 * multiple times.
1473 */
1474int snd_soc_cache_exit(struct snd_soc_codec *codec)
1475{
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001476 if (codec->cache_ops && codec->cache_ops->exit) {
1477 if (codec->cache_ops->name)
1478 dev_dbg(codec->dev, "Destroying %s cache for %s codec\n",
1479 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001480 return codec->cache_ops->exit(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001481 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001482 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001483}
1484
1485/**
1486 * snd_soc_cache_read: Fetch the value of a given register from the cache.
1487 *
1488 * @codec: CODEC to configure.
1489 * @reg: The register index.
1490 * @value: The value to be returned.
1491 */
1492int snd_soc_cache_read(struct snd_soc_codec *codec,
1493 unsigned int reg, unsigned int *value)
1494{
1495 int ret;
1496
1497 mutex_lock(&codec->cache_rw_mutex);
1498
1499 if (value && codec->cache_ops && codec->cache_ops->read) {
1500 ret = codec->cache_ops->read(codec, reg, value);
1501 mutex_unlock(&codec->cache_rw_mutex);
1502 return ret;
1503 }
1504
1505 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001506 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001507}
1508EXPORT_SYMBOL_GPL(snd_soc_cache_read);
1509
1510/**
1511 * snd_soc_cache_write: Set the value of a given register in the cache.
1512 *
1513 * @codec: CODEC to configure.
1514 * @reg: The register index.
1515 * @value: The new register value.
1516 */
1517int snd_soc_cache_write(struct snd_soc_codec *codec,
1518 unsigned int reg, unsigned int value)
1519{
1520 int ret;
1521
1522 mutex_lock(&codec->cache_rw_mutex);
1523
1524 if (codec->cache_ops && codec->cache_ops->write) {
1525 ret = codec->cache_ops->write(codec, reg, value);
1526 mutex_unlock(&codec->cache_rw_mutex);
1527 return ret;
1528 }
1529
1530 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001531 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001532}
1533EXPORT_SYMBOL_GPL(snd_soc_cache_write);
1534
1535/**
1536 * snd_soc_cache_sync: Sync the register cache with the hardware.
1537 *
1538 * @codec: CODEC to configure.
1539 *
1540 * Any registers that should not be synced should be marked as
1541 * volatile. In general drivers can choose not to use the provided
1542 * syncing functionality if they so require.
1543 */
1544int snd_soc_cache_sync(struct snd_soc_codec *codec)
1545{
1546 int ret;
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001547 const char *name;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001548
1549 if (!codec->cache_sync) {
1550 return 0;
1551 }
1552
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001553 if (!codec->cache_ops || !codec->cache_ops->sync)
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001554 return -ENOSYS;
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001555
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001556 if (codec->cache_ops->name)
1557 name = codec->cache_ops->name;
1558 else
1559 name = "unknown";
1560
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001561 if (codec->cache_ops->name)
1562 dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
1563 codec->cache_ops->name, codec->name);
1564 trace_snd_soc_cache_sync(codec, name, "start");
1565 ret = codec->cache_ops->sync(codec);
1566 if (!ret)
1567 codec->cache_sync = 0;
1568 trace_snd_soc_cache_sync(codec, name, "end");
1569 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001570}
1571EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
Dimitris Papastamos066d16c2011-01-13 12:20:36 +00001572
1573static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec,
1574 unsigned int reg)
1575{
1576 const struct snd_soc_codec_driver *codec_drv;
1577 unsigned int min, max, index;
1578
1579 codec_drv = codec->driver;
1580 min = 0;
1581 max = codec_drv->reg_access_size - 1;
1582 do {
1583 index = (min + max) / 2;
1584 if (codec_drv->reg_access_default[index].reg == reg)
1585 return index;
1586 if (codec_drv->reg_access_default[index].reg < reg)
1587 min = index + 1;
1588 else
1589 max = index;
1590 } while (min <= max);
1591 return -1;
1592}
1593
1594int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
1595 unsigned int reg)
1596{
1597 int index;
1598
1599 if (reg >= codec->driver->reg_cache_size)
1600 return 1;
1601 index = snd_soc_get_reg_access_index(codec, reg);
1602 if (index < 0)
1603 return 0;
1604 return codec->driver->reg_access_default[index].vol;
1605}
1606EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register);
1607
1608int snd_soc_default_readable_register(struct snd_soc_codec *codec,
1609 unsigned int reg)
1610{
1611 int index;
1612
1613 if (reg >= codec->driver->reg_cache_size)
1614 return 1;
1615 index = snd_soc_get_reg_access_index(codec, reg);
1616 if (index < 0)
1617 return 0;
1618 return codec->driver->reg_access_default[index].read;
1619}
1620EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
Dimitris Papastamos80204542011-03-24 13:45:17 +00001621
1622int snd_soc_default_writable_register(struct snd_soc_codec *codec,
1623 unsigned int reg)
1624{
1625 int index;
1626
1627 if (reg >= codec->driver->reg_cache_size)
1628 return 1;
1629 index = snd_soc_get_reg_access_index(codec, reg);
1630 if (index < 0)
1631 return 0;
1632 return codec->driver->reg_access_default[index].write;
1633}
1634EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);