blob: 6d6395fad486823d6a402d93351cb6797f929fce [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 Brown60c655e2011-05-11 01:02:35 +0200369 u16 data[2];
Mark Brownbc6552f2010-03-05 16:27:15 +0000370
Mark Brown60c655e2011-05-11 01:02:35 +0200371 data[0] = cpu_to_be16(reg);
372 data[1] = cpu_to_be16(value);
Mark Brownbc6552f2010-03-05 16:27:15 +0000373
Mark Brown60c655e2011-05-11 01:02:35 +0200374 return do_hw_write(codec, reg, value, data, sizeof(data));
Mark Brownbc6552f2010-03-05 16:27:15 +0000375}
Barry Song994dc422010-01-27 11:46:18 +0800376
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100377#if defined(CONFIG_SPI_MASTER)
378static int snd_soc_16_16_spi_write(void *control_data, const char *data,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100379 int len)
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100380{
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100381 u8 msg[4];
382
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100383 msg[0] = data[0];
384 msg[1] = data[1];
385 msg[2] = data[2];
386 msg[3] = data[3];
387
Dimitris Papastamos30539a12011-03-22 10:37:00 +0000388 return do_spi_write(control_data, msg, len);
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100389}
390#else
391#define snd_soc_16_16_spi_write NULL
392#endif
393
Mark Brown34bad692011-04-04 17:55:42 +0900394/* Primitive bulk write support for soc-cache. The data pointed to by
395 * `data' needs to already be in the form the hardware expects
396 * including any leading register specific data. Any data written
397 * through this function will not go through the cache as it only
398 * handles writing to volatile or out of bounds registers.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000399 */
400static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
401 const void *data, size_t len)
402{
403 int ret;
404
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100405 /* To ensure that we don't get out of sync with the cache, check
406 * whether the base register is volatile or if we've directly asked
407 * to bypass the cache. Out of bounds registers are considered
408 * volatile.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000409 */
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100410 if (!codec->cache_bypass
411 && !snd_soc_codec_volatile_register(codec, reg)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000412 && reg < codec->driver->reg_cache_size)
413 return -EINVAL;
414
415 switch (codec->control_type) {
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900416#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000417 case SND_SOC_I2C:
418 ret = i2c_master_send(codec->control_data, data, len);
419 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900420#endif
421#if defined(CONFIG_SPI_MASTER)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000422 case SND_SOC_SPI:
423 ret = do_spi_write(codec->control_data, data, len);
424 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900425#endif
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000426 default:
427 BUG();
428 }
429
430 if (ret == len)
431 return 0;
432 if (ret < 0)
433 return ret;
434 else
435 return -EIO;
436}
437
Mark Brown17a52fd2009-07-05 17:24:50 +0100438static struct {
439 int addr_bits;
440 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100441 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown27ded042009-07-10 23:28:16 +0100442 int (*spi_write)(void *, const char *, int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100443 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100444 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100445} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700446 {
Barry Song63b62ab2010-01-27 11:46:17 +0800447 .addr_bits = 4, .data_bits = 12,
448 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
449 .spi_write = snd_soc_4_12_spi_write,
450 },
451 {
Mark Brownd62ab352009-09-21 04:21:47 -0700452 .addr_bits = 7, .data_bits = 9,
453 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Barry Song8998c892009-12-31 10:30:34 +0800454 .spi_write = snd_soc_7_9_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700455 },
456 {
457 .addr_bits = 8, .data_bits = 8,
458 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800459 .i2c_read = snd_soc_8_8_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100460 .spi_write = snd_soc_8_8_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700461 },
462 {
463 .addr_bits = 8, .data_bits = 16,
464 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
465 .i2c_read = snd_soc_8_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100466 .spi_write = snd_soc_8_16_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700467 },
Barry Song994dc422010-01-27 11:46:18 +0800468 {
469 .addr_bits = 16, .data_bits = 8,
470 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
471 .i2c_read = snd_soc_16_8_read_i2c,
472 .spi_write = snd_soc_16_8_spi_write,
473 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000474 {
475 .addr_bits = 16, .data_bits = 16,
476 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
477 .i2c_read = snd_soc_16_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100478 .spi_write = snd_soc_16_16_spi_write,
Mark Brownbc6552f2010-03-05 16:27:15 +0000479 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100480};
481
482/**
483 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
484 *
485 * @codec: CODEC to configure.
Mark Brown17a52fd2009-07-05 17:24:50 +0100486 * @addr_bits: Number of bits of register address data.
487 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100488 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100489 *
490 * Register formats are frequently shared between many I2C and SPI
491 * devices. In order to promote code reuse the ASoC core provides
492 * some standard implementations of CODEC read and write operations
493 * which can be set up using this function.
494 *
495 * The caller is responsible for allocating and initialising the
496 * actual cache.
497 *
498 * Note that at present this code cannot be used by CODECs with
499 * volatile registers.
500 */
501int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100502 int addr_bits, int data_bits,
503 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100504{
505 int i;
506
Mark Brown17a52fd2009-07-05 17:24:50 +0100507 for (i = 0; i < ARRAY_SIZE(io_types); i++)
508 if (io_types[i].addr_bits == addr_bits &&
509 io_types[i].data_bits == data_bits)
510 break;
511 if (i == ARRAY_SIZE(io_types)) {
512 printk(KERN_ERR
513 "No I/O functions for %d bit address %d bit data\n",
514 addr_bits, data_bits);
515 return -EINVAL;
516 }
517
Mark Brownc3acec22010-12-02 16:15:29 +0000518 codec->write = io_types[i].write;
519 codec->read = io_types[i].read;
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000520 codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
Mark Brown17a52fd2009-07-05 17:24:50 +0100521
Mark Brown7084a422009-07-10 22:24:27 +0100522 switch (control) {
523 case SND_SOC_CUSTOM:
524 break;
525
526 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700527#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100528 codec->hw_write = (hw_write_t)i2c_master_send;
529#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100530 if (io_types[i].i2c_read)
531 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100532
533 codec->control_data = container_of(codec->dev,
534 struct i2c_client,
535 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100536 break;
537
538 case SND_SOC_SPI:
Mark Brown27ded042009-07-10 23:28:16 +0100539 if (io_types[i].spi_write)
540 codec->hw_write = io_types[i].spi_write;
Mark Browna6d14342010-08-12 10:59:15 +0100541
542 codec->control_data = container_of(codec->dev,
543 struct spi_device,
544 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100545 break;
546 }
547
Mark Brown17a52fd2009-07-05 17:24:50 +0100548 return 0;
549}
550EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000551
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000552static bool snd_soc_set_cache_val(void *base, unsigned int idx,
553 unsigned int val, unsigned int word_size)
554{
555 switch (word_size) {
556 case 1: {
557 u8 *cache = base;
558 if (cache[idx] == val)
559 return true;
560 cache[idx] = val;
561 break;
562 }
563 case 2: {
564 u16 *cache = base;
565 if (cache[idx] == val)
566 return true;
567 cache[idx] = val;
568 break;
569 }
570 default:
571 BUG();
572 }
573 return false;
574}
575
576static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
577 unsigned int word_size)
578{
579 switch (word_size) {
580 case 1: {
581 const u8 *cache = base;
582 return cache[idx];
583 }
584 case 2: {
585 const u16 *cache = base;
586 return cache[idx];
587 }
588 default:
589 BUG();
590 }
591 /* unreachable */
592 return -1;
593}
594
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000595struct snd_soc_rbtree_node {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100596 struct rb_node node; /* the actual rbtree node holding this block */
597 unsigned int base_reg; /* base register handled by this block */
598 unsigned int word_size; /* number of bytes needed to represent the register index */
599 void *block; /* block of adjacent registers */
600 unsigned int blklen; /* number of registers available in the block */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000601} __attribute__ ((packed));
602
603struct snd_soc_rbtree_ctx {
604 struct rb_root root;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100605 struct snd_soc_rbtree_node *cached_rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000606};
607
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100608static inline void snd_soc_rbtree_get_base_top_reg(
609 struct snd_soc_rbtree_node *rbnode,
610 unsigned int *base, unsigned int *top)
611{
612 *base = rbnode->base_reg;
613 *top = rbnode->base_reg + rbnode->blklen - 1;
614}
615
616static unsigned int snd_soc_rbtree_get_register(
617 struct snd_soc_rbtree_node *rbnode, unsigned int idx)
618{
619 unsigned int val;
620
621 switch (rbnode->word_size) {
622 case 1: {
623 u8 *p = rbnode->block;
624 val = p[idx];
625 return val;
626 }
627 case 2: {
628 u16 *p = rbnode->block;
629 val = p[idx];
630 return val;
631 }
632 default:
633 BUG();
634 break;
635 }
636 return -1;
637}
638
639static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
640 unsigned int idx, unsigned int val)
641{
642 switch (rbnode->word_size) {
643 case 1: {
644 u8 *p = rbnode->block;
645 p[idx] = val;
646 break;
647 }
648 case 2: {
649 u16 *p = rbnode->block;
650 p[idx] = val;
651 break;
652 }
653 default:
654 BUG();
655 break;
656 }
657}
658
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000659static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
660 struct rb_root *root, unsigned int reg)
661{
662 struct rb_node *node;
663 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100664 unsigned int base_reg, top_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000665
666 node = root->rb_node;
667 while (node) {
668 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100669 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
670 if (reg >= base_reg && reg <= top_reg)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000671 return rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100672 else if (reg > top_reg)
673 node = node->rb_right;
674 else if (reg < base_reg)
675 node = node->rb_left;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000676 }
677
678 return NULL;
679}
680
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000681static int snd_soc_rbtree_insert(struct rb_root *root,
682 struct snd_soc_rbtree_node *rbnode)
683{
684 struct rb_node **new, *parent;
685 struct snd_soc_rbtree_node *rbnode_tmp;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100686 unsigned int base_reg_tmp, top_reg_tmp;
687 unsigned int base_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000688
689 parent = NULL;
690 new = &root->rb_node;
691 while (*new) {
692 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
693 node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100694 /* base and top registers of the current rbnode */
695 snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
696 &top_reg_tmp);
697 /* base register of the rbnode to be added */
698 base_reg = rbnode->base_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000699 parent = *new;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100700 /* if this register has already been inserted, just return */
701 if (base_reg >= base_reg_tmp &&
702 base_reg <= top_reg_tmp)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000703 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100704 else if (base_reg > top_reg_tmp)
705 new = &((*new)->rb_right);
706 else if (base_reg < base_reg_tmp)
707 new = &((*new)->rb_left);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000708 }
709
710 /* insert the node into the rbtree */
711 rb_link_node(&rbnode->node, parent, new);
712 rb_insert_color(&rbnode->node, root);
713
714 return 1;
715}
716
717static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
718{
719 struct snd_soc_rbtree_ctx *rbtree_ctx;
720 struct rb_node *node;
721 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100722 unsigned int regtmp;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000723 unsigned int val;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000724 int ret;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100725 int i;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000726
727 rbtree_ctx = codec->reg_cache;
728 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
729 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100730 for (i = 0; i < rbnode->blklen; ++i) {
731 regtmp = rbnode->base_reg + i;
732 WARN_ON(codec->writable_register &&
733 codec->writable_register(codec, regtmp));
734 val = snd_soc_rbtree_get_register(rbnode, i);
735 codec->cache_bypass = 1;
736 ret = snd_soc_write(codec, regtmp, val);
737 codec->cache_bypass = 0;
738 if (ret)
739 return ret;
740 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
741 regtmp, val);
742 }
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000743 }
744
745 return 0;
746}
747
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100748static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
749 unsigned int pos, unsigned int reg,
750 unsigned int value)
751{
752 u8 *blk;
753
754 blk = krealloc(rbnode->block,
755 (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
756 if (!blk)
757 return -ENOMEM;
758
759 /* insert the register value in the correct place in the rbnode block */
760 memmove(blk + (pos + 1) * rbnode->word_size,
761 blk + pos * rbnode->word_size,
762 (rbnode->blklen - pos) * rbnode->word_size);
763
764 /* update the rbnode block, its size and the base register */
765 rbnode->block = blk;
766 rbnode->blklen++;
767 if (!pos)
768 rbnode->base_reg = reg;
769
770 snd_soc_rbtree_set_register(rbnode, pos, value);
771 return 0;
772}
773
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000774static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
775 unsigned int reg, unsigned int value)
776{
777 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100778 struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
779 struct rb_node *node;
780 unsigned int val;
781 unsigned int reg_tmp;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100782 unsigned int base_reg, top_reg;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100783 unsigned int pos;
784 int i;
785 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000786
787 rbtree_ctx = codec->reg_cache;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100788 /* look up the required register in the cached rbnode */
789 rbnode = rbtree_ctx->cached_rbnode;
790 if (rbnode) {
791 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
792 if (reg >= base_reg && reg <= top_reg) {
793 reg_tmp = reg - base_reg;
794 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
795 if (val == value)
796 return 0;
797 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
798 return 0;
799 }
800 }
801 /* if we can't locate it in the cached rbnode we'll have
802 * to traverse the rbtree looking for it.
803 */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000804 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
805 if (rbnode) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100806 reg_tmp = reg - rbnode->base_reg;
807 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
808 if (val == value)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000809 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100810 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100811 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000812 } else {
813 /* bail out early, no need to create the rbnode yet */
814 if (!value)
815 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100816 /* look for an adjacent register to the one we are about to add */
817 for (node = rb_first(&rbtree_ctx->root); node;
818 node = rb_next(node)) {
819 rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
820 for (i = 0; i < rbnode_tmp->blklen; ++i) {
821 reg_tmp = rbnode_tmp->base_reg + i;
822 if (abs(reg_tmp - reg) != 1)
823 continue;
824 /* decide where in the block to place our register */
825 if (reg_tmp + 1 == reg)
826 pos = i + 1;
827 else
828 pos = i;
829 ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
830 reg, value);
831 if (ret)
832 return ret;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100833 rbtree_ctx->cached_rbnode = rbnode_tmp;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100834 return 0;
835 }
836 }
837 /* we did not manage to find a place to insert it in an existing
838 * block so create a new rbnode with a single register in its block.
839 * This block will get populated further if any other adjacent
840 * registers get modified in the future.
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000841 */
842 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
843 if (!rbnode)
844 return -ENOMEM;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100845 rbnode->blklen = 1;
846 rbnode->base_reg = reg;
847 rbnode->word_size = codec->driver->reg_word_size;
848 rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
849 GFP_KERNEL);
850 if (!rbnode->block) {
851 kfree(rbnode);
852 return -ENOMEM;
853 }
854 snd_soc_rbtree_set_register(rbnode, 0, value);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000855 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100856 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000857 }
858
859 return 0;
860}
861
862static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
863 unsigned int reg, unsigned int *value)
864{
865 struct snd_soc_rbtree_ctx *rbtree_ctx;
866 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100867 unsigned int base_reg, top_reg;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100868 unsigned int reg_tmp;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000869
870 rbtree_ctx = codec->reg_cache;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100871 /* look up the required register in the cached rbnode */
872 rbnode = rbtree_ctx->cached_rbnode;
873 if (rbnode) {
874 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
875 if (reg >= base_reg && reg <= top_reg) {
876 reg_tmp = reg - base_reg;
877 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
878 return 0;
879 }
880 }
881 /* if we can't locate it in the cached rbnode we'll have
882 * to traverse the rbtree looking for it.
883 */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000884 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
885 if (rbnode) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100886 reg_tmp = reg - rbnode->base_reg;
887 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100888 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000889 } else {
890 /* uninitialized registers default to 0 */
891 *value = 0;
892 }
893
894 return 0;
895}
896
897static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
898{
899 struct rb_node *next;
900 struct snd_soc_rbtree_ctx *rbtree_ctx;
901 struct snd_soc_rbtree_node *rbtree_node;
902
903 /* if we've already been called then just return */
904 rbtree_ctx = codec->reg_cache;
905 if (!rbtree_ctx)
906 return 0;
907
908 /* free up the rbtree */
909 next = rb_first(&rbtree_ctx->root);
910 while (next) {
911 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
912 next = rb_next(&rbtree_node->node);
913 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100914 kfree(rbtree_node->block);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000915 kfree(rbtree_node);
916 }
917
918 /* release the resources */
919 kfree(codec->reg_cache);
920 codec->reg_cache = NULL;
921
922 return 0;
923}
924
925static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
926{
927 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000928 unsigned int word_size;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100929 unsigned int val;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000930 int i;
931 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000932
933 codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
934 if (!codec->reg_cache)
935 return -ENOMEM;
936
937 rbtree_ctx = codec->reg_cache;
938 rbtree_ctx->root = RB_ROOT;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100939 rbtree_ctx->cached_rbnode = NULL;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000940
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000941 if (!codec->reg_def_copy)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000942 return 0;
943
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000944 word_size = codec->driver->reg_word_size;
945 for (i = 0; i < codec->driver->reg_cache_size; ++i) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100946 val = snd_soc_get_cache_val(codec->reg_def_copy, i,
947 word_size);
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000948 if (!val)
949 continue;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100950 ret = snd_soc_rbtree_cache_write(codec, i, val);
951 if (ret)
952 goto err;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000953 }
954
955 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100956
957err:
958 snd_soc_cache_exit(codec);
959 return ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000960}
961
Mark Brown68d44ee2010-12-21 17:19:56 +0000962#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000963struct snd_soc_lzo_ctx {
964 void *wmem;
965 void *dst;
966 const void *src;
967 size_t src_len;
968 size_t dst_len;
969 size_t decompressed_size;
970 unsigned long *sync_bmp;
971 int sync_bmp_nbits;
972};
973
974#define LZO_BLOCK_NUM 8
975static int snd_soc_lzo_block_count(void)
976{
977 return LZO_BLOCK_NUM;
978}
979
980static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx)
981{
982 lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
983 if (!lzo_ctx->wmem)
984 return -ENOMEM;
985 return 0;
986}
987
988static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx)
989{
990 size_t compress_size;
991 int ret;
992
993 ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
994 lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
995 if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
996 return -EINVAL;
997 lzo_ctx->dst_len = compress_size;
998 return 0;
999}
1000
1001static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx)
1002{
1003 size_t dst_len;
1004 int ret;
1005
1006 dst_len = lzo_ctx->dst_len;
1007 ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
1008 lzo_ctx->dst, &dst_len);
1009 if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
1010 return -EINVAL;
1011 return 0;
1012}
1013
1014static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec,
1015 struct snd_soc_lzo_ctx *lzo_ctx)
1016{
1017 int ret;
1018
1019 lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
1020 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
1021 if (!lzo_ctx->dst) {
1022 lzo_ctx->dst_len = 0;
1023 return -ENOMEM;
1024 }
1025
1026 ret = snd_soc_lzo_compress(lzo_ctx);
1027 if (ret < 0)
1028 return ret;
1029 return 0;
1030}
1031
1032static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec,
1033 struct snd_soc_lzo_ctx *lzo_ctx)
1034{
1035 int ret;
1036
1037 lzo_ctx->dst_len = lzo_ctx->decompressed_size;
1038 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
1039 if (!lzo_ctx->dst) {
1040 lzo_ctx->dst_len = 0;
1041 return -ENOMEM;
1042 }
1043
1044 ret = snd_soc_lzo_decompress(lzo_ctx);
1045 if (ret < 0)
1046 return ret;
1047 return 0;
1048}
1049
1050static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
1051 unsigned int reg)
1052{
Mark Brown001ae4c2010-12-02 16:21:08 +00001053 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001054
1055 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001056 return (reg * codec_drv->reg_word_size) /
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001057 DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001058}
1059
1060static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
1061 unsigned int reg)
1062{
Mark Brown001ae4c2010-12-02 16:21:08 +00001063 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001064
1065 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001066 return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) /
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001067 codec_drv->reg_word_size);
1068}
1069
1070static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
1071{
Mark Brown001ae4c2010-12-02 16:21:08 +00001072 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001073
1074 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001075 return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001076}
1077
1078static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
1079{
1080 struct snd_soc_lzo_ctx **lzo_blocks;
1081 unsigned int val;
1082 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001083 int ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001084
1085 lzo_blocks = codec->reg_cache;
1086 for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +01001087 WARN_ON(codec->writable_register &&
1088 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001089 ret = snd_soc_cache_read(codec, i, &val);
1090 if (ret)
1091 return ret;
Dimitris Papastamos99780072011-01-19 14:53:37 +00001092 codec->cache_bypass = 1;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001093 ret = snd_soc_write(codec, i, val);
Dimitris Papastamos99780072011-01-19 14:53:37 +00001094 codec->cache_bypass = 0;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001095 if (ret)
1096 return ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001097 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1098 i, val);
1099 }
1100
1101 return 0;
1102}
1103
1104static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
1105 unsigned int reg, unsigned int value)
1106{
1107 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1108 int ret, blkindex, blkpos;
1109 size_t blksize, tmp_dst_len;
1110 void *tmp_dst;
1111
1112 /* index of the compressed lzo block */
1113 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1114 /* register index within the decompressed block */
1115 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1116 /* size of the compressed block */
1117 blksize = snd_soc_lzo_get_blksize(codec);
1118 lzo_blocks = codec->reg_cache;
1119 lzo_block = lzo_blocks[blkindex];
1120
1121 /* save the pointer and length of the compressed block */
1122 tmp_dst = lzo_block->dst;
1123 tmp_dst_len = lzo_block->dst_len;
1124
1125 /* prepare the source to be the compressed block */
1126 lzo_block->src = lzo_block->dst;
1127 lzo_block->src_len = lzo_block->dst_len;
1128
1129 /* decompress the block */
1130 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
1131 if (ret < 0) {
1132 kfree(lzo_block->dst);
1133 goto out;
1134 }
1135
1136 /* write the new value to the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001137 if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value,
1138 codec->driver->reg_word_size)) {
1139 kfree(lzo_block->dst);
1140 goto out;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001141 }
1142
1143 /* prepare the source to be the decompressed block */
1144 lzo_block->src = lzo_block->dst;
1145 lzo_block->src_len = lzo_block->dst_len;
1146
1147 /* compress the block */
1148 ret = snd_soc_lzo_compress_cache_block(codec, lzo_block);
1149 if (ret < 0) {
1150 kfree(lzo_block->dst);
1151 kfree(lzo_block->src);
1152 goto out;
1153 }
1154
1155 /* set the bit so we know we have to sync this register */
1156 set_bit(reg, lzo_block->sync_bmp);
1157 kfree(tmp_dst);
1158 kfree(lzo_block->src);
1159 return 0;
1160out:
1161 lzo_block->dst = tmp_dst;
1162 lzo_block->dst_len = tmp_dst_len;
1163 return ret;
1164}
1165
1166static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
1167 unsigned int reg, unsigned int *value)
1168{
1169 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1170 int ret, blkindex, blkpos;
1171 size_t blksize, tmp_dst_len;
1172 void *tmp_dst;
1173
1174 *value = 0;
1175 /* index of the compressed lzo block */
1176 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1177 /* register index within the decompressed block */
1178 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1179 /* size of the compressed block */
1180 blksize = snd_soc_lzo_get_blksize(codec);
1181 lzo_blocks = codec->reg_cache;
1182 lzo_block = lzo_blocks[blkindex];
1183
1184 /* save the pointer and length of the compressed block */
1185 tmp_dst = lzo_block->dst;
1186 tmp_dst_len = lzo_block->dst_len;
1187
1188 /* prepare the source to be the compressed block */
1189 lzo_block->src = lzo_block->dst;
1190 lzo_block->src_len = lzo_block->dst_len;
1191
1192 /* decompress the block */
1193 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001194 if (ret >= 0)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001195 /* fetch the value from the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001196 *value = snd_soc_get_cache_val(lzo_block->dst, blkpos,
1197 codec->driver->reg_word_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001198
1199 kfree(lzo_block->dst);
1200 /* restore the pointer and length of the compressed block */
1201 lzo_block->dst = tmp_dst;
1202 lzo_block->dst_len = tmp_dst_len;
1203 return 0;
1204}
1205
1206static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
1207{
1208 struct snd_soc_lzo_ctx **lzo_blocks;
1209 int i, blkcount;
1210
1211 lzo_blocks = codec->reg_cache;
1212 if (!lzo_blocks)
1213 return 0;
1214
1215 blkcount = snd_soc_lzo_block_count();
1216 /*
1217 * the pointer to the bitmap used for syncing the cache
1218 * is shared amongst all lzo_blocks. Ensure it is freed
1219 * only once.
1220 */
1221 if (lzo_blocks[0])
1222 kfree(lzo_blocks[0]->sync_bmp);
1223 for (i = 0; i < blkcount; ++i) {
1224 if (lzo_blocks[i]) {
1225 kfree(lzo_blocks[i]->wmem);
1226 kfree(lzo_blocks[i]->dst);
1227 }
1228 /* each lzo_block is a pointer returned by kmalloc or NULL */
1229 kfree(lzo_blocks[i]);
1230 }
1231 kfree(lzo_blocks);
1232 codec->reg_cache = NULL;
1233 return 0;
1234}
1235
1236static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
1237{
1238 struct snd_soc_lzo_ctx **lzo_blocks;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001239 size_t bmp_size;
Mark Brown001ae4c2010-12-02 16:21:08 +00001240 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001241 int ret, tofree, i, blksize, blkcount;
1242 const char *p, *end;
1243 unsigned long *sync_bmp;
1244
1245 ret = 0;
1246 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001247
1248 /*
1249 * If we have not been given a default register cache
1250 * then allocate a dummy zero-ed out region, compress it
1251 * and remember to free it afterwards.
1252 */
1253 tofree = 0;
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001254 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001255 tofree = 1;
1256
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001257 if (!codec->reg_def_copy) {
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001258 codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001259 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001260 return -ENOMEM;
1261 }
1262
1263 blkcount = snd_soc_lzo_block_count();
1264 codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks,
1265 GFP_KERNEL);
1266 if (!codec->reg_cache) {
1267 ret = -ENOMEM;
1268 goto err_tofree;
1269 }
1270 lzo_blocks = codec->reg_cache;
1271
1272 /*
1273 * allocate a bitmap to be used when syncing the cache with
1274 * the hardware. Each time a register is modified, the corresponding
1275 * bit is set in the bitmap, so we know that we have to sync
1276 * that register.
1277 */
1278 bmp_size = codec_drv->reg_cache_size;
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +00001279 sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001280 GFP_KERNEL);
1281 if (!sync_bmp) {
1282 ret = -ENOMEM;
1283 goto err;
1284 }
Dimitris Papastamos09c74a92010-11-29 11:43:33 +00001285 bitmap_zero(sync_bmp, bmp_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001286
1287 /* allocate the lzo blocks and initialize them */
1288 for (i = 0; i < blkcount; ++i) {
1289 lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
1290 GFP_KERNEL);
1291 if (!lzo_blocks[i]) {
1292 kfree(sync_bmp);
1293 ret = -ENOMEM;
1294 goto err;
1295 }
1296 lzo_blocks[i]->sync_bmp = sync_bmp;
Dimitris Papastamos04f8fd12011-01-11 11:24:02 +00001297 lzo_blocks[i]->sync_bmp_nbits = bmp_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001298 /* alloc the working space for the compressed block */
1299 ret = snd_soc_lzo_prepare(lzo_blocks[i]);
1300 if (ret < 0)
1301 goto err;
1302 }
1303
1304 blksize = snd_soc_lzo_get_blksize(codec);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001305 p = codec->reg_def_copy;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001306 end = codec->reg_def_copy + codec->reg_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001307 /* compress the register map and fill the lzo blocks */
1308 for (i = 0; i < blkcount; ++i, p += blksize) {
1309 lzo_blocks[i]->src = p;
1310 if (p + blksize > end)
1311 lzo_blocks[i]->src_len = end - p;
1312 else
1313 lzo_blocks[i]->src_len = blksize;
1314 ret = snd_soc_lzo_compress_cache_block(codec,
1315 lzo_blocks[i]);
1316 if (ret < 0)
1317 goto err;
1318 lzo_blocks[i]->decompressed_size =
1319 lzo_blocks[i]->src_len;
1320 }
1321
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001322 if (tofree) {
1323 kfree(codec->reg_def_copy);
1324 codec->reg_def_copy = NULL;
1325 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001326 return 0;
1327err:
1328 snd_soc_cache_exit(codec);
1329err_tofree:
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001330 if (tofree) {
1331 kfree(codec->reg_def_copy);
1332 codec->reg_def_copy = NULL;
1333 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001334 return ret;
1335}
Mark Brown68d44ee2010-12-21 17:19:56 +00001336#endif
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001337
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001338static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
1339{
1340 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001341 int ret;
Mark Brown001ae4c2010-12-02 16:21:08 +00001342 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001343 unsigned int val;
1344
1345 codec_drv = codec->driver;
1346 for (i = 0; i < codec_drv->reg_cache_size; ++i) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +01001347 WARN_ON(codec->writable_register &&
1348 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001349 ret = snd_soc_cache_read(codec, i, &val);
1350 if (ret)
1351 return ret;
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001352 if (codec->reg_def_copy)
1353 if (snd_soc_get_cache_val(codec->reg_def_copy,
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001354 i, codec_drv->reg_word_size) == val)
1355 continue;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001356 ret = snd_soc_write(codec, i, val);
1357 if (ret)
1358 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001359 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1360 i, val);
1361 }
1362 return 0;
1363}
1364
1365static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
1366 unsigned int reg, unsigned int value)
1367{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001368 snd_soc_set_cache_val(codec->reg_cache, reg, value,
1369 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001370 return 0;
1371}
1372
1373static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
1374 unsigned int reg, unsigned int *value)
1375{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001376 *value = snd_soc_get_cache_val(codec->reg_cache, reg,
1377 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001378 return 0;
1379}
1380
1381static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
1382{
1383 if (!codec->reg_cache)
1384 return 0;
1385 kfree(codec->reg_cache);
1386 codec->reg_cache = NULL;
1387 return 0;
1388}
1389
1390static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
1391{
Mark Brown001ae4c2010-12-02 16:21:08 +00001392 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001393
1394 codec_drv = codec->driver;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001395
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001396 if (codec->reg_def_copy)
1397 codec->reg_cache = kmemdup(codec->reg_def_copy,
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001398 codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001399 else
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001400 codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001401 if (!codec->reg_cache)
1402 return -ENOMEM;
1403
1404 return 0;
1405}
1406
1407/* an array of all supported compression types */
1408static const struct snd_soc_cache_ops cache_types[] = {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001409 /* Flat *must* be the first entry for fallback */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001410 {
Dimitris Papastamosdf0701b2010-11-29 10:54:28 +00001411 .id = SND_SOC_FLAT_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001412 .name = "flat",
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001413 .init = snd_soc_flat_cache_init,
1414 .exit = snd_soc_flat_cache_exit,
1415 .read = snd_soc_flat_cache_read,
1416 .write = snd_soc_flat_cache_write,
1417 .sync = snd_soc_flat_cache_sync
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001418 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001419#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001420 {
1421 .id = SND_SOC_LZO_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001422 .name = "LZO",
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001423 .init = snd_soc_lzo_cache_init,
1424 .exit = snd_soc_lzo_cache_exit,
1425 .read = snd_soc_lzo_cache_read,
1426 .write = snd_soc_lzo_cache_write,
1427 .sync = snd_soc_lzo_cache_sync
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001428 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001429#endif
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001430 {
1431 .id = SND_SOC_RBTREE_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001432 .name = "rbtree",
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001433 .init = snd_soc_rbtree_cache_init,
1434 .exit = snd_soc_rbtree_cache_exit,
1435 .read = snd_soc_rbtree_cache_read,
1436 .write = snd_soc_rbtree_cache_write,
1437 .sync = snd_soc_rbtree_cache_sync
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001438 }
1439};
1440
1441int snd_soc_cache_init(struct snd_soc_codec *codec)
1442{
1443 int i;
1444
1445 for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
Dimitris Papastamos23bbce32010-12-02 14:53:01 +00001446 if (cache_types[i].id == codec->compress_type)
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001447 break;
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001448
1449 /* Fall back to flat compression */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001450 if (i == ARRAY_SIZE(cache_types)) {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001451 dev_warn(codec->dev, "Could not match compress type: %d\n",
1452 codec->compress_type);
1453 i = 0;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001454 }
1455
1456 mutex_init(&codec->cache_rw_mutex);
1457 codec->cache_ops = &cache_types[i];
1458
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001459 if (codec->cache_ops->init) {
1460 if (codec->cache_ops->name)
1461 dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
1462 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001463 return codec->cache_ops->init(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001464 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001465 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001466}
1467
1468/*
1469 * NOTE: keep in mind that this function might be called
1470 * multiple times.
1471 */
1472int snd_soc_cache_exit(struct snd_soc_codec *codec)
1473{
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001474 if (codec->cache_ops && codec->cache_ops->exit) {
1475 if (codec->cache_ops->name)
1476 dev_dbg(codec->dev, "Destroying %s cache for %s codec\n",
1477 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001478 return codec->cache_ops->exit(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001479 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001480 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001481}
1482
1483/**
1484 * snd_soc_cache_read: Fetch the value of a given register from the cache.
1485 *
1486 * @codec: CODEC to configure.
1487 * @reg: The register index.
1488 * @value: The value to be returned.
1489 */
1490int snd_soc_cache_read(struct snd_soc_codec *codec,
1491 unsigned int reg, unsigned int *value)
1492{
1493 int ret;
1494
1495 mutex_lock(&codec->cache_rw_mutex);
1496
1497 if (value && codec->cache_ops && codec->cache_ops->read) {
1498 ret = codec->cache_ops->read(codec, reg, value);
1499 mutex_unlock(&codec->cache_rw_mutex);
1500 return ret;
1501 }
1502
1503 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001504 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001505}
1506EXPORT_SYMBOL_GPL(snd_soc_cache_read);
1507
1508/**
1509 * snd_soc_cache_write: Set the value of a given register in the cache.
1510 *
1511 * @codec: CODEC to configure.
1512 * @reg: The register index.
1513 * @value: The new register value.
1514 */
1515int snd_soc_cache_write(struct snd_soc_codec *codec,
1516 unsigned int reg, unsigned int value)
1517{
1518 int ret;
1519
1520 mutex_lock(&codec->cache_rw_mutex);
1521
1522 if (codec->cache_ops && codec->cache_ops->write) {
1523 ret = codec->cache_ops->write(codec, reg, value);
1524 mutex_unlock(&codec->cache_rw_mutex);
1525 return ret;
1526 }
1527
1528 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001529 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001530}
1531EXPORT_SYMBOL_GPL(snd_soc_cache_write);
1532
1533/**
1534 * snd_soc_cache_sync: Sync the register cache with the hardware.
1535 *
1536 * @codec: CODEC to configure.
1537 *
1538 * Any registers that should not be synced should be marked as
1539 * volatile. In general drivers can choose not to use the provided
1540 * syncing functionality if they so require.
1541 */
1542int snd_soc_cache_sync(struct snd_soc_codec *codec)
1543{
1544 int ret;
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001545 const char *name;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001546
1547 if (!codec->cache_sync) {
1548 return 0;
1549 }
1550
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001551 if (!codec->cache_ops || !codec->cache_ops->sync)
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001552 return -ENOSYS;
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001553
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001554 if (codec->cache_ops->name)
1555 name = codec->cache_ops->name;
1556 else
1557 name = "unknown";
1558
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001559 if (codec->cache_ops->name)
1560 dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
1561 codec->cache_ops->name, codec->name);
1562 trace_snd_soc_cache_sync(codec, name, "start");
1563 ret = codec->cache_ops->sync(codec);
1564 if (!ret)
1565 codec->cache_sync = 0;
1566 trace_snd_soc_cache_sync(codec, name, "end");
1567 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001568}
1569EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
Dimitris Papastamos066d16c2011-01-13 12:20:36 +00001570
1571static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec,
1572 unsigned int reg)
1573{
1574 const struct snd_soc_codec_driver *codec_drv;
1575 unsigned int min, max, index;
1576
1577 codec_drv = codec->driver;
1578 min = 0;
1579 max = codec_drv->reg_access_size - 1;
1580 do {
1581 index = (min + max) / 2;
1582 if (codec_drv->reg_access_default[index].reg == reg)
1583 return index;
1584 if (codec_drv->reg_access_default[index].reg < reg)
1585 min = index + 1;
1586 else
1587 max = index;
1588 } while (min <= max);
1589 return -1;
1590}
1591
1592int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
1593 unsigned int reg)
1594{
1595 int index;
1596
1597 if (reg >= codec->driver->reg_cache_size)
1598 return 1;
1599 index = snd_soc_get_reg_access_index(codec, reg);
1600 if (index < 0)
1601 return 0;
1602 return codec->driver->reg_access_default[index].vol;
1603}
1604EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register);
1605
1606int snd_soc_default_readable_register(struct snd_soc_codec *codec,
1607 unsigned int reg)
1608{
1609 int index;
1610
1611 if (reg >= codec->driver->reg_cache_size)
1612 return 1;
1613 index = snd_soc_get_reg_access_index(codec, reg);
1614 if (index < 0)
1615 return 0;
1616 return codec->driver->reg_access_default[index].read;
1617}
1618EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
Dimitris Papastamos80204542011-03-24 13:45:17 +00001619
1620int snd_soc_default_writable_register(struct snd_soc_codec *codec,
1621 unsigned int reg)
1622{
1623 int index;
1624
1625 if (reg >= codec->driver->reg_cache_size)
1626 return 1;
1627 index = snd_soc_get_reg_access_index(codec, reg);
1628 if (index < 0)
1629 return 0;
1630 return codec->driver->reg_access_default[index].write;
1631}
1632EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);