blob: 01e5b98464360631c81364f67660d23307aa9489 [file] [log] [blame]
Mark Brown17a52fd2009-07-05 17:24:50 +01001/*
2 * soc-cache.c -- ASoC register cache helpers
3 *
4 * Copyright 2009 Wolfson Microelectronics PLC.
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
Mark Brown7084a422009-07-10 22:24:27 +010014#include <linux/i2c.h>
Mark Brown27ded042009-07-10 23:28:16 +010015#include <linux/spi/spi.h>
Mark Brown17a52fd2009-07-05 17:24:50 +010016#include <sound/soc.h>
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +000017#include <linux/lzo.h>
18#include <linux/bitmap.h>
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +000019#include <linux/rbtree.h>
Mark Brown17a52fd2009-07-05 17:24:50 +010020
Dimitris Papastamosc358e642011-01-21 15:29:02 +000021#include <trace/events/asoc.h>
22
Dimitris Papastamos26e99842011-03-22 10:36:58 +000023static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
24 unsigned int value, const void *data, int len)
25{
26 int ret;
27
28 if (!snd_soc_codec_volatile_register(codec, reg) &&
29 reg < codec->driver->reg_cache_size &&
30 !codec->cache_bypass) {
31 ret = snd_soc_cache_write(codec, reg, value);
32 if (ret < 0)
33 return -1;
34 }
35
36 if (codec->cache_only) {
37 codec->cache_sync = 1;
38 return 0;
39 }
40
41 ret = codec->hw_write(codec->control_data, data, len);
42 if (ret == len)
43 return 0;
44 if (ret < 0)
45 return ret;
46 else
47 return -EIO;
48}
49
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000050static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg)
Barry Song63b62ab2010-01-27 11:46:17 +080051{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000052 int ret;
53 unsigned int val;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010054
55 if (reg >= codec->driver->reg_cache_size ||
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000056 snd_soc_codec_volatile_register(codec, reg) ||
57 codec->cache_bypass) {
58 if (codec->cache_only)
59 return -1;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010060
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000061 BUG_ON(!codec->hw_read);
62 return codec->hw_read(codec, reg);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010063 }
64
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000065 ret = snd_soc_cache_read(codec, reg, &val);
66 if (ret < 0)
67 return -1;
68 return val;
Barry Song63b62ab2010-01-27 11:46:17 +080069}
70
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000071static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +010072 unsigned int reg)
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000073{
74 return do_hw_read(codec, reg);
75}
76
Barry Song63b62ab2010-01-27 11:46:17 +080077static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +010078 unsigned int value)
Barry Song63b62ab2010-01-27 11:46:17 +080079{
Mark Brown063b7cc2011-05-10 23:55:21 +020080 u16 data;
Barry Song63b62ab2010-01-27 11:46:17 +080081
Mark Brown063b7cc2011-05-10 23:55:21 +020082 data = cpu_to_be16((reg << 12) | (value & 0xffffff));
Barry Song63b62ab2010-01-27 11:46:17 +080083
Mark Brown063b7cc2011-05-10 23:55:21 +020084 return do_hw_write(codec, reg, value, &data, 2);
Barry Song63b62ab2010-01-27 11:46:17 +080085}
86
Mark Brown17a52fd2009-07-05 17:24:50 +010087static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
88 unsigned int reg)
89{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +000090 return do_hw_read(codec, reg);
Mark Brown17a52fd2009-07-05 17:24:50 +010091}
92
93static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
94 unsigned int value)
95{
Mark Brown17a52fd2009-07-05 17:24:50 +010096 u8 data[2];
Mark Brown17a52fd2009-07-05 17:24:50 +010097
Mark Brown17a52fd2009-07-05 17:24:50 +010098 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
99 data[1] = value & 0x00ff;
100
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000101 return do_hw_write(codec, reg, value, data, 2);
Mark Brown17a52fd2009-07-05 17:24:50 +0100102}
103
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900104static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
105 unsigned int value)
106{
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900107 u8 data[2];
108
Barry Songf4bee1b2010-03-18 16:17:01 +0800109 reg &= 0xff;
110 data[0] = reg;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900111 data[1] = value & 0xff;
112
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000113 return do_hw_write(codec, reg, value, data, 2);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900114}
115
116static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
117 unsigned int reg)
118{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000119 return do_hw_read(codec, reg);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900120}
121
Mark Brownafa2f102009-07-10 23:11:24 +0100122static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
123 unsigned int value)
124{
Mark Brownafa2f102009-07-10 23:11:24 +0100125 u8 data[3];
126
127 data[0] = reg;
128 data[1] = (value >> 8) & 0xff;
129 data[2] = value & 0xff;
130
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000131 return do_hw_write(codec, reg, value, data, 3);
Mark Brownafa2f102009-07-10 23:11:24 +0100132}
133
134static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
135 unsigned int reg)
136{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000137 return do_hw_read(codec, reg);
Mark Brownafa2f102009-07-10 23:11:24 +0100138}
139
Randy Dunlap17244c22009-08-10 16:04:39 -0700140#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000141static unsigned int do_i2c_read(struct snd_soc_codec *codec,
142 void *reg, int reglen,
143 void *data, int datalen)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800144{
145 struct i2c_msg xfer[2];
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800146 int ret;
147 struct i2c_client *client = codec->control_data;
148
149 /* Write register */
150 xfer[0].addr = client->addr;
151 xfer[0].flags = 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000152 xfer[0].len = reglen;
153 xfer[0].buf = reg;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800154
155 /* Read data */
156 xfer[1].addr = client->addr;
157 xfer[1].flags = I2C_M_RD;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000158 xfer[1].len = datalen;
159 xfer[1].buf = data;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800160
161 ret = i2c_transfer(client->adapter, xfer, 2);
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000162 if (ret == 2)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800163 return 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000164 else if (ret < 0)
165 return ret;
166 else
167 return -EIO;
168}
169#endif
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800170
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000171#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
172static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100173 unsigned int r)
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000174{
175 u8 reg = r;
176 u8 data;
177 int ret;
178
179 ret = do_i2c_read(codec, &reg, 1, &data, 1);
180 if (ret < 0)
181 return 0;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800182 return data;
183}
184#else
185#define snd_soc_8_8_read_i2c NULL
186#endif
187
188#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100189static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
190 unsigned int r)
191{
Mark Brownafa2f102009-07-10 23:11:24 +0100192 u8 reg = r;
193 u16 data;
194 int ret;
Mark Brownafa2f102009-07-10 23:11:24 +0100195
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000196 ret = do_i2c_read(codec, &reg, 1, &data, 2);
197 if (ret < 0)
Mark Brownafa2f102009-07-10 23:11:24 +0100198 return 0;
Mark Brownafa2f102009-07-10 23:11:24 +0100199 return (data >> 8) | ((data & 0xff) << 8);
200}
201#else
202#define snd_soc_8_16_read_i2c NULL
203#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100204
Barry Song994dc422010-01-27 11:46:18 +0800205#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
206static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
207 unsigned int r)
208{
Barry Song994dc422010-01-27 11:46:18 +0800209 u16 reg = r;
210 u8 data;
211 int ret;
Barry Song994dc422010-01-27 11:46:18 +0800212
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000213 ret = do_i2c_read(codec, &reg, 2, &data, 1);
214 if (ret < 0)
Barry Song994dc422010-01-27 11:46:18 +0800215 return 0;
Barry Song994dc422010-01-27 11:46:18 +0800216 return data;
217}
218#else
219#define snd_soc_16_8_read_i2c NULL
220#endif
221
222static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100223 unsigned int reg)
Barry Song994dc422010-01-27 11:46:18 +0800224{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000225 return do_hw_read(codec, reg);
Barry Song994dc422010-01-27 11:46:18 +0800226}
227
228static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100229 unsigned int value)
Barry Song994dc422010-01-27 11:46:18 +0800230{
Barry Song994dc422010-01-27 11:46:18 +0800231 u8 data[3];
Barry Song994dc422010-01-27 11:46:18 +0800232
Barry Song994dc422010-01-27 11:46:18 +0800233 data[0] = (reg >> 8) & 0xff;
234 data[1] = reg & 0xff;
235 data[2] = value;
Mark Brown8c961bc2010-02-01 18:46:10 +0000236
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000237 return do_hw_write(codec, reg, value, data, 3);
Barry Song994dc422010-01-27 11:46:18 +0800238}
239
Mark Brownbc6552f2010-03-05 16:27:15 +0000240#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
241static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
242 unsigned int r)
243{
Mark Brownbc6552f2010-03-05 16:27:15 +0000244 u16 reg = cpu_to_be16(r);
245 u16 data;
246 int ret;
Mark Brownbc6552f2010-03-05 16:27:15 +0000247
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000248 ret = do_i2c_read(codec, &reg, 2, &data, 2);
249 if (ret < 0)
Mark Brownbc6552f2010-03-05 16:27:15 +0000250 return 0;
Mark Brownbc6552f2010-03-05 16:27:15 +0000251 return be16_to_cpu(data);
252}
253#else
254#define snd_soc_16_16_read_i2c NULL
255#endif
256
257static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
258 unsigned int reg)
259{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000260 return do_hw_read(codec, reg);
Mark Brownbc6552f2010-03-05 16:27:15 +0000261}
262
263static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
264 unsigned int value)
265{
Mark Brownbc6552f2010-03-05 16:27:15 +0000266 u8 data[4];
Mark Brownbc6552f2010-03-05 16:27:15 +0000267
268 data[0] = (reg >> 8) & 0xff;
269 data[1] = reg & 0xff;
270 data[2] = (value >> 8) & 0xff;
271 data[3] = value & 0xff;
272
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000273 return do_hw_write(codec, reg, value, data, 4);
Mark Brownbc6552f2010-03-05 16:27:15 +0000274}
Barry Song994dc422010-01-27 11:46:18 +0800275
Mark Brown34bad692011-04-04 17:55:42 +0900276/* Primitive bulk write support for soc-cache. The data pointed to by
277 * `data' needs to already be in the form the hardware expects
278 * including any leading register specific data. Any data written
279 * through this function will not go through the cache as it only
280 * handles writing to volatile or out of bounds registers.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000281 */
282static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
283 const void *data, size_t len)
284{
285 int ret;
286
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100287 /* To ensure that we don't get out of sync with the cache, check
288 * whether the base register is volatile or if we've directly asked
289 * to bypass the cache. Out of bounds registers are considered
290 * volatile.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000291 */
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100292 if (!codec->cache_bypass
293 && !snd_soc_codec_volatile_register(codec, reg)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000294 && reg < codec->driver->reg_cache_size)
295 return -EINVAL;
296
297 switch (codec->control_type) {
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900298#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000299 case SND_SOC_I2C:
300 ret = i2c_master_send(codec->control_data, data, len);
301 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900302#endif
303#if defined(CONFIG_SPI_MASTER)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000304 case SND_SOC_SPI:
Mark Brown6e28f972011-05-10 23:33:48 +0200305 ret = spi_write(codec->control_data, data, len);
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000306 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900307#endif
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000308 default:
309 BUG();
310 }
311
312 if (ret == len)
313 return 0;
314 if (ret < 0)
315 return ret;
316 else
317 return -EIO;
318}
319
Mark Brown17a52fd2009-07-05 17:24:50 +0100320static struct {
321 int addr_bits;
322 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100323 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100324 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100325 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100326} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700327 {
Barry Song63b62ab2010-01-27 11:46:17 +0800328 .addr_bits = 4, .data_bits = 12,
329 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
Barry Song63b62ab2010-01-27 11:46:17 +0800330 },
331 {
Mark Brownd62ab352009-09-21 04:21:47 -0700332 .addr_bits = 7, .data_bits = 9,
333 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Mark Brownd62ab352009-09-21 04:21:47 -0700334 },
335 {
336 .addr_bits = 8, .data_bits = 8,
337 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800338 .i2c_read = snd_soc_8_8_read_i2c,
Mark Brownd62ab352009-09-21 04:21:47 -0700339 },
340 {
341 .addr_bits = 8, .data_bits = 16,
342 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
343 .i2c_read = snd_soc_8_16_read_i2c,
344 },
Barry Song994dc422010-01-27 11:46:18 +0800345 {
346 .addr_bits = 16, .data_bits = 8,
347 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
348 .i2c_read = snd_soc_16_8_read_i2c,
Barry Song994dc422010-01-27 11:46:18 +0800349 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000350 {
351 .addr_bits = 16, .data_bits = 16,
352 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
353 .i2c_read = snd_soc_16_16_read_i2c,
354 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100355};
356
357/**
358 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
359 *
360 * @codec: CODEC to configure.
Mark Brown17a52fd2009-07-05 17:24:50 +0100361 * @addr_bits: Number of bits of register address data.
362 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100363 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100364 *
365 * Register formats are frequently shared between many I2C and SPI
366 * devices. In order to promote code reuse the ASoC core provides
367 * some standard implementations of CODEC read and write operations
368 * which can be set up using this function.
369 *
370 * The caller is responsible for allocating and initialising the
371 * actual cache.
372 *
373 * Note that at present this code cannot be used by CODECs with
374 * volatile registers.
375 */
376int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100377 int addr_bits, int data_bits,
378 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100379{
380 int i;
381
Mark Brown17a52fd2009-07-05 17:24:50 +0100382 for (i = 0; i < ARRAY_SIZE(io_types); i++)
383 if (io_types[i].addr_bits == addr_bits &&
384 io_types[i].data_bits == data_bits)
385 break;
386 if (i == ARRAY_SIZE(io_types)) {
387 printk(KERN_ERR
388 "No I/O functions for %d bit address %d bit data\n",
389 addr_bits, data_bits);
390 return -EINVAL;
391 }
392
Mark Brownc3acec22010-12-02 16:15:29 +0000393 codec->write = io_types[i].write;
394 codec->read = io_types[i].read;
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000395 codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
Mark Brown17a52fd2009-07-05 17:24:50 +0100396
Mark Brown7084a422009-07-10 22:24:27 +0100397 switch (control) {
398 case SND_SOC_CUSTOM:
399 break;
400
401 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700402#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100403 codec->hw_write = (hw_write_t)i2c_master_send;
404#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100405 if (io_types[i].i2c_read)
406 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100407
408 codec->control_data = container_of(codec->dev,
409 struct i2c_client,
410 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100411 break;
412
413 case SND_SOC_SPI:
Mark Brown6e28f972011-05-10 23:33:48 +0200414#ifdef CONFIG_SPI_MASTER
415 codec->hw_write = (hw_write_t)spi_write;
416#endif
Mark Browna6d14342010-08-12 10:59:15 +0100417
418 codec->control_data = container_of(codec->dev,
419 struct spi_device,
420 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100421 break;
422 }
423
Mark Brown17a52fd2009-07-05 17:24:50 +0100424 return 0;
425}
426EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000427
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000428static bool snd_soc_set_cache_val(void *base, unsigned int idx,
429 unsigned int val, unsigned int word_size)
430{
431 switch (word_size) {
432 case 1: {
433 u8 *cache = base;
434 if (cache[idx] == val)
435 return true;
436 cache[idx] = val;
437 break;
438 }
439 case 2: {
440 u16 *cache = base;
441 if (cache[idx] == val)
442 return true;
443 cache[idx] = val;
444 break;
445 }
446 default:
447 BUG();
448 }
449 return false;
450}
451
452static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
453 unsigned int word_size)
454{
455 switch (word_size) {
456 case 1: {
457 const u8 *cache = base;
458 return cache[idx];
459 }
460 case 2: {
461 const u16 *cache = base;
462 return cache[idx];
463 }
464 default:
465 BUG();
466 }
467 /* unreachable */
468 return -1;
469}
470
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000471struct snd_soc_rbtree_node {
472 struct rb_node node;
473 unsigned int reg;
474 unsigned int value;
475 unsigned int defval;
476} __attribute__ ((packed));
477
478struct snd_soc_rbtree_ctx {
479 struct rb_root root;
480};
481
482static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
483 struct rb_root *root, unsigned int reg)
484{
485 struct rb_node *node;
486 struct snd_soc_rbtree_node *rbnode;
487
488 node = root->rb_node;
489 while (node) {
490 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
491 if (rbnode->reg < reg)
492 node = node->rb_left;
493 else if (rbnode->reg > reg)
494 node = node->rb_right;
495 else
496 return rbnode;
497 }
498
499 return NULL;
500}
501
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000502static int snd_soc_rbtree_insert(struct rb_root *root,
503 struct snd_soc_rbtree_node *rbnode)
504{
505 struct rb_node **new, *parent;
506 struct snd_soc_rbtree_node *rbnode_tmp;
507
508 parent = NULL;
509 new = &root->rb_node;
510 while (*new) {
511 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
512 node);
513 parent = *new;
514 if (rbnode_tmp->reg < rbnode->reg)
515 new = &((*new)->rb_left);
516 else if (rbnode_tmp->reg > rbnode->reg)
517 new = &((*new)->rb_right);
518 else
519 return 0;
520 }
521
522 /* insert the node into the rbtree */
523 rb_link_node(&rbnode->node, parent, new);
524 rb_insert_color(&rbnode->node, root);
525
526 return 1;
527}
528
529static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
530{
531 struct snd_soc_rbtree_ctx *rbtree_ctx;
532 struct rb_node *node;
533 struct snd_soc_rbtree_node *rbnode;
534 unsigned int val;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000535 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000536
537 rbtree_ctx = codec->reg_cache;
538 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
539 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
540 if (rbnode->value == rbnode->defval)
541 continue;
Dimitris Papastamosf20eda52011-03-28 11:39:15 +0100542 WARN_ON(codec->writable_register &&
543 codec->writable_register(codec, rbnode->reg));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000544 ret = snd_soc_cache_read(codec, rbnode->reg, &val);
545 if (ret)
546 return ret;
Dimitris Papastamos99780072011-01-19 14:53:37 +0000547 codec->cache_bypass = 1;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000548 ret = snd_soc_write(codec, rbnode->reg, val);
Dimitris Papastamos99780072011-01-19 14:53:37 +0000549 codec->cache_bypass = 0;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000550 if (ret)
551 return ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000552 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
553 rbnode->reg, val);
554 }
555
556 return 0;
557}
558
559static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
560 unsigned int reg, unsigned int value)
561{
562 struct snd_soc_rbtree_ctx *rbtree_ctx;
563 struct snd_soc_rbtree_node *rbnode;
564
565 rbtree_ctx = codec->reg_cache;
566 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
567 if (rbnode) {
568 if (rbnode->value == value)
569 return 0;
570 rbnode->value = value;
571 } else {
572 /* bail out early, no need to create the rbnode yet */
573 if (!value)
574 return 0;
575 /*
576 * for uninitialized registers whose value is changed
577 * from the default zero, create an rbnode and insert
578 * it into the tree.
579 */
580 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
581 if (!rbnode)
582 return -ENOMEM;
583 rbnode->reg = reg;
584 rbnode->value = value;
585 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
586 }
587
588 return 0;
589}
590
591static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
592 unsigned int reg, unsigned int *value)
593{
594 struct snd_soc_rbtree_ctx *rbtree_ctx;
595 struct snd_soc_rbtree_node *rbnode;
596
597 rbtree_ctx = codec->reg_cache;
598 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
599 if (rbnode) {
600 *value = rbnode->value;
601 } else {
602 /* uninitialized registers default to 0 */
603 *value = 0;
604 }
605
606 return 0;
607}
608
609static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
610{
611 struct rb_node *next;
612 struct snd_soc_rbtree_ctx *rbtree_ctx;
613 struct snd_soc_rbtree_node *rbtree_node;
614
615 /* if we've already been called then just return */
616 rbtree_ctx = codec->reg_cache;
617 if (!rbtree_ctx)
618 return 0;
619
620 /* free up the rbtree */
621 next = rb_first(&rbtree_ctx->root);
622 while (next) {
623 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
624 next = rb_next(&rbtree_node->node);
625 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
626 kfree(rbtree_node);
627 }
628
629 /* release the resources */
630 kfree(codec->reg_cache);
631 codec->reg_cache = NULL;
632
633 return 0;
634}
635
636static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
637{
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000638 struct snd_soc_rbtree_node *rbtree_node;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000639 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000640 unsigned int val;
641 unsigned int word_size;
642 int i;
643 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000644
645 codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
646 if (!codec->reg_cache)
647 return -ENOMEM;
648
649 rbtree_ctx = codec->reg_cache;
650 rbtree_ctx->root = RB_ROOT;
651
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000652 if (!codec->reg_def_copy)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000653 return 0;
654
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000655 /*
656 * populate the rbtree with the initialized registers. All other
657 * registers will be inserted when they are first modified.
658 */
659 word_size = codec->driver->reg_word_size;
660 for (i = 0; i < codec->driver->reg_cache_size; ++i) {
661 val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size);
662 if (!val)
663 continue;
664 rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL);
665 if (!rbtree_node) {
666 ret = -ENOMEM;
667 snd_soc_cache_exit(codec);
668 break;
669 }
670 rbtree_node->reg = i;
671 rbtree_node->value = val;
672 rbtree_node->defval = val;
673 snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000674 }
675
676 return 0;
677}
678
Mark Brown68d44ee2010-12-21 17:19:56 +0000679#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000680struct snd_soc_lzo_ctx {
681 void *wmem;
682 void *dst;
683 const void *src;
684 size_t src_len;
685 size_t dst_len;
686 size_t decompressed_size;
687 unsigned long *sync_bmp;
688 int sync_bmp_nbits;
689};
690
691#define LZO_BLOCK_NUM 8
692static int snd_soc_lzo_block_count(void)
693{
694 return LZO_BLOCK_NUM;
695}
696
697static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx)
698{
699 lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
700 if (!lzo_ctx->wmem)
701 return -ENOMEM;
702 return 0;
703}
704
705static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx)
706{
707 size_t compress_size;
708 int ret;
709
710 ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
711 lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
712 if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
713 return -EINVAL;
714 lzo_ctx->dst_len = compress_size;
715 return 0;
716}
717
718static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx)
719{
720 size_t dst_len;
721 int ret;
722
723 dst_len = lzo_ctx->dst_len;
724 ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
725 lzo_ctx->dst, &dst_len);
726 if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
727 return -EINVAL;
728 return 0;
729}
730
731static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec,
732 struct snd_soc_lzo_ctx *lzo_ctx)
733{
734 int ret;
735
736 lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
737 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
738 if (!lzo_ctx->dst) {
739 lzo_ctx->dst_len = 0;
740 return -ENOMEM;
741 }
742
743 ret = snd_soc_lzo_compress(lzo_ctx);
744 if (ret < 0)
745 return ret;
746 return 0;
747}
748
749static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec,
750 struct snd_soc_lzo_ctx *lzo_ctx)
751{
752 int ret;
753
754 lzo_ctx->dst_len = lzo_ctx->decompressed_size;
755 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
756 if (!lzo_ctx->dst) {
757 lzo_ctx->dst_len = 0;
758 return -ENOMEM;
759 }
760
761 ret = snd_soc_lzo_decompress(lzo_ctx);
762 if (ret < 0)
763 return ret;
764 return 0;
765}
766
767static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
768 unsigned int reg)
769{
Mark Brown001ae4c2010-12-02 16:21:08 +0000770 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000771
772 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000773 return (reg * codec_drv->reg_word_size) /
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000774 DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000775}
776
777static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
778 unsigned int reg)
779{
Mark Brown001ae4c2010-12-02 16:21:08 +0000780 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000781
782 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000783 return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) /
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000784 codec_drv->reg_word_size);
785}
786
787static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
788{
Mark Brown001ae4c2010-12-02 16:21:08 +0000789 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000790
791 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000792 return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000793}
794
795static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
796{
797 struct snd_soc_lzo_ctx **lzo_blocks;
798 unsigned int val;
799 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000800 int ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000801
802 lzo_blocks = codec->reg_cache;
803 for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +0100804 WARN_ON(codec->writable_register &&
805 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000806 ret = snd_soc_cache_read(codec, i, &val);
807 if (ret)
808 return ret;
Dimitris Papastamos99780072011-01-19 14:53:37 +0000809 codec->cache_bypass = 1;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000810 ret = snd_soc_write(codec, i, val);
Dimitris Papastamos99780072011-01-19 14:53:37 +0000811 codec->cache_bypass = 0;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000812 if (ret)
813 return ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000814 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
815 i, val);
816 }
817
818 return 0;
819}
820
821static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
822 unsigned int reg, unsigned int value)
823{
824 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
825 int ret, blkindex, blkpos;
826 size_t blksize, tmp_dst_len;
827 void *tmp_dst;
828
829 /* index of the compressed lzo block */
830 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
831 /* register index within the decompressed block */
832 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
833 /* size of the compressed block */
834 blksize = snd_soc_lzo_get_blksize(codec);
835 lzo_blocks = codec->reg_cache;
836 lzo_block = lzo_blocks[blkindex];
837
838 /* save the pointer and length of the compressed block */
839 tmp_dst = lzo_block->dst;
840 tmp_dst_len = lzo_block->dst_len;
841
842 /* prepare the source to be the compressed block */
843 lzo_block->src = lzo_block->dst;
844 lzo_block->src_len = lzo_block->dst_len;
845
846 /* decompress the block */
847 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
848 if (ret < 0) {
849 kfree(lzo_block->dst);
850 goto out;
851 }
852
853 /* write the new value to the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000854 if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value,
855 codec->driver->reg_word_size)) {
856 kfree(lzo_block->dst);
857 goto out;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000858 }
859
860 /* prepare the source to be the decompressed block */
861 lzo_block->src = lzo_block->dst;
862 lzo_block->src_len = lzo_block->dst_len;
863
864 /* compress the block */
865 ret = snd_soc_lzo_compress_cache_block(codec, lzo_block);
866 if (ret < 0) {
867 kfree(lzo_block->dst);
868 kfree(lzo_block->src);
869 goto out;
870 }
871
872 /* set the bit so we know we have to sync this register */
873 set_bit(reg, lzo_block->sync_bmp);
874 kfree(tmp_dst);
875 kfree(lzo_block->src);
876 return 0;
877out:
878 lzo_block->dst = tmp_dst;
879 lzo_block->dst_len = tmp_dst_len;
880 return ret;
881}
882
883static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
884 unsigned int reg, unsigned int *value)
885{
886 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
887 int ret, blkindex, blkpos;
888 size_t blksize, tmp_dst_len;
889 void *tmp_dst;
890
891 *value = 0;
892 /* index of the compressed lzo block */
893 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
894 /* register index within the decompressed block */
895 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
896 /* size of the compressed block */
897 blksize = snd_soc_lzo_get_blksize(codec);
898 lzo_blocks = codec->reg_cache;
899 lzo_block = lzo_blocks[blkindex];
900
901 /* save the pointer and length of the compressed block */
902 tmp_dst = lzo_block->dst;
903 tmp_dst_len = lzo_block->dst_len;
904
905 /* prepare the source to be the compressed block */
906 lzo_block->src = lzo_block->dst;
907 lzo_block->src_len = lzo_block->dst_len;
908
909 /* decompress the block */
910 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000911 if (ret >= 0)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000912 /* fetch the value from the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000913 *value = snd_soc_get_cache_val(lzo_block->dst, blkpos,
914 codec->driver->reg_word_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000915
916 kfree(lzo_block->dst);
917 /* restore the pointer and length of the compressed block */
918 lzo_block->dst = tmp_dst;
919 lzo_block->dst_len = tmp_dst_len;
920 return 0;
921}
922
923static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
924{
925 struct snd_soc_lzo_ctx **lzo_blocks;
926 int i, blkcount;
927
928 lzo_blocks = codec->reg_cache;
929 if (!lzo_blocks)
930 return 0;
931
932 blkcount = snd_soc_lzo_block_count();
933 /*
934 * the pointer to the bitmap used for syncing the cache
935 * is shared amongst all lzo_blocks. Ensure it is freed
936 * only once.
937 */
938 if (lzo_blocks[0])
939 kfree(lzo_blocks[0]->sync_bmp);
940 for (i = 0; i < blkcount; ++i) {
941 if (lzo_blocks[i]) {
942 kfree(lzo_blocks[i]->wmem);
943 kfree(lzo_blocks[i]->dst);
944 }
945 /* each lzo_block is a pointer returned by kmalloc or NULL */
946 kfree(lzo_blocks[i]);
947 }
948 kfree(lzo_blocks);
949 codec->reg_cache = NULL;
950 return 0;
951}
952
953static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
954{
955 struct snd_soc_lzo_ctx **lzo_blocks;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000956 size_t bmp_size;
Mark Brown001ae4c2010-12-02 16:21:08 +0000957 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000958 int ret, tofree, i, blksize, blkcount;
959 const char *p, *end;
960 unsigned long *sync_bmp;
961
962 ret = 0;
963 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000964
965 /*
966 * If we have not been given a default register cache
967 * then allocate a dummy zero-ed out region, compress it
968 * and remember to free it afterwards.
969 */
970 tofree = 0;
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000971 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000972 tofree = 1;
973
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000974 if (!codec->reg_def_copy) {
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000975 codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000976 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000977 return -ENOMEM;
978 }
979
980 blkcount = snd_soc_lzo_block_count();
981 codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks,
982 GFP_KERNEL);
983 if (!codec->reg_cache) {
984 ret = -ENOMEM;
985 goto err_tofree;
986 }
987 lzo_blocks = codec->reg_cache;
988
989 /*
990 * allocate a bitmap to be used when syncing the cache with
991 * the hardware. Each time a register is modified, the corresponding
992 * bit is set in the bitmap, so we know that we have to sync
993 * that register.
994 */
995 bmp_size = codec_drv->reg_cache_size;
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +0000996 sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000997 GFP_KERNEL);
998 if (!sync_bmp) {
999 ret = -ENOMEM;
1000 goto err;
1001 }
Dimitris Papastamos09c74a92010-11-29 11:43:33 +00001002 bitmap_zero(sync_bmp, bmp_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001003
1004 /* allocate the lzo blocks and initialize them */
1005 for (i = 0; i < blkcount; ++i) {
1006 lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
1007 GFP_KERNEL);
1008 if (!lzo_blocks[i]) {
1009 kfree(sync_bmp);
1010 ret = -ENOMEM;
1011 goto err;
1012 }
1013 lzo_blocks[i]->sync_bmp = sync_bmp;
Dimitris Papastamos04f8fd12011-01-11 11:24:02 +00001014 lzo_blocks[i]->sync_bmp_nbits = bmp_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001015 /* alloc the working space for the compressed block */
1016 ret = snd_soc_lzo_prepare(lzo_blocks[i]);
1017 if (ret < 0)
1018 goto err;
1019 }
1020
1021 blksize = snd_soc_lzo_get_blksize(codec);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001022 p = codec->reg_def_copy;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001023 end = codec->reg_def_copy + codec->reg_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001024 /* compress the register map and fill the lzo blocks */
1025 for (i = 0; i < blkcount; ++i, p += blksize) {
1026 lzo_blocks[i]->src = p;
1027 if (p + blksize > end)
1028 lzo_blocks[i]->src_len = end - p;
1029 else
1030 lzo_blocks[i]->src_len = blksize;
1031 ret = snd_soc_lzo_compress_cache_block(codec,
1032 lzo_blocks[i]);
1033 if (ret < 0)
1034 goto err;
1035 lzo_blocks[i]->decompressed_size =
1036 lzo_blocks[i]->src_len;
1037 }
1038
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001039 if (tofree) {
1040 kfree(codec->reg_def_copy);
1041 codec->reg_def_copy = NULL;
1042 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001043 return 0;
1044err:
1045 snd_soc_cache_exit(codec);
1046err_tofree:
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001047 if (tofree) {
1048 kfree(codec->reg_def_copy);
1049 codec->reg_def_copy = NULL;
1050 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001051 return ret;
1052}
Mark Brown68d44ee2010-12-21 17:19:56 +00001053#endif
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001054
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001055static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
1056{
1057 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001058 int ret;
Mark Brown001ae4c2010-12-02 16:21:08 +00001059 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001060 unsigned int val;
1061
1062 codec_drv = codec->driver;
1063 for (i = 0; i < codec_drv->reg_cache_size; ++i) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +01001064 WARN_ON(codec->writable_register &&
1065 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001066 ret = snd_soc_cache_read(codec, i, &val);
1067 if (ret)
1068 return ret;
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001069 if (codec->reg_def_copy)
1070 if (snd_soc_get_cache_val(codec->reg_def_copy,
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001071 i, codec_drv->reg_word_size) == val)
1072 continue;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001073 ret = snd_soc_write(codec, i, val);
1074 if (ret)
1075 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001076 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1077 i, val);
1078 }
1079 return 0;
1080}
1081
1082static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
1083 unsigned int reg, unsigned int value)
1084{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001085 snd_soc_set_cache_val(codec->reg_cache, reg, value,
1086 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001087 return 0;
1088}
1089
1090static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
1091 unsigned int reg, unsigned int *value)
1092{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001093 *value = snd_soc_get_cache_val(codec->reg_cache, reg,
1094 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001095 return 0;
1096}
1097
1098static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
1099{
1100 if (!codec->reg_cache)
1101 return 0;
1102 kfree(codec->reg_cache);
1103 codec->reg_cache = NULL;
1104 return 0;
1105}
1106
1107static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
1108{
Mark Brown001ae4c2010-12-02 16:21:08 +00001109 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001110
1111 codec_drv = codec->driver;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001112
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001113 if (codec->reg_def_copy)
1114 codec->reg_cache = kmemdup(codec->reg_def_copy,
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001115 codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001116 else
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001117 codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001118 if (!codec->reg_cache)
1119 return -ENOMEM;
1120
1121 return 0;
1122}
1123
1124/* an array of all supported compression types */
1125static const struct snd_soc_cache_ops cache_types[] = {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001126 /* Flat *must* be the first entry for fallback */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001127 {
Dimitris Papastamosdf0701b2010-11-29 10:54:28 +00001128 .id = SND_SOC_FLAT_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001129 .name = "flat",
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001130 .init = snd_soc_flat_cache_init,
1131 .exit = snd_soc_flat_cache_exit,
1132 .read = snd_soc_flat_cache_read,
1133 .write = snd_soc_flat_cache_write,
1134 .sync = snd_soc_flat_cache_sync
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001135 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001136#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001137 {
1138 .id = SND_SOC_LZO_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001139 .name = "LZO",
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001140 .init = snd_soc_lzo_cache_init,
1141 .exit = snd_soc_lzo_cache_exit,
1142 .read = snd_soc_lzo_cache_read,
1143 .write = snd_soc_lzo_cache_write,
1144 .sync = snd_soc_lzo_cache_sync
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001145 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001146#endif
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001147 {
1148 .id = SND_SOC_RBTREE_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001149 .name = "rbtree",
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001150 .init = snd_soc_rbtree_cache_init,
1151 .exit = snd_soc_rbtree_cache_exit,
1152 .read = snd_soc_rbtree_cache_read,
1153 .write = snd_soc_rbtree_cache_write,
1154 .sync = snd_soc_rbtree_cache_sync
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001155 }
1156};
1157
1158int snd_soc_cache_init(struct snd_soc_codec *codec)
1159{
1160 int i;
1161
1162 for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
Dimitris Papastamos23bbce32010-12-02 14:53:01 +00001163 if (cache_types[i].id == codec->compress_type)
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001164 break;
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001165
1166 /* Fall back to flat compression */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001167 if (i == ARRAY_SIZE(cache_types)) {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001168 dev_warn(codec->dev, "Could not match compress type: %d\n",
1169 codec->compress_type);
1170 i = 0;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001171 }
1172
1173 mutex_init(&codec->cache_rw_mutex);
1174 codec->cache_ops = &cache_types[i];
1175
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001176 if (codec->cache_ops->init) {
1177 if (codec->cache_ops->name)
1178 dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
1179 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001180 return codec->cache_ops->init(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001181 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001182 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001183}
1184
1185/*
1186 * NOTE: keep in mind that this function might be called
1187 * multiple times.
1188 */
1189int snd_soc_cache_exit(struct snd_soc_codec *codec)
1190{
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001191 if (codec->cache_ops && codec->cache_ops->exit) {
1192 if (codec->cache_ops->name)
1193 dev_dbg(codec->dev, "Destroying %s cache for %s codec\n",
1194 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001195 return codec->cache_ops->exit(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001196 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001197 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001198}
1199
1200/**
1201 * snd_soc_cache_read: Fetch the value of a given register from the cache.
1202 *
1203 * @codec: CODEC to configure.
1204 * @reg: The register index.
1205 * @value: The value to be returned.
1206 */
1207int snd_soc_cache_read(struct snd_soc_codec *codec,
1208 unsigned int reg, unsigned int *value)
1209{
1210 int ret;
1211
1212 mutex_lock(&codec->cache_rw_mutex);
1213
1214 if (value && codec->cache_ops && codec->cache_ops->read) {
1215 ret = codec->cache_ops->read(codec, reg, value);
1216 mutex_unlock(&codec->cache_rw_mutex);
1217 return ret;
1218 }
1219
1220 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001221 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001222}
1223EXPORT_SYMBOL_GPL(snd_soc_cache_read);
1224
1225/**
1226 * snd_soc_cache_write: Set the value of a given register in the cache.
1227 *
1228 * @codec: CODEC to configure.
1229 * @reg: The register index.
1230 * @value: The new register value.
1231 */
1232int snd_soc_cache_write(struct snd_soc_codec *codec,
1233 unsigned int reg, unsigned int value)
1234{
1235 int ret;
1236
1237 mutex_lock(&codec->cache_rw_mutex);
1238
1239 if (codec->cache_ops && codec->cache_ops->write) {
1240 ret = codec->cache_ops->write(codec, reg, value);
1241 mutex_unlock(&codec->cache_rw_mutex);
1242 return ret;
1243 }
1244
1245 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001246 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001247}
1248EXPORT_SYMBOL_GPL(snd_soc_cache_write);
1249
1250/**
1251 * snd_soc_cache_sync: Sync the register cache with the hardware.
1252 *
1253 * @codec: CODEC to configure.
1254 *
1255 * Any registers that should not be synced should be marked as
1256 * volatile. In general drivers can choose not to use the provided
1257 * syncing functionality if they so require.
1258 */
1259int snd_soc_cache_sync(struct snd_soc_codec *codec)
1260{
1261 int ret;
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001262 const char *name;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001263
1264 if (!codec->cache_sync) {
1265 return 0;
1266 }
1267
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001268 if (!codec->cache_ops || !codec->cache_ops->sync)
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001269 return -ENOSYS;
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001270
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001271 if (codec->cache_ops->name)
1272 name = codec->cache_ops->name;
1273 else
1274 name = "unknown";
1275
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001276 if (codec->cache_ops->name)
1277 dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
1278 codec->cache_ops->name, codec->name);
1279 trace_snd_soc_cache_sync(codec, name, "start");
1280 ret = codec->cache_ops->sync(codec);
1281 if (!ret)
1282 codec->cache_sync = 0;
1283 trace_snd_soc_cache_sync(codec, name, "end");
1284 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001285}
1286EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
Dimitris Papastamos066d16c2011-01-13 12:20:36 +00001287
1288static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec,
1289 unsigned int reg)
1290{
1291 const struct snd_soc_codec_driver *codec_drv;
1292 unsigned int min, max, index;
1293
1294 codec_drv = codec->driver;
1295 min = 0;
1296 max = codec_drv->reg_access_size - 1;
1297 do {
1298 index = (min + max) / 2;
1299 if (codec_drv->reg_access_default[index].reg == reg)
1300 return index;
1301 if (codec_drv->reg_access_default[index].reg < reg)
1302 min = index + 1;
1303 else
1304 max = index;
1305 } while (min <= max);
1306 return -1;
1307}
1308
1309int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
1310 unsigned int reg)
1311{
1312 int index;
1313
1314 if (reg >= codec->driver->reg_cache_size)
1315 return 1;
1316 index = snd_soc_get_reg_access_index(codec, reg);
1317 if (index < 0)
1318 return 0;
1319 return codec->driver->reg_access_default[index].vol;
1320}
1321EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register);
1322
1323int snd_soc_default_readable_register(struct snd_soc_codec *codec,
1324 unsigned int reg)
1325{
1326 int index;
1327
1328 if (reg >= codec->driver->reg_cache_size)
1329 return 1;
1330 index = snd_soc_get_reg_access_index(codec, reg);
1331 if (index < 0)
1332 return 0;
1333 return codec->driver->reg_access_default[index].read;
1334}
1335EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
Dimitris Papastamos80204542011-03-24 13:45:17 +00001336
1337int snd_soc_default_writable_register(struct snd_soc_codec *codec,
1338 unsigned int reg)
1339{
1340 int index;
1341
1342 if (reg >= codec->driver->reg_cache_size)
1343 return 1;
1344 index = snd_soc_get_reg_access_index(codec, reg);
1345 if (index < 0)
1346 return 0;
1347 return codec->driver->reg_access_default[index].write;
1348}
1349EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);