diff options
Diffstat (limited to 'sound/soc/soc-cache.c')
-rw-r--r-- | sound/soc/soc-cache.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c new file mode 100644 index 000000000000..56ec3f22bf1c --- /dev/null +++ b/sound/soc/soc-cache.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
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 | |||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <sound/soc.h> | ||
17 | |||
18 | static unsigned int snd_soc_7_9_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 | |||
27 | static int snd_soc_7_9_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 << 1) | ((value >> 8) & 0x0001); | ||
37 | data[1] = value & 0x00ff; | ||
38 | |||
39 | if (reg < codec->reg_cache_size) | ||
40 | cache[reg] = value; | ||
41 | ret = codec->hw_write(codec->control_data, data, 2); | ||
42 | if (ret == 2) | ||
43 | return 0; | ||
44 | if (ret < 0) | ||
45 | return ret; | ||
46 | else | ||
47 | return -EIO; | ||
48 | } | ||
49 | |||
50 | #if defined(CONFIG_SPI_MASTER) | ||
51 | static int snd_soc_7_9_spi_write(void *control_data, const char *data, | ||
52 | int len) | ||
53 | { | ||
54 | struct spi_device *spi = control_data; | ||
55 | struct spi_transfer t; | ||
56 | struct spi_message m; | ||
57 | u8 msg[2]; | ||
58 | |||
59 | if (len <= 0) | ||
60 | return 0; | ||
61 | |||
62 | msg[0] = data[0]; | ||
63 | msg[1] = data[1]; | ||
64 | |||
65 | spi_message_init(&m); | ||
66 | memset(&t, 0, (sizeof t)); | ||
67 | |||
68 | t.tx_buf = &msg[0]; | ||
69 | t.len = len; | ||
70 | |||
71 | spi_message_add_tail(&t, &m); | ||
72 | spi_sync(spi, &m); | ||
73 | |||
74 | return len; | ||
75 | } | ||
76 | #else | ||
77 | #define snd_soc_7_9_spi_write NULL | ||
78 | #endif | ||
79 | |||
80 | static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, | ||
81 | unsigned int value) | ||
82 | { | ||
83 | u16 *reg_cache = codec->reg_cache; | ||
84 | u8 data[3]; | ||
85 | |||
86 | data[0] = reg; | ||
87 | data[1] = (value >> 8) & 0xff; | ||
88 | data[2] = value & 0xff; | ||
89 | |||
90 | if (!snd_soc_codec_volatile_register(codec, reg)) | ||
91 | reg_cache[reg] = value; | ||
92 | |||
93 | if (codec->hw_write(codec->control_data, data, 3) == 3) | ||
94 | return 0; | ||
95 | else | ||
96 | return -EIO; | ||
97 | } | ||
98 | |||
99 | static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, | ||
100 | unsigned int reg) | ||
101 | { | ||
102 | u16 *cache = codec->reg_cache; | ||
103 | |||
104 | if (reg >= codec->reg_cache_size || | ||
105 | snd_soc_codec_volatile_register(codec, reg)) | ||
106 | return codec->hw_read(codec, reg); | ||
107 | else | ||
108 | return cache[reg]; | ||
109 | } | ||
110 | |||
111 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
112 | static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, | ||
113 | unsigned int r) | ||
114 | { | ||
115 | struct i2c_msg xfer[2]; | ||
116 | u8 reg = r; | ||
117 | u16 data; | ||
118 | int ret; | ||
119 | struct i2c_client *client = codec->control_data; | ||
120 | |||
121 | /* Write register */ | ||
122 | xfer[0].addr = client->addr; | ||
123 | xfer[0].flags = 0; | ||
124 | xfer[0].len = 1; | ||
125 | xfer[0].buf = ® | ||
126 | |||
127 | /* Read data */ | ||
128 | xfer[1].addr = client->addr; | ||
129 | xfer[1].flags = I2C_M_RD; | ||
130 | xfer[1].len = 2; | ||
131 | xfer[1].buf = (u8 *)&data; | ||
132 | |||
133 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
134 | if (ret != 2) { | ||
135 | dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | return (data >> 8) | ((data & 0xff) << 8); | ||
140 | } | ||
141 | #else | ||
142 | #define snd_soc_8_16_read_i2c NULL | ||
143 | #endif | ||
144 | |||
145 | static struct { | ||
146 | int addr_bits; | ||
147 | int data_bits; | ||
148 | int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); | ||
149 | int (*spi_write)(void *, const char *, int); | ||
150 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | ||
151 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); | ||
152 | } io_types[] = { | ||
153 | { 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read }, | ||
154 | { 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read, | ||
155 | snd_soc_8_16_read_i2c }, | ||
156 | }; | ||
157 | |||
158 | /** | ||
159 | * snd_soc_codec_set_cache_io: Set up standard I/O functions. | ||
160 | * | ||
161 | * @codec: CODEC to configure. | ||
162 | * @type: Type of cache. | ||
163 | * @addr_bits: Number of bits of register address data. | ||
164 | * @data_bits: Number of bits of data per register. | ||
165 | * @control: Control bus used. | ||
166 | * | ||
167 | * Register formats are frequently shared between many I2C and SPI | ||
168 | * devices. In order to promote code reuse the ASoC core provides | ||
169 | * some standard implementations of CODEC read and write operations | ||
170 | * which can be set up using this function. | ||
171 | * | ||
172 | * The caller is responsible for allocating and initialising the | ||
173 | * actual cache. | ||
174 | * | ||
175 | * Note that at present this code cannot be used by CODECs with | ||
176 | * volatile registers. | ||
177 | */ | ||
178 | int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, | ||
179 | int addr_bits, int data_bits, | ||
180 | enum snd_soc_control_type control) | ||
181 | { | ||
182 | int i; | ||
183 | |||
184 | for (i = 0; i < ARRAY_SIZE(io_types); i++) | ||
185 | if (io_types[i].addr_bits == addr_bits && | ||
186 | io_types[i].data_bits == data_bits) | ||
187 | break; | ||
188 | if (i == ARRAY_SIZE(io_types)) { | ||
189 | printk(KERN_ERR | ||
190 | "No I/O functions for %d bit address %d bit data\n", | ||
191 | addr_bits, data_bits); | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | |||
195 | codec->write = io_types[i].write; | ||
196 | codec->read = io_types[i].read; | ||
197 | |||
198 | switch (control) { | ||
199 | case SND_SOC_CUSTOM: | ||
200 | break; | ||
201 | |||
202 | case SND_SOC_I2C: | ||
203 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
204 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
205 | #endif | ||
206 | if (io_types[i].i2c_read) | ||
207 | codec->hw_read = io_types[i].i2c_read; | ||
208 | break; | ||
209 | |||
210 | case SND_SOC_SPI: | ||
211 | if (io_types[i].spi_write) | ||
212 | codec->hw_write = io_types[i].spi_write; | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); | ||