diff options
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r-- | sound/soc/soc-core.c | 115 |
1 files changed, 110 insertions, 5 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e048e0910099..844ae8221a3a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -84,7 +84,7 @@ static int run_delayed_work(struct delayed_work *dwork) | |||
84 | /* codec register dump */ | 84 | /* codec register dump */ |
85 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) | 85 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) |
86 | { | 86 | { |
87 | int i, step = 1, count = 0; | 87 | int ret, i, step = 1, count = 0; |
88 | 88 | ||
89 | if (!codec->reg_cache_size) | 89 | if (!codec->reg_cache_size) |
90 | return 0; | 90 | return 0; |
@@ -101,12 +101,24 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) | |||
101 | if (count >= PAGE_SIZE - 1) | 101 | if (count >= PAGE_SIZE - 1) |
102 | break; | 102 | break; |
103 | 103 | ||
104 | if (codec->display_register) | 104 | if (codec->display_register) { |
105 | count += codec->display_register(codec, buf + count, | 105 | count += codec->display_register(codec, buf + count, |
106 | PAGE_SIZE - count, i); | 106 | PAGE_SIZE - count, i); |
107 | else | 107 | } else { |
108 | count += snprintf(buf + count, PAGE_SIZE - count, | 108 | /* If the read fails it's almost certainly due to |
109 | "%4x", codec->read(codec, i)); | 109 | * the register being volatile and the device being |
110 | * powered off. | ||
111 | */ | ||
112 | ret = codec->read(codec, i); | ||
113 | if (ret >= 0) | ||
114 | count += snprintf(buf + count, | ||
115 | PAGE_SIZE - count, | ||
116 | "%4x", ret); | ||
117 | else | ||
118 | count += snprintf(buf + count, | ||
119 | PAGE_SIZE - count, | ||
120 | "<no data: %d>", ret); | ||
121 | } | ||
110 | 122 | ||
111 | if (count >= PAGE_SIZE - 1) | 123 | if (count >= PAGE_SIZE - 1) |
112 | break; | 124 | break; |
@@ -2353,6 +2365,99 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec, | |||
2353 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); | 2365 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); |
2354 | 2366 | ||
2355 | /** | 2367 | /** |
2368 | * snd_soc_info_volsw_2r_sx - double with tlv and variable data size | ||
2369 | * mixer info callback | ||
2370 | * @kcontrol: mixer control | ||
2371 | * @uinfo: control element information | ||
2372 | * | ||
2373 | * Returns 0 for success. | ||
2374 | */ | ||
2375 | int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol, | ||
2376 | struct snd_ctl_elem_info *uinfo) | ||
2377 | { | ||
2378 | struct soc_mixer_control *mc = | ||
2379 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2380 | int max = mc->max; | ||
2381 | int min = mc->min; | ||
2382 | |||
2383 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2384 | uinfo->count = 2; | ||
2385 | uinfo->value.integer.min = 0; | ||
2386 | uinfo->value.integer.max = max-min; | ||
2387 | |||
2388 | return 0; | ||
2389 | } | ||
2390 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx); | ||
2391 | |||
2392 | /** | ||
2393 | * snd_soc_get_volsw_2r_sx - double with tlv and variable data size | ||
2394 | * mixer get callback | ||
2395 | * @kcontrol: mixer control | ||
2396 | * @uinfo: control element information | ||
2397 | * | ||
2398 | * Returns 0 for success. | ||
2399 | */ | ||
2400 | int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, | ||
2401 | struct snd_ctl_elem_value *ucontrol) | ||
2402 | { | ||
2403 | struct soc_mixer_control *mc = | ||
2404 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2405 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2406 | unsigned int mask = (1<<mc->shift)-1; | ||
2407 | int min = mc->min; | ||
2408 | int val = snd_soc_read(codec, mc->reg) & mask; | ||
2409 | int valr = snd_soc_read(codec, mc->rreg) & mask; | ||
2410 | |||
2411 | ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask; | ||
2412 | ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask; | ||
2413 | return 0; | ||
2414 | } | ||
2415 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx); | ||
2416 | |||
2417 | /** | ||
2418 | * snd_soc_put_volsw_2r_sx - double with tlv and variable data size | ||
2419 | * mixer put callback | ||
2420 | * @kcontrol: mixer control | ||
2421 | * @uinfo: control element information | ||
2422 | * | ||
2423 | * Returns 0 for success. | ||
2424 | */ | ||
2425 | int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, | ||
2426 | struct snd_ctl_elem_value *ucontrol) | ||
2427 | { | ||
2428 | struct soc_mixer_control *mc = | ||
2429 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2430 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2431 | unsigned int mask = (1<<mc->shift)-1; | ||
2432 | int min = mc->min; | ||
2433 | int ret; | ||
2434 | unsigned int val, valr, oval, ovalr; | ||
2435 | |||
2436 | val = ((ucontrol->value.integer.value[0]+min) & 0xff); | ||
2437 | val &= mask; | ||
2438 | valr = ((ucontrol->value.integer.value[1]+min) & 0xff); | ||
2439 | valr &= mask; | ||
2440 | |||
2441 | oval = snd_soc_read(codec, mc->reg) & mask; | ||
2442 | ovalr = snd_soc_read(codec, mc->rreg) & mask; | ||
2443 | |||
2444 | ret = 0; | ||
2445 | if (oval != val) { | ||
2446 | ret = snd_soc_write(codec, mc->reg, val); | ||
2447 | if (ret < 0) | ||
2448 | return ret; | ||
2449 | } | ||
2450 | if (ovalr != valr) { | ||
2451 | ret = snd_soc_write(codec, mc->rreg, valr); | ||
2452 | if (ret < 0) | ||
2453 | return ret; | ||
2454 | } | ||
2455 | |||
2456 | return 0; | ||
2457 | } | ||
2458 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx); | ||
2459 | |||
2460 | /** | ||
2356 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. | 2461 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. |
2357 | * @dai: DAI | 2462 | * @dai: DAI |
2358 | * @clk_id: DAI specific clock ID | 2463 | * @clk_id: DAI specific clock ID |