blob: c005ceb70c9d1dfc624ffa11a13eec427e2215b9 [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)
25{
26 struct spi_device *spi = control;
27 int ret;
28
29 ret = spi_write(spi, data, len);
30 if (ret < 0)
31 return ret;
32
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 Brown17a52fd2009-07-05 17:24:50 +0100110 u8 data[2];
Mark Brown17a52fd2009-07-05 17:24:50 +0100111
Mark Brown17a52fd2009-07-05 17:24:50 +0100112 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
113 data[1] = value & 0x00ff;
114
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000115 return do_hw_write(codec, reg, value, data, 2);
Mark Brown17a52fd2009-07-05 17:24:50 +0100116}
117
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900118static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
119 unsigned int value)
120{
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900121 u8 data[2];
122
Barry Songf4bee1b2010-03-18 16:17:01 +0800123 reg &= 0xff;
124 data[0] = reg;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900125 data[1] = value & 0xff;
126
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000127 return do_hw_write(codec, reg, value, data, 2);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900128}
129
130static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
131 unsigned int reg)
132{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000133 return do_hw_read(codec, reg);
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900134}
135
Mark Brownafa2f102009-07-10 23:11:24 +0100136static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
137 unsigned int value)
138{
Mark Brownafa2f102009-07-10 23:11:24 +0100139 u8 data[3];
140
141 data[0] = reg;
142 data[1] = (value >> 8) & 0xff;
143 data[2] = value & 0xff;
144
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000145 return do_hw_write(codec, reg, value, data, 3);
Mark Brownafa2f102009-07-10 23:11:24 +0100146}
147
148static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
149 unsigned int reg)
150{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000151 return do_hw_read(codec, reg);
Mark Brownafa2f102009-07-10 23:11:24 +0100152}
153
Randy Dunlap17244c22009-08-10 16:04:39 -0700154#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000155static unsigned int do_i2c_read(struct snd_soc_codec *codec,
156 void *reg, int reglen,
157 void *data, int datalen)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800158{
159 struct i2c_msg xfer[2];
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800160 int ret;
161 struct i2c_client *client = codec->control_data;
162
163 /* Write register */
164 xfer[0].addr = client->addr;
165 xfer[0].flags = 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000166 xfer[0].len = reglen;
167 xfer[0].buf = reg;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800168
169 /* Read data */
170 xfer[1].addr = client->addr;
171 xfer[1].flags = I2C_M_RD;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000172 xfer[1].len = datalen;
173 xfer[1].buf = data;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800174
175 ret = i2c_transfer(client->adapter, xfer, 2);
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000176 if (ret == 2)
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800177 return 0;
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000178 else if (ret < 0)
179 return ret;
180 else
181 return -EIO;
182}
183#endif
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800184
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000185#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
186static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100187 unsigned int r)
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000188{
189 u8 reg = r;
190 u8 data;
191 int ret;
192
193 ret = do_i2c_read(codec, &reg, 1, &data, 1);
194 if (ret < 0)
195 return 0;
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800196 return data;
197}
198#else
199#define snd_soc_8_8_read_i2c NULL
200#endif
201
202#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100203static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
204 unsigned int r)
205{
Mark Brownafa2f102009-07-10 23:11:24 +0100206 u8 reg = r;
207 u16 data;
208 int ret;
Mark Brownafa2f102009-07-10 23:11:24 +0100209
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000210 ret = do_i2c_read(codec, &reg, 1, &data, 2);
211 if (ret < 0)
Mark Brownafa2f102009-07-10 23:11:24 +0100212 return 0;
Mark Brownafa2f102009-07-10 23:11:24 +0100213 return (data >> 8) | ((data & 0xff) << 8);
214}
215#else
216#define snd_soc_8_16_read_i2c NULL
217#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100218
Barry Song994dc422010-01-27 11:46:18 +0800219#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
220static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
221 unsigned int r)
222{
Barry Song994dc422010-01-27 11:46:18 +0800223 u16 reg = r;
224 u8 data;
225 int ret;
Barry Song994dc422010-01-27 11:46:18 +0800226
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000227 ret = do_i2c_read(codec, &reg, 2, &data, 1);
228 if (ret < 0)
Barry Song994dc422010-01-27 11:46:18 +0800229 return 0;
Barry Song994dc422010-01-27 11:46:18 +0800230 return data;
231}
232#else
233#define snd_soc_16_8_read_i2c NULL
234#endif
235
236static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100237 unsigned int reg)
Barry Song994dc422010-01-27 11:46:18 +0800238{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000239 return do_hw_read(codec, reg);
Barry Song994dc422010-01-27 11:46:18 +0800240}
241
242static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
Dimitris Papastamosfbda1822011-03-28 11:39:14 +0100243 unsigned int value)
Barry Song994dc422010-01-27 11:46:18 +0800244{
Barry Song994dc422010-01-27 11:46:18 +0800245 u8 data[3];
Barry Song994dc422010-01-27 11:46:18 +0800246
Barry Song994dc422010-01-27 11:46:18 +0800247 data[0] = (reg >> 8) & 0xff;
248 data[1] = reg & 0xff;
249 data[2] = value;
Mark Brown8c961bc2010-02-01 18:46:10 +0000250
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000251 return do_hw_write(codec, reg, value, data, 3);
Barry Song994dc422010-01-27 11:46:18 +0800252}
253
Mark Brownbc6552f2010-03-05 16:27:15 +0000254#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
255static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
256 unsigned int r)
257{
Mark Brownbc6552f2010-03-05 16:27:15 +0000258 u16 reg = cpu_to_be16(r);
259 u16 data;
260 int ret;
Mark Brownbc6552f2010-03-05 16:27:15 +0000261
Dimitris Papastamosf3594f52011-03-22 10:37:01 +0000262 ret = do_i2c_read(codec, &reg, 2, &data, 2);
263 if (ret < 0)
Mark Brownbc6552f2010-03-05 16:27:15 +0000264 return 0;
Mark Brownbc6552f2010-03-05 16:27:15 +0000265 return be16_to_cpu(data);
266}
267#else
268#define snd_soc_16_16_read_i2c NULL
269#endif
270
271static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
272 unsigned int reg)
273{
Dimitris Papastamosb8cbc192011-03-22 10:36:59 +0000274 return do_hw_read(codec, reg);
Mark Brownbc6552f2010-03-05 16:27:15 +0000275}
276
277static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
278 unsigned int value)
279{
Mark Brownbc6552f2010-03-05 16:27:15 +0000280 u8 data[4];
Mark Brownbc6552f2010-03-05 16:27:15 +0000281
282 data[0] = (reg >> 8) & 0xff;
283 data[1] = reg & 0xff;
284 data[2] = (value >> 8) & 0xff;
285 data[3] = value & 0xff;
286
Dimitris Papastamos26e99842011-03-22 10:36:58 +0000287 return do_hw_write(codec, reg, value, data, 4);
Mark Brownbc6552f2010-03-05 16:27:15 +0000288}
Barry Song994dc422010-01-27 11:46:18 +0800289
Mark Brown34bad692011-04-04 17:55:42 +0900290/* Primitive bulk write support for soc-cache. The data pointed to by
291 * `data' needs to already be in the form the hardware expects
292 * including any leading register specific data. Any data written
293 * through this function will not go through the cache as it only
294 * handles writing to volatile or out of bounds registers.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000295 */
296static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
297 const void *data, size_t len)
298{
299 int ret;
300
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100301 /* To ensure that we don't get out of sync with the cache, check
302 * whether the base register is volatile or if we've directly asked
303 * to bypass the cache. Out of bounds registers are considered
304 * volatile.
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000305 */
Dimitris Papastamos64d27062011-05-05 14:18:11 +0100306 if (!codec->cache_bypass
307 && !snd_soc_codec_volatile_register(codec, reg)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000308 && reg < codec->driver->reg_cache_size)
309 return -EINVAL;
310
311 switch (codec->control_type) {
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900312#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000313 case SND_SOC_I2C:
314 ret = i2c_master_send(codec->control_data, data, len);
315 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900316#endif
317#if defined(CONFIG_SPI_MASTER)
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000318 case SND_SOC_SPI:
Mark Brown6e28f972011-05-10 23:33:48 +0200319 ret = spi_write(codec->control_data, data, len);
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000320 break;
Seungwhan Youn898f8b02011-04-04 13:43:42 +0900321#endif
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000322 default:
323 BUG();
324 }
325
326 if (ret == len)
327 return 0;
328 if (ret < 0)
329 return ret;
330 else
331 return -EIO;
332}
333
Mark Brown17a52fd2009-07-05 17:24:50 +0100334static struct {
335 int addr_bits;
336 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100337 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100338 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100339 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100340} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700341 {
Barry Song63b62ab2010-01-27 11:46:17 +0800342 .addr_bits = 4, .data_bits = 12,
343 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
Barry Song63b62ab2010-01-27 11:46:17 +0800344 },
345 {
Mark Brownd62ab352009-09-21 04:21:47 -0700346 .addr_bits = 7, .data_bits = 9,
347 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Mark Brownd62ab352009-09-21 04:21:47 -0700348 },
349 {
350 .addr_bits = 8, .data_bits = 8,
351 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800352 .i2c_read = snd_soc_8_8_read_i2c,
Mark Brownd62ab352009-09-21 04:21:47 -0700353 },
354 {
355 .addr_bits = 8, .data_bits = 16,
356 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
357 .i2c_read = snd_soc_8_16_read_i2c,
358 },
Barry Song994dc422010-01-27 11:46:18 +0800359 {
360 .addr_bits = 16, .data_bits = 8,
361 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
362 .i2c_read = snd_soc_16_8_read_i2c,
Barry Song994dc422010-01-27 11:46:18 +0800363 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000364 {
365 .addr_bits = 16, .data_bits = 16,
366 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
367 .i2c_read = snd_soc_16_16_read_i2c,
368 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100369};
370
371/**
372 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
373 *
374 * @codec: CODEC to configure.
Mark Brown17a52fd2009-07-05 17:24:50 +0100375 * @addr_bits: Number of bits of register address data.
376 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100377 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100378 *
379 * Register formats are frequently shared between many I2C and SPI
380 * devices. In order to promote code reuse the ASoC core provides
381 * some standard implementations of CODEC read and write operations
382 * which can be set up using this function.
383 *
384 * The caller is responsible for allocating and initialising the
385 * actual cache.
386 *
387 * Note that at present this code cannot be used by CODECs with
388 * volatile registers.
389 */
390int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100391 int addr_bits, int data_bits,
392 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100393{
394 int i;
395
Mark Brown17a52fd2009-07-05 17:24:50 +0100396 for (i = 0; i < ARRAY_SIZE(io_types); i++)
397 if (io_types[i].addr_bits == addr_bits &&
398 io_types[i].data_bits == data_bits)
399 break;
400 if (i == ARRAY_SIZE(io_types)) {
401 printk(KERN_ERR
402 "No I/O functions for %d bit address %d bit data\n",
403 addr_bits, data_bits);
404 return -EINVAL;
405 }
406
Mark Brownc3acec22010-12-02 16:15:29 +0000407 codec->write = io_types[i].write;
408 codec->read = io_types[i].read;
Dimitris Papastamos5fb609d2011-03-22 10:37:03 +0000409 codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
Mark Brown17a52fd2009-07-05 17:24:50 +0100410
Mark Brown7084a422009-07-10 22:24:27 +0100411 switch (control) {
412 case SND_SOC_CUSTOM:
413 break;
414
415 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700416#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100417 codec->hw_write = (hw_write_t)i2c_master_send;
418#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100419 if (io_types[i].i2c_read)
420 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100421
422 codec->control_data = container_of(codec->dev,
423 struct i2c_client,
424 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100425 break;
426
427 case SND_SOC_SPI:
Mark Brown6e28f972011-05-10 23:33:48 +0200428#ifdef CONFIG_SPI_MASTER
Mark Brownf7391fc2011-05-11 19:25:42 +0200429 codec->hw_write = do_spi_write;
Mark Brown6e28f972011-05-10 23:33:48 +0200430#endif
Mark Browna6d14342010-08-12 10:59:15 +0100431
432 codec->control_data = container_of(codec->dev,
433 struct spi_device,
434 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100435 break;
436 }
437
Mark Brown17a52fd2009-07-05 17:24:50 +0100438 return 0;
439}
440EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000441
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000442static bool snd_soc_set_cache_val(void *base, unsigned int idx,
443 unsigned int val, unsigned int word_size)
444{
445 switch (word_size) {
446 case 1: {
447 u8 *cache = base;
448 if (cache[idx] == val)
449 return true;
450 cache[idx] = val;
451 break;
452 }
453 case 2: {
454 u16 *cache = base;
455 if (cache[idx] == val)
456 return true;
457 cache[idx] = val;
458 break;
459 }
460 default:
461 BUG();
462 }
463 return false;
464}
465
466static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
467 unsigned int word_size)
468{
Mark Brownfd137e22011-06-06 11:26:15 +0100469 if (!base)
470 return -1;
471
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000472 switch (word_size) {
473 case 1: {
474 const u8 *cache = base;
475 return cache[idx];
476 }
477 case 2: {
478 const u16 *cache = base;
479 return cache[idx];
480 }
481 default:
482 BUG();
483 }
484 /* unreachable */
485 return -1;
486}
487
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000488struct snd_soc_rbtree_node {
489 struct rb_node node;
490 unsigned int reg;
491 unsigned int value;
492 unsigned int defval;
493} __attribute__ ((packed));
494
495struct snd_soc_rbtree_ctx {
496 struct rb_root root;
497};
498
499static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
500 struct rb_root *root, unsigned int reg)
501{
502 struct rb_node *node;
503 struct snd_soc_rbtree_node *rbnode;
504
505 node = root->rb_node;
506 while (node) {
507 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
508 if (rbnode->reg < reg)
509 node = node->rb_left;
510 else if (rbnode->reg > reg)
511 node = node->rb_right;
512 else
513 return rbnode;
514 }
515
516 return NULL;
517}
518
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000519static int snd_soc_rbtree_insert(struct rb_root *root,
520 struct snd_soc_rbtree_node *rbnode)
521{
522 struct rb_node **new, *parent;
523 struct snd_soc_rbtree_node *rbnode_tmp;
524
525 parent = NULL;
526 new = &root->rb_node;
527 while (*new) {
528 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
529 node);
530 parent = *new;
531 if (rbnode_tmp->reg < rbnode->reg)
532 new = &((*new)->rb_left);
533 else if (rbnode_tmp->reg > rbnode->reg)
534 new = &((*new)->rb_right);
535 else
536 return 0;
537 }
538
539 /* insert the node into the rbtree */
540 rb_link_node(&rbnode->node, parent, new);
541 rb_insert_color(&rbnode->node, root);
542
543 return 1;
544}
545
546static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
547{
548 struct snd_soc_rbtree_ctx *rbtree_ctx;
549 struct rb_node *node;
550 struct snd_soc_rbtree_node *rbnode;
551 unsigned int val;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000552 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000553
554 rbtree_ctx = codec->reg_cache;
555 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
556 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
557 if (rbnode->value == rbnode->defval)
558 continue;
Dimitris Papastamosf20eda52011-03-28 11:39:15 +0100559 WARN_ON(codec->writable_register &&
560 codec->writable_register(codec, rbnode->reg));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000561 ret = snd_soc_cache_read(codec, rbnode->reg, &val);
562 if (ret)
563 return ret;
Dimitris Papastamos99780072011-01-19 14:53:37 +0000564 codec->cache_bypass = 1;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000565 ret = snd_soc_write(codec, rbnode->reg, val);
Dimitris Papastamos99780072011-01-19 14:53:37 +0000566 codec->cache_bypass = 0;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000567 if (ret)
568 return ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000569 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
570 rbnode->reg, val);
571 }
572
573 return 0;
574}
575
576static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
577 unsigned int reg, unsigned int value)
578{
579 struct snd_soc_rbtree_ctx *rbtree_ctx;
580 struct snd_soc_rbtree_node *rbnode;
581
582 rbtree_ctx = codec->reg_cache;
583 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
584 if (rbnode) {
585 if (rbnode->value == value)
586 return 0;
587 rbnode->value = value;
588 } else {
589 /* bail out early, no need to create the rbnode yet */
590 if (!value)
591 return 0;
592 /*
593 * for uninitialized registers whose value is changed
594 * from the default zero, create an rbnode and insert
595 * it into the tree.
596 */
597 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
598 if (!rbnode)
599 return -ENOMEM;
600 rbnode->reg = reg;
601 rbnode->value = value;
602 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
603 }
604
605 return 0;
606}
607
608static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
609 unsigned int reg, unsigned int *value)
610{
611 struct snd_soc_rbtree_ctx *rbtree_ctx;
612 struct snd_soc_rbtree_node *rbnode;
613
614 rbtree_ctx = codec->reg_cache;
615 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
616 if (rbnode) {
617 *value = rbnode->value;
618 } else {
619 /* uninitialized registers default to 0 */
620 *value = 0;
621 }
622
623 return 0;
624}
625
626static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
627{
628 struct rb_node *next;
629 struct snd_soc_rbtree_ctx *rbtree_ctx;
630 struct snd_soc_rbtree_node *rbtree_node;
631
632 /* if we've already been called then just return */
633 rbtree_ctx = codec->reg_cache;
634 if (!rbtree_ctx)
635 return 0;
636
637 /* free up the rbtree */
638 next = rb_first(&rbtree_ctx->root);
639 while (next) {
640 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
641 next = rb_next(&rbtree_node->node);
642 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
643 kfree(rbtree_node);
644 }
645
646 /* release the resources */
647 kfree(codec->reg_cache);
648 codec->reg_cache = NULL;
649
650 return 0;
651}
652
653static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
654{
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000655 struct snd_soc_rbtree_node *rbtree_node;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000656 struct snd_soc_rbtree_ctx *rbtree_ctx;
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000657 unsigned int val;
658 unsigned int word_size;
659 int i;
660 int ret;
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000661
662 codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
663 if (!codec->reg_cache)
664 return -ENOMEM;
665
666 rbtree_ctx = codec->reg_cache;
667 rbtree_ctx->root = RB_ROOT;
668
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000669 if (!codec->reg_def_copy)
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000670 return 0;
671
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000672 /*
673 * populate the rbtree with the initialized registers. All other
674 * registers will be inserted when they are first modified.
675 */
676 word_size = codec->driver->reg_word_size;
677 for (i = 0; i < codec->driver->reg_cache_size; ++i) {
678 val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size);
679 if (!val)
680 continue;
681 rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL);
682 if (!rbtree_node) {
683 ret = -ENOMEM;
684 snd_soc_cache_exit(codec);
685 break;
686 }
687 rbtree_node->reg = i;
688 rbtree_node->value = val;
689 rbtree_node->defval = val;
690 snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node);
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +0000691 }
692
693 return 0;
694}
695
Mark Brown68d44ee2010-12-21 17:19:56 +0000696#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000697struct snd_soc_lzo_ctx {
698 void *wmem;
699 void *dst;
700 const void *src;
701 size_t src_len;
702 size_t dst_len;
703 size_t decompressed_size;
704 unsigned long *sync_bmp;
705 int sync_bmp_nbits;
706};
707
708#define LZO_BLOCK_NUM 8
709static int snd_soc_lzo_block_count(void)
710{
711 return LZO_BLOCK_NUM;
712}
713
714static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx)
715{
716 lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
717 if (!lzo_ctx->wmem)
718 return -ENOMEM;
719 return 0;
720}
721
722static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx)
723{
724 size_t compress_size;
725 int ret;
726
727 ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
728 lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
729 if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
730 return -EINVAL;
731 lzo_ctx->dst_len = compress_size;
732 return 0;
733}
734
735static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx)
736{
737 size_t dst_len;
738 int ret;
739
740 dst_len = lzo_ctx->dst_len;
741 ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
742 lzo_ctx->dst, &dst_len);
743 if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
744 return -EINVAL;
745 return 0;
746}
747
748static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec,
749 struct snd_soc_lzo_ctx *lzo_ctx)
750{
751 int ret;
752
753 lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
754 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
755 if (!lzo_ctx->dst) {
756 lzo_ctx->dst_len = 0;
757 return -ENOMEM;
758 }
759
760 ret = snd_soc_lzo_compress(lzo_ctx);
761 if (ret < 0)
762 return ret;
763 return 0;
764}
765
766static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec,
767 struct snd_soc_lzo_ctx *lzo_ctx)
768{
769 int ret;
770
771 lzo_ctx->dst_len = lzo_ctx->decompressed_size;
772 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
773 if (!lzo_ctx->dst) {
774 lzo_ctx->dst_len = 0;
775 return -ENOMEM;
776 }
777
778 ret = snd_soc_lzo_decompress(lzo_ctx);
779 if (ret < 0)
780 return ret;
781 return 0;
782}
783
784static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
785 unsigned int reg)
786{
Mark Brown001ae4c2010-12-02 16:21:08 +0000787 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000788
789 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000790 return (reg * codec_drv->reg_word_size) /
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000791 DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000792}
793
794static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
795 unsigned int reg)
796{
Mark Brown001ae4c2010-12-02 16:21:08 +0000797 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000798
799 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000800 return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) /
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000801 codec_drv->reg_word_size);
802}
803
804static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
805{
Mark Brown001ae4c2010-12-02 16:21:08 +0000806 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000807
808 codec_drv = codec->driver;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000809 return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000810}
811
812static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
813{
814 struct snd_soc_lzo_ctx **lzo_blocks;
815 unsigned int val;
816 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000817 int ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000818
819 lzo_blocks = codec->reg_cache;
820 for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +0100821 WARN_ON(codec->writable_register &&
822 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000823 ret = snd_soc_cache_read(codec, i, &val);
824 if (ret)
825 return ret;
Dimitris Papastamos99780072011-01-19 14:53:37 +0000826 codec->cache_bypass = 1;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000827 ret = snd_soc_write(codec, i, val);
Dimitris Papastamos99780072011-01-19 14:53:37 +0000828 codec->cache_bypass = 0;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +0000829 if (ret)
830 return ret;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000831 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
832 i, val);
833 }
834
835 return 0;
836}
837
838static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
839 unsigned int reg, unsigned int value)
840{
841 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
842 int ret, blkindex, blkpos;
843 size_t blksize, tmp_dst_len;
844 void *tmp_dst;
845
846 /* index of the compressed lzo block */
847 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
848 /* register index within the decompressed block */
849 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
850 /* size of the compressed block */
851 blksize = snd_soc_lzo_get_blksize(codec);
852 lzo_blocks = codec->reg_cache;
853 lzo_block = lzo_blocks[blkindex];
854
855 /* save the pointer and length of the compressed block */
856 tmp_dst = lzo_block->dst;
857 tmp_dst_len = lzo_block->dst_len;
858
859 /* prepare the source to be the compressed block */
860 lzo_block->src = lzo_block->dst;
861 lzo_block->src_len = lzo_block->dst_len;
862
863 /* decompress the block */
864 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
865 if (ret < 0) {
866 kfree(lzo_block->dst);
867 goto out;
868 }
869
870 /* write the new value to the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000871 if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value,
872 codec->driver->reg_word_size)) {
873 kfree(lzo_block->dst);
874 goto out;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000875 }
876
877 /* prepare the source to be the decompressed block */
878 lzo_block->src = lzo_block->dst;
879 lzo_block->src_len = lzo_block->dst_len;
880
881 /* compress the block */
882 ret = snd_soc_lzo_compress_cache_block(codec, lzo_block);
883 if (ret < 0) {
884 kfree(lzo_block->dst);
885 kfree(lzo_block->src);
886 goto out;
887 }
888
889 /* set the bit so we know we have to sync this register */
890 set_bit(reg, lzo_block->sync_bmp);
891 kfree(tmp_dst);
892 kfree(lzo_block->src);
893 return 0;
894out:
895 lzo_block->dst = tmp_dst;
896 lzo_block->dst_len = tmp_dst_len;
897 return ret;
898}
899
900static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
901 unsigned int reg, unsigned int *value)
902{
903 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
904 int ret, blkindex, blkpos;
905 size_t blksize, tmp_dst_len;
906 void *tmp_dst;
907
908 *value = 0;
909 /* index of the compressed lzo block */
910 blkindex = snd_soc_lzo_get_blkindex(codec, reg);
911 /* register index within the decompressed block */
912 blkpos = snd_soc_lzo_get_blkpos(codec, reg);
913 /* size of the compressed block */
914 blksize = snd_soc_lzo_get_blksize(codec);
915 lzo_blocks = codec->reg_cache;
916 lzo_block = lzo_blocks[blkindex];
917
918 /* save the pointer and length of the compressed block */
919 tmp_dst = lzo_block->dst;
920 tmp_dst_len = lzo_block->dst_len;
921
922 /* prepare the source to be the compressed block */
923 lzo_block->src = lzo_block->dst;
924 lzo_block->src_len = lzo_block->dst_len;
925
926 /* decompress the block */
927 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000928 if (ret >= 0)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000929 /* fetch the value from the cache */
Dimitris Papastamos1321e882011-01-11 11:29:49 +0000930 *value = snd_soc_get_cache_val(lzo_block->dst, blkpos,
931 codec->driver->reg_word_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000932
933 kfree(lzo_block->dst);
934 /* restore the pointer and length of the compressed block */
935 lzo_block->dst = tmp_dst;
936 lzo_block->dst_len = tmp_dst_len;
937 return 0;
938}
939
940static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
941{
942 struct snd_soc_lzo_ctx **lzo_blocks;
943 int i, blkcount;
944
945 lzo_blocks = codec->reg_cache;
946 if (!lzo_blocks)
947 return 0;
948
949 blkcount = snd_soc_lzo_block_count();
950 /*
951 * the pointer to the bitmap used for syncing the cache
952 * is shared amongst all lzo_blocks. Ensure it is freed
953 * only once.
954 */
955 if (lzo_blocks[0])
956 kfree(lzo_blocks[0]->sync_bmp);
957 for (i = 0; i < blkcount; ++i) {
958 if (lzo_blocks[i]) {
959 kfree(lzo_blocks[i]->wmem);
960 kfree(lzo_blocks[i]->dst);
961 }
962 /* each lzo_block is a pointer returned by kmalloc or NULL */
963 kfree(lzo_blocks[i]);
964 }
965 kfree(lzo_blocks);
966 codec->reg_cache = NULL;
967 return 0;
968}
969
970static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
971{
972 struct snd_soc_lzo_ctx **lzo_blocks;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000973 size_t bmp_size;
Mark Brown001ae4c2010-12-02 16:21:08 +0000974 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000975 int ret, tofree, i, blksize, blkcount;
976 const char *p, *end;
977 unsigned long *sync_bmp;
978
979 ret = 0;
980 codec_drv = codec->driver;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000981
982 /*
983 * If we have not been given a default register cache
984 * then allocate a dummy zero-ed out region, compress it
985 * and remember to free it afterwards.
986 */
987 tofree = 0;
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000988 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000989 tofree = 1;
990
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000991 if (!codec->reg_def_copy) {
Dimitris Papastamosaea170a2011-01-12 10:38:58 +0000992 codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +0000993 if (!codec->reg_def_copy)
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +0000994 return -ENOMEM;
995 }
996
997 blkcount = snd_soc_lzo_block_count();
998 codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks,
999 GFP_KERNEL);
1000 if (!codec->reg_cache) {
1001 ret = -ENOMEM;
1002 goto err_tofree;
1003 }
1004 lzo_blocks = codec->reg_cache;
1005
1006 /*
1007 * allocate a bitmap to be used when syncing the cache with
1008 * the hardware. Each time a register is modified, the corresponding
1009 * bit is set in the bitmap, so we know that we have to sync
1010 * that register.
1011 */
1012 bmp_size = codec_drv->reg_cache_size;
Dimitris Papastamos465d7fc2010-12-14 15:15:36 +00001013 sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001014 GFP_KERNEL);
1015 if (!sync_bmp) {
1016 ret = -ENOMEM;
1017 goto err;
1018 }
Dimitris Papastamos09c74a92010-11-29 11:43:33 +00001019 bitmap_zero(sync_bmp, bmp_size);
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001020
1021 /* allocate the lzo blocks and initialize them */
1022 for (i = 0; i < blkcount; ++i) {
1023 lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
1024 GFP_KERNEL);
1025 if (!lzo_blocks[i]) {
1026 kfree(sync_bmp);
1027 ret = -ENOMEM;
1028 goto err;
1029 }
1030 lzo_blocks[i]->sync_bmp = sync_bmp;
Dimitris Papastamos04f8fd12011-01-11 11:24:02 +00001031 lzo_blocks[i]->sync_bmp_nbits = bmp_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001032 /* alloc the working space for the compressed block */
1033 ret = snd_soc_lzo_prepare(lzo_blocks[i]);
1034 if (ret < 0)
1035 goto err;
1036 }
1037
1038 blksize = snd_soc_lzo_get_blksize(codec);
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001039 p = codec->reg_def_copy;
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001040 end = codec->reg_def_copy + codec->reg_size;
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001041 /* compress the register map and fill the lzo blocks */
1042 for (i = 0; i < blkcount; ++i, p += blksize) {
1043 lzo_blocks[i]->src = p;
1044 if (p + blksize > end)
1045 lzo_blocks[i]->src_len = end - p;
1046 else
1047 lzo_blocks[i]->src_len = blksize;
1048 ret = snd_soc_lzo_compress_cache_block(codec,
1049 lzo_blocks[i]);
1050 if (ret < 0)
1051 goto err;
1052 lzo_blocks[i]->decompressed_size =
1053 lzo_blocks[i]->src_len;
1054 }
1055
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001056 if (tofree) {
1057 kfree(codec->reg_def_copy);
1058 codec->reg_def_copy = NULL;
1059 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001060 return 0;
1061err:
1062 snd_soc_cache_exit(codec);
1063err_tofree:
Dimitris Papastamos3335ddc2010-12-02 16:11:05 +00001064 if (tofree) {
1065 kfree(codec->reg_def_copy);
1066 codec->reg_def_copy = NULL;
1067 }
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001068 return ret;
1069}
Mark Brown68d44ee2010-12-21 17:19:56 +00001070#endif
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001071
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001072static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
1073{
1074 int i;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001075 int ret;
Mark Brown001ae4c2010-12-02 16:21:08 +00001076 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001077 unsigned int val;
1078
1079 codec_drv = codec->driver;
1080 for (i = 0; i < codec_drv->reg_cache_size; ++i) {
Dimitris Papastamosf20eda52011-03-28 11:39:15 +01001081 WARN_ON(codec->writable_register &&
1082 codec->writable_register(codec, i));
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001083 ret = snd_soc_cache_read(codec, i, &val);
1084 if (ret)
1085 return ret;
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001086 if (codec->reg_def_copy)
1087 if (snd_soc_get_cache_val(codec->reg_def_copy,
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001088 i, codec_drv->reg_word_size) == val)
1089 continue;
Dimitris Papastamos7a33d4c2010-11-29 10:24:54 +00001090 ret = snd_soc_write(codec, i, val);
1091 if (ret)
1092 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001093 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
1094 i, val);
1095 }
1096 return 0;
1097}
1098
1099static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
1100 unsigned int reg, unsigned int value)
1101{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001102 snd_soc_set_cache_val(codec->reg_cache, reg, value,
1103 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001104 return 0;
1105}
1106
1107static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
1108 unsigned int reg, unsigned int *value)
1109{
Dimitris Papastamos1321e882011-01-11 11:29:49 +00001110 *value = snd_soc_get_cache_val(codec->reg_cache, reg,
1111 codec->driver->reg_word_size);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001112 return 0;
1113}
1114
1115static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
1116{
1117 if (!codec->reg_cache)
1118 return 0;
1119 kfree(codec->reg_cache);
1120 codec->reg_cache = NULL;
1121 return 0;
1122}
1123
1124static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
1125{
Mark Brown001ae4c2010-12-02 16:21:08 +00001126 const struct snd_soc_codec_driver *codec_drv;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001127
1128 codec_drv = codec->driver;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001129
Dimitris Papastamosd779fce2011-01-12 10:22:28 +00001130 if (codec->reg_def_copy)
1131 codec->reg_cache = kmemdup(codec->reg_def_copy,
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001132 codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001133 else
Dimitris Papastamosaea170a2011-01-12 10:38:58 +00001134 codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001135 if (!codec->reg_cache)
1136 return -ENOMEM;
1137
1138 return 0;
1139}
1140
1141/* an array of all supported compression types */
1142static const struct snd_soc_cache_ops cache_types[] = {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001143 /* Flat *must* be the first entry for fallback */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001144 {
Dimitris Papastamosdf0701b2010-11-29 10:54:28 +00001145 .id = SND_SOC_FLAT_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001146 .name = "flat",
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001147 .init = snd_soc_flat_cache_init,
1148 .exit = snd_soc_flat_cache_exit,
1149 .read = snd_soc_flat_cache_read,
1150 .write = snd_soc_flat_cache_write,
1151 .sync = snd_soc_flat_cache_sync
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001152 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001153#ifdef CONFIG_SND_SOC_CACHE_LZO
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001154 {
1155 .id = SND_SOC_LZO_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001156 .name = "LZO",
Dimitris Papastamoscc28fb82010-11-11 10:04:58 +00001157 .init = snd_soc_lzo_cache_init,
1158 .exit = snd_soc_lzo_cache_exit,
1159 .read = snd_soc_lzo_cache_read,
1160 .write = snd_soc_lzo_cache_write,
1161 .sync = snd_soc_lzo_cache_sync
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001162 },
Mark Brown68d44ee2010-12-21 17:19:56 +00001163#endif
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001164 {
1165 .id = SND_SOC_RBTREE_COMPRESSION,
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001166 .name = "rbtree",
Dimitris Papastamosa7f387d2010-11-11 10:04:59 +00001167 .init = snd_soc_rbtree_cache_init,
1168 .exit = snd_soc_rbtree_cache_exit,
1169 .read = snd_soc_rbtree_cache_read,
1170 .write = snd_soc_rbtree_cache_write,
1171 .sync = snd_soc_rbtree_cache_sync
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001172 }
1173};
1174
1175int snd_soc_cache_init(struct snd_soc_codec *codec)
1176{
1177 int i;
1178
1179 for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
Dimitris Papastamos23bbce32010-12-02 14:53:01 +00001180 if (cache_types[i].id == codec->compress_type)
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001181 break;
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001182
1183 /* Fall back to flat compression */
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001184 if (i == ARRAY_SIZE(cache_types)) {
Mark Brownbe4fcdd2010-12-21 17:09:48 +00001185 dev_warn(codec->dev, "Could not match compress type: %d\n",
1186 codec->compress_type);
1187 i = 0;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001188 }
1189
1190 mutex_init(&codec->cache_rw_mutex);
1191 codec->cache_ops = &cache_types[i];
1192
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001193 if (codec->cache_ops->init) {
1194 if (codec->cache_ops->name)
1195 dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
1196 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001197 return codec->cache_ops->init(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001198 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001199 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001200}
1201
1202/*
1203 * NOTE: keep in mind that this function might be called
1204 * multiple times.
1205 */
1206int snd_soc_cache_exit(struct snd_soc_codec *codec)
1207{
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001208 if (codec->cache_ops && codec->cache_ops->exit) {
1209 if (codec->cache_ops->name)
1210 dev_dbg(codec->dev, "Destroying %s cache for %s codec\n",
1211 codec->cache_ops->name, codec->name);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001212 return codec->cache_ops->exit(codec);
Dimitris Papastamos0d735ea2010-12-06 09:51:57 +00001213 }
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001214 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001215}
1216
1217/**
1218 * snd_soc_cache_read: Fetch the value of a given register from the cache.
1219 *
1220 * @codec: CODEC to configure.
1221 * @reg: The register index.
1222 * @value: The value to be returned.
1223 */
1224int snd_soc_cache_read(struct snd_soc_codec *codec,
1225 unsigned int reg, unsigned int *value)
1226{
1227 int ret;
1228
1229 mutex_lock(&codec->cache_rw_mutex);
1230
1231 if (value && codec->cache_ops && codec->cache_ops->read) {
1232 ret = codec->cache_ops->read(codec, reg, value);
1233 mutex_unlock(&codec->cache_rw_mutex);
1234 return ret;
1235 }
1236
1237 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001238 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001239}
1240EXPORT_SYMBOL_GPL(snd_soc_cache_read);
1241
1242/**
1243 * snd_soc_cache_write: Set the value of a given register in the cache.
1244 *
1245 * @codec: CODEC to configure.
1246 * @reg: The register index.
1247 * @value: The new register value.
1248 */
1249int snd_soc_cache_write(struct snd_soc_codec *codec,
1250 unsigned int reg, unsigned int value)
1251{
1252 int ret;
1253
1254 mutex_lock(&codec->cache_rw_mutex);
1255
1256 if (codec->cache_ops && codec->cache_ops->write) {
1257 ret = codec->cache_ops->write(codec, reg, value);
1258 mutex_unlock(&codec->cache_rw_mutex);
1259 return ret;
1260 }
1261
1262 mutex_unlock(&codec->cache_rw_mutex);
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001263 return -ENOSYS;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001264}
1265EXPORT_SYMBOL_GPL(snd_soc_cache_write);
1266
1267/**
1268 * snd_soc_cache_sync: Sync the register cache with the hardware.
1269 *
1270 * @codec: CODEC to configure.
1271 *
1272 * Any registers that should not be synced should be marked as
1273 * volatile. In general drivers can choose not to use the provided
1274 * syncing functionality if they so require.
1275 */
1276int snd_soc_cache_sync(struct snd_soc_codec *codec)
1277{
1278 int ret;
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001279 const char *name;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001280
1281 if (!codec->cache_sync) {
1282 return 0;
1283 }
1284
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001285 if (!codec->cache_ops || !codec->cache_ops->sync)
Dimitris Papastamosacd61452011-03-22 10:48:49 +00001286 return -ENOSYS;
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001287
Dimitris Papastamosc358e642011-01-21 15:29:02 +00001288 if (codec->cache_ops->name)
1289 name = codec->cache_ops->name;
1290 else
1291 name = "unknown";
1292
Dan Carpenter46fdaa32011-02-07 22:01:41 +03001293 if (codec->cache_ops->name)
1294 dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
1295 codec->cache_ops->name, codec->name);
1296 trace_snd_soc_cache_sync(codec, name, "start");
1297 ret = codec->cache_ops->sync(codec);
1298 if (!ret)
1299 codec->cache_sync = 0;
1300 trace_snd_soc_cache_sync(codec, name, "end");
1301 return ret;
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +00001302}
1303EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
Dimitris Papastamos066d16c2011-01-13 12:20:36 +00001304
1305static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec,
1306 unsigned int reg)
1307{
1308 const struct snd_soc_codec_driver *codec_drv;
1309 unsigned int min, max, index;
1310
1311 codec_drv = codec->driver;
1312 min = 0;
1313 max = codec_drv->reg_access_size - 1;
1314 do {
1315 index = (min + max) / 2;
1316 if (codec_drv->reg_access_default[index].reg == reg)
1317 return index;
1318 if (codec_drv->reg_access_default[index].reg < reg)
1319 min = index + 1;
1320 else
1321 max = index;
1322 } while (min <= max);
1323 return -1;
1324}
1325
1326int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
1327 unsigned int reg)
1328{
1329 int index;
1330
1331 if (reg >= codec->driver->reg_cache_size)
1332 return 1;
1333 index = snd_soc_get_reg_access_index(codec, reg);
1334 if (index < 0)
1335 return 0;
1336 return codec->driver->reg_access_default[index].vol;
1337}
1338EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register);
1339
1340int snd_soc_default_readable_register(struct snd_soc_codec *codec,
1341 unsigned int reg)
1342{
1343 int index;
1344
1345 if (reg >= codec->driver->reg_cache_size)
1346 return 1;
1347 index = snd_soc_get_reg_access_index(codec, reg);
1348 if (index < 0)
1349 return 0;
1350 return codec->driver->reg_access_default[index].read;
1351}
1352EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
Dimitris Papastamos80204542011-03-24 13:45:17 +00001353
1354int snd_soc_default_writable_register(struct snd_soc_codec *codec,
1355 unsigned int reg)
1356{
1357 int index;
1358
1359 if (reg >= codec->driver->reg_cache_size)
1360 return 1;
1361 index = snd_soc_get_reg_access_index(codec, reg);
1362 if (index < 0)
1363 return 0;
1364 return codec->driver->reg_access_default[index].write;
1365}
1366EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);