blob: d214f02cbb65a46314a121948525cb2b005734e1 [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{
21 u16 *cache = codec->reg_cache;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010022
23 if (reg >= codec->driver->reg_cache_size ||
24 snd_soc_codec_volatile_register(codec, reg)) {
25 if (codec->cache_only)
26 return -1;
27
28 return codec->hw_read(codec, reg);
29 }
30
Barry Song63b62ab2010-01-27 11:46:17 +080031 return cache[reg];
32}
33
34static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
35 unsigned int value)
36{
37 u16 *cache = codec->reg_cache;
38 u8 data[2];
39 int ret;
40
Barry Song63b62ab2010-01-27 11:46:17 +080041 data[0] = (reg << 4) | ((value >> 8) & 0x000f);
42 data[1] = value & 0x00ff;
43
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010044 if (!snd_soc_codec_volatile_register(codec, reg) &&
45 reg < codec->driver->reg_cache_size)
46 cache[reg] = value;
Mark Brown8c961bc2010-02-01 18:46:10 +000047
Mark Browna3032b42010-02-01 18:48:03 +000048 if (codec->cache_only) {
49 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +000050 return 0;
Mark Browna3032b42010-02-01 18:48:03 +000051 }
Mark Brown8c961bc2010-02-01 18:46:10 +000052
Mark Brown985d8c42010-05-03 16:25:52 +010053 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
54
Barry Song63b62ab2010-01-27 11:46:17 +080055 ret = codec->hw_write(codec->control_data, data, 2);
56 if (ret == 2)
57 return 0;
58 if (ret < 0)
59 return ret;
60 else
61 return -EIO;
62}
63
64#if defined(CONFIG_SPI_MASTER)
65static int snd_soc_4_12_spi_write(void *control_data, const char *data,
66 int len)
67{
68 struct spi_device *spi = control_data;
69 struct spi_transfer t;
70 struct spi_message m;
71 u8 msg[2];
72
73 if (len <= 0)
74 return 0;
75
76 msg[0] = data[1];
77 msg[1] = data[0];
78
79 spi_message_init(&m);
80 memset(&t, 0, (sizeof t));
81
82 t.tx_buf = &msg[0];
83 t.len = len;
84
85 spi_message_add_tail(&t, &m);
86 spi_sync(spi, &m);
87
88 return len;
89}
90#else
91#define snd_soc_4_12_spi_write NULL
92#endif
93
Mark Brown17a52fd2009-07-05 17:24:50 +010094static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
95 unsigned int reg)
96{
97 u16 *cache = codec->reg_cache;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +010098
99 if (reg >= codec->driver->reg_cache_size ||
100 snd_soc_codec_volatile_register(codec, reg)) {
101 if (codec->cache_only)
102 return -1;
103
104 return codec->hw_read(codec, reg);
105 }
106
Mark Brown17a52fd2009-07-05 17:24:50 +0100107 return cache[reg];
108}
109
110static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
111 unsigned int value)
112{
113 u16 *cache = codec->reg_cache;
114 u8 data[2];
115 int ret;
116
Mark Brown17a52fd2009-07-05 17:24:50 +0100117 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
118 data[1] = value & 0x00ff;
119
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100120 if (!snd_soc_codec_volatile_register(codec, reg) &&
121 reg < codec->driver->reg_cache_size)
122 cache[reg] = value;
Mark Brown8c961bc2010-02-01 18:46:10 +0000123
Mark Browna3032b42010-02-01 18:48:03 +0000124 if (codec->cache_only) {
125 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000126 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000127 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000128
Mark Brown985d8c42010-05-03 16:25:52 +0100129 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
130
Mark Brown17a52fd2009-07-05 17:24:50 +0100131 ret = codec->hw_write(codec->control_data, data, 2);
132 if (ret == 2)
133 return 0;
134 if (ret < 0)
135 return ret;
136 else
137 return -EIO;
138}
139
Mark Brown27ded042009-07-10 23:28:16 +0100140#if defined(CONFIG_SPI_MASTER)
141static int snd_soc_7_9_spi_write(void *control_data, const char *data,
142 int len)
143{
144 struct spi_device *spi = control_data;
145 struct spi_transfer t;
146 struct spi_message m;
147 u8 msg[2];
148
149 if (len <= 0)
150 return 0;
151
152 msg[0] = data[0];
153 msg[1] = data[1];
154
155 spi_message_init(&m);
156 memset(&t, 0, (sizeof t));
157
158 t.tx_buf = &msg[0];
159 t.len = len;
160
161 spi_message_add_tail(&t, &m);
162 spi_sync(spi, &m);
163
164 return len;
165}
166#else
167#define snd_soc_7_9_spi_write NULL
168#endif
169
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900170static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
171 unsigned int value)
172{
173 u8 *cache = codec->reg_cache;
174 u8 data[2];
175
Barry Songf4bee1b2010-03-18 16:17:01 +0800176 reg &= 0xff;
177 data[0] = reg;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900178 data[1] = value & 0xff;
179
Dimitris Papastamos005d65f2010-09-22 16:16:06 +0100180 if (!snd_soc_codec_volatile_register(codec, reg) &&
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100181 reg < codec->driver->reg_cache_size)
182 cache[reg] = value;
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900183
Mark Browna3032b42010-02-01 18:48:03 +0000184 if (codec->cache_only) {
185 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000186 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000187 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000188
Mark Brown985d8c42010-05-03 16:25:52 +0100189 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
190
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900191 if (codec->hw_write(codec->control_data, data, 2) == 2)
192 return 0;
193 else
194 return -EIO;
195}
196
197static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
198 unsigned int reg)
199{
200 u8 *cache = codec->reg_cache;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100201
Barry Songf4bee1b2010-03-18 16:17:01 +0800202 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100203 if (reg >= codec->driver->reg_cache_size ||
204 snd_soc_codec_volatile_register(codec, reg)) {
205 if (codec->cache_only)
206 return -1;
207
208 return codec->hw_read(codec, reg);
209 }
210
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900211 return cache[reg];
212}
213
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100214#if defined(CONFIG_SPI_MASTER)
215static int snd_soc_8_8_spi_write(void *control_data, const char *data,
216 int len)
217{
218 struct spi_device *spi = control_data;
219 struct spi_transfer t;
220 struct spi_message m;
221 u8 msg[2];
222
223 if (len <= 0)
224 return 0;
225
226 msg[0] = data[0];
227 msg[1] = data[1];
228
229 spi_message_init(&m);
230 memset(&t, 0, (sizeof t));
231
232 t.tx_buf = &msg[0];
233 t.len = len;
234
235 spi_message_add_tail(&t, &m);
236 spi_sync(spi, &m);
237
238 return len;
239}
240#else
241#define snd_soc_8_8_spi_write NULL
242#endif
243
Mark Brownafa2f102009-07-10 23:11:24 +0100244static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
245 unsigned int value)
246{
247 u16 *reg_cache = codec->reg_cache;
248 u8 data[3];
249
250 data[0] = reg;
251 data[1] = (value >> 8) & 0xff;
252 data[2] = value & 0xff;
253
Takashi Iwai3e13f652010-09-23 07:40:16 +0200254 if (!snd_soc_codec_volatile_register(codec, reg) &&
255 reg < codec->driver->reg_cache_size)
256 reg_cache[reg] = value;
Mark Brownafa2f102009-07-10 23:11:24 +0100257
Mark Browna3032b42010-02-01 18:48:03 +0000258 if (codec->cache_only) {
259 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000260 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000261 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000262
Mark Brown985d8c42010-05-03 16:25:52 +0100263 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
264
Mark Brownafa2f102009-07-10 23:11:24 +0100265 if (codec->hw_write(codec->control_data, data, 3) == 3)
266 return 0;
267 else
268 return -EIO;
269}
270
271static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
272 unsigned int reg)
273{
274 u16 *cache = codec->reg_cache;
275
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000276 if (reg >= codec->driver->reg_cache_size ||
Mark Brown8c961bc2010-02-01 18:46:10 +0000277 snd_soc_codec_volatile_register(codec, reg)) {
278 if (codec->cache_only)
Dimitris Papastamos391d8a02010-09-21 17:04:07 +0100279 return -1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000280
Mark Brownafa2f102009-07-10 23:11:24 +0100281 return codec->hw_read(codec, reg);
Mark Brown8c961bc2010-02-01 18:46:10 +0000282 } else {
Mark Brownafa2f102009-07-10 23:11:24 +0100283 return cache[reg];
Mark Brown8c961bc2010-02-01 18:46:10 +0000284 }
Mark Brownafa2f102009-07-10 23:11:24 +0100285}
286
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100287#if defined(CONFIG_SPI_MASTER)
288static int snd_soc_8_16_spi_write(void *control_data, const char *data,
289 int len)
290{
291 struct spi_device *spi = control_data;
292 struct spi_transfer t;
293 struct spi_message m;
294 u8 msg[3];
295
296 if (len <= 0)
297 return 0;
298
299 msg[0] = data[0];
300 msg[1] = data[1];
301 msg[2] = data[2];
302
303 spi_message_init(&m);
304 memset(&t, 0, (sizeof t));
305
306 t.tx_buf = &msg[0];
307 t.len = len;
308
309 spi_message_add_tail(&t, &m);
310 spi_sync(spi, &m);
311
312 return len;
313}
314#else
315#define snd_soc_8_16_spi_write NULL
316#endif
317
Randy Dunlap17244c22009-08-10 16:04:39 -0700318#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800319static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
320 unsigned int r)
321{
322 struct i2c_msg xfer[2];
323 u8 reg = r;
324 u8 data;
325 int ret;
326 struct i2c_client *client = codec->control_data;
327
328 /* Write register */
329 xfer[0].addr = client->addr;
330 xfer[0].flags = 0;
331 xfer[0].len = 1;
332 xfer[0].buf = &reg;
333
334 /* Read data */
335 xfer[1].addr = client->addr;
336 xfer[1].flags = I2C_M_RD;
337 xfer[1].len = 1;
338 xfer[1].buf = &data;
339
340 ret = i2c_transfer(client->adapter, xfer, 2);
341 if (ret != 2) {
342 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
343 return 0;
344 }
345
346 return data;
347}
348#else
349#define snd_soc_8_8_read_i2c NULL
350#endif
351
352#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100353static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
354 unsigned int r)
355{
356 struct i2c_msg xfer[2];
357 u8 reg = r;
358 u16 data;
359 int ret;
360 struct i2c_client *client = codec->control_data;
361
362 /* Write register */
363 xfer[0].addr = client->addr;
364 xfer[0].flags = 0;
365 xfer[0].len = 1;
366 xfer[0].buf = &reg;
367
368 /* Read data */
369 xfer[1].addr = client->addr;
370 xfer[1].flags = I2C_M_RD;
371 xfer[1].len = 2;
372 xfer[1].buf = (u8 *)&data;
373
374 ret = i2c_transfer(client->adapter, xfer, 2);
375 if (ret != 2) {
376 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
377 return 0;
378 }
379
380 return (data >> 8) | ((data & 0xff) << 8);
381}
382#else
383#define snd_soc_8_16_read_i2c NULL
384#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100385
Barry Song994dc422010-01-27 11:46:18 +0800386#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
387static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
388 unsigned int r)
389{
390 struct i2c_msg xfer[2];
391 u16 reg = r;
392 u8 data;
393 int ret;
394 struct i2c_client *client = codec->control_data;
395
396 /* Write register */
397 xfer[0].addr = client->addr;
398 xfer[0].flags = 0;
399 xfer[0].len = 2;
400 xfer[0].buf = (u8 *)&reg;
401
402 /* Read data */
403 xfer[1].addr = client->addr;
404 xfer[1].flags = I2C_M_RD;
405 xfer[1].len = 1;
406 xfer[1].buf = &data;
407
408 ret = i2c_transfer(client->adapter, xfer, 2);
409 if (ret != 2) {
410 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
411 return 0;
412 }
413
414 return data;
415}
416#else
417#define snd_soc_16_8_read_i2c NULL
418#endif
419
420static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
421 unsigned int reg)
422{
Cliff Caiac770262010-08-07 11:16:27 -0400423 u8 *cache = codec->reg_cache;
Barry Song994dc422010-01-27 11:46:18 +0800424
425 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100426 if (reg >= codec->driver->reg_cache_size ||
427 snd_soc_codec_volatile_register(codec, reg)) {
428 if (codec->cache_only)
429 return -1;
430
431 return codec->hw_read(codec, reg);
432 }
433
Barry Song994dc422010-01-27 11:46:18 +0800434 return cache[reg];
435}
436
437static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
438 unsigned int value)
439{
Cliff Caiac770262010-08-07 11:16:27 -0400440 u8 *cache = codec->reg_cache;
Barry Song994dc422010-01-27 11:46:18 +0800441 u8 data[3];
442 int ret;
443
Barry Song994dc422010-01-27 11:46:18 +0800444 data[0] = (reg >> 8) & 0xff;
445 data[1] = reg & 0xff;
446 data[2] = value;
447
448 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100449 if (!snd_soc_codec_volatile_register(codec, reg) &&
450 reg < codec->driver->reg_cache_size)
451 cache[reg] = value;
Mark Brown8c961bc2010-02-01 18:46:10 +0000452
Mark Browna3032b42010-02-01 18:48:03 +0000453 if (codec->cache_only) {
454 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000455 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000456 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000457
Mark Brown985d8c42010-05-03 16:25:52 +0100458 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
459
Barry Song994dc422010-01-27 11:46:18 +0800460 ret = codec->hw_write(codec->control_data, data, 3);
461 if (ret == 3)
462 return 0;
463 if (ret < 0)
464 return ret;
465 else
466 return -EIO;
467}
468
469#if defined(CONFIG_SPI_MASTER)
470static int snd_soc_16_8_spi_write(void *control_data, const char *data,
471 int len)
472{
473 struct spi_device *spi = control_data;
474 struct spi_transfer t;
475 struct spi_message m;
476 u8 msg[3];
477
478 if (len <= 0)
479 return 0;
480
481 msg[0] = data[0];
482 msg[1] = data[1];
483 msg[2] = data[2];
484
485 spi_message_init(&m);
486 memset(&t, 0, (sizeof t));
487
488 t.tx_buf = &msg[0];
489 t.len = len;
490
491 spi_message_add_tail(&t, &m);
492 spi_sync(spi, &m);
493
494 return len;
495}
496#else
497#define snd_soc_16_8_spi_write NULL
498#endif
499
Mark Brownbc6552f2010-03-05 16:27:15 +0000500#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
501static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
502 unsigned int r)
503{
504 struct i2c_msg xfer[2];
505 u16 reg = cpu_to_be16(r);
506 u16 data;
507 int ret;
508 struct i2c_client *client = codec->control_data;
509
510 /* Write register */
511 xfer[0].addr = client->addr;
512 xfer[0].flags = 0;
513 xfer[0].len = 2;
514 xfer[0].buf = (u8 *)&reg;
515
516 /* Read data */
517 xfer[1].addr = client->addr;
518 xfer[1].flags = I2C_M_RD;
519 xfer[1].len = 2;
520 xfer[1].buf = (u8 *)&data;
521
522 ret = i2c_transfer(client->adapter, xfer, 2);
523 if (ret != 2) {
524 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
525 return 0;
526 }
527
528 return be16_to_cpu(data);
529}
530#else
531#define snd_soc_16_16_read_i2c NULL
532#endif
533
534static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
535 unsigned int reg)
536{
537 u16 *cache = codec->reg_cache;
538
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000539 if (reg >= codec->driver->reg_cache_size ||
Mark Brownbc6552f2010-03-05 16:27:15 +0000540 snd_soc_codec_volatile_register(codec, reg)) {
541 if (codec->cache_only)
Dimitris Papastamos391d8a02010-09-21 17:04:07 +0100542 return -1;
Mark Brownbc6552f2010-03-05 16:27:15 +0000543
544 return codec->hw_read(codec, reg);
545 }
546
547 return cache[reg];
548}
549
550static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
551 unsigned int value)
552{
553 u16 *cache = codec->reg_cache;
554 u8 data[4];
555 int ret;
556
557 data[0] = (reg >> 8) & 0xff;
558 data[1] = reg & 0xff;
559 data[2] = (value >> 8) & 0xff;
560 data[3] = value & 0xff;
561
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100562 if (!snd_soc_codec_volatile_register(codec, reg) &&
563 reg < codec->driver->reg_cache_size)
564 cache[reg] = value;
Mark Brownbc6552f2010-03-05 16:27:15 +0000565
566 if (codec->cache_only) {
567 codec->cache_sync = 1;
568 return 0;
569 }
570
Mark Brown985d8c42010-05-03 16:25:52 +0100571 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
572
Mark Brownbc6552f2010-03-05 16:27:15 +0000573 ret = codec->hw_write(codec->control_data, data, 4);
574 if (ret == 4)
575 return 0;
576 if (ret < 0)
577 return ret;
578 else
579 return -EIO;
580}
Barry Song994dc422010-01-27 11:46:18 +0800581
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100582#if defined(CONFIG_SPI_MASTER)
583static int snd_soc_16_16_spi_write(void *control_data, const char *data,
584 int len)
585{
586 struct spi_device *spi = control_data;
587 struct spi_transfer t;
588 struct spi_message m;
589 u8 msg[4];
590
591 if (len <= 0)
592 return 0;
593
594 msg[0] = data[0];
595 msg[1] = data[1];
596 msg[2] = data[2];
597 msg[3] = data[3];
598
599 spi_message_init(&m);
600 memset(&t, 0, (sizeof t));
601
602 t.tx_buf = &msg[0];
603 t.len = len;
604
605 spi_message_add_tail(&t, &m);
606 spi_sync(spi, &m);
607
608 return len;
609}
610#else
611#define snd_soc_16_16_spi_write NULL
612#endif
613
Mark Brown17a52fd2009-07-05 17:24:50 +0100614static struct {
615 int addr_bits;
616 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100617 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown27ded042009-07-10 23:28:16 +0100618 int (*spi_write)(void *, const char *, int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100619 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100620 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100621} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700622 {
Barry Song63b62ab2010-01-27 11:46:17 +0800623 .addr_bits = 4, .data_bits = 12,
624 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
625 .spi_write = snd_soc_4_12_spi_write,
626 },
627 {
Mark Brownd62ab352009-09-21 04:21:47 -0700628 .addr_bits = 7, .data_bits = 9,
629 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Barry Song8998c892009-12-31 10:30:34 +0800630 .spi_write = snd_soc_7_9_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700631 },
632 {
633 .addr_bits = 8, .data_bits = 8,
634 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800635 .i2c_read = snd_soc_8_8_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100636 .spi_write = snd_soc_8_8_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700637 },
638 {
639 .addr_bits = 8, .data_bits = 16,
640 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
641 .i2c_read = snd_soc_8_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100642 .spi_write = snd_soc_8_16_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700643 },
Barry Song994dc422010-01-27 11:46:18 +0800644 {
645 .addr_bits = 16, .data_bits = 8,
646 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
647 .i2c_read = snd_soc_16_8_read_i2c,
648 .spi_write = snd_soc_16_8_spi_write,
649 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000650 {
651 .addr_bits = 16, .data_bits = 16,
652 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
653 .i2c_read = snd_soc_16_16_read_i2c,
Dimitris Papastamosf479fd92010-10-04 11:25:13 +0100654 .spi_write = snd_soc_16_16_spi_write,
Mark Brownbc6552f2010-03-05 16:27:15 +0000655 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100656};
657
658/**
659 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
660 *
661 * @codec: CODEC to configure.
662 * @type: Type of cache.
663 * @addr_bits: Number of bits of register address data.
664 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100665 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100666 *
667 * Register formats are frequently shared between many I2C and SPI
668 * devices. In order to promote code reuse the ASoC core provides
669 * some standard implementations of CODEC read and write operations
670 * which can be set up using this function.
671 *
672 * The caller is responsible for allocating and initialising the
673 * actual cache.
674 *
675 * Note that at present this code cannot be used by CODECs with
676 * volatile registers.
677 */
678int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100679 int addr_bits, int data_bits,
680 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100681{
682 int i;
683
Mark Brown17a52fd2009-07-05 17:24:50 +0100684 for (i = 0; i < ARRAY_SIZE(io_types); i++)
685 if (io_types[i].addr_bits == addr_bits &&
686 io_types[i].data_bits == data_bits)
687 break;
688 if (i == ARRAY_SIZE(io_types)) {
689 printk(KERN_ERR
690 "No I/O functions for %d bit address %d bit data\n",
691 addr_bits, data_bits);
692 return -EINVAL;
693 }
694
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000695 codec->driver->write = io_types[i].write;
696 codec->driver->read = io_types[i].read;
Mark Brown17a52fd2009-07-05 17:24:50 +0100697
Mark Brown7084a422009-07-10 22:24:27 +0100698 switch (control) {
699 case SND_SOC_CUSTOM:
700 break;
701
702 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700703#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100704 codec->hw_write = (hw_write_t)i2c_master_send;
705#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100706 if (io_types[i].i2c_read)
707 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100708
709 codec->control_data = container_of(codec->dev,
710 struct i2c_client,
711 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100712 break;
713
714 case SND_SOC_SPI:
Mark Brown27ded042009-07-10 23:28:16 +0100715 if (io_types[i].spi_write)
716 codec->hw_write = io_types[i].spi_write;
Mark Browna6d14342010-08-12 10:59:15 +0100717
718 codec->control_data = container_of(codec->dev,
719 struct spi_device,
720 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100721 break;
722 }
723
Mark Brown17a52fd2009-07-05 17:24:50 +0100724 return 0;
725}
726EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);