Lines Matching +full:codec +full:- +full:2

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Apple Onboard Audio driver for Onyx codec
7 * This is a driver for the pcm3052 codec chip (codenamed Onyx)
10 * The Onyx codec has the following connections (listed by the bit
14 * 2: line input
24 * But snd-aoa assumes that there's at most one card, so
36 MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa");
43 #define PFX "snd-aoa-codec-onyx: "
46 /* cache registers 65 to 80, they are write-only! */
49 struct aoa_codec codec; member
53 original_mute:2;
62 #define codec_to_onyx(c) container_of(c, struct onyx, codec)
70 *value = onyx->cache[reg-FIRSTREGISTER]; in onyx_read_register()
73 v = i2c_smbus_read_byte_data(onyx->i2c, reg); in onyx_read_register()
76 return -1; in onyx_read_register()
79 onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value; in onyx_read_register()
87 result = i2c_smbus_write_byte_data(onyx->i2c, reg, value); in onyx_write_register()
89 onyx->cache[reg-FIRSTREGISTER] = value; in onyx_write_register()
111 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; in onyx_snd_vol_info()
112 uinfo->count = 2; in onyx_snd_vol_info()
113 uinfo->value.integer.min = -128 + VOLUME_RANGE_SHIFT; in onyx_snd_vol_info()
114 uinfo->value.integer.max = -1 + VOLUME_RANGE_SHIFT; in onyx_snd_vol_info()
124 mutex_lock(&onyx->mutex); in onyx_snd_vol_get()
127 mutex_unlock(&onyx->mutex); in onyx_snd_vol_get()
129 ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT; in onyx_snd_vol_get()
130 ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT; in onyx_snd_vol_get()
141 if (ucontrol->value.integer.value[0] < -128 + VOLUME_RANGE_SHIFT || in onyx_snd_vol_put()
142 ucontrol->value.integer.value[0] > -1 + VOLUME_RANGE_SHIFT) in onyx_snd_vol_put()
143 return -EINVAL; in onyx_snd_vol_put()
144 if (ucontrol->value.integer.value[1] < -128 + VOLUME_RANGE_SHIFT || in onyx_snd_vol_put()
145 ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT) in onyx_snd_vol_put()
146 return -EINVAL; in onyx_snd_vol_put()
148 mutex_lock(&onyx->mutex); in onyx_snd_vol_put()
152 if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] && in onyx_snd_vol_put()
153 r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) { in onyx_snd_vol_put()
154 mutex_unlock(&onyx->mutex); in onyx_snd_vol_put()
159 ucontrol->value.integer.value[0] in onyx_snd_vol_put()
160 - VOLUME_RANGE_SHIFT); in onyx_snd_vol_put()
162 ucontrol->value.integer.value[1] in onyx_snd_vol_put()
163 - VOLUME_RANGE_SHIFT); in onyx_snd_vol_put()
164 mutex_unlock(&onyx->mutex); in onyx_snd_vol_put()
182 #define INPUTGAIN_RANGE_SHIFT (-3)
187 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; in onyx_snd_inputgain_info()
188 uinfo->count = 1; in onyx_snd_inputgain_info()
189 uinfo->value.integer.min = 3 + INPUTGAIN_RANGE_SHIFT; in onyx_snd_inputgain_info()
190 uinfo->value.integer.max = 28 + INPUTGAIN_RANGE_SHIFT; in onyx_snd_inputgain_info()
200 mutex_lock(&onyx->mutex); in onyx_snd_inputgain_get()
202 mutex_unlock(&onyx->mutex); in onyx_snd_inputgain_get()
204 ucontrol->value.integer.value[0] = in onyx_snd_inputgain_get()
216 if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT || in onyx_snd_inputgain_put()
217 ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT) in onyx_snd_inputgain_put()
218 return -EINVAL; in onyx_snd_inputgain_put()
219 mutex_lock(&onyx->mutex); in onyx_snd_inputgain_put()
223 n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT) in onyx_snd_inputgain_put()
226 mutex_unlock(&onyx->mutex); in onyx_snd_inputgain_put()
243 static const char * const texts[] = { "Line-In", "Microphone" }; in onyx_snd_capture_source_info()
245 return snd_ctl_enum_info(uinfo, 1, 2, texts); in onyx_snd_capture_source_info()
254 mutex_lock(&onyx->mutex); in onyx_snd_capture_source_get()
256 mutex_unlock(&onyx->mutex); in onyx_snd_capture_source_get()
258 ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC); in onyx_snd_capture_source_get()
267 mutex_lock(&onyx->mutex); in onyx_set_capture_source()
273 mutex_unlock(&onyx->mutex); in onyx_set_capture_source()
279 if (ucontrol->value.enumerated.item[0] > 1) in onyx_snd_capture_source_put()
280 return -EINVAL; in onyx_snd_capture_source_put()
282 ucontrol->value.enumerated.item[0]); in onyx_snd_capture_source_put()
314 mutex_lock(&onyx->mutex); in onyx_snd_mute_get()
316 mutex_unlock(&onyx->mutex); in onyx_snd_mute_get()
318 ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT); in onyx_snd_mute_get()
319 ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT); in onyx_snd_mute_get()
329 int err = -EBUSY; in onyx_snd_mute_put()
331 mutex_lock(&onyx->mutex); in onyx_snd_mute_put()
332 if (onyx->analog_locked) in onyx_snd_mute_put()
338 if (!ucontrol->value.integer.value[0]) in onyx_snd_mute_put()
340 if (!ucontrol->value.integer.value[1]) in onyx_snd_mute_put()
345 mutex_unlock(&onyx->mutex); in onyx_snd_mute_put()
363 #define FLAG_SPDIFLOCK 2
370 long int pv = kcontrol->private_value; in onyx_snd_single_bit_get()
375 mutex_lock(&onyx->mutex); in onyx_snd_single_bit_get()
377 mutex_unlock(&onyx->mutex); in onyx_snd_single_bit_get()
379 ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity; in onyx_snd_single_bit_get()
390 long int pv = kcontrol->private_value; in onyx_snd_single_bit_put()
396 mutex_lock(&onyx->mutex); in onyx_snd_single_bit_put()
397 if (spdiflock && onyx->spdif_locked) { in onyx_snd_single_bit_put()
399 err = -EBUSY; in onyx_snd_single_bit_put()
405 if (!!ucontrol->value.integer.value[0] ^ polarity) in onyx_snd_single_bit_put()
410 mutex_unlock(&onyx->mutex); in onyx_snd_single_bit_put()
452 "Digital De-Emphasis",
460 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; in onyx_spdif_info()
461 uinfo->count = 1; in onyx_spdif_info()
469 ucontrol->value.iec958.status[0] = 0x3e; in onyx_spdif_mask_get()
470 ucontrol->value.iec958.status[1] = 0xff; in onyx_spdif_mask_get()
472 ucontrol->value.iec958.status[3] = 0x3f; in onyx_spdif_mask_get()
473 ucontrol->value.iec958.status[4] = 0x0f; in onyx_spdif_mask_get()
492 mutex_lock(&onyx->mutex); in onyx_spdif_get()
494 ucontrol->value.iec958.status[0] = v & 0x3e; in onyx_spdif_get()
497 ucontrol->value.iec958.status[1] = v; in onyx_spdif_get()
500 ucontrol->value.iec958.status[3] = v & 0x3f; in onyx_spdif_get()
503 ucontrol->value.iec958.status[4] = v & 0x0f; in onyx_spdif_get()
504 mutex_unlock(&onyx->mutex); in onyx_spdif_get()
515 mutex_lock(&onyx->mutex); in onyx_spdif_put()
517 v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e); in onyx_spdif_put()
520 v = ucontrol->value.iec958.status[1]; in onyx_spdif_put()
524 v = (v & ~0x3f) | (ucontrol->value.iec958.status[3] & 0x3f); in onyx_spdif_put()
528 v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f); in onyx_spdif_put()
530 mutex_unlock(&onyx->mutex); in onyx_spdif_put()
569 (-1 /*dB*/ + 8) & 0xF, /* line in selected, -1 dB gain*/
571 (1<<2), /* pcm audio */
572 2, /* category: pcm coder */
584 if (!onyx->initialised) { in onyx_register_init()
587 return -1; in onyx_register_init()
593 regs[i] = onyx->cache[register_map[i]-FIRSTREGISTER]; in onyx_register_init()
598 return -1; in onyx_register_init()
600 onyx->initialised = 1; in onyx_register_init()
651 .tag = 2,
661 .tag = 2,
672 struct onyx *onyx = cii->codec_data; in onyx_usable()
675 mutex_lock(&onyx->mutex); in onyx_usable()
682 mutex_unlock(&onyx->mutex); in onyx_usable()
684 switch (ti->tag) { in onyx_usable()
687 case 2: return spdif_enabled; in onyx_usable()
697 struct onyx *onyx = cii->codec_data; in onyx_prepare()
698 int err = -EBUSY; in onyx_prepare()
700 mutex_lock(&onyx->mutex); in onyx_prepare()
703 if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) { in onyx_prepare()
710 onyx->analog_locked = 1; in onyx_prepare()
715 switch (substream->runtime->rate) { in onyx_prepare()
727 onyx_read_register(cii->codec_data, ONYX_REG_DIG_INFO4, &v); in onyx_prepare()
732 onyx->spdif_locked = 1; in onyx_prepare()
738 mutex_unlock(&onyx->mutex); in onyx_prepare()
746 struct onyx *onyx = cii->codec_data; in onyx_open()
748 mutex_lock(&onyx->mutex); in onyx_open()
749 onyx->open_count++; in onyx_open()
750 mutex_unlock(&onyx->mutex); in onyx_open()
758 struct onyx *onyx = cii->codec_data; in onyx_close()
760 mutex_lock(&onyx->mutex); in onyx_close()
761 onyx->open_count--; in onyx_close()
762 if (!onyx->open_count) in onyx_close()
763 onyx->spdif_locked = onyx->analog_locked = 0; in onyx_close()
764 mutex_unlock(&onyx->mutex); in onyx_close()
772 struct onyx *onyx = cii->codec_data; in onyx_switch_clock()
774 mutex_lock(&onyx->mutex); in onyx_switch_clock()
778 onyx->codec.gpio->methods->all_amps_off(onyx->codec.gpio); in onyx_switch_clock()
781 onyx->codec.gpio->methods->all_amps_restore(onyx->codec.gpio); in onyx_switch_clock()
786 mutex_unlock(&onyx->mutex); in onyx_switch_clock()
795 struct onyx *onyx = cii->codec_data; in onyx_suspend()
797 int err = -ENXIO; in onyx_suspend()
799 mutex_lock(&onyx->mutex); in onyx_suspend()
806 mutex_unlock(&onyx->mutex); in onyx_suspend()
813 struct onyx *onyx = cii->codec_data; in onyx_resume()
815 int err = -ENXIO; in onyx_resume()
817 mutex_lock(&onyx->mutex); in onyx_resume()
819 /* reset codec */ in onyx_resume()
820 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); in onyx_resume()
822 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1); in onyx_resume()
824 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); in onyx_resume()
827 /* take codec out of suspend (if it still is after reset) */ in onyx_resume()
837 mutex_unlock(&onyx->mutex); in onyx_resume()
860 static int onyx_init_codec(struct aoa_codec *codec) in onyx_init_codec() argument
862 struct onyx *onyx = codec_to_onyx(codec); in onyx_init_codec()
868 if (!onyx->codec.gpio || !onyx->codec.gpio->methods) { in onyx_init_codec()
870 return -EINVAL; in onyx_init_codec()
873 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); in onyx_init_codec()
875 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1); in onyx_init_codec()
877 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); in onyx_init_codec()
882 return -ENODEV; in onyx_init_codec()
887 return -ENODEV; in onyx_init_codec()
891 if ((onyx->codec.connected & 0xF) == 0) in onyx_init_codec()
892 return -ENOTCONN; in onyx_init_codec()
895 if ((onyx->codec.connected & 0xC) == 0) { in onyx_init_codec()
896 if (!onyx->codec_info) in onyx_init_codec()
897 onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL); in onyx_init_codec()
898 if (!onyx->codec_info) in onyx_init_codec()
899 return -ENOMEM; in onyx_init_codec()
900 ci = onyx->codec_info; in onyx_init_codec()
902 ci->transfers++; in onyx_init_codec()
906 if ((onyx->codec.connected & 3) == 0) { in onyx_init_codec()
907 if (!onyx->codec_info) in onyx_init_codec()
908 onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL); in onyx_init_codec()
909 if (!onyx->codec_info) in onyx_init_codec()
910 return -ENOMEM; in onyx_init_codec()
911 ci = onyx->codec_info; in onyx_init_codec()
915 ci->transfers[1].formats = 0; in onyx_init_codec()
918 if (onyx->codec.soundbus_dev->attach_codec(onyx->codec.soundbus_dev, in onyx_init_codec()
922 return -ENODEV; in onyx_init_codec()
928 ctl->id.device = \ in onyx_init_codec()
929 onyx->codec.soundbus_dev->pcm->device; \ in onyx_init_codec()
936 if (onyx->codec.soundbus_dev->pcm) { in onyx_init_codec()
939 if ((onyx->codec.connected & 0xC) == 0xC) in onyx_init_codec()
941 else if (onyx->codec.connected & 4) in onyx_init_codec()
945 if (onyx->codec.connected & 0xC) in onyx_init_codec()
950 if (onyx->codec.connected & 1) { in onyx_init_codec()
959 if (onyx->codec.connected & 2) { in onyx_init_codec()
963 if ((onyx->codec.connected & 3) == 3) in onyx_init_codec()
966 if ((onyx->codec.connected & 3) == 2) { in onyx_init_codec()
973 printk(KERN_INFO PFX "attached to onyx codec via i2c\n"); in onyx_init_codec()
977 onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx); in onyx_init_codec()
982 static void onyx_exit_codec(struct aoa_codec *codec) in onyx_exit_codec() argument
984 struct onyx *onyx = codec_to_onyx(codec); in onyx_exit_codec()
986 if (!onyx->codec.soundbus_dev) { in onyx_exit_codec()
990 onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx); in onyx_exit_codec()
995 struct device_node *node = client->dev.of_node; in onyx_i2c_probe()
1002 return -ENOMEM; in onyx_i2c_probe()
1004 mutex_init(&onyx->mutex); in onyx_i2c_probe()
1005 onyx->i2c = client; in onyx_i2c_probe()
1009 * to check if the codec is present */ in onyx_i2c_probe()
1015 strscpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN); in onyx_i2c_probe()
1016 onyx->codec.owner = THIS_MODULE; in onyx_i2c_probe()
1017 onyx->codec.init = onyx_init_codec; in onyx_i2c_probe()
1018 onyx->codec.exit = onyx_exit_codec; in onyx_i2c_probe()
1019 onyx->codec.node = of_node_get(node); in onyx_i2c_probe()
1021 if (aoa_codec_register(&onyx->codec)) { in onyx_i2c_probe()
1028 return -ENODEV; in onyx_i2c_probe()
1035 aoa_codec_unregister(&onyx->codec); in onyx_i2c_remove()
1036 of_node_put(onyx->codec.node); in onyx_i2c_remove()
1037 kfree(onyx->codec_info); in onyx_i2c_remove()