blob: 84b6916db87d4c090c1d78a2c6a60e9156eb3d49 [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;
22 if (reg >= codec->reg_cache_size)
23 return -1;
24 return cache[reg];
25}
26
27static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
28 unsigned int value)
29{
30 u16 *cache = codec->reg_cache;
31 u8 data[2];
32 int ret;
33
34 BUG_ON(codec->volatile_register);
35
36 data[0] = (reg << 4) | ((value >> 8) & 0x000f);
37 data[1] = value & 0x00ff;
38
39 if (reg < codec->reg_cache_size)
40 cache[reg] = value;
Mark Brown8c961bc2010-02-01 18:46:10 +000041
42 if (codec->cache_only)
43 return 0;
44
Barry Song63b62ab2010-01-27 11:46:17 +080045 ret = codec->hw_write(codec->control_data, data, 2);
46 if (ret == 2)
47 return 0;
48 if (ret < 0)
49 return ret;
50 else
51 return -EIO;
52}
53
54#if defined(CONFIG_SPI_MASTER)
55static int snd_soc_4_12_spi_write(void *control_data, const char *data,
56 int len)
57{
58 struct spi_device *spi = control_data;
59 struct spi_transfer t;
60 struct spi_message m;
61 u8 msg[2];
62
63 if (len <= 0)
64 return 0;
65
66 msg[0] = data[1];
67 msg[1] = data[0];
68
69 spi_message_init(&m);
70 memset(&t, 0, (sizeof t));
71
72 t.tx_buf = &msg[0];
73 t.len = len;
74
75 spi_message_add_tail(&t, &m);
76 spi_sync(spi, &m);
77
78 return len;
79}
80#else
81#define snd_soc_4_12_spi_write NULL
82#endif
83
Mark Brown17a52fd2009-07-05 17:24:50 +010084static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
85 unsigned int reg)
86{
87 u16 *cache = codec->reg_cache;
88 if (reg >= codec->reg_cache_size)
89 return -1;
90 return cache[reg];
91}
92
93static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
94 unsigned int value)
95{
96 u16 *cache = codec->reg_cache;
97 u8 data[2];
98 int ret;
99
100 BUG_ON(codec->volatile_register);
101
102 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
103 data[1] = value & 0x00ff;
104
105 if (reg < codec->reg_cache_size)
106 cache[reg] = value;
Mark Brown8c961bc2010-02-01 18:46:10 +0000107
108 if (codec->cache_only)
109 return 0;
110
Mark Brown17a52fd2009-07-05 17:24:50 +0100111 ret = codec->hw_write(codec->control_data, data, 2);
112 if (ret == 2)
113 return 0;
114 if (ret < 0)
115 return ret;
116 else
117 return -EIO;
118}
119
Mark Brown27ded042009-07-10 23:28:16 +0100120#if defined(CONFIG_SPI_MASTER)
121static int snd_soc_7_9_spi_write(void *control_data, const char *data,
122 int len)
123{
124 struct spi_device *spi = control_data;
125 struct spi_transfer t;
126 struct spi_message m;
127 u8 msg[2];
128
129 if (len <= 0)
130 return 0;
131
132 msg[0] = data[0];
133 msg[1] = data[1];
134
135 spi_message_init(&m);
136 memset(&t, 0, (sizeof t));
137
138 t.tx_buf = &msg[0];
139 t.len = len;
140
141 spi_message_add_tail(&t, &m);
142 spi_sync(spi, &m);
143
144 return len;
145}
146#else
147#define snd_soc_7_9_spi_write NULL
148#endif
149
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900150static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
151 unsigned int value)
152{
153 u8 *cache = codec->reg_cache;
154 u8 data[2];
155
156 BUG_ON(codec->volatile_register);
157
158 data[0] = reg & 0xff;
159 data[1] = value & 0xff;
160
161 if (reg < codec->reg_cache_size)
162 cache[reg] = value;
163
Mark Brown8c961bc2010-02-01 18:46:10 +0000164 if (codec->cache_only)
165 return 0;
166
Joonyoung Shim341c9b82009-09-07 12:04:37 +0900167 if (codec->hw_write(codec->control_data, data, 2) == 2)
168 return 0;
169 else
170 return -EIO;
171}
172
173static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
174 unsigned int reg)
175{
176 u8 *cache = codec->reg_cache;
177 if (reg >= codec->reg_cache_size)
178 return -1;
179 return cache[reg];
180}
181
Mark Brownafa2f102009-07-10 23:11:24 +0100182static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
183 unsigned int value)
184{
185 u16 *reg_cache = codec->reg_cache;
186 u8 data[3];
187
188 data[0] = reg;
189 data[1] = (value >> 8) & 0xff;
190 data[2] = value & 0xff;
191
192 if (!snd_soc_codec_volatile_register(codec, reg))
193 reg_cache[reg] = value;
194
Mark Brown8c961bc2010-02-01 18:46:10 +0000195 if (codec->cache_only)
196 return 0;
197
Mark Brownafa2f102009-07-10 23:11:24 +0100198 if (codec->hw_write(codec->control_data, data, 3) == 3)
199 return 0;
200 else
201 return -EIO;
202}
203
204static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
205 unsigned int reg)
206{
207 u16 *cache = codec->reg_cache;
208
209 if (reg >= codec->reg_cache_size ||
Mark Brown8c961bc2010-02-01 18:46:10 +0000210 snd_soc_codec_volatile_register(codec, reg)) {
211 if (codec->cache_only)
212 return -EINVAL;
213
Mark Brownafa2f102009-07-10 23:11:24 +0100214 return codec->hw_read(codec, reg);
Mark Brown8c961bc2010-02-01 18:46:10 +0000215 } else {
Mark Brownafa2f102009-07-10 23:11:24 +0100216 return cache[reg];
Mark Brown8c961bc2010-02-01 18:46:10 +0000217 }
Mark Brownafa2f102009-07-10 23:11:24 +0100218}
219
Randy Dunlap17244c22009-08-10 16:04:39 -0700220#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brownafa2f102009-07-10 23:11:24 +0100221static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
222 unsigned int r)
223{
224 struct i2c_msg xfer[2];
225 u8 reg = r;
226 u16 data;
227 int ret;
228 struct i2c_client *client = codec->control_data;
229
230 /* Write register */
231 xfer[0].addr = client->addr;
232 xfer[0].flags = 0;
233 xfer[0].len = 1;
234 xfer[0].buf = &reg;
235
236 /* Read data */
237 xfer[1].addr = client->addr;
238 xfer[1].flags = I2C_M_RD;
239 xfer[1].len = 2;
240 xfer[1].buf = (u8 *)&data;
241
242 ret = i2c_transfer(client->adapter, xfer, 2);
243 if (ret != 2) {
244 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
245 return 0;
246 }
247
248 return (data >> 8) | ((data & 0xff) << 8);
249}
250#else
251#define snd_soc_8_16_read_i2c NULL
252#endif
Mark Brown17a52fd2009-07-05 17:24:50 +0100253
Barry Song994dc422010-01-27 11:46:18 +0800254#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
255static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
256 unsigned int r)
257{
258 struct i2c_msg xfer[2];
259 u16 reg = r;
260 u8 data;
261 int ret;
262 struct i2c_client *client = codec->control_data;
263
264 /* Write register */
265 xfer[0].addr = client->addr;
266 xfer[0].flags = 0;
267 xfer[0].len = 2;
268 xfer[0].buf = (u8 *)&reg;
269
270 /* Read data */
271 xfer[1].addr = client->addr;
272 xfer[1].flags = I2C_M_RD;
273 xfer[1].len = 1;
274 xfer[1].buf = &data;
275
276 ret = i2c_transfer(client->adapter, xfer, 2);
277 if (ret != 2) {
278 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
279 return 0;
280 }
281
282 return data;
283}
284#else
285#define snd_soc_16_8_read_i2c NULL
286#endif
287
288static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
289 unsigned int reg)
290{
291 u16 *cache = codec->reg_cache;
292
293 reg &= 0xff;
294 if (reg >= codec->reg_cache_size)
295 return -1;
296 return cache[reg];
297}
298
299static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
300 unsigned int value)
301{
302 u16 *cache = codec->reg_cache;
303 u8 data[3];
304 int ret;
305
306 BUG_ON(codec->volatile_register);
307
308 data[0] = (reg >> 8) & 0xff;
309 data[1] = reg & 0xff;
310 data[2] = value;
311
312 reg &= 0xff;
313 if (reg < codec->reg_cache_size)
314 cache[reg] = value;
Mark Brown8c961bc2010-02-01 18:46:10 +0000315
316 if (codec->cache_only)
317 return 0;
318
Barry Song994dc422010-01-27 11:46:18 +0800319 ret = codec->hw_write(codec->control_data, data, 3);
320 if (ret == 3)
321 return 0;
322 if (ret < 0)
323 return ret;
324 else
325 return -EIO;
326}
327
328#if defined(CONFIG_SPI_MASTER)
329static int snd_soc_16_8_spi_write(void *control_data, const char *data,
330 int len)
331{
332 struct spi_device *spi = control_data;
333 struct spi_transfer t;
334 struct spi_message m;
335 u8 msg[3];
336
337 if (len <= 0)
338 return 0;
339
340 msg[0] = data[0];
341 msg[1] = data[1];
342 msg[2] = data[2];
343
344 spi_message_init(&m);
345 memset(&t, 0, (sizeof t));
346
347 t.tx_buf = &msg[0];
348 t.len = len;
349
350 spi_message_add_tail(&t, &m);
351 spi_sync(spi, &m);
352
353 return len;
354}
355#else
356#define snd_soc_16_8_spi_write NULL
357#endif
358
359
Mark Brown17a52fd2009-07-05 17:24:50 +0100360static struct {
361 int addr_bits;
362 int data_bits;
Mark Brownafa2f102009-07-10 23:11:24 +0100363 int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
Mark Brown27ded042009-07-10 23:28:16 +0100364 int (*spi_write)(void *, const char *, int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100365 unsigned int (*read)(struct snd_soc_codec *, unsigned int);
Mark Brownafa2f102009-07-10 23:11:24 +0100366 unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
Mark Brown17a52fd2009-07-05 17:24:50 +0100367} io_types[] = {
Mark Brownd62ab352009-09-21 04:21:47 -0700368 {
Barry Song63b62ab2010-01-27 11:46:17 +0800369 .addr_bits = 4, .data_bits = 12,
370 .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
371 .spi_write = snd_soc_4_12_spi_write,
372 },
373 {
Mark Brownd62ab352009-09-21 04:21:47 -0700374 .addr_bits = 7, .data_bits = 9,
375 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
Barry Song8998c892009-12-31 10:30:34 +0800376 .spi_write = snd_soc_7_9_spi_write,
Mark Brownd62ab352009-09-21 04:21:47 -0700377 },
378 {
379 .addr_bits = 8, .data_bits = 8,
380 .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
381 },
382 {
383 .addr_bits = 8, .data_bits = 16,
384 .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
385 .i2c_read = snd_soc_8_16_read_i2c,
386 },
Barry Song994dc422010-01-27 11:46:18 +0800387 {
388 .addr_bits = 16, .data_bits = 8,
389 .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
390 .i2c_read = snd_soc_16_8_read_i2c,
391 .spi_write = snd_soc_16_8_spi_write,
392 },
Mark Brown17a52fd2009-07-05 17:24:50 +0100393};
394
395/**
396 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
397 *
398 * @codec: CODEC to configure.
399 * @type: Type of cache.
400 * @addr_bits: Number of bits of register address data.
401 * @data_bits: Number of bits of data per register.
Mark Brown7084a422009-07-10 22:24:27 +0100402 * @control: Control bus used.
Mark Brown17a52fd2009-07-05 17:24:50 +0100403 *
404 * Register formats are frequently shared between many I2C and SPI
405 * devices. In order to promote code reuse the ASoC core provides
406 * some standard implementations of CODEC read and write operations
407 * which can be set up using this function.
408 *
409 * The caller is responsible for allocating and initialising the
410 * actual cache.
411 *
412 * Note that at present this code cannot be used by CODECs with
413 * volatile registers.
414 */
415int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
Mark Brown7084a422009-07-10 22:24:27 +0100416 int addr_bits, int data_bits,
417 enum snd_soc_control_type control)
Mark Brown17a52fd2009-07-05 17:24:50 +0100418{
419 int i;
420
Mark Brown17a52fd2009-07-05 17:24:50 +0100421 for (i = 0; i < ARRAY_SIZE(io_types); i++)
422 if (io_types[i].addr_bits == addr_bits &&
423 io_types[i].data_bits == data_bits)
424 break;
425 if (i == ARRAY_SIZE(io_types)) {
426 printk(KERN_ERR
427 "No I/O functions for %d bit address %d bit data\n",
428 addr_bits, data_bits);
429 return -EINVAL;
430 }
431
432 codec->write = io_types[i].write;
433 codec->read = io_types[i].read;
434
Mark Brown7084a422009-07-10 22:24:27 +0100435 switch (control) {
436 case SND_SOC_CUSTOM:
437 break;
438
439 case SND_SOC_I2C:
Randy Dunlap17244c22009-08-10 16:04:39 -0700440#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
Mark Brown7084a422009-07-10 22:24:27 +0100441 codec->hw_write = (hw_write_t)i2c_master_send;
442#endif
Mark Brownafa2f102009-07-10 23:11:24 +0100443 if (io_types[i].i2c_read)
444 codec->hw_read = io_types[i].i2c_read;
Mark Brown7084a422009-07-10 22:24:27 +0100445 break;
446
447 case SND_SOC_SPI:
Mark Brown27ded042009-07-10 23:28:16 +0100448 if (io_types[i].spi_write)
449 codec->hw_write = io_types[i].spi_write;
Mark Brown7084a422009-07-10 22:24:27 +0100450 break;
451 }
452
Mark Brown17a52fd2009-07-05 17:24:50 +0100453 return 0;
454}
455EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);