blob: 62f1e2b776c47bc25ea394cdfd140dd7f424d454 [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
Mark Brownafa2f102009-07-10 23:11:24 +0100214static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
215 unsigned int value)
216{
217 u16 *reg_cache = codec->reg_cache;
218 u8 data[3];
219
220 data[0] = reg;
221 data[1] = (value >> 8) & 0xff;
222 data[2] = value & 0xff;
223
Takashi Iwai3e13f652010-09-23 07:40:16 +0200224 if (!snd_soc_codec_volatile_register(codec, reg) &&
225 reg < codec->driver->reg_cache_size)
226 reg_cache[reg] = value;
Mark Brownafa2f102009-07-10 23:11:24 +0100227
Mark Browna3032b42010-02-01 18:48:03 +0000228 if (codec->cache_only) {
229 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000230 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000231 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000232
Mark Brown985d8c42010-05-03 16:25:52 +0100233 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
234
Mark Brownafa2f102009-07-10 23:11:24 +0100235 if (codec->hw_write(codec->control_data, data, 3) == 3)
236 return 0;
237 else
238 return -EIO;
239}
240
241static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
242 unsigned int reg)
243{
244 u16 *cache = codec->reg_cache;
245
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000246 if (reg >= codec->driver->reg_cache_size ||
Mark Brown8c961bc2010-02-01 18:46:10 +0000247 snd_soc_codec_volatile_register(codec, reg)) {
248 if (codec->cache_only)
Dimitris Papastamos391d8a02010-09-21 17:04:07 +0100249 return -1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000250
Mark Brownafa2f102009-07-10 23:11:24 +0100251 return codec->hw_read(codec, reg);
Mark Brown8c961bc2010-02-01 18:46:10 +0000252 } else {
Mark Brownafa2f102009-07-10 23:11:24 +0100253 return cache[reg];
Mark Brown8c961bc2010-02-01 18:46:10 +0000254 }
Mark Brownafa2f102009-07-10 23:11:24 +0100255}
256
Randy Dunlap17244c22009-08-10 16:04:39 -0700257#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800258static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
259 unsigned int r)
260{
261 struct i2c_msg xfer[2];
262 u8 reg = r;
263 u8 data;
264 int ret;
265 struct i2c_client *client = codec->control_data;
266
267 /* Write register */
268 xfer[0].addr = client->addr;
269 xfer[0].flags = 0;
270 xfer[0].len = 1;
271 xfer[0].buf = &reg;
272
273 /* Read data */
274 xfer[1].addr = client->addr;
275 xfer[1].flags = I2C_M_RD;
276 xfer[1].len = 1;
277 xfer[1].buf = &data;
278
279 ret = i2c_transfer(client->adapter, xfer, 2);
280 if (ret != 2) {
281 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
282 return 0;
283 }
284
285 return data;
286}
287#else
288#define snd_soc_8_8_read_i2c NULL
289#endif
290
291#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100292static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
293 unsigned int r)
294{
295 struct i2c_msg xfer[2];
296 u8 reg = r;
297 u16 data;
298 int ret;
299 struct i2c_client *client = codec->control_data;
300
301 /* Write register */
302 xfer[0].addr = client->addr;
303 xfer[0].flags = 0;
304 xfer[0].len = 1;
305 xfer[0].buf = &reg;
306
307 /* Read data */
308 xfer[1].addr = client->addr;
309 xfer[1].flags = I2C_M_RD;
310 xfer[1].len = 2;
311 xfer[1].buf = (u8 *)&data;
312
313 ret = i2c_transfer(client->adapter, xfer, 2);
314 if (ret != 2) {
315 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
316 return 0;
317 }
318
319 return (data >> 8) | ((data & 0xff) << 8);
320}
321#else
322#define snd_soc_8_16_read_i2c NULL
323#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100324
Barry Song994dc422010-01-27 11:46:18 +0800325#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
326static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
327 unsigned int r)
328{
329 struct i2c_msg xfer[2];
330 u16 reg = r;
331 u8 data;
332 int ret;
333 struct i2c_client *client = codec->control_data;
334
335 /* Write register */
336 xfer[0].addr = client->addr;
337 xfer[0].flags = 0;
338 xfer[0].len = 2;
339 xfer[0].buf = (u8 *)&reg;
340
341 /* Read data */
342 xfer[1].addr = client->addr;
343 xfer[1].flags = I2C_M_RD;
344 xfer[1].len = 1;
345 xfer[1].buf = &data;
346
347 ret = i2c_transfer(client->adapter, xfer, 2);
348 if (ret != 2) {
349 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
350 return 0;
351 }
352
353 return data;
354}
355#else
356#define snd_soc_16_8_read_i2c NULL
357#endif
358
359static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
360 unsigned int reg)
361{
Cliff Caiac770262010-08-07 11:16:27 -0400362 u8 *cache = codec->reg_cache;
Barry Song994dc422010-01-27 11:46:18 +0800363
364 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100365 if (reg >= codec->driver->reg_cache_size ||
366 snd_soc_codec_volatile_register(codec, reg)) {
367 if (codec->cache_only)
368 return -1;
369
370 return codec->hw_read(codec, reg);
371 }
372
Barry Song994dc422010-01-27 11:46:18 +0800373 return cache[reg];
374}
375
376static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
377 unsigned int value)
378{
Cliff Caiac770262010-08-07 11:16:27 -0400379 u8 *cache = codec->reg_cache;
Barry Song994dc422010-01-27 11:46:18 +0800380 u8 data[3];
381 int ret;
382
Barry Song994dc422010-01-27 11:46:18 +0800383 data[0] = (reg >> 8) & 0xff;
384 data[1] = reg & 0xff;
385 data[2] = value;
386
387 reg &= 0xff;
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100388 if (!snd_soc_codec_volatile_register(codec, reg) &&
389 reg < codec->driver->reg_cache_size)
390 cache[reg] = value;
Mark Brown8c961bc2010-02-01 18:46:10 +0000391
Mark Browna3032b42010-02-01 18:48:03 +0000392 if (codec->cache_only) {
393 codec->cache_sync = 1;
Mark Brown8c961bc2010-02-01 18:46:10 +0000394 return 0;
Mark Browna3032b42010-02-01 18:48:03 +0000395 }
Mark Brown8c961bc2010-02-01 18:46:10 +0000396
Mark Brown985d8c42010-05-03 16:25:52 +0100397 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
398
Barry Song994dc422010-01-27 11:46:18 +0800399 ret = codec->hw_write(codec->control_data, data, 3);
400 if (ret == 3)
401 return 0;
402 if (ret < 0)
403 return ret;
404 else
405 return -EIO;
406}
407
408#if defined(CONFIG_SPI_MASTER)
409static int snd_soc_16_8_spi_write(void *control_data, const char *data,
410 int len)
411{
412 struct spi_device *spi = control_data;
413 struct spi_transfer t;
414 struct spi_message m;
415 u8 msg[3];
416
417 if (len <= 0)
418 return 0;
419
420 msg[0] = data[0];
421 msg[1] = data[1];
422 msg[2] = data[2];
423
424 spi_message_init(&m);
425 memset(&t, 0, (sizeof t));
426
427 t.tx_buf = &msg[0];
428 t.len = len;
429
430 spi_message_add_tail(&t, &m);
431 spi_sync(spi, &m);
432
433 return len;
434}
435#else
436#define snd_soc_16_8_spi_write NULL
437#endif
438
Mark Brownbc6552f2010-03-05 16:27:15 +0000439#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
440static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
441 unsigned int r)
442{
443 struct i2c_msg xfer[2];
444 u16 reg = cpu_to_be16(r);
445 u16 data;
446 int ret;
447 struct i2c_client *client = codec->control_data;
448
449 /* Write register */
450 xfer[0].addr = client->addr;
451 xfer[0].flags = 0;
452 xfer[0].len = 2;
453 xfer[0].buf = (u8 *)&reg;
454
455 /* Read data */
456 xfer[1].addr = client->addr;
457 xfer[1].flags = I2C_M_RD;
458 xfer[1].len = 2;
459 xfer[1].buf = (u8 *)&data;
460
461 ret = i2c_transfer(client->adapter, xfer, 2);
462 if (ret != 2) {
463 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
464 return 0;
465 }
466
467 return be16_to_cpu(data);
468}
469#else
470#define snd_soc_16_16_read_i2c NULL
471#endif
472
473static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
474 unsigned int reg)
475{
476 u16 *cache = codec->reg_cache;
477
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000478 if (reg >= codec->driver->reg_cache_size ||
Mark Brownbc6552f2010-03-05 16:27:15 +0000479 snd_soc_codec_volatile_register(codec, reg)) {
480 if (codec->cache_only)
Dimitris Papastamos391d8a02010-09-21 17:04:07 +0100481 return -1;
Mark Brownbc6552f2010-03-05 16:27:15 +0000482
483 return codec->hw_read(codec, reg);
484 }
485
486 return cache[reg];
487}
488
489static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
490 unsigned int value)
491{
492 u16 *cache = codec->reg_cache;
493 u8 data[4];
494 int ret;
495
496 data[0] = (reg >> 8) & 0xff;
497 data[1] = reg & 0xff;
498 data[2] = (value >> 8) & 0xff;
499 data[3] = value & 0xff;
500
Dimitris Papastamosdb49c142010-09-22 13:25:47 +0100501 if (!snd_soc_codec_volatile_register(codec, reg) &&
502 reg < codec->driver->reg_cache_size)
503 cache[reg] = value;
Mark Brownbc6552f2010-03-05 16:27:15 +0000504
505 if (codec->cache_only) {
506 codec->cache_sync = 1;
507 return 0;
508 }
509
Mark Brown985d8c42010-05-03 16:25:52 +0100510 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
511
Mark Brownbc6552f2010-03-05 16:27:15 +0000512 ret = codec->hw_write(codec->control_data, data, 4);
513 if (ret == 4)
514 return 0;
515 if (ret < 0)
516 return ret;
517 else
518 return -EIO;
519}
Barry Song994dc422010-01-27 11:46:18 +0800520
Mark Brown17a52fd2009-07-05 17:24:50 +0100521static struct {
522 int addr_bits;
523 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100524 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown27ded042009-07-10 23:28:16 +0100525 int (*spi_write)(void *, const char *, int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100526 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100527 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100528} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700529 {
Barry Song63b62ab2010-01-27 11:46:17 +0800530 .addr_bits = 4, .data_bits = 12,
531 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
532 .spi_write = snd_soc_4_12_spi_write,
533 },
534 {
Mark Brownd62ab352009-09-21 04:21:47 -0700535 .addr_bits = 7, .data_bits = 9,
536 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Barry Song8998c892009-12-31 10:30:34 +0800537 .spi_write = snd_soc_7_9_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700538 },
539 {
540 .addr_bits = 8, .data_bits = 8,
541 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
Cliff Cai85dfcdf2010-03-18 16:17:00 +0800542 .i2c_read = snd_soc_8_8_read_i2c,
Mark Brownd62ab352009-09-21 04:21:47 -0700543 },
544 {
545 .addr_bits = 8, .data_bits = 16,
546 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
547 .i2c_read = snd_soc_8_16_read_i2c,
548 },
Barry Song994dc422010-01-27 11:46:18 +0800549 {
550 .addr_bits = 16, .data_bits = 8,
551 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
552 .i2c_read = snd_soc_16_8_read_i2c,
553 .spi_write = snd_soc_16_8_spi_write,
554 },
Mark Brownbc6552f2010-03-05 16:27:15 +0000555 {
556 .addr_bits = 16, .data_bits = 16,
557 .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
558 .i2c_read = snd_soc_16_16_read_i2c,
559 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100560};
561
562/**
563 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
564 *
565 * @codec: CODEC to configure.
566 * @type: Type of cache.
567 * @addr_bits: Number of bits of register address data.
568 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100569 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100570 *
571 * Register formats are frequently shared between many I2C and SPI
572 * devices. In order to promote code reuse the ASoC core provides
573 * some standard implementations of CODEC read and write operations
574 * which can be set up using this function.
575 *
576 * The caller is responsible for allocating and initialising the
577 * actual cache.
578 *
579 * Note that at present this code cannot be used by CODECs with
580 * volatile registers.
581 */
582int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100583 int addr_bits, int data_bits,
584 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100585{
586 int i;
587
Mark Brown17a52fd2009-07-05 17:24:50 +0100588 for (i = 0; i < ARRAY_SIZE(io_types); i++)
589 if (io_types[i].addr_bits == addr_bits &&
590 io_types[i].data_bits == data_bits)
591 break;
592 if (i == ARRAY_SIZE(io_types)) {
593 printk(KERN_ERR
594 "No I/O functions for %d bit address %d bit data\n",
595 addr_bits, data_bits);
596 return -EINVAL;
597 }
598
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000599 codec->driver->write = io_types[i].write;
600 codec->driver->read = io_types[i].read;
Mark Brown17a52fd2009-07-05 17:24:50 +0100601
Mark Brown7084a422009-07-10 22:24:27 +0100602 switch (control) {
603 case SND_SOC_CUSTOM:
604 break;
605
606 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700607#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100608 codec->hw_write = (hw_write_t)i2c_master_send;
609#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100610 if (io_types[i].i2c_read)
611 codec->hw_read = io_types[i].i2c_read;
Mark Browna6d14342010-08-12 10:59:15 +0100612
613 codec->control_data = container_of(codec->dev,
614 struct i2c_client,
615 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100616 break;
617
618 case SND_SOC_SPI:
Mark Brown27ded042009-07-10 23:28:16 +0100619 if (io_types[i].spi_write)
620 codec->hw_write = io_types[i].spi_write;
Mark Browna6d14342010-08-12 10:59:15 +0100621
622 codec->control_data = container_of(codec->dev,
623 struct spi_device,
624 dev);
Mark Brown7084a422009-07-10 22:24:27 +0100625 break;
626 }
627
Mark Brown17a52fd2009-07-05 17:24:50 +0100628 return 0;
629}
630EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);