blob: cbf9694097b244351b6aa05f7656b1a44427336e [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>
17
Barry Song63b62ab2010-01-27 11:46:17 +080018static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
19 unsigned int reg)
20{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000021 int ret;
22 unsigned int val;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010023
24 if (reg >= codec->driver->reg_cache_size ||
25 snd_soc_codec_volatile_register(codec, reg)) {
26 if (codec->cache_only)
27 return -1;
28
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +000029 BUG_ON(!codec->hw_read);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010030 return codec->hw_read(codec, reg);
31 }
32
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000033 ret = snd_soc_cache_read(codec, reg, &val);
34 if (ret < 0)
35 return -1;
36 return val;
Barry Song63b62ab2010-01-27 11:46:17 +080037}
38
39static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
40 unsigned int value)
41{
Barry Song63b62ab2010-01-27 11:46:17 +080042 u8 data[2];
43 int ret;
44
Barry Song63b62ab2010-01-27 11:46:17 +080045 data[0] = (reg << 4) | ((value >> 8) & 0x000f);
46 data[1] = value & 0x00ff;
47
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010048 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +000049 reg < codec->driver->reg_cache_size) {
50 ret = snd_soc_cache_write(codec, reg, value);
51 if (ret < 0)
52 return -1;
53 }
Mark Brown8c961bc2010-02-01 18:46:10 +000054
Mark Browna3032b42010-02-01 18:48:03 +000055 if (codec->cache_only) {
56 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +000057 return 0;
Mark Browna3032b42010-02-01 18:48:03 +000058 }
Mark Brown8c961bc2010-02-01 18:46:10 +000059
Barry Song63b62ab2010-01-27 11:46:17 +080060 ret = codec->hw_write(codec->control_data, data, 2);
61 if (ret == 2)
62 return 0;
63 if (ret < 0)
64 return ret;
65 else
66 return -EIO;
67}
68
69#if defined(CONFIG_SPI_MASTER)
70static int snd_soc_4_12_spi_write(void *control_data, const char *data,
71 int len)
72{
73 struct spi_device *spi = control_data;
74 struct spi_transfer t;
75 struct spi_message m;
76 u8 msg[2];
77
78 if (len <= 0)
79 return 0;
80
81 msg[0] = data[1];
82 msg[1] = data[0];
83
84 spi_message_init(&m);
85 memset(&t, 0, (sizeof t));
86
87 t.tx_buf = &msg[0];
88 t.len = len;
89
90 spi_message_add_tail(&t, &m);
91 spi_sync(spi, &m);
92
93 return len;
94}
95#else
96#define snd_soc_4_12_spi_write NULL
97#endif
98
Mark Brown17a52fd2009-07-05 17:24:50 +010099static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
100 unsigned int reg)
101{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000102 int ret;
103 unsigned int val;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100104
105 if (reg >= codec->driver->reg_cache_size ||
106 snd_soc_codec_volatile_register(codec, reg)) {
107 if (codec->cache_only)
108 return -1;
109
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +0000110 BUG_ON(!codec->hw_read);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100111 return codec->hw_read(codec, reg);
112 }
113
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000114 ret = snd_soc_cache_read(codec, reg, &val);
115 if (ret < 0)
116 return -1;
117 return val;
Mark Brown17a52fd2009-07-05 17:24:50 +0100118}
119
120static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
121 unsigned int value)
122{
Mark Brown17a52fd2009-07-05 17:24:50 +0100123 u8 data[2];
124 int ret;
125
Mark Brown17a52fd2009-07-05 17:24:50 +0100126 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
127 data[1] = value & 0x00ff;
128
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100129 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000130 reg < codec->driver->reg_cache_size) {
131 ret = snd_soc_cache_write(codec, reg, value);
132 if (ret < 0)
133 return -1;
134 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000135
Mark Browna3032b42010-02-01 18:48:03 +0000136 if (codec->cache_only) {
137 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000138 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000139 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000140
Mark Brown17a52fd2009-07-05 17:24:50 +0100141 ret = codec->hw_write(codec->control_data, data, 2);
142 if (ret == 2)
143 return 0;
144 if (ret < 0)
145 return ret;
146 else
147 return -EIO;
148}
149
Mark Brown27ded042009-07-10 23:28:16 +0100150#if defined(CONFIG_SPI_MASTER)
151static int snd_soc_7_9_spi_write(void *control_data, const char *data,
152 int len)
153{
154 struct spi_device *spi = control_data;
155 struct spi_transfer t;
156 struct spi_message m;
157 u8 msg[2];
158
159 if (len <= 0)
160 return 0;
161
162 msg[0] = data[0];
163 msg[1] = data[1];
164
165 spi_message_init(&m);
166 memset(&t, 0, (sizeof t));
167
168 t.tx_buf = &msg[0];
169 t.len = len;
170
171 spi_message_add_tail(&t, &m);
172 spi_sync(spi, &m);
173
174 return len;
175}
176#else
177#define snd_soc_7_9_spi_write NULL
178#endif
179
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900180static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
181 unsigned int value)
182{
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900183 u8 data[2];
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000184 int ret;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900185
Barry Songf4bee1b2010-03-18 16:17:01 +0800186 reg &= 0xff;
187 data[0] = reg;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900188 data[1] = value & 0xff;
189
Dimitris Papastamos005d65f2010-09-22 16:16:06 +0100190 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000191 reg < codec->driver->reg_cache_size) {
192 ret = snd_soc_cache_write(codec, reg, value);
193 if (ret < 0)
194 return -1;
195 }
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900196
Mark Browna3032b42010-02-01 18:48:03 +0000197 if (codec->cache_only) {
198 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000199 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000200 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000201
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900202 if (codec->hw_write(codec->control_data, data, 2) == 2)
203 return 0;
204 else
205 return -EIO;
206}
207
208static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
209 unsigned int reg)
210{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000211 int ret;
212 unsigned int val;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100213
Barry Songf4bee1b2010-03-18 16:17:01 +0800214 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100215 if (reg >= codec->driver->reg_cache_size ||
216 snd_soc_codec_volatile_register(codec, reg)) {
217 if (codec->cache_only)
218 return -1;
219
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +0000220 BUG_ON(!codec->hw_read);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100221 return codec->hw_read(codec, reg);
222 }
223
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000224 ret = snd_soc_cache_read(codec, reg, &val);
225 if (ret < 0)
226 return -1;
227 return val;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900228}
229
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100230#if defined(CONFIG_SPI_MASTER)
231static int snd_soc_8_8_spi_write(void *control_data, const char *data,
232 int len)
233{
234 struct spi_device *spi = control_data;
235 struct spi_transfer t;
236 struct spi_message m;
237 u8 msg[2];
238
239 if (len <= 0)
240 return 0;
241
242 msg[0] = data[0];
243 msg[1] = data[1];
244
245 spi_message_init(&m);
246 memset(&t, 0, (sizeof t));
247
248 t.tx_buf = &msg[0];
249 t.len = len;
250
251 spi_message_add_tail(&t, &m);
252 spi_sync(spi, &m);
253
254 return len;
255}
256#else
257#define snd_soc_8_8_spi_write NULL
258#endif
259
Mark Brownafa2f102009-07-10 23:11:24 +0100260static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
261 unsigned int value)
262{
Mark Brownafa2f102009-07-10 23:11:24 +0100263 u8 data[3];
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000264 int ret;
Mark Brownafa2f102009-07-10 23:11:24 +0100265
266 data[0] = reg;
267 data[1] = (value >> 8) & 0xff;
268 data[2] = value & 0xff;
269
Takashi Iwai3e13f652010-09-23 07:40:16 +0200270 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000271 reg < codec->driver->reg_cache_size) {
272 ret = snd_soc_cache_write(codec, reg, value);
273 if (ret < 0)
274 return -1;
275 }
Mark Brownafa2f102009-07-10 23:11:24 +0100276
Mark Browna3032b42010-02-01 18:48:03 +0000277 if (codec->cache_only) {
278 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000279 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000280 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000281
Mark Brownafa2f102009-07-10 23:11:24 +0100282 if (codec->hw_write(codec->control_data, data, 3) == 3)
283 return 0;
284 else
285 return -EIO;
286}
287
288static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
289 unsigned int reg)
290{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000291 int ret;
292 unsigned int val;
Mark Brownafa2f102009-07-10 23:11:24 +0100293
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000294 if (reg >= codec->driver->reg_cache_size ||
Mark Brown8c961bc2010-02-01 18:46:10 +0000295 snd_soc_codec_volatile_register(codec, reg)) {
296 if (codec->cache_only)
Dimitris Papastamos391d8a02010-09-21 17:04:07 +0100297 return -1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000298
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +0000299 BUG_ON(!codec->hw_read);
Mark Brownafa2f102009-07-10 23:11:24 +0100300 return codec->hw_read(codec, reg);
Mark Brown8c961bc2010-02-01 18:46:10 +0000301 }
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000302
303 ret = snd_soc_cache_read(codec, reg, &val);
304 if (ret < 0)
305 return -1;
306 return val;
Mark Brownafa2f102009-07-10 23:11:24 +0100307}
308
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100309#if defined(CONFIG_SPI_MASTER)
310static int snd_soc_8_16_spi_write(void *control_data, const char *data,
311 int len)
312{
313 struct spi_device *spi = control_data;
314 struct spi_transfer t;
315 struct spi_message m;
316 u8 msg[3];
317
318 if (len <= 0)
319 return 0;
320
321 msg[0] = data[0];
322 msg[1] = data[1];
323 msg[2] = data[2];
324
325 spi_message_init(&m);
326 memset(&t, 0, (sizeof t));
327
328 t.tx_buf = &msg[0];
329 t.len = len;
330
331 spi_message_add_tail(&t, &m);
332 spi_sync(spi, &m);
333
334 return len;
335}
336#else
337#define snd_soc_8_16_spi_write NULL
338#endif
339
Randy Dunlap17244c22009-08-10 16:04:39 -0700340#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800341static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
342 unsigned int r)
343{
344 struct i2c_msg xfer[2];
345 u8 reg = r;
346 u8 data;
347 int ret;
348 struct i2c_client *client = codec->control_data;
349
350 /* Write register */
351 xfer[0].addr = client->addr;
352 xfer[0].flags = 0;
353 xfer[0].len = 1;
354 xfer[0].buf = &reg;
355
356 /* Read data */
357 xfer[1].addr = client->addr;
358 xfer[1].flags = I2C_M_RD;
359 xfer[1].len = 1;
360 xfer[1].buf = &data;
361
362 ret = i2c_transfer(client->adapter, xfer, 2);
363 if (ret != 2) {
364 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
365 return 0;
366 }
367
368 return data;
369}
370#else
371#define snd_soc_8_8_read_i2c NULL
372#endif
373
374#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100375static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
376 unsigned int r)
377{
378 struct i2c_msg xfer[2];
379 u8 reg = r;
380 u16 data;
381 int ret;
382 struct i2c_client *client = codec->control_data;
383
384 /* Write register */
385 xfer[0].addr = client->addr;
386 xfer[0].flags = 0;
387 xfer[0].len = 1;
388 xfer[0].buf = &reg;
389
390 /* Read data */
391 xfer[1].addr = client->addr;
392 xfer[1].flags = I2C_M_RD;
393 xfer[1].len = 2;
394 xfer[1].buf = (u8 *)&data;
395
396 ret = i2c_transfer(client->adapter, xfer, 2);
397 if (ret != 2) {
398 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
399 return 0;
400 }
401
402 return (data >> 8) | ((data & 0xff) << 8);
403}
404#else
405#define snd_soc_8_16_read_i2c NULL
406#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100407
Barry Song994dc422010-01-27 11:46:18 +0800408#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
409static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
410 unsigned int r)
411{
412 struct i2c_msg xfer[2];
413 u16 reg = r;
414 u8 data;
415 int ret;
416 struct i2c_client *client = codec->control_data;
417
418 /* Write register */
419 xfer[0].addr = client->addr;
420 xfer[0].flags = 0;
421 xfer[0].len = 2;
422 xfer[0].buf = (u8 *)&reg;
423
424 /* Read data */
425 xfer[1].addr = client->addr;
426 xfer[1].flags = I2C_M_RD;
427 xfer[1].len = 1;
428 xfer[1].buf = &data;
429
430 ret = i2c_transfer(client->adapter, xfer, 2);
431 if (ret != 2) {
432 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
433 return 0;
434 }
435
436 return data;
437}
438#else
439#define snd_soc_16_8_read_i2c NULL
440#endif
441
442static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
443 unsigned int reg)
444{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000445 int ret;
446 unsigned int val;
Barry Song994dc422010-01-27 11:46:18 +0800447
448 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100449 if (reg >= codec->driver->reg_cache_size ||
450 snd_soc_codec_volatile_register(codec, reg)) {
451 if (codec->cache_only)
452 return -1;
453
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +0000454 BUG_ON(!codec->hw_read);
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100455 return codec->hw_read(codec, reg);
456 }
457
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000458 ret = snd_soc_cache_read(codec, reg, &val);
459 if (ret < 0)
460 return -1;
461 return val;
Barry Song994dc422010-01-27 11:46:18 +0800462}
463
464static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
465 unsigned int value)
466{
Barry Song994dc422010-01-27 11:46:18 +0800467 u8 data[3];
468 int ret;
469
Barry Song994dc422010-01-27 11:46:18 +0800470 data[0] = (reg >> 8) & 0xff;
471 data[1] = reg & 0xff;
472 data[2] = value;
473
474 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100475 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000476 reg < codec->driver->reg_cache_size) {
477 ret = snd_soc_cache_write(codec, reg, value);
478 if (ret < 0)
479 return -1;
480 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000481
Mark Browna3032b42010-02-01 18:48:03 +0000482 if (codec->cache_only) {
483 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000484 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000485 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000486
Barry Song994dc422010-01-27 11:46:18 +0800487 ret = codec->hw_write(codec->control_data, data, 3);
488 if (ret == 3)
489 return 0;
490 if (ret < 0)
491 return ret;
492 else
493 return -EIO;
494}
495
496#if defined(CONFIG_SPI_MASTER)
497static int snd_soc_16_8_spi_write(void *control_data, const char *data,
498 int len)
499{
500 struct spi_device *spi = control_data;
501 struct spi_transfer t;
502 struct spi_message m;
503 u8 msg[3];
504
505 if (len <= 0)
506 return 0;
507
508 msg[0] = data[0];
509 msg[1] = data[1];
510 msg[2] = data[2];
511
512 spi_message_init(&m);
513 memset(&t, 0, (sizeof t));
514
515 t.tx_buf = &msg[0];
516 t.len = len;
517
518 spi_message_add_tail(&t, &m);
519 spi_sync(spi, &m);
520
521 return len;
522}
523#else
524#define snd_soc_16_8_spi_write NULL
525#endif
526
Mark Brownbc6552f2010-03-05 16:27:15 +0000527#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
528static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
529 unsigned int r)
530{
531 struct i2c_msg xfer[2];
532 u16 reg = cpu_to_be16(r);
533 u16 data;
534 int ret;
535 struct i2c_client *client = codec->control_data;
536
537 /* Write register */
538 xfer[0].addr = client->addr;
539 xfer[0].flags = 0;
540 xfer[0].len = 2;
541 xfer[0].buf = (u8 *)&reg;
542
543 /* Read data */
544 xfer[1].addr = client->addr;
545 xfer[1].flags = I2C_M_RD;
546 xfer[1].len = 2;
547 xfer[1].buf = (u8 *)&data;
548
549 ret = i2c_transfer(client->adapter, xfer, 2);
550 if (ret != 2) {
551 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
552 return 0;
553 }
554
555 return be16_to_cpu(data);
556}
557#else
558#define snd_soc_16_16_read_i2c NULL
559#endif
560
561static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
562 unsigned int reg)
563{
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000564 int ret;
565 unsigned int val;
Mark Brownbc6552f2010-03-05 16:27:15 +0000566
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000567 if (reg >= codec->driver->reg_cache_size ||
Mark Brownbc6552f2010-03-05 16:27:15 +0000568 snd_soc_codec_volatile_register(codec, reg)) {
569 if (codec->cache_only)
Dimitris Papastamos391d8a02010-09-21 17:04:07 +0100570 return -1;
Mark Brownbc6552f2010-03-05 16:27:15 +0000571
Dimitris Papastamos5aaa0622010-11-08 15:37:07 +0000572 BUG_ON(!codec->hw_read);
Mark Brownbc6552f2010-03-05 16:27:15 +0000573 return codec->hw_read(codec, reg);
574 }
575
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000576 ret = snd_soc_cache_read(codec, reg, &val);
577 if (ret < 0)
578 return -1;
579
580 return val;
Mark Brownbc6552f2010-03-05 16:27:15 +0000581}
582
583static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
584 unsigned int value)
585{
Mark Brownbc6552f2010-03-05 16:27:15 +0000586 u8 data[4];
587 int ret;
588
589 data[0] = (reg >> 8) & 0xff;
590 data[1] = reg & 0xff;
591 data[2] = (value >> 8) & 0xff;
592 data[3] = value & 0xff;
593
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100594 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000595 reg < codec->driver->reg_cache_size) {
596 ret = snd_soc_cache_write(codec, reg, value);
597 if (ret < 0)
598 return -1;
599 }
Mark Brownbc6552f2010-03-05 16:27:15 +0000600
601 if (codec->cache_only) {
602 codec->cache_sync = 1;
603 return 0;
604 }
605
606 ret = codec->hw_write(codec->control_data, data, 4);
607 if (ret == 4)
608 return 0;
609 if (ret < 0)
610 return ret;
611 else
612 return -EIO;
613}
Barry Song994dc422010-01-27 11:46:18 +0800614
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100615#if defined(CONFIG_SPI_MASTER)
616static int snd_soc_16_16_spi_write(void *control_data, const char *data,
617 int len)
618{
619 struct spi_device *spi = control_data;
620 struct spi_transfer t;
621 struct spi_message m;
622 u8 msg[4];
623
624 if (len <= 0)
625 return 0;
626
627 msg[0] = data[0];
628 msg[1] = data[1];
629 msg[2] = data[2];
630 msg[3] = data[3];
631
632 spi_message_init(&m);
633 memset(&t, 0, (sizeof t));
634
635 t.tx_buf = &msg[0];
636 t.len = len;
637
638 spi_message_add_tail(&t, &m);
639 spi_sync(spi, &m);
640
641 return len;
642}
643#else
644#define snd_soc_16_16_spi_write NULL
645#endif
646
Mark Brown17a52fd2009-07-05 17:24:50 +0100647static struct {
648 int addr_bits;
649 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100650 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown27ded042009-07-10 23:28:16 +0100651 int (*spi_write)(void *, const char *, int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100652 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100653 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100654} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700655 {
Barry Song63b62ab2010-01-27 11:46:17 +0800656 .addr_bits = 4, .data_bits = 12,
657 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
658 .spi_write = snd_soc_4_12_spi_write,
659 },
660 {
Mark Brownd62ab352009-09-21 04:21:47 -0700661 .addr_bits = 7, .data_bits = 9,
662 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Barry Song8998c892009-12-31 10:30:34 +0800663 .spi_write = snd_soc_7_9_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700664 },
665 {
666 .addr_bits = 8, .data_bits = 8,
667 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800668 .i2c_read = snd_soc_8_8_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100669 .spi_write = snd_soc_8_8_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700670 },
671 {
672 .addr_bits = 8, .data_bits = 16,
673 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
674 .i2c_read = snd_soc_8_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100675 .spi_write = snd_soc_8_16_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700676 },
Barry Song994dc422010-01-27 11:46:18 +0800677 {
678 .addr_bits = 16, .data_bits = 8,
679 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
680 .i2c_read = snd_soc_16_8_read_i2c,
681 .spi_write = snd_soc_16_8_spi_write,
682 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000683 {
684 .addr_bits = 16, .data_bits = 16,
685 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
686 .i2c_read = snd_soc_16_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100687 .spi_write = snd_soc_16_16_spi_write,
Mark Brownbc6552f2010-03-05 16:27:15 +0000688 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100689};
690
691/**
692 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
693 *
694 * @codec: CODEC to configure.
695 * @type: Type of cache.
696 * @addr_bits: Number of bits of register address data.
697 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100698 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100699 *
700 * Register formats are frequently shared between many I2C and SPI
701 * devices. In order to promote code reuse the ASoC core provides
702 * some standard implementations of CODEC read and write operations
703 * which can be set up using this function.
704 *
705 * The caller is responsible for allocating and initialising the
706 * actual cache.
707 *
708 * Note that at present this code cannot be used by CODECs with
709 * volatile registers.
710 */
711int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100712 int addr_bits, int data_bits,
713 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100714{
715 int i;
716
Mark Brown17a52fd2009-07-05 17:24:50 +0100717 for (i = 0; i < ARRAY_SIZE(io_types); i++)
718 if (io_types[i].addr_bits == addr_bits &&
719 io_types[i].data_bits == data_bits)
720 break;
721 if (i == ARRAY_SIZE(io_types)) {
722 printk(KERN_ERR
723 "No I/O functions for %d bit address %d bit data\n",
724 addr_bits, data_bits);
725 return -EINVAL;
726 }
727
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000728 codec->driver->write = io_types[i].write;
729 codec->driver->read = io_types[i].read;
Mark Brown17a52fd2009-07-05 17:24:50 +0100730
Mark Brown7084a422009-07-10 22:24:27 +0100731 switch (control) {
732 case SND_SOC_CUSTOM:
733 break;
734
735 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700736#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100737 codec->hw_write = (hw_write_t)i2c_master_send;
738#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100739 if (io_types[i].i2c_read)
740 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100741
742 codec->control_data = container_of(codec->dev,
743 struct i2c_client,
744 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100745 break;
746
747 case SND_SOC_SPI:
Mark Brown27ded042009-07-10 23:28:16 +0100748 if (io_types[i].spi_write)
749 codec->hw_write = io_types[i].spi_write;
Mark Browna6d14342010-08-12 10:59:15 +0100750
751 codec->control_data = container_of(codec->dev,
752 struct spi_device,
753 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100754 break;
755 }
756
Mark Brown17a52fd2009-07-05 17:24:50 +0100757 return 0;
758}
759EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
Dimitris Papastamos7a30a3d2010-11-11 10:04:57 +0000760
761static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
762{
763 int i;
764 struct snd_soc_codec_driver *codec_drv;
765 unsigned int val;
766
767 codec_drv = codec->driver;
768 for (i = 0; i < codec_drv->reg_cache_size; ++i) {
769 snd_soc_cache_read(codec, i, &val);
770 if (codec_drv->reg_cache_default) {
771 switch (codec_drv->reg_word_size) {
772 case 1: {
773 const u8 *cache;
774
775 cache = codec_drv->reg_cache_default;
776 if (cache[i] == val)
777 continue;
778 }
779 break;
780 case 2: {
781 const u16 *cache;
782
783 cache = codec_drv->reg_cache_default;
784 if (cache[i] == val)
785 continue;
786 }
787 break;
788 default:
789 BUG();
790 }
791 }
792 snd_soc_write(codec, i, val);
793 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
794 i, val);
795 }
796 return 0;
797}
798
799static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
800 unsigned int reg, unsigned int value)
801{
802 switch (codec->driver->reg_word_size) {
803 case 1: {
804 u8 *cache;
805
806 cache = codec->reg_cache;
807 cache[reg] = value;
808 }
809 break;
810 case 2: {
811 u16 *cache;
812
813 cache = codec->reg_cache;
814 cache[reg] = value;
815 }
816 break;
817 default:
818 BUG();
819 }
820
821 return 0;
822}
823
824static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
825 unsigned int reg, unsigned int *value)
826{
827 switch (codec->driver->reg_word_size) {
828 case 1: {
829 u8 *cache;
830
831 cache = codec->reg_cache;
832 *value = cache[reg];
833 }
834 break;
835 case 2: {
836 u16 *cache;
837
838 cache = codec->reg_cache;
839 *value = cache[reg];
840 }
841 break;
842 default:
843 BUG();
844 }
845
846 return 0;
847}
848
849static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
850{
851 if (!codec->reg_cache)
852 return 0;
853 kfree(codec->reg_cache);
854 codec->reg_cache = NULL;
855 return 0;
856}
857
858static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
859{
860 struct snd_soc_codec_driver *codec_drv;
861 size_t reg_size;
862
863 codec_drv = codec->driver;
864 reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
865
866 if (codec_drv->reg_cache_default)
867 codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
868 reg_size, GFP_KERNEL);
869 else
870 codec->reg_cache = kzalloc(reg_size, GFP_KERNEL);
871 if (!codec->reg_cache)
872 return -ENOMEM;
873
874 return 0;
875}
876
877/* an array of all supported compression types */
878static const struct snd_soc_cache_ops cache_types[] = {
879 {
880 .id = SND_SOC_NO_COMPRESSION,
881 .init = snd_soc_flat_cache_init,
882 .exit = snd_soc_flat_cache_exit,
883 .read = snd_soc_flat_cache_read,
884 .write = snd_soc_flat_cache_write,
885 .sync = snd_soc_flat_cache_sync
886 }
887};
888
889int snd_soc_cache_init(struct snd_soc_codec *codec)
890{
891 int i;
892
893 for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
894 if (cache_types[i].id == codec->driver->compress_type)
895 break;
896 if (i == ARRAY_SIZE(cache_types)) {
897 dev_err(codec->dev, "Could not match compress type: %d\n",
898 codec->driver->compress_type);
899 return -EINVAL;
900 }
901
902 mutex_init(&codec->cache_rw_mutex);
903 codec->cache_ops = &cache_types[i];
904
905 if (codec->cache_ops->init)
906 return codec->cache_ops->init(codec);
907 return -EINVAL;
908}
909
910/*
911 * NOTE: keep in mind that this function might be called
912 * multiple times.
913 */
914int snd_soc_cache_exit(struct snd_soc_codec *codec)
915{
916 if (codec->cache_ops && codec->cache_ops->exit)
917 return codec->cache_ops->exit(codec);
918 return -EINVAL;
919}
920
921/**
922 * snd_soc_cache_read: Fetch the value of a given register from the cache.
923 *
924 * @codec: CODEC to configure.
925 * @reg: The register index.
926 * @value: The value to be returned.
927 */
928int snd_soc_cache_read(struct snd_soc_codec *codec,
929 unsigned int reg, unsigned int *value)
930{
931 int ret;
932
933 mutex_lock(&codec->cache_rw_mutex);
934
935 if (value && codec->cache_ops && codec->cache_ops->read) {
936 ret = codec->cache_ops->read(codec, reg, value);
937 mutex_unlock(&codec->cache_rw_mutex);
938 return ret;
939 }
940
941 mutex_unlock(&codec->cache_rw_mutex);
942 return -EINVAL;
943}
944EXPORT_SYMBOL_GPL(snd_soc_cache_read);
945
946/**
947 * snd_soc_cache_write: Set the value of a given register in the cache.
948 *
949 * @codec: CODEC to configure.
950 * @reg: The register index.
951 * @value: The new register value.
952 */
953int snd_soc_cache_write(struct snd_soc_codec *codec,
954 unsigned int reg, unsigned int value)
955{
956 int ret;
957
958 mutex_lock(&codec->cache_rw_mutex);
959
960 if (codec->cache_ops && codec->cache_ops->write) {
961 ret = codec->cache_ops->write(codec, reg, value);
962 mutex_unlock(&codec->cache_rw_mutex);
963 return ret;
964 }
965
966 mutex_unlock(&codec->cache_rw_mutex);
967 return -EINVAL;
968}
969EXPORT_SYMBOL_GPL(snd_soc_cache_write);
970
971/**
972 * snd_soc_cache_sync: Sync the register cache with the hardware.
973 *
974 * @codec: CODEC to configure.
975 *
976 * Any registers that should not be synced should be marked as
977 * volatile. In general drivers can choose not to use the provided
978 * syncing functionality if they so require.
979 */
980int snd_soc_cache_sync(struct snd_soc_codec *codec)
981{
982 int ret;
983
984 if (!codec->cache_sync) {
985 return 0;
986 }
987
988 if (codec->cache_ops && codec->cache_ops->sync) {
989 ret = codec->cache_ops->sync(codec);
990 if (!ret)
991 codec->cache_sync = 0;
992 return ret;
993 }
994
995 return -EINVAL;
996}
997EXPORT_SYMBOL_GPL(snd_soc_cache_sync);