| OLD | NEW |
| 1 /* | 1 /* |
| 2 * soc-cache.c -- ASoC register cache helpers | 2 * soc-cache.c -- ASoC register cache helpers |
| 3 * | 3 * |
| 4 * Copyright 2009 Wolfson Microelectronics PLC. | 4 * Copyright 2009 Wolfson Microelectronics PLC. |
| 5 * | 5 * |
| 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
| 7 * | 7 * |
| 8 * This program is free software; you can redistribute it and/or modify it | 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 | 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 | 10 * Free Software Foundation; either version 2 of the License, or (at your |
| 11 * option) any later version. | 11 * option) any later version. |
| 12 */ | 12 */ |
| 13 | 13 |
| 14 #include <linux/i2c.h> | 14 #include <linux/i2c.h> |
| 15 #include <linux/spi/spi.h> | 15 #include <linux/spi/spi.h> |
| 16 #include <sound/soc.h> | 16 #include <sound/soc.h> |
| 17 #include <linux/lzo.h> |
| 18 #include <linux/bitmap.h> |
| 19 #include <linux/rbtree.h> |
| 20 |
| 21 #include <trace/events/asoc.h> |
| 17 | 22 |
| 18 static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, | 23 static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, |
| 19 unsigned int reg) | 24 unsigned int reg) |
| 20 { | 25 { |
| 21 » u16 *cache = codec->reg_cache; | 26 » int ret; |
| 27 » unsigned int val; |
| 22 | 28 |
| 23 if (reg >= codec->driver->reg_cache_size || | 29 if (reg >= codec->driver->reg_cache_size || |
| 24 » » snd_soc_codec_volatile_register(codec, reg)) { | 30 » » snd_soc_codec_volatile_register(codec, reg) || |
| 31 » » codec->cache_bypass) { |
| 25 if (codec->cache_only) | 32 if (codec->cache_only) |
| 26 return -1; | 33 return -1; |
| 27 | 34 |
| 35 BUG_ON(!codec->hw_read); |
| 28 return codec->hw_read(codec, reg); | 36 return codec->hw_read(codec, reg); |
| 29 } | 37 } |
| 30 | 38 |
| 31 » return cache[reg]; | 39 » ret = snd_soc_cache_read(codec, reg, &val); |
| 40 » if (ret < 0) |
| 41 » » return -1; |
| 42 » return val; |
| 32 } | 43 } |
| 33 | 44 |
| 34 static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, | 45 static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, |
| 35 unsigned int value) | 46 unsigned int value) |
| 36 { | 47 { |
| 37 u16 *cache = codec->reg_cache; | |
| 38 u8 data[2]; | 48 u8 data[2]; |
| 39 int ret; | 49 int ret; |
| 40 | 50 |
| 41 data[0] = (reg << 4) | ((value >> 8) & 0x000f); | 51 data[0] = (reg << 4) | ((value >> 8) & 0x000f); |
| 42 data[1] = value & 0x00ff; | 52 data[1] = value & 0x00ff; |
| 43 | 53 |
| 44 if (!snd_soc_codec_volatile_register(codec, reg) && | 54 if (!snd_soc_codec_volatile_register(codec, reg) && |
| 45 » » reg < codec->driver->reg_cache_size) | 55 » » reg < codec->driver->reg_cache_size && |
| 46 » » » cache[reg] = value; | 56 » » !codec->cache_bypass) { |
| 57 » » ret = snd_soc_cache_write(codec, reg, value); |
| 58 » » if (ret < 0) |
| 59 » » » return -1; |
| 60 » } |
| 47 | 61 |
| 48 if (codec->cache_only) { | 62 if (codec->cache_only) { |
| 49 codec->cache_sync = 1; | 63 codec->cache_sync = 1; |
| 50 return 0; | 64 return 0; |
| 51 } | 65 } |
| 52 | 66 |
| 53 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | |
| 54 | |
| 55 ret = codec->hw_write(codec->control_data, data, 2); | 67 ret = codec->hw_write(codec->control_data, data, 2); |
| 56 if (ret == 2) | 68 if (ret == 2) |
| 57 return 0; | 69 return 0; |
| 58 if (ret < 0) | 70 if (ret < 0) |
| 59 return ret; | 71 return ret; |
| 60 else | 72 else |
| 61 return -EIO; | 73 return -EIO; |
| 62 } | 74 } |
| 63 | 75 |
| 64 #if defined(CONFIG_SPI_MASTER) | 76 #if defined(CONFIG_SPI_MASTER) |
| 65 static int snd_soc_4_12_spi_write(void *control_data, const char *data, | 77 static int snd_soc_4_12_spi_write(void *control_data, const char *data, |
| 66 int len) | 78 int len) |
| 67 { | 79 { |
| 68 struct spi_device *spi = control_data; | 80 struct spi_device *spi = control_data; |
| 69 struct spi_transfer t; | 81 struct spi_transfer t; |
| 70 struct spi_message m; | 82 struct spi_message m; |
| 71 u8 msg[2]; | 83 u8 msg[2]; |
| 72 | 84 |
| 73 if (len <= 0) | 85 if (len <= 0) |
| 74 return 0; | 86 return 0; |
| 75 | 87 |
| 76 msg[0] = data[1]; | 88 msg[0] = data[1]; |
| 77 msg[1] = data[0]; | 89 msg[1] = data[0]; |
| 78 | 90 |
| 79 spi_message_init(&m); | 91 spi_message_init(&m); |
| 80 » memset(&t, 0, (sizeof t)); | 92 » memset(&t, 0, sizeof t); |
| 81 | 93 |
| 82 t.tx_buf = &msg[0]; | 94 t.tx_buf = &msg[0]; |
| 83 t.len = len; | 95 t.len = len; |
| 84 | 96 |
| 85 spi_message_add_tail(&t, &m); | 97 spi_message_add_tail(&t, &m); |
| 86 spi_sync(spi, &m); | 98 spi_sync(spi, &m); |
| 87 | 99 |
| 88 return len; | 100 return len; |
| 89 } | 101 } |
| 90 #else | 102 #else |
| 91 #define snd_soc_4_12_spi_write NULL | 103 #define snd_soc_4_12_spi_write NULL |
| 92 #endif | 104 #endif |
| 93 | 105 |
| 94 static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, | 106 static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, |
| 95 unsigned int reg) | 107 unsigned int reg) |
| 96 { | 108 { |
| 97 » u16 *cache = codec->reg_cache; | 109 » int ret; |
| 110 » unsigned int val; |
| 98 | 111 |
| 99 if (reg >= codec->driver->reg_cache_size || | 112 if (reg >= codec->driver->reg_cache_size || |
| 100 » » snd_soc_codec_volatile_register(codec, reg)) { | 113 » » snd_soc_codec_volatile_register(codec, reg) || |
| 114 » » codec->cache_bypass) { |
| 101 if (codec->cache_only) | 115 if (codec->cache_only) |
| 102 return -1; | 116 return -1; |
| 103 | 117 |
| 118 BUG_ON(!codec->hw_read); |
| 104 return codec->hw_read(codec, reg); | 119 return codec->hw_read(codec, reg); |
| 105 } | 120 } |
| 106 | 121 |
| 107 » return cache[reg]; | 122 » ret = snd_soc_cache_read(codec, reg, &val); |
| 123 » if (ret < 0) |
| 124 » » return -1; |
| 125 » return val; |
| 108 } | 126 } |
| 109 | 127 |
| 110 static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, | 128 static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, |
| 111 unsigned int value) | 129 unsigned int value) |
| 112 { | 130 { |
| 113 u16 *cache = codec->reg_cache; | |
| 114 u8 data[2]; | 131 u8 data[2]; |
| 115 int ret; | 132 int ret; |
| 116 | 133 |
| 117 data[0] = (reg << 1) | ((value >> 8) & 0x0001); | 134 data[0] = (reg << 1) | ((value >> 8) & 0x0001); |
| 118 data[1] = value & 0x00ff; | 135 data[1] = value & 0x00ff; |
| 119 | 136 |
| 120 if (!snd_soc_codec_volatile_register(codec, reg) && | 137 if (!snd_soc_codec_volatile_register(codec, reg) && |
| 121 » » reg < codec->driver->reg_cache_size) | 138 » » reg < codec->driver->reg_cache_size && |
| 122 » » » cache[reg] = value; | 139 » » !codec->cache_bypass) { |
| 140 » » ret = snd_soc_cache_write(codec, reg, value); |
| 141 » » if (ret < 0) |
| 142 » » » return -1; |
| 143 » } |
| 123 | 144 |
| 124 if (codec->cache_only) { | 145 if (codec->cache_only) { |
| 125 codec->cache_sync = 1; | 146 codec->cache_sync = 1; |
| 126 return 0; | 147 return 0; |
| 127 } | 148 } |
| 128 | 149 |
| 129 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | |
| 130 | |
| 131 ret = codec->hw_write(codec->control_data, data, 2); | 150 ret = codec->hw_write(codec->control_data, data, 2); |
| 132 if (ret == 2) | 151 if (ret == 2) |
| 133 return 0; | 152 return 0; |
| 134 if (ret < 0) | 153 if (ret < 0) |
| 135 return ret; | 154 return ret; |
| 136 else | 155 else |
| 137 return -EIO; | 156 return -EIO; |
| 138 } | 157 } |
| 139 | 158 |
| 140 #if defined(CONFIG_SPI_MASTER) | 159 #if defined(CONFIG_SPI_MASTER) |
| 141 static int snd_soc_7_9_spi_write(void *control_data, const char *data, | 160 static int snd_soc_7_9_spi_write(void *control_data, const char *data, |
| 142 int len) | 161 int len) |
| 143 { | 162 { |
| 144 struct spi_device *spi = control_data; | 163 struct spi_device *spi = control_data; |
| 145 struct spi_transfer t; | 164 struct spi_transfer t; |
| 146 struct spi_message m; | 165 struct spi_message m; |
| 147 u8 msg[2]; | 166 u8 msg[2]; |
| 148 | 167 |
| 149 if (len <= 0) | 168 if (len <= 0) |
| 150 return 0; | 169 return 0; |
| 151 | 170 |
| 152 msg[0] = data[0]; | 171 msg[0] = data[0]; |
| 153 msg[1] = data[1]; | 172 msg[1] = data[1]; |
| 154 | 173 |
| 155 spi_message_init(&m); | 174 spi_message_init(&m); |
| 156 » memset(&t, 0, (sizeof t)); | 175 » memset(&t, 0, sizeof t); |
| 157 | 176 |
| 158 t.tx_buf = &msg[0]; | 177 t.tx_buf = &msg[0]; |
| 159 t.len = len; | 178 t.len = len; |
| 160 | 179 |
| 161 spi_message_add_tail(&t, &m); | 180 spi_message_add_tail(&t, &m); |
| 162 spi_sync(spi, &m); | 181 spi_sync(spi, &m); |
| 163 | 182 |
| 164 return len; | 183 return len; |
| 165 } | 184 } |
| 166 #else | 185 #else |
| 167 #define snd_soc_7_9_spi_write NULL | 186 #define snd_soc_7_9_spi_write NULL |
| 168 #endif | 187 #endif |
| 169 | 188 |
| 170 static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, | 189 static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, |
| 171 unsigned int value) | 190 unsigned int value) |
| 172 { | 191 { |
| 173 u8 *cache = codec->reg_cache; | |
| 174 u8 data[2]; | 192 u8 data[2]; |
| 193 int ret; |
| 175 | 194 |
| 176 reg &= 0xff; | 195 reg &= 0xff; |
| 177 data[0] = reg; | 196 data[0] = reg; |
| 178 data[1] = value & 0xff; | 197 data[1] = value & 0xff; |
| 179 | 198 |
| 180 if (!snd_soc_codec_volatile_register(codec, reg) && | 199 if (!snd_soc_codec_volatile_register(codec, reg) && |
| 181 » » reg < codec->driver->reg_cache_size) | 200 » » reg < codec->driver->reg_cache_size && |
| 182 » » » cache[reg] = value; | 201 » » !codec->cache_bypass) { |
| 202 » » ret = snd_soc_cache_write(codec, reg, value); |
| 203 » » if (ret < 0) |
| 204 » » » return -1; |
| 205 » } |
| 183 | 206 |
| 184 if (codec->cache_only) { | 207 if (codec->cache_only) { |
| 185 codec->cache_sync = 1; | 208 codec->cache_sync = 1; |
| 186 return 0; | 209 return 0; |
| 187 } | 210 } |
| 188 | 211 |
| 189 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | |
| 190 | |
| 191 if (codec->hw_write(codec->control_data, data, 2) == 2) | 212 if (codec->hw_write(codec->control_data, data, 2) == 2) |
| 192 return 0; | 213 return 0; |
| 193 else | 214 else |
| 194 return -EIO; | 215 return -EIO; |
| 195 } | 216 } |
| 196 | 217 |
| 197 static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, | 218 static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, |
| 198 unsigned int reg) | 219 unsigned int reg) |
| 199 { | 220 { |
| 200 » u8 *cache = codec->reg_cache; | 221 » int ret; |
| 222 » unsigned int val; |
| 201 | 223 |
| 202 reg &= 0xff; | 224 reg &= 0xff; |
| 203 if (reg >= codec->driver->reg_cache_size || | 225 if (reg >= codec->driver->reg_cache_size || |
| 204 » » snd_soc_codec_volatile_register(codec, reg)) { | 226 » » snd_soc_codec_volatile_register(codec, reg) || |
| 227 » » codec->cache_bypass) { |
| 205 if (codec->cache_only) | 228 if (codec->cache_only) |
| 206 return -1; | 229 return -1; |
| 207 | 230 |
| 231 BUG_ON(!codec->hw_read); |
| 208 return codec->hw_read(codec, reg); | 232 return codec->hw_read(codec, reg); |
| 209 } | 233 } |
| 210 | 234 |
| 211 » return cache[reg]; | 235 » ret = snd_soc_cache_read(codec, reg, &val); |
| 236 » if (ret < 0) |
| 237 » » return -1; |
| 238 » return val; |
| 212 } | 239 } |
| 213 | 240 |
| 214 #if defined(CONFIG_SPI_MASTER) | 241 #if defined(CONFIG_SPI_MASTER) |
| 215 static int snd_soc_8_8_spi_write(void *control_data, const char *data, | 242 static int snd_soc_8_8_spi_write(void *control_data, const char *data, |
| 216 int len) | 243 int len) |
| 217 { | 244 { |
| 218 struct spi_device *spi = control_data; | 245 struct spi_device *spi = control_data; |
| 219 struct spi_transfer t; | 246 struct spi_transfer t; |
| 220 struct spi_message m; | 247 struct spi_message m; |
| 221 u8 msg[2]; | 248 u8 msg[2]; |
| 222 | 249 |
| 223 if (len <= 0) | 250 if (len <= 0) |
| 224 return 0; | 251 return 0; |
| 225 | 252 |
| 226 msg[0] = data[0]; | 253 msg[0] = data[0]; |
| 227 msg[1] = data[1]; | 254 msg[1] = data[1]; |
| 228 | 255 |
| 229 spi_message_init(&m); | 256 spi_message_init(&m); |
| 230 » memset(&t, 0, (sizeof t)); | 257 » memset(&t, 0, sizeof t); |
| 231 | 258 |
| 232 t.tx_buf = &msg[0]; | 259 t.tx_buf = &msg[0]; |
| 233 t.len = len; | 260 t.len = len; |
| 234 | 261 |
| 235 spi_message_add_tail(&t, &m); | 262 spi_message_add_tail(&t, &m); |
| 236 spi_sync(spi, &m); | 263 spi_sync(spi, &m); |
| 237 | 264 |
| 238 return len; | 265 return len; |
| 239 } | 266 } |
| 240 #else | 267 #else |
| 241 #define snd_soc_8_8_spi_write NULL | 268 #define snd_soc_8_8_spi_write NULL |
| 242 #endif | 269 #endif |
| 243 | 270 |
| 244 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, | 271 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, |
| 245 unsigned int value) | 272 unsigned int value) |
| 246 { | 273 { |
| 247 u16 *reg_cache = codec->reg_cache; | |
| 248 u8 data[3]; | 274 u8 data[3]; |
| 275 int ret; |
| 249 | 276 |
| 250 data[0] = reg; | 277 data[0] = reg; |
| 251 data[1] = (value >> 8) & 0xff; | 278 data[1] = (value >> 8) & 0xff; |
| 252 data[2] = value & 0xff; | 279 data[2] = value & 0xff; |
| 253 | 280 |
| 254 if (!snd_soc_codec_volatile_register(codec, reg) && | 281 if (!snd_soc_codec_volatile_register(codec, reg) && |
| 255 » reg < codec->driver->reg_cache_size) | 282 » » reg < codec->driver->reg_cache_size && |
| 256 » » reg_cache[reg] = value; | 283 » » !codec->cache_bypass) { |
| 284 » » ret = snd_soc_cache_write(codec, reg, value); |
| 285 » » if (ret < 0) |
| 286 » » » return -1; |
| 287 » } |
| 257 | 288 |
| 258 if (codec->cache_only) { | 289 if (codec->cache_only) { |
| 259 codec->cache_sync = 1; | 290 codec->cache_sync = 1; |
| 260 return 0; | 291 return 0; |
| 261 } | 292 } |
| 262 | 293 |
| 263 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | |
| 264 | |
| 265 if (codec->hw_write(codec->control_data, data, 3) == 3) | 294 if (codec->hw_write(codec->control_data, data, 3) == 3) |
| 266 return 0; | 295 return 0; |
| 267 else | 296 else |
| 268 return -EIO; | 297 return -EIO; |
| 269 } | 298 } |
| 270 | 299 |
| 271 static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, | 300 static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, |
| 272 unsigned int reg) | 301 unsigned int reg) |
| 273 { | 302 { |
| 274 » u16 *cache = codec->reg_cache; | 303 » int ret; |
| 304 » unsigned int val; |
| 275 | 305 |
| 276 if (reg >= codec->driver->reg_cache_size || | 306 if (reg >= codec->driver->reg_cache_size || |
| 277 » snd_soc_codec_volatile_register(codec, reg)) { | 307 » snd_soc_codec_volatile_register(codec, reg) || |
| 308 » codec->cache_bypass) { |
| 278 if (codec->cache_only) | 309 if (codec->cache_only) |
| 279 return -1; | 310 return -1; |
| 280 | 311 |
| 312 BUG_ON(!codec->hw_read); |
| 281 return codec->hw_read(codec, reg); | 313 return codec->hw_read(codec, reg); |
| 282 } else { | |
| 283 return cache[reg]; | |
| 284 } | 314 } |
| 315 |
| 316 ret = snd_soc_cache_read(codec, reg, &val); |
| 317 if (ret < 0) |
| 318 return -1; |
| 319 return val; |
| 285 } | 320 } |
| 286 | 321 |
| 287 #if defined(CONFIG_SPI_MASTER) | 322 #if defined(CONFIG_SPI_MASTER) |
| 288 static int snd_soc_8_16_spi_write(void *control_data, const char *data, | 323 static int snd_soc_8_16_spi_write(void *control_data, const char *data, |
| 289 int len) | 324 int len) |
| 290 { | 325 { |
| 291 struct spi_device *spi = control_data; | 326 struct spi_device *spi = control_data; |
| 292 struct spi_transfer t; | 327 struct spi_transfer t; |
| 293 struct spi_message m; | 328 struct spi_message m; |
| 294 u8 msg[3]; | 329 u8 msg[3]; |
| 295 | 330 |
| 296 if (len <= 0) | 331 if (len <= 0) |
| 297 return 0; | 332 return 0; |
| 298 | 333 |
| 299 msg[0] = data[0]; | 334 msg[0] = data[0]; |
| 300 msg[1] = data[1]; | 335 msg[1] = data[1]; |
| 301 msg[2] = data[2]; | 336 msg[2] = data[2]; |
| 302 | 337 |
| 303 spi_message_init(&m); | 338 spi_message_init(&m); |
| 304 » memset(&t, 0, (sizeof t)); | 339 » memset(&t, 0, sizeof t); |
| 305 | 340 |
| 306 t.tx_buf = &msg[0]; | 341 t.tx_buf = &msg[0]; |
| 307 t.len = len; | 342 t.len = len; |
| 308 | 343 |
| 309 spi_message_add_tail(&t, &m); | 344 spi_message_add_tail(&t, &m); |
| 310 spi_sync(spi, &m); | 345 spi_sync(spi, &m); |
| 311 | 346 |
| 312 return len; | 347 return len; |
| 313 } | 348 } |
| 314 #else | 349 #else |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 | 448 |
| 414 return data; | 449 return data; |
| 415 } | 450 } |
| 416 #else | 451 #else |
| 417 #define snd_soc_16_8_read_i2c NULL | 452 #define snd_soc_16_8_read_i2c NULL |
| 418 #endif | 453 #endif |
| 419 | 454 |
| 420 static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, | 455 static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, |
| 421 unsigned int reg) | 456 unsigned int reg) |
| 422 { | 457 { |
| 423 » u8 *cache = codec->reg_cache; | 458 » int ret; |
| 459 » unsigned int val; |
| 424 | 460 |
| 425 reg &= 0xff; | 461 reg &= 0xff; |
| 426 if (reg >= codec->driver->reg_cache_size || | 462 if (reg >= codec->driver->reg_cache_size || |
| 427 » » snd_soc_codec_volatile_register(codec, reg)) { | 463 » » snd_soc_codec_volatile_register(codec, reg) || |
| 464 » » codec->cache_bypass) { |
| 428 if (codec->cache_only) | 465 if (codec->cache_only) |
| 429 return -1; | 466 return -1; |
| 430 | 467 |
| 468 BUG_ON(!codec->hw_read); |
| 431 return codec->hw_read(codec, reg); | 469 return codec->hw_read(codec, reg); |
| 432 } | 470 } |
| 433 | 471 |
| 434 » return cache[reg]; | 472 » ret = snd_soc_cache_read(codec, reg, &val); |
| 473 » if (ret < 0) |
| 474 » » return -1; |
| 475 » return val; |
| 435 } | 476 } |
| 436 | 477 |
| 437 static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, | 478 static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, |
| 438 unsigned int value) | 479 unsigned int value) |
| 439 { | 480 { |
| 440 u8 *cache = codec->reg_cache; | |
| 441 u8 data[3]; | 481 u8 data[3]; |
| 442 int ret; | 482 int ret; |
| 443 | 483 |
| 444 data[0] = (reg >> 8) & 0xff; | 484 data[0] = (reg >> 8) & 0xff; |
| 445 data[1] = reg & 0xff; | 485 data[1] = reg & 0xff; |
| 446 data[2] = value; | 486 data[2] = value; |
| 447 | 487 |
| 448 reg &= 0xff; | 488 reg &= 0xff; |
| 449 if (!snd_soc_codec_volatile_register(codec, reg) && | 489 if (!snd_soc_codec_volatile_register(codec, reg) && |
| 450 » » reg < codec->driver->reg_cache_size) | 490 » » reg < codec->driver->reg_cache_size && |
| 451 » » » cache[reg] = value; | 491 » » !codec->cache_bypass) { |
| 492 » » ret = snd_soc_cache_write(codec, reg, value); |
| 493 » » if (ret < 0) |
| 494 » » » return -1; |
| 495 » } |
| 452 | 496 |
| 453 if (codec->cache_only) { | 497 if (codec->cache_only) { |
| 454 codec->cache_sync = 1; | 498 codec->cache_sync = 1; |
| 455 return 0; | 499 return 0; |
| 456 } | 500 } |
| 457 | 501 |
| 458 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | |
| 459 | |
| 460 ret = codec->hw_write(codec->control_data, data, 3); | 502 ret = codec->hw_write(codec->control_data, data, 3); |
| 461 if (ret == 3) | 503 if (ret == 3) |
| 462 return 0; | 504 return 0; |
| 463 if (ret < 0) | 505 if (ret < 0) |
| 464 return ret; | 506 return ret; |
| 465 else | 507 else |
| 466 return -EIO; | 508 return -EIO; |
| 467 } | 509 } |
| 468 | 510 |
| 469 #if defined(CONFIG_SPI_MASTER) | 511 #if defined(CONFIG_SPI_MASTER) |
| 470 static int snd_soc_16_8_spi_write(void *control_data, const char *data, | 512 static int snd_soc_16_8_spi_write(void *control_data, const char *data, |
| 471 int len) | 513 int len) |
| 472 { | 514 { |
| 473 struct spi_device *spi = control_data; | 515 struct spi_device *spi = control_data; |
| 474 struct spi_transfer t; | 516 struct spi_transfer t; |
| 475 struct spi_message m; | 517 struct spi_message m; |
| 476 u8 msg[3]; | 518 u8 msg[3]; |
| 477 | 519 |
| 478 if (len <= 0) | 520 if (len <= 0) |
| 479 return 0; | 521 return 0; |
| 480 | 522 |
| 481 msg[0] = data[0]; | 523 msg[0] = data[0]; |
| 482 msg[1] = data[1]; | 524 msg[1] = data[1]; |
| 483 msg[2] = data[2]; | 525 msg[2] = data[2]; |
| 484 | 526 |
| 485 spi_message_init(&m); | 527 spi_message_init(&m); |
| 486 » memset(&t, 0, (sizeof t)); | 528 » memset(&t, 0, sizeof t); |
| 487 | 529 |
| 488 t.tx_buf = &msg[0]; | 530 t.tx_buf = &msg[0]; |
| 489 t.len = len; | 531 t.len = len; |
| 490 | 532 |
| 491 spi_message_add_tail(&t, &m); | 533 spi_message_add_tail(&t, &m); |
| 492 spi_sync(spi, &m); | 534 spi_sync(spi, &m); |
| 493 | 535 |
| 494 return len; | 536 return len; |
| 495 } | 537 } |
| 496 #else | 538 #else |
| (...skipping 30 matching lines...) Expand all Loading... |
| 527 | 569 |
| 528 return be16_to_cpu(data); | 570 return be16_to_cpu(data); |
| 529 } | 571 } |
| 530 #else | 572 #else |
| 531 #define snd_soc_16_16_read_i2c NULL | 573 #define snd_soc_16_16_read_i2c NULL |
| 532 #endif | 574 #endif |
| 533 | 575 |
| 534 static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, | 576 static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, |
| 535 unsigned int reg) | 577 unsigned int reg) |
| 536 { | 578 { |
| 537 » u16 *cache = codec->reg_cache; | 579 » int ret; |
| 580 » unsigned int val; |
| 538 | 581 |
| 539 if (reg >= codec->driver->reg_cache_size || | 582 if (reg >= codec->driver->reg_cache_size || |
| 540 » snd_soc_codec_volatile_register(codec, reg)) { | 583 » snd_soc_codec_volatile_register(codec, reg) || |
| 584 » codec->cache_bypass) { |
| 541 if (codec->cache_only) | 585 if (codec->cache_only) |
| 542 return -1; | 586 return -1; |
| 543 | 587 |
| 588 BUG_ON(!codec->hw_read); |
| 544 return codec->hw_read(codec, reg); | 589 return codec->hw_read(codec, reg); |
| 545 } | 590 } |
| 546 | 591 |
| 547 » return cache[reg]; | 592 » ret = snd_soc_cache_read(codec, reg, &val); |
| 593 » if (ret < 0) |
| 594 » » return -1; |
| 595 |
| 596 » return val; |
| 548 } | 597 } |
| 549 | 598 |
| 550 static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, | 599 static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, |
| 551 unsigned int value) | 600 unsigned int value) |
| 552 { | 601 { |
| 553 u16 *cache = codec->reg_cache; | |
| 554 u8 data[4]; | 602 u8 data[4]; |
| 555 int ret; | 603 int ret; |
| 556 | 604 |
| 557 data[0] = (reg >> 8) & 0xff; | 605 data[0] = (reg >> 8) & 0xff; |
| 558 data[1] = reg & 0xff; | 606 data[1] = reg & 0xff; |
| 559 data[2] = (value >> 8) & 0xff; | 607 data[2] = (value >> 8) & 0xff; |
| 560 data[3] = value & 0xff; | 608 data[3] = value & 0xff; |
| 561 | 609 |
| 562 if (!snd_soc_codec_volatile_register(codec, reg) && | 610 if (!snd_soc_codec_volatile_register(codec, reg) && |
| 563 » » reg < codec->driver->reg_cache_size) | 611 » » reg < codec->driver->reg_cache_size && |
| 564 » » » cache[reg] = value; | 612 » » !codec->cache_bypass) { |
| 613 » » ret = snd_soc_cache_write(codec, reg, value); |
| 614 » » if (ret < 0) |
| 615 » » » return -1; |
| 616 » } |
| 565 | 617 |
| 566 if (codec->cache_only) { | 618 if (codec->cache_only) { |
| 567 codec->cache_sync = 1; | 619 codec->cache_sync = 1; |
| 568 return 0; | 620 return 0; |
| 569 } | 621 } |
| 570 | 622 |
| 571 dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); | |
| 572 | |
| 573 ret = codec->hw_write(codec->control_data, data, 4); | 623 ret = codec->hw_write(codec->control_data, data, 4); |
| 574 if (ret == 4) | 624 if (ret == 4) |
| 575 return 0; | 625 return 0; |
| 576 if (ret < 0) | 626 if (ret < 0) |
| 577 return ret; | 627 return ret; |
| 578 else | 628 else |
| 579 return -EIO; | 629 return -EIO; |
| 580 } | 630 } |
| 581 | 631 |
| 582 #if defined(CONFIG_SPI_MASTER) | 632 #if defined(CONFIG_SPI_MASTER) |
| 583 static int snd_soc_16_16_spi_write(void *control_data, const char *data, | 633 static int snd_soc_16_16_spi_write(void *control_data, const char *data, |
| 584 int len) | 634 int len) |
| 585 { | 635 { |
| 586 struct spi_device *spi = control_data; | 636 struct spi_device *spi = control_data; |
| 587 struct spi_transfer t; | 637 struct spi_transfer t; |
| 588 struct spi_message m; | 638 struct spi_message m; |
| 589 u8 msg[4]; | 639 u8 msg[4]; |
| 590 | 640 |
| 591 if (len <= 0) | 641 if (len <= 0) |
| 592 return 0; | 642 return 0; |
| 593 | 643 |
| 594 msg[0] = data[0]; | 644 msg[0] = data[0]; |
| 595 msg[1] = data[1]; | 645 msg[1] = data[1]; |
| 596 msg[2] = data[2]; | 646 msg[2] = data[2]; |
| 597 msg[3] = data[3]; | 647 msg[3] = data[3]; |
| 598 | 648 |
| 599 spi_message_init(&m); | 649 spi_message_init(&m); |
| 600 » memset(&t, 0, (sizeof t)); | 650 » memset(&t, 0, sizeof t); |
| 601 | 651 |
| 602 t.tx_buf = &msg[0]; | 652 t.tx_buf = &msg[0]; |
| 603 t.len = len; | 653 t.len = len; |
| 604 | 654 |
| 605 spi_message_add_tail(&t, &m); | 655 spi_message_add_tail(&t, &m); |
| 606 spi_sync(spi, &m); | 656 spi_sync(spi, &m); |
| 607 | 657 |
| 608 return len; | 658 return len; |
| 609 } | 659 } |
| 610 #else | 660 #else |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 685 if (io_types[i].addr_bits == addr_bits && | 735 if (io_types[i].addr_bits == addr_bits && |
| 686 io_types[i].data_bits == data_bits) | 736 io_types[i].data_bits == data_bits) |
| 687 break; | 737 break; |
| 688 if (i == ARRAY_SIZE(io_types)) { | 738 if (i == ARRAY_SIZE(io_types)) { |
| 689 printk(KERN_ERR | 739 printk(KERN_ERR |
| 690 "No I/O functions for %d bit address %d bit data\n", | 740 "No I/O functions for %d bit address %d bit data\n", |
| 691 addr_bits, data_bits); | 741 addr_bits, data_bits); |
| 692 return -EINVAL; | 742 return -EINVAL; |
| 693 } | 743 } |
| 694 | 744 |
| 695 » codec->driver->write = io_types[i].write; | 745 » codec->write = io_types[i].write; |
| 696 » codec->driver->read = io_types[i].read; | 746 » codec->read = io_types[i].read; |
| 697 | 747 |
| 698 switch (control) { | 748 switch (control) { |
| 699 case SND_SOC_CUSTOM: | 749 case SND_SOC_CUSTOM: |
| 700 break; | 750 break; |
| 701 | 751 |
| 702 case SND_SOC_I2C: | 752 case SND_SOC_I2C: |
| 703 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | 753 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) |
| 704 codec->hw_write = (hw_write_t)i2c_master_send; | 754 codec->hw_write = (hw_write_t)i2c_master_send; |
| 705 #endif | 755 #endif |
| 706 if (io_types[i].i2c_read) | 756 if (io_types[i].i2c_read) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 717 | 767 |
| 718 codec->control_data = container_of(codec->dev, | 768 codec->control_data = container_of(codec->dev, |
| 719 struct spi_device, | 769 struct spi_device, |
| 720 dev); | 770 dev); |
| 721 break; | 771 break; |
| 722 } | 772 } |
| 723 | 773 |
| 724 return 0; | 774 return 0; |
| 725 } | 775 } |
| 726 EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); | 776 EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); |
| 777 |
| 778 static bool snd_soc_set_cache_val(void *base, unsigned int idx, |
| 779 unsigned int val, unsigned int word_size) |
| 780 { |
| 781 switch (word_size) { |
| 782 case 1: { |
| 783 u8 *cache = base; |
| 784 if (cache[idx] == val) |
| 785 return true; |
| 786 cache[idx] = val; |
| 787 break; |
| 788 } |
| 789 case 2: { |
| 790 u16 *cache = base; |
| 791 if (cache[idx] == val) |
| 792 return true; |
| 793 cache[idx] = val; |
| 794 break; |
| 795 } |
| 796 default: |
| 797 BUG(); |
| 798 } |
| 799 return false; |
| 800 } |
| 801 |
| 802 static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, |
| 803 unsigned int word_size) |
| 804 { |
| 805 switch (word_size) { |
| 806 case 1: { |
| 807 const u8 *cache = base; |
| 808 return cache[idx]; |
| 809 } |
| 810 case 2: { |
| 811 const u16 *cache = base; |
| 812 return cache[idx]; |
| 813 } |
| 814 default: |
| 815 BUG(); |
| 816 } |
| 817 /* unreachable */ |
| 818 return -1; |
| 819 } |
| 820 |
| 821 struct snd_soc_rbtree_node { |
| 822 struct rb_node node; |
| 823 unsigned int reg; |
| 824 unsigned int value; |
| 825 unsigned int defval; |
| 826 } __attribute__ ((packed)); |
| 827 |
| 828 struct snd_soc_rbtree_ctx { |
| 829 struct rb_root root; |
| 830 }; |
| 831 |
| 832 static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup( |
| 833 struct rb_root *root, unsigned int reg) |
| 834 { |
| 835 struct rb_node *node; |
| 836 struct snd_soc_rbtree_node *rbnode; |
| 837 |
| 838 node = root->rb_node; |
| 839 while (node) { |
| 840 rbnode = container_of(node, struct snd_soc_rbtree_node, node); |
| 841 if (rbnode->reg < reg) |
| 842 node = node->rb_left; |
| 843 else if (rbnode->reg > reg) |
| 844 node = node->rb_right; |
| 845 else |
| 846 return rbnode; |
| 847 } |
| 848 |
| 849 return NULL; |
| 850 } |
| 851 |
| 852 static int snd_soc_rbtree_insert(struct rb_root *root, |
| 853 struct snd_soc_rbtree_node *rbnode) |
| 854 { |
| 855 struct rb_node **new, *parent; |
| 856 struct snd_soc_rbtree_node *rbnode_tmp; |
| 857 |
| 858 parent = NULL; |
| 859 new = &root->rb_node; |
| 860 while (*new) { |
| 861 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node, |
| 862 node); |
| 863 parent = *new; |
| 864 if (rbnode_tmp->reg < rbnode->reg) |
| 865 new = &((*new)->rb_left); |
| 866 else if (rbnode_tmp->reg > rbnode->reg) |
| 867 new = &((*new)->rb_right); |
| 868 else |
| 869 return 0; |
| 870 } |
| 871 |
| 872 /* insert the node into the rbtree */ |
| 873 rb_link_node(&rbnode->node, parent, new); |
| 874 rb_insert_color(&rbnode->node, root); |
| 875 |
| 876 return 1; |
| 877 } |
| 878 |
| 879 static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec) |
| 880 { |
| 881 struct snd_soc_rbtree_ctx *rbtree_ctx; |
| 882 struct rb_node *node; |
| 883 struct snd_soc_rbtree_node *rbnode; |
| 884 unsigned int val; |
| 885 int ret; |
| 886 |
| 887 rbtree_ctx = codec->reg_cache; |
| 888 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { |
| 889 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node); |
| 890 if (rbnode->value == rbnode->defval) |
| 891 continue; |
| 892 ret = snd_soc_cache_read(codec, rbnode->reg, &val); |
| 893 if (ret) |
| 894 return ret; |
| 895 codec->cache_bypass = 1; |
| 896 ret = snd_soc_write(codec, rbnode->reg, val); |
| 897 codec->cache_bypass = 0; |
| 898 if (ret) |
| 899 return ret; |
| 900 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", |
| 901 rbnode->reg, val); |
| 902 } |
| 903 |
| 904 return 0; |
| 905 } |
| 906 |
| 907 static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, |
| 908 unsigned int reg, unsigned int value) |
| 909 { |
| 910 struct snd_soc_rbtree_ctx *rbtree_ctx; |
| 911 struct snd_soc_rbtree_node *rbnode; |
| 912 |
| 913 rbtree_ctx = codec->reg_cache; |
| 914 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); |
| 915 if (rbnode) { |
| 916 if (rbnode->value == value) |
| 917 return 0; |
| 918 rbnode->value = value; |
| 919 } else { |
| 920 /* bail out early, no need to create the rbnode yet */ |
| 921 if (!value) |
| 922 return 0; |
| 923 /* |
| 924 * for uninitialized registers whose value is changed |
| 925 * from the default zero, create an rbnode and insert |
| 926 * it into the tree. |
| 927 */ |
| 928 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); |
| 929 if (!rbnode) |
| 930 return -ENOMEM; |
| 931 rbnode->reg = reg; |
| 932 rbnode->value = value; |
| 933 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode); |
| 934 } |
| 935 |
| 936 return 0; |
| 937 } |
| 938 |
| 939 static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec, |
| 940 unsigned int reg, unsigned int *value) |
| 941 { |
| 942 struct snd_soc_rbtree_ctx *rbtree_ctx; |
| 943 struct snd_soc_rbtree_node *rbnode; |
| 944 |
| 945 rbtree_ctx = codec->reg_cache; |
| 946 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); |
| 947 if (rbnode) { |
| 948 *value = rbnode->value; |
| 949 } else { |
| 950 /* uninitialized registers default to 0 */ |
| 951 *value = 0; |
| 952 } |
| 953 |
| 954 return 0; |
| 955 } |
| 956 |
| 957 static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec) |
| 958 { |
| 959 struct rb_node *next; |
| 960 struct snd_soc_rbtree_ctx *rbtree_ctx; |
| 961 struct snd_soc_rbtree_node *rbtree_node; |
| 962 |
| 963 /* if we've already been called then just return */ |
| 964 rbtree_ctx = codec->reg_cache; |
| 965 if (!rbtree_ctx) |
| 966 return 0; |
| 967 |
| 968 /* free up the rbtree */ |
| 969 next = rb_first(&rbtree_ctx->root); |
| 970 while (next) { |
| 971 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node); |
| 972 next = rb_next(&rbtree_node->node); |
| 973 rb_erase(&rbtree_node->node, &rbtree_ctx->root); |
| 974 kfree(rbtree_node); |
| 975 } |
| 976 |
| 977 /* release the resources */ |
| 978 kfree(codec->reg_cache); |
| 979 codec->reg_cache = NULL; |
| 980 |
| 981 return 0; |
| 982 } |
| 983 |
| 984 static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) |
| 985 { |
| 986 struct snd_soc_rbtree_node *rbtree_node; |
| 987 struct snd_soc_rbtree_ctx *rbtree_ctx; |
| 988 unsigned int val; |
| 989 unsigned int word_size; |
| 990 int i; |
| 991 int ret; |
| 992 |
| 993 codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL); |
| 994 if (!codec->reg_cache) |
| 995 return -ENOMEM; |
| 996 |
| 997 rbtree_ctx = codec->reg_cache; |
| 998 rbtree_ctx->root = RB_ROOT; |
| 999 |
| 1000 if (!codec->reg_def_copy) |
| 1001 return 0; |
| 1002 |
| 1003 /* |
| 1004 * populate the rbtree with the initialized registers. All other |
| 1005 * registers will be inserted when they are first modified. |
| 1006 */ |
| 1007 word_size = codec->driver->reg_word_size; |
| 1008 for (i = 0; i < codec->driver->reg_cache_size; ++i) { |
| 1009 val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size); |
| 1010 if (!val) |
| 1011 continue; |
| 1012 rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); |
| 1013 if (!rbtree_node) { |
| 1014 ret = -ENOMEM; |
| 1015 snd_soc_cache_exit(codec); |
| 1016 break; |
| 1017 } |
| 1018 rbtree_node->reg = i; |
| 1019 rbtree_node->value = val; |
| 1020 rbtree_node->defval = val; |
| 1021 snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node); |
| 1022 } |
| 1023 |
| 1024 return 0; |
| 1025 } |
| 1026 |
| 1027 #ifdef CONFIG_SND_SOC_CACHE_LZO |
| 1028 struct snd_soc_lzo_ctx { |
| 1029 void *wmem; |
| 1030 void *dst; |
| 1031 const void *src; |
| 1032 size_t src_len; |
| 1033 size_t dst_len; |
| 1034 size_t decompressed_size; |
| 1035 unsigned long *sync_bmp; |
| 1036 int sync_bmp_nbits; |
| 1037 }; |
| 1038 |
| 1039 #define LZO_BLOCK_NUM 8 |
| 1040 static int snd_soc_lzo_block_count(void) |
| 1041 { |
| 1042 return LZO_BLOCK_NUM; |
| 1043 } |
| 1044 |
| 1045 static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx) |
| 1046 { |
| 1047 lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); |
| 1048 if (!lzo_ctx->wmem) |
| 1049 return -ENOMEM; |
| 1050 return 0; |
| 1051 } |
| 1052 |
| 1053 static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx) |
| 1054 { |
| 1055 size_t compress_size; |
| 1056 int ret; |
| 1057 |
| 1058 ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len, |
| 1059 lzo_ctx->dst, &compress_size, lzo_ctx->wmem); |
| 1060 if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len) |
| 1061 return -EINVAL; |
| 1062 lzo_ctx->dst_len = compress_size; |
| 1063 return 0; |
| 1064 } |
| 1065 |
| 1066 static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx) |
| 1067 { |
| 1068 size_t dst_len; |
| 1069 int ret; |
| 1070 |
| 1071 dst_len = lzo_ctx->dst_len; |
| 1072 ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len, |
| 1073 lzo_ctx->dst, &dst_len); |
| 1074 if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len) |
| 1075 return -EINVAL; |
| 1076 return 0; |
| 1077 } |
| 1078 |
| 1079 static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec, |
| 1080 struct snd_soc_lzo_ctx *lzo_ctx) |
| 1081 { |
| 1082 int ret; |
| 1083 |
| 1084 lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE); |
| 1085 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL); |
| 1086 if (!lzo_ctx->dst) { |
| 1087 lzo_ctx->dst_len = 0; |
| 1088 return -ENOMEM; |
| 1089 } |
| 1090 |
| 1091 ret = snd_soc_lzo_compress(lzo_ctx); |
| 1092 if (ret < 0) |
| 1093 return ret; |
| 1094 return 0; |
| 1095 } |
| 1096 |
| 1097 static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec, |
| 1098 struct snd_soc_lzo_ctx *lzo_ctx) |
| 1099 { |
| 1100 int ret; |
| 1101 |
| 1102 lzo_ctx->dst_len = lzo_ctx->decompressed_size; |
| 1103 lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL); |
| 1104 if (!lzo_ctx->dst) { |
| 1105 lzo_ctx->dst_len = 0; |
| 1106 return -ENOMEM; |
| 1107 } |
| 1108 |
| 1109 ret = snd_soc_lzo_decompress(lzo_ctx); |
| 1110 if (ret < 0) |
| 1111 return ret; |
| 1112 return 0; |
| 1113 } |
| 1114 |
| 1115 static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec, |
| 1116 unsigned int reg) |
| 1117 { |
| 1118 const struct snd_soc_codec_driver *codec_drv; |
| 1119 |
| 1120 codec_drv = codec->driver; |
| 1121 return (reg * codec_drv->reg_word_size) / |
| 1122 DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()); |
| 1123 } |
| 1124 |
| 1125 static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec, |
| 1126 unsigned int reg) |
| 1127 { |
| 1128 const struct snd_soc_codec_driver *codec_drv; |
| 1129 |
| 1130 codec_drv = codec->driver; |
| 1131 return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) / |
| 1132 codec_drv->reg_word_size); |
| 1133 } |
| 1134 |
| 1135 static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec) |
| 1136 { |
| 1137 const struct snd_soc_codec_driver *codec_drv; |
| 1138 |
| 1139 codec_drv = codec->driver; |
| 1140 return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()); |
| 1141 } |
| 1142 |
| 1143 static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) |
| 1144 { |
| 1145 struct snd_soc_lzo_ctx **lzo_blocks; |
| 1146 unsigned int val; |
| 1147 int i; |
| 1148 int ret; |
| 1149 |
| 1150 lzo_blocks = codec->reg_cache; |
| 1151 for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbi
ts) { |
| 1152 ret = snd_soc_cache_read(codec, i, &val); |
| 1153 if (ret) |
| 1154 return ret; |
| 1155 codec->cache_bypass = 1; |
| 1156 ret = snd_soc_write(codec, i, val); |
| 1157 codec->cache_bypass = 0; |
| 1158 if (ret) |
| 1159 return ret; |
| 1160 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", |
| 1161 i, val); |
| 1162 } |
| 1163 |
| 1164 return 0; |
| 1165 } |
| 1166 |
| 1167 static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec, |
| 1168 unsigned int reg, unsigned int value) |
| 1169 { |
| 1170 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks; |
| 1171 int ret, blkindex, blkpos; |
| 1172 size_t blksize, tmp_dst_len; |
| 1173 void *tmp_dst; |
| 1174 |
| 1175 /* index of the compressed lzo block */ |
| 1176 blkindex = snd_soc_lzo_get_blkindex(codec, reg); |
| 1177 /* register index within the decompressed block */ |
| 1178 blkpos = snd_soc_lzo_get_blkpos(codec, reg); |
| 1179 /* size of the compressed block */ |
| 1180 blksize = snd_soc_lzo_get_blksize(codec); |
| 1181 lzo_blocks = codec->reg_cache; |
| 1182 lzo_block = lzo_blocks[blkindex]; |
| 1183 |
| 1184 /* save the pointer and length of the compressed block */ |
| 1185 tmp_dst = lzo_block->dst; |
| 1186 tmp_dst_len = lzo_block->dst_len; |
| 1187 |
| 1188 /* prepare the source to be the compressed block */ |
| 1189 lzo_block->src = lzo_block->dst; |
| 1190 lzo_block->src_len = lzo_block->dst_len; |
| 1191 |
| 1192 /* decompress the block */ |
| 1193 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block); |
| 1194 if (ret < 0) { |
| 1195 kfree(lzo_block->dst); |
| 1196 goto out; |
| 1197 } |
| 1198 |
| 1199 /* write the new value to the cache */ |
| 1200 if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value, |
| 1201 codec->driver->reg_word_size)) { |
| 1202 kfree(lzo_block->dst); |
| 1203 goto out; |
| 1204 } |
| 1205 |
| 1206 /* prepare the source to be the decompressed block */ |
| 1207 lzo_block->src = lzo_block->dst; |
| 1208 lzo_block->src_len = lzo_block->dst_len; |
| 1209 |
| 1210 /* compress the block */ |
| 1211 ret = snd_soc_lzo_compress_cache_block(codec, lzo_block); |
| 1212 if (ret < 0) { |
| 1213 kfree(lzo_block->dst); |
| 1214 kfree(lzo_block->src); |
| 1215 goto out; |
| 1216 } |
| 1217 |
| 1218 /* set the bit so we know we have to sync this register */ |
| 1219 set_bit(reg, lzo_block->sync_bmp); |
| 1220 kfree(tmp_dst); |
| 1221 kfree(lzo_block->src); |
| 1222 return 0; |
| 1223 out: |
| 1224 lzo_block->dst = tmp_dst; |
| 1225 lzo_block->dst_len = tmp_dst_len; |
| 1226 return ret; |
| 1227 } |
| 1228 |
| 1229 static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec, |
| 1230 unsigned int reg, unsigned int *value) |
| 1231 { |
| 1232 struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks; |
| 1233 int ret, blkindex, blkpos; |
| 1234 size_t blksize, tmp_dst_len; |
| 1235 void *tmp_dst; |
| 1236 |
| 1237 *value = 0; |
| 1238 /* index of the compressed lzo block */ |
| 1239 blkindex = snd_soc_lzo_get_blkindex(codec, reg); |
| 1240 /* register index within the decompressed block */ |
| 1241 blkpos = snd_soc_lzo_get_blkpos(codec, reg); |
| 1242 /* size of the compressed block */ |
| 1243 blksize = snd_soc_lzo_get_blksize(codec); |
| 1244 lzo_blocks = codec->reg_cache; |
| 1245 lzo_block = lzo_blocks[blkindex]; |
| 1246 |
| 1247 /* save the pointer and length of the compressed block */ |
| 1248 tmp_dst = lzo_block->dst; |
| 1249 tmp_dst_len = lzo_block->dst_len; |
| 1250 |
| 1251 /* prepare the source to be the compressed block */ |
| 1252 lzo_block->src = lzo_block->dst; |
| 1253 lzo_block->src_len = lzo_block->dst_len; |
| 1254 |
| 1255 /* decompress the block */ |
| 1256 ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block); |
| 1257 if (ret >= 0) |
| 1258 /* fetch the value from the cache */ |
| 1259 *value = snd_soc_get_cache_val(lzo_block->dst, blkpos, |
| 1260 codec->driver->reg_word_size); |
| 1261 |
| 1262 kfree(lzo_block->dst); |
| 1263 /* restore the pointer and length of the compressed block */ |
| 1264 lzo_block->dst = tmp_dst; |
| 1265 lzo_block->dst_len = tmp_dst_len; |
| 1266 return 0; |
| 1267 } |
| 1268 |
| 1269 static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec) |
| 1270 { |
| 1271 struct snd_soc_lzo_ctx **lzo_blocks; |
| 1272 int i, blkcount; |
| 1273 |
| 1274 lzo_blocks = codec->reg_cache; |
| 1275 if (!lzo_blocks) |
| 1276 return 0; |
| 1277 |
| 1278 blkcount = snd_soc_lzo_block_count(); |
| 1279 /* |
| 1280 * the pointer to the bitmap used for syncing the cache |
| 1281 * is shared amongst all lzo_blocks. Ensure it is freed |
| 1282 * only once. |
| 1283 */ |
| 1284 if (lzo_blocks[0]) |
| 1285 kfree(lzo_blocks[0]->sync_bmp); |
| 1286 for (i = 0; i < blkcount; ++i) { |
| 1287 if (lzo_blocks[i]) { |
| 1288 kfree(lzo_blocks[i]->wmem); |
| 1289 kfree(lzo_blocks[i]->dst); |
| 1290 } |
| 1291 /* each lzo_block is a pointer returned by kmalloc or NULL */ |
| 1292 kfree(lzo_blocks[i]); |
| 1293 } |
| 1294 kfree(lzo_blocks); |
| 1295 codec->reg_cache = NULL; |
| 1296 return 0; |
| 1297 } |
| 1298 |
| 1299 static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) |
| 1300 { |
| 1301 struct snd_soc_lzo_ctx **lzo_blocks; |
| 1302 size_t bmp_size; |
| 1303 const struct snd_soc_codec_driver *codec_drv; |
| 1304 int ret, tofree, i, blksize, blkcount; |
| 1305 const char *p, *end; |
| 1306 unsigned long *sync_bmp; |
| 1307 |
| 1308 ret = 0; |
| 1309 codec_drv = codec->driver; |
| 1310 |
| 1311 /* |
| 1312 * If we have not been given a default register cache |
| 1313 * then allocate a dummy zero-ed out region, compress it |
| 1314 * and remember to free it afterwards. |
| 1315 */ |
| 1316 tofree = 0; |
| 1317 if (!codec->reg_def_copy) |
| 1318 tofree = 1; |
| 1319 |
| 1320 if (!codec->reg_def_copy) { |
| 1321 codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL); |
| 1322 if (!codec->reg_def_copy) |
| 1323 return -ENOMEM; |
| 1324 } |
| 1325 |
| 1326 blkcount = snd_soc_lzo_block_count(); |
| 1327 codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks, |
| 1328 GFP_KERNEL); |
| 1329 if (!codec->reg_cache) { |
| 1330 ret = -ENOMEM; |
| 1331 goto err_tofree; |
| 1332 } |
| 1333 lzo_blocks = codec->reg_cache; |
| 1334 |
| 1335 /* |
| 1336 * allocate a bitmap to be used when syncing the cache with |
| 1337 * the hardware. Each time a register is modified, the corresponding |
| 1338 * bit is set in the bitmap, so we know that we have to sync |
| 1339 * that register. |
| 1340 */ |
| 1341 bmp_size = codec_drv->reg_cache_size; |
| 1342 sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long), |
| 1343 GFP_KERNEL); |
| 1344 if (!sync_bmp) { |
| 1345 ret = -ENOMEM; |
| 1346 goto err; |
| 1347 } |
| 1348 bitmap_zero(sync_bmp, bmp_size); |
| 1349 |
| 1350 /* allocate the lzo blocks and initialize them */ |
| 1351 for (i = 0; i < blkcount; ++i) { |
| 1352 lzo_blocks[i] = kzalloc(sizeof **lzo_blocks, |
| 1353 GFP_KERNEL); |
| 1354 if (!lzo_blocks[i]) { |
| 1355 kfree(sync_bmp); |
| 1356 ret = -ENOMEM; |
| 1357 goto err; |
| 1358 } |
| 1359 lzo_blocks[i]->sync_bmp = sync_bmp; |
| 1360 lzo_blocks[i]->sync_bmp_nbits = bmp_size; |
| 1361 /* alloc the working space for the compressed block */ |
| 1362 ret = snd_soc_lzo_prepare(lzo_blocks[i]); |
| 1363 if (ret < 0) |
| 1364 goto err; |
| 1365 } |
| 1366 |
| 1367 blksize = snd_soc_lzo_get_blksize(codec); |
| 1368 p = codec->reg_def_copy; |
| 1369 end = codec->reg_def_copy + codec->reg_size; |
| 1370 /* compress the register map and fill the lzo blocks */ |
| 1371 for (i = 0; i < blkcount; ++i, p += blksize) { |
| 1372 lzo_blocks[i]->src = p; |
| 1373 if (p + blksize > end) |
| 1374 lzo_blocks[i]->src_len = end - p; |
| 1375 else |
| 1376 lzo_blocks[i]->src_len = blksize; |
| 1377 ret = snd_soc_lzo_compress_cache_block(codec, |
| 1378 lzo_blocks[i]); |
| 1379 if (ret < 0) |
| 1380 goto err; |
| 1381 lzo_blocks[i]->decompressed_size = |
| 1382 lzo_blocks[i]->src_len; |
| 1383 } |
| 1384 |
| 1385 if (tofree) { |
| 1386 kfree(codec->reg_def_copy); |
| 1387 codec->reg_def_copy = NULL; |
| 1388 } |
| 1389 return 0; |
| 1390 err: |
| 1391 snd_soc_cache_exit(codec); |
| 1392 err_tofree: |
| 1393 if (tofree) { |
| 1394 kfree(codec->reg_def_copy); |
| 1395 codec->reg_def_copy = NULL; |
| 1396 } |
| 1397 return ret; |
| 1398 } |
| 1399 #endif |
| 1400 |
| 1401 static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) |
| 1402 { |
| 1403 int i; |
| 1404 int ret; |
| 1405 const struct snd_soc_codec_driver *codec_drv; |
| 1406 unsigned int val; |
| 1407 |
| 1408 codec_drv = codec->driver; |
| 1409 for (i = 0; i < codec_drv->reg_cache_size; ++i) { |
| 1410 ret = snd_soc_cache_read(codec, i, &val); |
| 1411 if (ret) |
| 1412 return ret; |
| 1413 if (codec->reg_def_copy) |
| 1414 if (snd_soc_get_cache_val(codec->reg_def_copy, |
| 1415 i, codec_drv->reg_word_size) =
= val) |
| 1416 continue; |
| 1417 ret = snd_soc_write(codec, i, val); |
| 1418 if (ret) |
| 1419 return ret; |
| 1420 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", |
| 1421 i, val); |
| 1422 } |
| 1423 return 0; |
| 1424 } |
| 1425 |
| 1426 static int snd_soc_flat_cache_write(struct snd_soc_codec *codec, |
| 1427 unsigned int reg, unsigned int value) |
| 1428 { |
| 1429 snd_soc_set_cache_val(codec->reg_cache, reg, value, |
| 1430 codec->driver->reg_word_size); |
| 1431 return 0; |
| 1432 } |
| 1433 |
| 1434 static int snd_soc_flat_cache_read(struct snd_soc_codec *codec, |
| 1435 unsigned int reg, unsigned int *value) |
| 1436 { |
| 1437 *value = snd_soc_get_cache_val(codec->reg_cache, reg, |
| 1438 codec->driver->reg_word_size); |
| 1439 return 0; |
| 1440 } |
| 1441 |
| 1442 static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec) |
| 1443 { |
| 1444 if (!codec->reg_cache) |
| 1445 return 0; |
| 1446 kfree(codec->reg_cache); |
| 1447 codec->reg_cache = NULL; |
| 1448 return 0; |
| 1449 } |
| 1450 |
| 1451 static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) |
| 1452 { |
| 1453 const struct snd_soc_codec_driver *codec_drv; |
| 1454 |
| 1455 codec_drv = codec->driver; |
| 1456 |
| 1457 if (codec->reg_def_copy) |
| 1458 codec->reg_cache = kmemdup(codec->reg_def_copy, |
| 1459 codec->reg_size, GFP_KERNEL); |
| 1460 else |
| 1461 codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL); |
| 1462 if (!codec->reg_cache) |
| 1463 return -ENOMEM; |
| 1464 |
| 1465 return 0; |
| 1466 } |
| 1467 |
| 1468 /* an array of all supported compression types */ |
| 1469 static const struct snd_soc_cache_ops cache_types[] = { |
| 1470 /* Flat *must* be the first entry for fallback */ |
| 1471 { |
| 1472 .id = SND_SOC_FLAT_COMPRESSION, |
| 1473 .name = "flat", |
| 1474 .init = snd_soc_flat_cache_init, |
| 1475 .exit = snd_soc_flat_cache_exit, |
| 1476 .read = snd_soc_flat_cache_read, |
| 1477 .write = snd_soc_flat_cache_write, |
| 1478 .sync = snd_soc_flat_cache_sync |
| 1479 }, |
| 1480 #ifdef CONFIG_SND_SOC_CACHE_LZO |
| 1481 { |
| 1482 .id = SND_SOC_LZO_COMPRESSION, |
| 1483 .name = "LZO", |
| 1484 .init = snd_soc_lzo_cache_init, |
| 1485 .exit = snd_soc_lzo_cache_exit, |
| 1486 .read = snd_soc_lzo_cache_read, |
| 1487 .write = snd_soc_lzo_cache_write, |
| 1488 .sync = snd_soc_lzo_cache_sync |
| 1489 }, |
| 1490 #endif |
| 1491 { |
| 1492 .id = SND_SOC_RBTREE_COMPRESSION, |
| 1493 .name = "rbtree", |
| 1494 .init = snd_soc_rbtree_cache_init, |
| 1495 .exit = snd_soc_rbtree_cache_exit, |
| 1496 .read = snd_soc_rbtree_cache_read, |
| 1497 .write = snd_soc_rbtree_cache_write, |
| 1498 .sync = snd_soc_rbtree_cache_sync |
| 1499 } |
| 1500 }; |
| 1501 |
| 1502 int snd_soc_cache_init(struct snd_soc_codec *codec) |
| 1503 { |
| 1504 int i; |
| 1505 |
| 1506 for (i = 0; i < ARRAY_SIZE(cache_types); ++i) |
| 1507 if (cache_types[i].id == codec->compress_type) |
| 1508 break; |
| 1509 |
| 1510 /* Fall back to flat compression */ |
| 1511 if (i == ARRAY_SIZE(cache_types)) { |
| 1512 dev_warn(codec->dev, "Could not match compress type: %d\n", |
| 1513 codec->compress_type); |
| 1514 i = 0; |
| 1515 } |
| 1516 |
| 1517 mutex_init(&codec->cache_rw_mutex); |
| 1518 codec->cache_ops = &cache_types[i]; |
| 1519 |
| 1520 if (codec->cache_ops->init) { |
| 1521 if (codec->cache_ops->name) |
| 1522 dev_dbg(codec->dev, "Initializing %s cache for %s codec\
n", |
| 1523 codec->cache_ops->name, codec->name); |
| 1524 return codec->cache_ops->init(codec); |
| 1525 } |
| 1526 return -EINVAL; |
| 1527 } |
| 1528 |
| 1529 /* |
| 1530 * NOTE: keep in mind that this function might be called |
| 1531 * multiple times. |
| 1532 */ |
| 1533 int snd_soc_cache_exit(struct snd_soc_codec *codec) |
| 1534 { |
| 1535 if (codec->cache_ops && codec->cache_ops->exit) { |
| 1536 if (codec->cache_ops->name) |
| 1537 dev_dbg(codec->dev, "Destroying %s cache for %s codec\n"
, |
| 1538 codec->cache_ops->name, codec->name); |
| 1539 return codec->cache_ops->exit(codec); |
| 1540 } |
| 1541 return -EINVAL; |
| 1542 } |
| 1543 |
| 1544 /** |
| 1545 * snd_soc_cache_read: Fetch the value of a given register from the cache. |
| 1546 * |
| 1547 * @codec: CODEC to configure. |
| 1548 * @reg: The register index. |
| 1549 * @value: The value to be returned. |
| 1550 */ |
| 1551 int snd_soc_cache_read(struct snd_soc_codec *codec, |
| 1552 unsigned int reg, unsigned int *value) |
| 1553 { |
| 1554 int ret; |
| 1555 |
| 1556 mutex_lock(&codec->cache_rw_mutex); |
| 1557 |
| 1558 if (value && codec->cache_ops && codec->cache_ops->read) { |
| 1559 ret = codec->cache_ops->read(codec, reg, value); |
| 1560 mutex_unlock(&codec->cache_rw_mutex); |
| 1561 return ret; |
| 1562 } |
| 1563 |
| 1564 mutex_unlock(&codec->cache_rw_mutex); |
| 1565 return -EINVAL; |
| 1566 } |
| 1567 EXPORT_SYMBOL_GPL(snd_soc_cache_read); |
| 1568 |
| 1569 /** |
| 1570 * snd_soc_cache_write: Set the value of a given register in the cache. |
| 1571 * |
| 1572 * @codec: CODEC to configure. |
| 1573 * @reg: The register index. |
| 1574 * @value: The new register value. |
| 1575 */ |
| 1576 int snd_soc_cache_write(struct snd_soc_codec *codec, |
| 1577 unsigned int reg, unsigned int value) |
| 1578 { |
| 1579 int ret; |
| 1580 |
| 1581 mutex_lock(&codec->cache_rw_mutex); |
| 1582 |
| 1583 if (codec->cache_ops && codec->cache_ops->write) { |
| 1584 ret = codec->cache_ops->write(codec, reg, value); |
| 1585 mutex_unlock(&codec->cache_rw_mutex); |
| 1586 return ret; |
| 1587 } |
| 1588 |
| 1589 mutex_unlock(&codec->cache_rw_mutex); |
| 1590 return -EINVAL; |
| 1591 } |
| 1592 EXPORT_SYMBOL_GPL(snd_soc_cache_write); |
| 1593 |
| 1594 /** |
| 1595 * snd_soc_cache_sync: Sync the register cache with the hardware. |
| 1596 * |
| 1597 * @codec: CODEC to configure. |
| 1598 * |
| 1599 * Any registers that should not be synced should be marked as |
| 1600 * volatile. In general drivers can choose not to use the provided |
| 1601 * syncing functionality if they so require. |
| 1602 */ |
| 1603 int snd_soc_cache_sync(struct snd_soc_codec *codec) |
| 1604 { |
| 1605 int ret; |
| 1606 const char *name; |
| 1607 |
| 1608 if (!codec->cache_sync) { |
| 1609 return 0; |
| 1610 } |
| 1611 |
| 1612 if (!codec->cache_ops || !codec->cache_ops->sync) |
| 1613 return -EINVAL; |
| 1614 |
| 1615 if (codec->cache_ops->name) |
| 1616 name = codec->cache_ops->name; |
| 1617 else |
| 1618 name = "unknown"; |
| 1619 |
| 1620 if (codec->cache_ops->name) |
| 1621 dev_dbg(codec->dev, "Syncing %s cache for %s codec\n", |
| 1622 codec->cache_ops->name, codec->name); |
| 1623 trace_snd_soc_cache_sync(codec, name, "start"); |
| 1624 ret = codec->cache_ops->sync(codec); |
| 1625 if (!ret) |
| 1626 codec->cache_sync = 0; |
| 1627 trace_snd_soc_cache_sync(codec, name, "end"); |
| 1628 return ret; |
| 1629 } |
| 1630 EXPORT_SYMBOL_GPL(snd_soc_cache_sync); |
| 1631 |
| 1632 static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec, |
| 1633 unsigned int reg) |
| 1634 { |
| 1635 const struct snd_soc_codec_driver *codec_drv; |
| 1636 unsigned int min, max, index; |
| 1637 |
| 1638 codec_drv = codec->driver; |
| 1639 min = 0; |
| 1640 max = codec_drv->reg_access_size - 1; |
| 1641 do { |
| 1642 index = (min + max) / 2; |
| 1643 if (codec_drv->reg_access_default[index].reg == reg) |
| 1644 return index; |
| 1645 if (codec_drv->reg_access_default[index].reg < reg) |
| 1646 min = index + 1; |
| 1647 else |
| 1648 max = index; |
| 1649 } while (min <= max); |
| 1650 return -1; |
| 1651 } |
| 1652 |
| 1653 int snd_soc_default_volatile_register(struct snd_soc_codec *codec, |
| 1654 unsigned int reg) |
| 1655 { |
| 1656 int index; |
| 1657 |
| 1658 if (reg >= codec->driver->reg_cache_size) |
| 1659 return 1; |
| 1660 index = snd_soc_get_reg_access_index(codec, reg); |
| 1661 if (index < 0) |
| 1662 return 0; |
| 1663 return codec->driver->reg_access_default[index].vol; |
| 1664 } |
| 1665 EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register); |
| 1666 |
| 1667 int snd_soc_default_readable_register(struct snd_soc_codec *codec, |
| 1668 unsigned int reg) |
| 1669 { |
| 1670 int index; |
| 1671 |
| 1672 if (reg >= codec->driver->reg_cache_size) |
| 1673 return 1; |
| 1674 index = snd_soc_get_reg_access_index(codec, reg); |
| 1675 if (index < 0) |
| 1676 return 0; |
| 1677 return codec->driver->reg_access_default[index].read; |
| 1678 } |
| 1679 EXPORT_SYMBOL_GPL(snd_soc_default_readable_register); |
| OLD | NEW |