blob: 9a88a276a0abbae8d87bc192de71621988bf0266 [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
Mark Brownf7391fc2011-05-11 19:25:42 +020023#ifdef CONFIG_SPI_MASTER
24static int do_spi_write(void *control, const char *data, int len)
Dimitris Papastamos30539a12011-03-22 10:37:00 +000025{
Mark Brownf7391fc2011-05-11 19:25:42 +020026 struct spi_device *spi = control;
27 int ret;
Dimitris Papastamos30539a12011-03-22 10:37:00 +000028
Mark Brownf7391fc2011-05-11 19:25:42 +020029 ret = spi_write(spi, data, len);
30 if (ret < 0)
31 return ret;
Dimitris Papastamos30539a12011-03-22 10:37:00 +000032
33 return len;
34}
35#endif
36
Dimitris Papastamos26e99842011-03-22 10:36:58 +000037static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
38 unsigned int value, const void *data, int len)
39{
40 int ret;
41
42 if (!snd_soc_codec_volatile_register(codec, reg) &&
43 reg < codec->driver->reg_cache_size &&
44 !codec->cache_bypass) {
45 ret = snd_soc_cache_write(codec, reg, value);
46 if (ret < 0)
47 return -1;
48 }
49
50 if (codec->cache_only) {
51 codec->cache_sync = 1;
52 return 0;
53 }
54
55 ret = codec->hw_write(codec->control_data, data, len);
56 if (ret == len)
57 return 0;
58 if (ret < 0)
59 return ret;
60 else
61 return -EIO;
62}
63
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000064static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg)
Barry Song63b62ab2010-01-27 11:46:17 +080065{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000066 int ret;
67 unsigned int val;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010068
69 if (reg >= codec->driver->reg_cache_size ||
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000070 snd_soc_codec_volatile_register(codec, reg) ||
71 codec->cache_bypass) {
72 if (codec->cache_only)
73 return -1;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010074
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000075 BUG_ON(!codec->hw_read);
76 return codec->hw_read(codec, reg);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010077 }
78
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000079 ret = snd_soc_cache_read(codec, reg, &val);
80 if (ret < 0)
81 return -1;
82 return val;
Barry Song63b62ab2010-01-27 11:46:17 +080083}
84
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000085static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +010086 unsigned int reg)
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000087{
88 return do_hw_read(codec, reg);
89}
90
Barry Song63b62ab2010-01-27 11:46:17 +080091static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +010092 unsigned int value)
Barry Song63b62ab2010-01-27 11:46:17 +080093{
Mark Brown063b7cc2011-05-10 23:55:21 +020094 u16 data;
Barry Song63b62ab2010-01-27 11:46:17 +080095
Mark Brown063b7cc2011-05-10 23:55:21 +020096 data = cpu_to_be16((reg << 12) | (value & 0xffffff));
Barry Song63b62ab2010-01-27 11:46:17 +080097
Mark Brown063b7cc2011-05-10 23:55:21 +020098 return do_hw_write(codec, reg, value, &data, 2);
Barry Song63b62ab2010-01-27 11:46:17 +080099}
100
Mark Brown17a52fd2009-07-05 17:24:50 +0100101static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
102 unsigned int reg)
103{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000104 return do_hw_read(codec, reg);
Mark Brown17a52fd2009-07-05 17:24:50 +0100105}
106
107static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
108 unsigned int value)
109{
Mark Brownf06f1362011-05-11 00:56:13 +0200110 u16 data;
Mark Brown17a52fd2009-07-05 17:24:50 +0100111
Mark Brownf06f1362011-05-11 00:56:13 +0200112 data = cpu_to_be16((reg << 9) | (value & 0x1ff));
Mark Brown17a52fd2009-07-05 17:24:50 +0100113
Mark Brownf06f1362011-05-11 00:56:13 +0200114 return do_hw_write(codec, reg, value, &data, 2);
Mark Brown17a52fd2009-07-05 17:24:50 +0100115}
116
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900117static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
118 unsigned int value)
119{
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900120 u8 data[2];
121
Barry Songf4bee1b2010-03-18 16:17:01 +0800122 reg &= 0xff;
123 data[0] = reg;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900124 data[1] = value & 0xff;
125
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000126 return do_hw_write(codec, reg, value, data, 2);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900127}
128
129static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
130 unsigned int reg)
131{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000132 return do_hw_read(codec, reg);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900133}
134
Mark Brownafa2f102009-07-10 23:11:24 +0100135static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
136 unsigned int value)
137{
Mark Brownafa2f102009-07-10 23:11:24 +0100138 u8 data[3];
Mark Brown94228bcf2011-05-11 11:18:00 +0200139 u16 val = cpu_to_be16(value);
Mark Brownafa2f102009-07-10 23:11:24 +0100140
141 data[0] = reg;
Mark Brown94228bcf2011-05-11 11:18:00 +0200142 memcpy(&data[1], &val, sizeof(val));
Mark Brownafa2f102009-07-10 23:11:24 +0100143
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000144 return do_hw_write(codec, reg, value, data, 3);
Mark Brownafa2f102009-07-10 23:11:24 +0100145}
146
147static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
148 unsigned int reg)
149{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000150 return do_hw_read(codec, reg);
Mark Brownafa2f102009-07-10 23:11:24 +0100151}
152
Randy Dunlap17244c22009-08-10 16:04:39 -0700153#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000154static unsigned int do_i2c_read(struct snd_soc_codec *codec,
155 void *reg, int reglen,
156 void *data, int datalen)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800157{
158 struct i2c_msg xfer[2];
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800159 int ret;
160 struct i2c_client *client = codec->control_data;
161
162 /* Write register */
163 xfer[0].addr = client->addr;
164 xfer[0].flags = 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000165 xfer[0].len = reglen;
166 xfer[0].buf = reg;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800167
168 /* Read data */
169 xfer[1].addr = client->addr;
170 xfer[1].flags = I2C_M_RD;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000171 xfer[1].len = datalen;
172 xfer[1].buf = data;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800173
174 ret = i2c_transfer(client->adapter, xfer, 2);
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000175 if (ret == 2)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800176 return 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000177 else if (ret < 0)
178 return ret;
179 else
180 return -EIO;
181}
182#endif
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800183
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000184#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
185static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100186 unsigned int r)
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000187{
188 u8 reg = r;
189 u8 data;
190 int ret;
191
192 ret = do_i2c_read(codec, &reg, 1, &data, 1);
193 if (ret < 0)
194 return 0;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800195 return data;
196}
197#else
198#define snd_soc_8_8_read_i2c NULL
199#endif
200
201#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100202static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
203 unsigned int r)
204{
Mark Brownafa2f102009-07-10 23:11:24 +0100205 u8 reg = r;
206 u16 data;
207 int ret;
Mark Brownafa2f102009-07-10 23:11:24 +0100208
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000209 ret = do_i2c_read(codec, &reg, 1, &data, 2);
210 if (ret < 0)
Mark Brownafa2f102009-07-10 23:11:24 +0100211 return 0;
Mark Brownafa2f102009-07-10 23:11:24 +0100212 return (data >> 8) | ((data & 0xff) << 8);
213}
214#else
215#define snd_soc_8_16_read_i2c NULL
216#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100217
Barry Song994dc422010-01-27 11:46:18 +0800218#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
219static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
220 unsigned int r)
221{
Barry Song994dc422010-01-27 11:46:18 +0800222 u16 reg = r;
223 u8 data;
224 int ret;
Barry Song994dc422010-01-27 11:46:18 +0800225
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000226 ret = do_i2c_read(codec, &reg, 2, &data, 1);
227 if (ret < 0)
Barry Song994dc422010-01-27 11:46:18 +0800228 return 0;
Barry Song994dc422010-01-27 11:46:18 +0800229 return data;
230}
231#else
232#define snd_soc_16_8_read_i2c NULL
233#endif
234
235static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100236 unsigned int reg)
Barry Song994dc422010-01-27 11:46:18 +0800237{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000238 return do_hw_read(codec, reg);
Barry Song994dc422010-01-27 11:46:18 +0800239}
240
241static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100242 unsigned int value)
Barry Song994dc422010-01-27 11:46:18 +0800243{
Barry Song994dc422010-01-27 11:46:18 +0800244 u8 data[3];
Mark Brown2ac8b6f2011-05-11 15:15:56 +0200245 u16 rval = cpu_to_be16(reg);
Barry Song994dc422010-01-27 11:46:18 +0800246
Mark Brown2ac8b6f2011-05-11 15:15:56 +0200247 memcpy(data, &rval, sizeof(rval));
Barry Song994dc422010-01-27 11:46:18 +0800248 data[2] = value;
Mark Brown8c961bc2010-02-01 18:46:10 +0000249
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000250 return do_hw_write(codec, reg, value, data, 3);
Barry Song994dc422010-01-27 11:46:18 +0800251}
252
Mark Brownbc6552f2010-03-05 16:27:15 +0000253#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
254static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
255 unsigned int r)
256{
Mark Brownbc6552f2010-03-05 16:27:15 +0000257 u16 reg = cpu_to_be16(r);
258 u16 data;
259 int ret;
Mark Brownbc6552f2010-03-05 16:27:15 +0000260
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000261 ret = do_i2c_read(codec, &reg, 2, &data, 2);
262 if (ret < 0)
Mark Brownbc6552f2010-03-05 16:27:15 +0000263 return 0;
Mark Brownbc6552f2010-03-05 16:27:15 +0000264 return be16_to_cpu(data);
265}
266#else
267#define snd_soc_16_16_read_i2c NULL
268#endif
269
270static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
271 unsigned int reg)
272{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000273 return do_hw_read(codec, reg);
Mark Brownbc6552f2010-03-05 16:27:15 +0000274}
275
276static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
277 unsigned int value)
278{
Mark Brown60c655e2011-05-11 01:02:35 +0200279 u16 data[2];
Mark Brownbc6552f2010-03-05 16:27:15 +0000280
Mark Brown60c655e2011-05-11 01:02:35 +0200281 data[0] = cpu_to_be16(reg);
282 data[1] = cpu_to_be16(value);
Mark Brownbc6552f2010-03-05 16:27:15 +0000283
Mark Brown60c655e2011-05-11 01:02:35 +0200284 return do_hw_write(codec, reg, value, data, sizeof(data));
Mark Brownbc6552f2010-03-05 16:27:15 +0000285}
Barry Song994dc422010-01-27 11:46:18 +0800286
Mark Brown34bad692011-04-04 17:55:42 +0900287/* Primitive bulk write support for soc-cache. The data pointed to by
288 * `data' needs to already be in the form the hardware expects
289 * including any leading register specific data. Any data written
290 * through this function will not go through the cache as it only
291 * handles writing to volatile or out of bounds registers.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000292 */
293static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
294 const void *data, size_t len)
295{
296 int ret;
297
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100298 /* To ensure that we don't get out of sync with the cache, check
299 * whether the base register is volatile or if we've directly asked
300 * to bypass the cache. Out of bounds registers are considered
301 * volatile.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000302 */
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100303 if (!codec->cache_bypass
304 && !snd_soc_codec_volatile_register(codec, reg)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000305 && reg < codec->driver->reg_cache_size)
306 return -EINVAL;
307
308 switch (codec->control_type) {
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900309#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000310 case SND_SOC_I2C:
311 ret = i2c_master_send(codec->control_data, data, len);
312 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900313#endif
314#if defined(CONFIG_SPI_MASTER)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000315 case SND_SOC_SPI:
Mark Brown6e28f972011-05-10 23:33:48 +0200316 ret = spi_write(codec->control_data, data, len);
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000317 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900318#endif
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000319 default:
320 BUG();
321 }
322
323 if (ret == len)
324 return 0;
325 if (ret < 0)
326 return ret;
327 else
328 return -EIO;
329}
330
Mark Brown17a52fd2009-07-05 17:24:50 +0100331static struct {
332 int addr_bits;
333 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100334 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100335 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100336 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100337} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700338 {
Barry Song63b62ab2010-01-27 11:46:17 +0800339 .addr_bits = 4, .data_bits = 12,
340 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
Barry Song63b62ab2010-01-27 11:46:17 +0800341 },
342 {
Mark Brownd62ab352009-09-21 04:21:47 -0700343 .addr_bits = 7, .data_bits = 9,
344 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Mark Brownd62ab352009-09-21 04:21:47 -0700345 },
346 {
347 .addr_bits = 8, .data_bits = 8,
348 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800349 .i2c_read = snd_soc_8_8_read_i2c,
Mark Brownd62ab352009-09-21 04:21:47 -0700350 },
351 {
352 .addr_bits = 8, .data_bits = 16,
353 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
354 .i2c_read = snd_soc_8_16_read_i2c,
355 },
Barry Song994dc422010-01-27 11:46:18 +0800356 {
357 .addr_bits = 16, .data_bits = 8,
358 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
359 .i2c_read = snd_soc_16_8_read_i2c,
Barry Song994dc422010-01-27 11:46:18 +0800360 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000361 {
362 .addr_bits = 16, .data_bits = 16,
363 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
364 .i2c_read = snd_soc_16_16_read_i2c,
365 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100366};
367
368/**
369 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
370 *
371 * @codec: CODEC to configure.
Mark Brown17a52fd2009-07-05 17:24:50 +0100372 * @addr_bits: Number of bits of register address data.
373 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100374 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100375 *
376 * Register formats are frequently shared between many I2C and SPI
377 * devices. In order to promote code reuse the ASoC core provides
378 * some standard implementations of CODEC read and write operations
379 * which can be set up using this function.
380 *
381 * The caller is responsible for allocating and initialising the
382 * actual cache.
383 *
384 * Note that at present this code cannot be used by CODECs with
385 * volatile registers.
386 */
387int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100388 int addr_bits, int data_bits,
389 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100390{
391 int i;
392
Mark Brown17a52fd2009-07-05 17:24:50 +0100393 for (i = 0; i < ARRAY_SIZE(io_types); i++)
394 if (io_types[i].addr_bits == addr_bits &&
395 io_types[i].data_bits == data_bits)
396 break;
397 if (i == ARRAY_SIZE(io_types)) {
398 printk(KERN_ERR
399 "No I/O functions for %d bit address %d bit data\n",
400 addr_bits, data_bits);
401 return -EINVAL;
402 }
403
Mark Brownc3acec22010-12-02 16:15:29 +0000404 codec->write = io_types[i].write;
405 codec->read = io_types[i].read;
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000406 codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
Mark Brown17a52fd2009-07-05 17:24:50 +0100407
Mark Brown7084a422009-07-10 22:24:27 +0100408 switch (control) {
409 case SND_SOC_CUSTOM:
410 break;
411
412 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700413#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100414 codec->hw_write = (hw_write_t)i2c_master_send;
415#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100416 if (io_types[i].i2c_read)
417 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100418
419 codec->control_data = container_of(codec->dev,
420 struct i2c_client,
421 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100422 break;
423
424 case SND_SOC_SPI:
Mark Brown6e28f972011-05-10 23:33:48 +0200425#ifdef CONFIG_SPI_MASTER
Mark Brownf7391fc2011-05-11 19:25:42 +0200426 codec->hw_write = do_spi_write;
Mark Brown6e28f972011-05-10 23:33:48 +0200427#endif
Mark Browna6d14342010-08-12 10:59:15 +0100428
429 codec->control_data = container_of(codec->dev,
430 struct spi_device,
431 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100432 break;
433 }
434
Mark Brown17a52fd2009-07-05 17:24:50 +0100435 return 0;
436}
437EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000438
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000439static bool snd_soc_set_cache_val(void *base, unsigned int idx,
440 unsigned int val, unsigned int word_size)
441{
442 switch (word_size) {
443 case 1: {
444 u8 *cache = base;
445 if (cache[idx] == val)
446 return true;
447 cache[idx] = val;
448 break;
449 }
450 case 2: {
451 u16 *cache = base;
452 if (cache[idx] == val)
453 return true;
454 cache[idx] = val;
455 break;
456 }
457 default:
458 BUG();
459 }
460 return false;
461}
462
463static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
464 unsigned int word_size)
465{
Mark Brownfd137e22011-06-06 11:26:15 +0100466 if (!base)
467 return -1;
468
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000469 switch (word_size) {
470 case 1: {
471 const u8 *cache = base;
472 return cache[idx];
473 }
474 case 2: {
475 const u16 *cache = base;
476 return cache[idx];
477 }
478 default:
479 BUG();
480 }
481 /* unreachable */
482 return -1;
483}
484
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000485struct snd_soc_rbtree_node {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100486 struct rb_node node; /* the actual rbtree node holding this block */
487 unsigned int base_reg; /* base register handled by this block */
488 unsigned int word_size; /* number of bytes needed to represent the register index */
489 void *block; /* block of adjacent registers */
490 unsigned int blklen; /* number of registers available in the block */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000491} __attribute__ ((packed));
492
493struct snd_soc_rbtree_ctx {
494 struct rb_root root;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100495 struct snd_soc_rbtree_node *cached_rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000496};
497
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100498static inline void snd_soc_rbtree_get_base_top_reg(
499 struct snd_soc_rbtree_node *rbnode,
500 unsigned int *base, unsigned int *top)
501{
502 *base = rbnode->base_reg;
503 *top = rbnode->base_reg + rbnode->blklen - 1;
504}
505
506static unsigned int snd_soc_rbtree_get_register(
507 struct snd_soc_rbtree_node *rbnode, unsigned int idx)
508{
509 unsigned int val;
510
511 switch (rbnode->word_size) {
512 case 1: {
513 u8 *p = rbnode->block;
514 val = p[idx];
515 return val;
516 }
517 case 2: {
518 u16 *p = rbnode->block;
519 val = p[idx];
520 return val;
521 }
522 default:
523 BUG();
524 break;
525 }
526 return -1;
527}
528
529static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
530 unsigned int idx, unsigned int val)
531{
532 switch (rbnode->word_size) {
533 case 1: {
534 u8 *p = rbnode->block;
535 p[idx] = val;
536 break;
537 }
538 case 2: {
539 u16 *p = rbnode->block;
540 p[idx] = val;
541 break;
542 }
543 default:
544 BUG();
545 break;
546 }
547}
548
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000549static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
550 struct rb_root *root, unsigned int reg)
551{
552 struct rb_node *node;
553 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100554 unsigned int base_reg, top_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000555
556 node = root->rb_node;
557 while (node) {
558 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100559 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
560 if (reg >= base_reg && reg <= top_reg)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000561 return rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100562 else if (reg > top_reg)
563 node = node->rb_right;
564 else if (reg < base_reg)
565 node = node->rb_left;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000566 }
567
568 return NULL;
569}
570
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000571static int snd_soc_rbtree_insert(struct rb_root *root,
572 struct snd_soc_rbtree_node *rbnode)
573{
574 struct rb_node **new, *parent;
575 struct snd_soc_rbtree_node *rbnode_tmp;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100576 unsigned int base_reg_tmp, top_reg_tmp;
577 unsigned int base_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000578
579 parent = NULL;
580 new = &root->rb_node;
581 while (*new) {
582 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
583 node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100584 /* base and top registers of the current rbnode */
585 snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
586 &top_reg_tmp);
587 /* base register of the rbnode to be added */
588 base_reg = rbnode->base_reg;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000589 parent = *new;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100590 /* if this register has already been inserted, just return */
591 if (base_reg >= base_reg_tmp &&
592 base_reg <= top_reg_tmp)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000593 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100594 else if (base_reg > top_reg_tmp)
595 new = &((*new)->rb_right);
596 else if (base_reg < base_reg_tmp)
597 new = &((*new)->rb_left);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000598 }
599
600 /* insert the node into the rbtree */
601 rb_link_node(&rbnode->node, parent, new);
602 rb_insert_color(&rbnode->node, root);
603
604 return 1;
605}
606
607static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
608{
609 struct snd_soc_rbtree_ctx *rbtree_ctx;
610 struct rb_node *node;
611 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100612 unsigned int regtmp;
Mark Brownffdaa482011-06-03 16:36:30 +0100613 unsigned int val, def;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000614 int ret;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100615 int i;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000616
617 rbtree_ctx = codec->reg_cache;
618 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
619 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100620 for (i = 0; i < rbnode->blklen; ++i) {
621 regtmp = rbnode->base_reg + i;
622 WARN_ON(codec->writable_register &&
623 codec->writable_register(codec, regtmp));
624 val = snd_soc_rbtree_get_register(rbnode, i);
Mark Brownffdaa482011-06-03 16:36:30 +0100625 def = snd_soc_get_cache_val(codec->reg_def_copy, i,
626 rbnode->word_size);
627 if (val == def)
628 continue;
629
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100630 codec->cache_bypass = 1;
631 ret = snd_soc_write(codec, regtmp, val);
632 codec->cache_bypass = 0;
633 if (ret)
634 return ret;
635 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
636 regtmp, val);
637 }
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000638 }
639
640 return 0;
641}
642
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100643static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
644 unsigned int pos, unsigned int reg,
645 unsigned int value)
646{
647 u8 *blk;
648
649 blk = krealloc(rbnode->block,
650 (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
651 if (!blk)
652 return -ENOMEM;
653
654 /* insert the register value in the correct place in the rbnode block */
655 memmove(blk + (pos + 1) * rbnode->word_size,
656 blk + pos * rbnode->word_size,
657 (rbnode->blklen - pos) * rbnode->word_size);
658
659 /* update the rbnode block, its size and the base register */
660 rbnode->block = blk;
661 rbnode->blklen++;
662 if (!pos)
663 rbnode->base_reg = reg;
664
665 snd_soc_rbtree_set_register(rbnode, pos, value);
666 return 0;
667}
668
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000669static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
670 unsigned int reg, unsigned int value)
671{
672 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100673 struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
674 struct rb_node *node;
675 unsigned int val;
676 unsigned int reg_tmp;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100677 unsigned int base_reg, top_reg;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100678 unsigned int pos;
679 int i;
680 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000681
682 rbtree_ctx = codec->reg_cache;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100683 /* look up the required register in the cached rbnode */
684 rbnode = rbtree_ctx->cached_rbnode;
685 if (rbnode) {
686 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
687 if (reg >= base_reg && reg <= top_reg) {
688 reg_tmp = reg - base_reg;
689 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
690 if (val == value)
691 return 0;
692 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
693 return 0;
694 }
695 }
696 /* if we can't locate it in the cached rbnode we'll have
697 * to traverse the rbtree looking for it.
698 */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000699 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
700 if (rbnode) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100701 reg_tmp = reg - rbnode->base_reg;
702 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
703 if (val == value)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000704 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100705 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100706 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000707 } else {
708 /* bail out early, no need to create the rbnode yet */
709 if (!value)
710 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100711 /* look for an adjacent register to the one we are about to add */
712 for (node = rb_first(&rbtree_ctx->root); node;
713 node = rb_next(node)) {
714 rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
715 for (i = 0; i < rbnode_tmp->blklen; ++i) {
716 reg_tmp = rbnode_tmp->base_reg + i;
717 if (abs(reg_tmp - reg) != 1)
718 continue;
719 /* decide where in the block to place our register */
720 if (reg_tmp + 1 == reg)
721 pos = i + 1;
722 else
723 pos = i;
724 ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
725 reg, value);
726 if (ret)
727 return ret;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100728 rbtree_ctx->cached_rbnode = rbnode_tmp;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100729 return 0;
730 }
731 }
732 /* we did not manage to find a place to insert it in an existing
733 * block so create a new rbnode with a single register in its block.
734 * This block will get populated further if any other adjacent
735 * registers get modified in the future.
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000736 */
737 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
738 if (!rbnode)
739 return -ENOMEM;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100740 rbnode->blklen = 1;
741 rbnode->base_reg = reg;
742 rbnode->word_size = codec->driver->reg_word_size;
743 rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
744 GFP_KERNEL);
745 if (!rbnode->block) {
746 kfree(rbnode);
747 return -ENOMEM;
748 }
749 snd_soc_rbtree_set_register(rbnode, 0, value);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000750 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100751 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000752 }
753
754 return 0;
755}
756
757static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
758 unsigned int reg, unsigned int *value)
759{
760 struct snd_soc_rbtree_ctx *rbtree_ctx;
761 struct snd_soc_rbtree_node *rbnode;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100762 unsigned int base_reg, top_reg;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100763 unsigned int reg_tmp;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000764
765 rbtree_ctx = codec->reg_cache;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100766 /* look up the required register in the cached rbnode */
767 rbnode = rbtree_ctx->cached_rbnode;
768 if (rbnode) {
769 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
770 if (reg >= base_reg && reg <= top_reg) {
771 reg_tmp = reg - base_reg;
772 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
773 return 0;
774 }
775 }
776 /* if we can't locate it in the cached rbnode we'll have
777 * to traverse the rbtree looking for it.
778 */
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000779 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
780 if (rbnode) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100781 reg_tmp = reg - rbnode->base_reg;
782 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100783 rbtree_ctx->cached_rbnode = rbnode;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000784 } else {
785 /* uninitialized registers default to 0 */
786 *value = 0;
787 }
788
789 return 0;
790}
791
792static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
793{
794 struct rb_node *next;
795 struct snd_soc_rbtree_ctx *rbtree_ctx;
796 struct snd_soc_rbtree_node *rbtree_node;
797
798 /* if we've already been called then just return */
799 rbtree_ctx = codec->reg_cache;
800 if (!rbtree_ctx)
801 return 0;
802
803 /* free up the rbtree */
804 next = rb_first(&rbtree_ctx->root);
805 while (next) {
806 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
807 next = rb_next(&rbtree_node->node);
808 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100809 kfree(rbtree_node->block);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000810 kfree(rbtree_node);
811 }
812
813 /* release the resources */
814 kfree(codec->reg_cache);
815 codec->reg_cache = NULL;
816
817 return 0;
818}
819
820static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
821{
822 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000823 unsigned int word_size;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100824 unsigned int val;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000825 int i;
826 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000827
828 codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
829 if (!codec->reg_cache)
830 return -ENOMEM;
831
832 rbtree_ctx = codec->reg_cache;
833 rbtree_ctx->root = RB_ROOT;
Dimitris Papastamos7e146b52011-05-19 13:45:30 +0100834 rbtree_ctx->cached_rbnode = NULL;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000835
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000836 if (!codec->reg_def_copy)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000837 return 0;
838
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000839 word_size = codec->driver->reg_word_size;
840 for (i = 0; i < codec->driver->reg_cache_size; ++i) {
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100841 val = snd_soc_get_cache_val(codec->reg_def_copy, i,
842 word_size);
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000843 if (!val)
844 continue;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100845 ret = snd_soc_rbtree_cache_write(codec, i, val);
846 if (ret)
847 goto err;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000848 }
849
850 return 0;
Dimitris Papastamos0944cc32011-05-19 13:45:29 +0100851
852err:
853 snd_soc_cache_exit(codec);
854 return ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000855}
856
Mark Brown68d44ee2010-12-21 17:19:56 +0000857#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000858struct snd_soc_lzo_ctx {
859 void *wmem;
860 void *dst;
861 const void *src;
862 size_t src_len;
863 size_t dst_len;
864 size_t decompressed_size;
865 unsigned long *sync_bmp;
866 int sync_bmp_nbits;
867};
868
869#define LZO_BLOCK_NUM 8
870static int snd_soc_lzo_block_count(void)
871{
872 return LZO_BLOCK_NUM;
873}
874
875static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx)
876{
877 lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
878 if (!lzo_ctx->wmem)
879 return -ENOMEM;
880 return 0;
881}
882
883static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx)
884{
885 size_t compress_size;
886 int ret;
887
888 ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
889 lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
890 if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
891 return -EINVAL;
892 lzo_ctx->dst_len = compress_size;
893 return 0;
894}
895
896static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx)
897{
898 size_t dst_len;
899 int ret;
900
901 dst_len = lzo_ctx->dst_len;
902 ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
903 lzo_ctx->dst, &dst_len);
904 if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
905 return -EINVAL;
906 return 0;
907}
908
909static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec,
910 struct snd_soc_lzo_ctx *lzo_ctx)
911{
912 int ret;
913
914 lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
915 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
916 if (!lzo_ctx->dst) {
917 lzo_ctx->dst_len = 0;
918 return -ENOMEM;
919 }
920
921 ret = snd_soc_lzo_compress(lzo_ctx);
922 if (ret < 0)
923 return ret;
924 return 0;
925}
926
927static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec,
928 struct snd_soc_lzo_ctx *lzo_ctx)
929{
930 int ret;
931
932 lzo_ctx->dst_len = lzo_ctx->decompressed_size;
933 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
934 if (!lzo_ctx->dst) {
935 lzo_ctx->dst_len = 0;
936 return -ENOMEM;
937 }
938
939 ret = snd_soc_lzo_decompress(lzo_ctx);
940 if (ret < 0)
941 return ret;
942 return 0;
943}
944
945static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
946 unsigned int reg)
947{
Mark Brown001ae4c2010-12-02 16:21:08 +0000948 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000949
950 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000951 return (reg * codec_drv->reg_word_size) /
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000952 DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000953}
954
955static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
956 unsigned int reg)
957{
Mark Brown001ae4c2010-12-02 16:21:08 +0000958 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000959
960 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000961 return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) /
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000962 codec_drv->reg_word_size);
963}
964
965static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
966{
Mark Brown001ae4c2010-12-02 16:21:08 +0000967 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000968
969 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000970 return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000971}
972
973static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
974{
975 struct snd_soc_lzo_ctx **lzo_blocks;
976 unsigned int val;
977 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000978 int ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000979
980 lzo_blocks = codec->reg_cache;
981 for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +0100982 WARN_ON(codec->writable_register &&
983 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000984 ret = snd_soc_cache_read(codec, i, &val);
985 if (ret)
986 return ret;
Dimitris Papastamos99780072011-01-19 14:53:37 +0000987 codec->cache_bypass = 1;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000988 ret = snd_soc_write(codec, i, val);
Dimitris Papastamos99780072011-01-19 14:53:37 +0000989 codec->cache_bypass = 0;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000990 if (ret)
991 return ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000992 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
993 i, val);
994 }
995
996 return 0;
997}
998
999static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
1000 unsigned int reg, unsigned int value)
1001{
1002 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1003 int ret, blkindex, blkpos;
1004 size_t blksize, tmp_dst_len;
1005 void *tmp_dst;
1006
1007 /* index of the compressed lzo block */
1008 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1009 /* register index within the decompressed block */
1010 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1011 /* size of the compressed block */
1012 blksize = snd_soc_lzo_get_blksize(codec);
1013 lzo_blocks = codec->reg_cache;
1014 lzo_block = lzo_blocks[blkindex];
1015
1016 /* save the pointer and length of the compressed block */
1017 tmp_dst = lzo_block->dst;
1018 tmp_dst_len = lzo_block->dst_len;
1019
1020 /* prepare the source to be the compressed block */
1021 lzo_block->src = lzo_block->dst;
1022 lzo_block->src_len = lzo_block->dst_len;
1023
1024 /* decompress the block */
1025 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
1026 if (ret < 0) {
1027 kfree(lzo_block->dst);
1028 goto out;
1029 }
1030
1031 /* write the new value to the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001032 if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value,
1033 codec->driver->reg_word_size)) {
1034 kfree(lzo_block->dst);
1035 goto out;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001036 }
1037
1038 /* prepare the source to be the decompressed block */
1039 lzo_block->src = lzo_block->dst;
1040 lzo_block->src_len = lzo_block->dst_len;
1041
1042 /* compress the block */
1043 ret = snd_soc_lzo_compress_cache_block(codec, lzo_block);
1044 if (ret < 0) {
1045 kfree(lzo_block->dst);
1046 kfree(lzo_block->src);
1047 goto out;
1048 }
1049
1050 /* set the bit so we know we have to sync this register */
1051 set_bit(reg, lzo_block->sync_bmp);
1052 kfree(tmp_dst);
1053 kfree(lzo_block->src);
1054 return 0;
1055out:
1056 lzo_block->dst = tmp_dst;
1057 lzo_block->dst_len = tmp_dst_len;
1058 return ret;
1059}
1060
1061static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
1062 unsigned int reg, unsigned int *value)
1063{
1064 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
1065 int ret, blkindex, blkpos;
1066 size_t blksize, tmp_dst_len;
1067 void *tmp_dst;
1068
1069 *value = 0;
1070 /* index of the compressed lzo block */
1071 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
1072 /* register index within the decompressed block */
1073 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
1074 /* size of the compressed block */
1075 blksize = snd_soc_lzo_get_blksize(codec);
1076 lzo_blocks = codec->reg_cache;
1077 lzo_block = lzo_blocks[blkindex];
1078
1079 /* save the pointer and length of the compressed block */
1080 tmp_dst = lzo_block->dst;
1081 tmp_dst_len = lzo_block->dst_len;
1082
1083 /* prepare the source to be the compressed block */
1084 lzo_block->src = lzo_block->dst;
1085 lzo_block->src_len = lzo_block->dst_len;
1086
1087 /* decompress the block */
1088 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001089 if (ret >= 0)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001090 /* fetch the value from the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001091 *value = snd_soc_get_cache_val(lzo_block->dst, blkpos,
1092 codec->driver->reg_word_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001093
1094 kfree(lzo_block->dst);
1095 /* restore the pointer and length of the compressed block */
1096 lzo_block->dst = tmp_dst;
1097 lzo_block->dst_len = tmp_dst_len;
1098 return 0;
1099}
1100
1101static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
1102{
1103 struct snd_soc_lzo_ctx **lzo_blocks;
1104 int i, blkcount;
1105
1106 lzo_blocks = codec->reg_cache;
1107 if (!lzo_blocks)
1108 return 0;
1109
1110 blkcount = snd_soc_lzo_block_count();
1111 /*
1112 * the pointer to the bitmap used for syncing the cache
1113 * is shared amongst all lzo_blocks. Ensure it is freed
1114 * only once.
1115 */
1116 if (lzo_blocks[0])
1117 kfree(lzo_blocks[0]->sync_bmp);
1118 for (i = 0; i < blkcount; ++i) {
1119 if (lzo_blocks[i]) {
1120 kfree(lzo_blocks[i]->wmem);
1121 kfree(lzo_blocks[i]->dst);
1122 }
1123 /* each lzo_block is a pointer returned by kmalloc or NULL */
1124 kfree(lzo_blocks[i]);
1125 }
1126 kfree(lzo_blocks);
1127 codec->reg_cache = NULL;
1128 return 0;
1129}
1130
1131static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
1132{
1133 struct snd_soc_lzo_ctx **lzo_blocks;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001134 size_t bmp_size;
Mark Brown001ae4c2010-12-02 16:21:08 +00001135 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001136 int ret, tofree, i, blksize, blkcount;
1137 const char *p, *end;
1138 unsigned long *sync_bmp;
1139
1140 ret = 0;
1141 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001142
1143 /*
1144 * If we have not been given a default register cache
1145 * then allocate a dummy zero-ed out region, compress it
1146 * and remember to free it afterwards.
1147 */
1148 tofree = 0;
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001149 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001150 tofree = 1;
1151
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001152 if (!codec->reg_def_copy) {
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001153 codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001154 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001155 return -ENOMEM;
1156 }
1157
1158 blkcount = snd_soc_lzo_block_count();
1159 codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks,
1160 GFP_KERNEL);
1161 if (!codec->reg_cache) {
1162 ret = -ENOMEM;
1163 goto err_tofree;
1164 }
1165 lzo_blocks = codec->reg_cache;
1166
1167 /*
1168 * allocate a bitmap to be used when syncing the cache with
1169 * the hardware. Each time a register is modified, the corresponding
1170 * bit is set in the bitmap, so we know that we have to sync
1171 * that register.
1172 */
1173 bmp_size = codec_drv->reg_cache_size;
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +00001174 sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001175 GFP_KERNEL);
1176 if (!sync_bmp) {
1177 ret = -ENOMEM;
1178 goto err;
1179 }
Dimitris Papastamos09c74a92010-11-29 11:43:33 +00001180 bitmap_zero(sync_bmp, bmp_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001181
1182 /* allocate the lzo blocks and initialize them */
1183 for (i = 0; i < blkcount; ++i) {
1184 lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
1185 GFP_KERNEL);
1186 if (!lzo_blocks[i]) {
1187 kfree(sync_bmp);
1188 ret = -ENOMEM;
1189 goto err;
1190 }
1191 lzo_blocks[i]->sync_bmp = sync_bmp;
Dimitris Papastamos04f8fd12011-01-11 11:24:02 +00001192 lzo_blocks[i]->sync_bmp_nbits = bmp_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001193 /* alloc the working space for the compressed block */
1194 ret = snd_soc_lzo_prepare(lzo_blocks[i]);
1195 if (ret < 0)
1196 goto err;
1197 }
1198
1199 blksize = snd_soc_lzo_get_blksize(codec);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001200 p = codec->reg_def_copy;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001201 end = codec->reg_def_copy + codec->reg_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001202 /* compress the register map and fill the lzo blocks */
1203 for (i = 0; i < blkcount; ++i, p += blksize) {
1204 lzo_blocks[i]->src = p;
1205 if (p + blksize > end)
1206 lzo_blocks[i]->src_len = end - p;
1207 else
1208 lzo_blocks[i]->src_len = blksize;
1209 ret = snd_soc_lzo_compress_cache_block(codec,
1210 lzo_blocks[i]);
1211 if (ret < 0)
1212 goto err;
1213 lzo_blocks[i]->decompressed_size =
1214 lzo_blocks[i]->src_len;
1215 }
1216
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001217 if (tofree) {
1218 kfree(codec->reg_def_copy);
1219 codec->reg_def_copy = NULL;
1220 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001221 return 0;
1222err:
1223 snd_soc_cache_exit(codec);
1224err_tofree:
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001225 if (tofree) {
1226 kfree(codec->reg_def_copy);
1227 codec->reg_def_copy = NULL;
1228 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001229 return ret;
1230}
Mark Brown68d44ee2010-12-21 17:19:56 +00001231#endif
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001232
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001233static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
1234{
1235 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001236 int ret;
Mark Brown001ae4c2010-12-02 16:21:08 +00001237 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001238 unsigned int val;
1239
1240 codec_drv = codec->driver;
1241 for (i = 0; i < codec_drv->reg_cache_size; ++i) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +01001242 WARN_ON(codec->writable_register &&
1243 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001244 ret = snd_soc_cache_read(codec, i, &val);
1245 if (ret)
1246 return ret;
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001247 if (codec->reg_def_copy)
1248 if (snd_soc_get_cache_val(codec->reg_def_copy,
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001249 i, codec_drv->reg_word_size) == val)
1250 continue;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001251 ret = snd_soc_write(codec, i, val);
1252 if (ret)
1253 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001254 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1255 i, val);
1256 }
1257 return 0;
1258}
1259
1260static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
1261 unsigned int reg, unsigned int value)
1262{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001263 snd_soc_set_cache_val(codec->reg_cache, reg, value,
1264 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001265 return 0;
1266}
1267
1268static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
1269 unsigned int reg, unsigned int *value)
1270{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001271 *value = snd_soc_get_cache_val(codec->reg_cache, reg,
1272 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001273 return 0;
1274}
1275
1276static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
1277{
1278 if (!codec->reg_cache)
1279 return 0;
1280 kfree(codec->reg_cache);
1281 codec->reg_cache = NULL;
1282 return 0;
1283}
1284
1285static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
1286{
Mark Brown001ae4c2010-12-02 16:21:08 +00001287 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001288
1289 codec_drv = codec->driver;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001290
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001291 if (codec->reg_def_copy)
1292 codec->reg_cache = kmemdup(codec->reg_def_copy,
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001293 codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001294 else
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001295 codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001296 if (!codec->reg_cache)
1297 return -ENOMEM;
1298
1299 return 0;
1300}
1301
1302/* an array of all supported compression types */
1303static const struct snd_soc_cache_ops cache_types[] = {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001304 /* Flat *must* be the first entry for fallback */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001305 {
Dimitris Papastamosdf0701b2010-11-29 10:54:28 +00001306 .id = SND_SOC_FLAT_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001307 .name = "flat",
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001308 .init = snd_soc_flat_cache_init,
1309 .exit = snd_soc_flat_cache_exit,
1310 .read = snd_soc_flat_cache_read,
1311 .write = snd_soc_flat_cache_write,
1312 .sync = snd_soc_flat_cache_sync
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001313 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001314#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001315 {
1316 .id = SND_SOC_LZO_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001317 .name = "LZO",
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001318 .init = snd_soc_lzo_cache_init,
1319 .exit = snd_soc_lzo_cache_exit,
1320 .read = snd_soc_lzo_cache_read,
1321 .write = snd_soc_lzo_cache_write,
1322 .sync = snd_soc_lzo_cache_sync
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001323 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001324#endif
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001325 {
1326 .id = SND_SOC_RBTREE_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001327 .name = "rbtree",
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001328 .init = snd_soc_rbtree_cache_init,
1329 .exit = snd_soc_rbtree_cache_exit,
1330 .read = snd_soc_rbtree_cache_read,
1331 .write = snd_soc_rbtree_cache_write,
1332 .sync = snd_soc_rbtree_cache_sync
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001333 }
1334};
1335
1336int snd_soc_cache_init(struct snd_soc_codec *codec)
1337{
1338 int i;
1339
1340 for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
Dimitris Papastamos23bbce32010-12-02 14:53:01 +00001341 if (cache_types[i].id == codec->compress_type)
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001342 break;
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001343
1344 /* Fall back to flat compression */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001345 if (i == ARRAY_SIZE(cache_types)) {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001346 dev_warn(codec->dev, "Could not match compress type: %d\n",
1347 codec->compress_type);
1348 i = 0;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001349 }
1350
1351 mutex_init(&codec->cache_rw_mutex);
1352 codec->cache_ops = &cache_types[i];
1353
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001354 if (codec->cache_ops->init) {
1355 if (codec->cache_ops->name)
1356 dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
1357 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001358 return codec->cache_ops->init(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001359 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001360 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001361}
1362
1363/*
1364 * NOTE: keep in mind that this function might be called
1365 * multiple times.
1366 */
1367int snd_soc_cache_exit(struct snd_soc_codec *codec)
1368{
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001369 if (codec->cache_ops && codec->cache_ops->exit) {
1370 if (codec->cache_ops->name)
1371 dev_dbg(codec->dev, "Destroying %s cache for %s codec\n",
1372 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001373 return codec->cache_ops->exit(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001374 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001375 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001376}
1377
1378/**
1379 * snd_soc_cache_read: Fetch the value of a given register from the cache.
1380 *
1381 * @codec: CODEC to configure.
1382 * @reg: The register index.
1383 * @value: The value to be returned.
1384 */
1385int snd_soc_cache_read(struct snd_soc_codec *codec,
1386 unsigned int reg, unsigned int *value)
1387{
1388 int ret;
1389
1390 mutex_lock(&codec->cache_rw_mutex);
1391
1392 if (value && codec->cache_ops && codec->cache_ops->read) {
1393 ret = codec->cache_ops->read(codec, reg, value);
1394 mutex_unlock(&codec->cache_rw_mutex);
1395 return ret;
1396 }
1397
1398 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001399 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001400}
1401EXPORT_SYMBOL_GPL(snd_soc_cache_read);
1402
1403/**
1404 * snd_soc_cache_write: Set the value of a given register in the cache.
1405 *
1406 * @codec: CODEC to configure.
1407 * @reg: The register index.
1408 * @value: The new register value.
1409 */
1410int snd_soc_cache_write(struct snd_soc_codec *codec,
1411 unsigned int reg, unsigned int value)
1412{
1413 int ret;
1414
1415 mutex_lock(&codec->cache_rw_mutex);
1416
1417 if (codec->cache_ops && codec->cache_ops->write) {
1418 ret = codec->cache_ops->write(codec, reg, value);
1419 mutex_unlock(&codec->cache_rw_mutex);
1420 return ret;
1421 }
1422
1423 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001424 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001425}
1426EXPORT_SYMBOL_GPL(snd_soc_cache_write);
1427
1428/**
1429 * snd_soc_cache_sync: Sync the register cache with the hardware.
1430 *
1431 * @codec: CODEC to configure.
1432 *
1433 * Any registers that should not be synced should be marked as
1434 * volatile. In general drivers can choose not to use the provided
1435 * syncing functionality if they so require.
1436 */
1437int snd_soc_cache_sync(struct snd_soc_codec *codec)
1438{
1439 int ret;
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001440 const char *name;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001441
1442 if (!codec->cache_sync) {
1443 return 0;
1444 }
1445
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001446 if (!codec->cache_ops || !codec->cache_ops->sync)
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001447 return -ENOSYS;
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001448
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001449 if (codec->cache_ops->name)
1450 name = codec->cache_ops->name;
1451 else
1452 name = "unknown";
1453
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001454 if (codec->cache_ops->name)
1455 dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
1456 codec->cache_ops->name, codec->name);
1457 trace_snd_soc_cache_sync(codec, name, "start");
1458 ret = codec->cache_ops->sync(codec);
1459 if (!ret)
1460 codec->cache_sync = 0;
1461 trace_snd_soc_cache_sync(codec, name, "end");
1462 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001463}
1464EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
Dimitris Papastamos066d16c2011-01-13 12:20:36 +00001465
1466static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec,
1467 unsigned int reg)
1468{
1469 const struct snd_soc_codec_driver *codec_drv;
1470 unsigned int min, max, index;
1471
1472 codec_drv = codec->driver;
1473 min = 0;
1474 max = codec_drv->reg_access_size - 1;
1475 do {
1476 index = (min + max) / 2;
1477 if (codec_drv->reg_access_default[index].reg == reg)
1478 return index;
1479 if (codec_drv->reg_access_default[index].reg < reg)
1480 min = index + 1;
1481 else
1482 max = index;
1483 } while (min <= max);
1484 return -1;
1485}
1486
1487int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
1488 unsigned int reg)
1489{
1490 int index;
1491
1492 if (reg >= codec->driver->reg_cache_size)
1493 return 1;
1494 index = snd_soc_get_reg_access_index(codec, reg);
1495 if (index < 0)
1496 return 0;
1497 return codec->driver->reg_access_default[index].vol;
1498}
1499EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register);
1500
1501int snd_soc_default_readable_register(struct snd_soc_codec *codec,
1502 unsigned int reg)
1503{
1504 int index;
1505
1506 if (reg >= codec->driver->reg_cache_size)
1507 return 1;
1508 index = snd_soc_get_reg_access_index(codec, reg);
1509 if (index < 0)
1510 return 0;
1511 return codec->driver->reg_access_default[index].read;
1512}
1513EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
Dimitris Papastamos80204542011-03-24 13:45:17 +00001514
1515int snd_soc_default_writable_register(struct snd_soc_codec *codec,
1516 unsigned int reg)
1517{
1518 int index;
1519
1520 if (reg >= codec->driver->reg_cache_size)
1521 return 1;
1522 index = snd_soc_get_reg_access_index(codec, reg);
1523 if (index < 0)
1524 return 0;
1525 return codec->driver->reg_access_default[index].write;
1526}
1527EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);