Lines Matching +full:codec +full:- +full:analog +full:- +full:controls

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
12 * 0: analog output
17 * the digital output connected but not the analog, I have handled
24 * But snd-aoa assumes that there's at most one card, so
37 MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa");
44 #define PFX "snd-aoa-codec-onyx: "
47 /* cache registers 65 to 80, they are write-only! */
50 struct aoa_codec codec; member
63 #define codec_to_onyx(c) container_of(c, struct onyx, codec)
71 *value = onyx->cache[reg-FIRSTREGISTER]; in onyx_read_register()
74 v = i2c_smbus_read_byte_data(onyx->i2c, reg); in onyx_read_register()
77 return -1; in onyx_read_register()
80 onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value; in onyx_read_register()
88 result = i2c_smbus_write_byte_data(onyx->i2c, reg, value); in onyx_write_register()
90 onyx->cache[reg-FIRSTREGISTER] = value; in onyx_write_register()
112 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; in onyx_snd_vol_info()
113 uinfo->count = 2; in onyx_snd_vol_info()
114 uinfo->value.integer.min = -128 + VOLUME_RANGE_SHIFT; in onyx_snd_vol_info()
115 uinfo->value.integer.max = -1 + VOLUME_RANGE_SHIFT; in onyx_snd_vol_info()
125 mutex_lock(&onyx->mutex); in onyx_snd_vol_get()
128 mutex_unlock(&onyx->mutex); in onyx_snd_vol_get()
130 ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT; in onyx_snd_vol_get()
131 ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT; in onyx_snd_vol_get()
142 if (ucontrol->value.integer.value[0] < -128 + VOLUME_RANGE_SHIFT || in onyx_snd_vol_put()
143 ucontrol->value.integer.value[0] > -1 + VOLUME_RANGE_SHIFT) in onyx_snd_vol_put()
144 return -EINVAL; in onyx_snd_vol_put()
145 if (ucontrol->value.integer.value[1] < -128 + VOLUME_RANGE_SHIFT || in onyx_snd_vol_put()
146 ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT) in onyx_snd_vol_put()
147 return -EINVAL; in onyx_snd_vol_put()
149 mutex_lock(&onyx->mutex); in onyx_snd_vol_put()
153 if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] && in onyx_snd_vol_put()
154 r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) { in onyx_snd_vol_put()
155 mutex_unlock(&onyx->mutex); in onyx_snd_vol_put()
160 ucontrol->value.integer.value[0] in onyx_snd_vol_put()
161 - VOLUME_RANGE_SHIFT); in onyx_snd_vol_put()
163 ucontrol->value.integer.value[1] in onyx_snd_vol_put()
164 - VOLUME_RANGE_SHIFT); in onyx_snd_vol_put()
165 mutex_unlock(&onyx->mutex); in onyx_snd_vol_put()
183 #define INPUTGAIN_RANGE_SHIFT (-3)
188 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; in onyx_snd_inputgain_info()
189 uinfo->count = 1; in onyx_snd_inputgain_info()
190 uinfo->value.integer.min = 3 + INPUTGAIN_RANGE_SHIFT; in onyx_snd_inputgain_info()
191 uinfo->value.integer.max = 28 + INPUTGAIN_RANGE_SHIFT; in onyx_snd_inputgain_info()
201 mutex_lock(&onyx->mutex); in onyx_snd_inputgain_get()
203 mutex_unlock(&onyx->mutex); in onyx_snd_inputgain_get()
205 ucontrol->value.integer.value[0] = in onyx_snd_inputgain_get()
217 if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT || in onyx_snd_inputgain_put()
218 ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT) in onyx_snd_inputgain_put()
219 return -EINVAL; in onyx_snd_inputgain_put()
220 mutex_lock(&onyx->mutex); in onyx_snd_inputgain_put()
224 n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT) in onyx_snd_inputgain_put()
227 mutex_unlock(&onyx->mutex); in onyx_snd_inputgain_put()
244 static const char * const texts[] = { "Line-In", "Microphone" }; in onyx_snd_capture_source_info()
255 mutex_lock(&onyx->mutex); in onyx_snd_capture_source_get()
257 mutex_unlock(&onyx->mutex); in onyx_snd_capture_source_get()
259 ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC); in onyx_snd_capture_source_get()
268 mutex_lock(&onyx->mutex); in onyx_set_capture_source()
274 mutex_unlock(&onyx->mutex); in onyx_set_capture_source()
280 if (ucontrol->value.enumerated.item[0] > 1) in onyx_snd_capture_source_put()
281 return -EINVAL; in onyx_snd_capture_source_put()
283 ucontrol->value.enumerated.item[0]); in onyx_snd_capture_source_put()
315 mutex_lock(&onyx->mutex); in onyx_snd_mute_get()
317 mutex_unlock(&onyx->mutex); in onyx_snd_mute_get()
319 ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT); in onyx_snd_mute_get()
320 ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT); in onyx_snd_mute_get()
330 int err = -EBUSY; in onyx_snd_mute_put()
332 mutex_lock(&onyx->mutex); in onyx_snd_mute_put()
333 if (onyx->analog_locked) in onyx_snd_mute_put()
339 if (!ucontrol->value.integer.value[0]) in onyx_snd_mute_put()
341 if (!ucontrol->value.integer.value[1]) in onyx_snd_mute_put()
346 mutex_unlock(&onyx->mutex); in onyx_snd_mute_put()
371 long int pv = kcontrol->private_value; in onyx_snd_single_bit_get()
376 mutex_lock(&onyx->mutex); in onyx_snd_single_bit_get()
378 mutex_unlock(&onyx->mutex); in onyx_snd_single_bit_get()
380 ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity; in onyx_snd_single_bit_get()
391 long int pv = kcontrol->private_value; in onyx_snd_single_bit_put()
397 mutex_lock(&onyx->mutex); in onyx_snd_single_bit_put()
398 if (spdiflock && onyx->spdif_locked) { in onyx_snd_single_bit_put()
400 err = -EBUSY; in onyx_snd_single_bit_put()
406 if (!!ucontrol->value.integer.value[0] ^ polarity) in onyx_snd_single_bit_put()
411 mutex_unlock(&onyx->mutex); in onyx_snd_single_bit_put()
453 "Digital De-Emphasis",
461 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; in onyx_spdif_info()
462 uinfo->count = 1; in onyx_spdif_info()
470 ucontrol->value.iec958.status[0] = 0x3e; in onyx_spdif_mask_get()
471 ucontrol->value.iec958.status[1] = 0xff; in onyx_spdif_mask_get()
473 ucontrol->value.iec958.status[3] = 0x3f; in onyx_spdif_mask_get()
474 ucontrol->value.iec958.status[4] = 0x0f; in onyx_spdif_mask_get()
493 mutex_lock(&onyx->mutex); in onyx_spdif_get()
495 ucontrol->value.iec958.status[0] = v & 0x3e; in onyx_spdif_get()
498 ucontrol->value.iec958.status[1] = v; in onyx_spdif_get()
501 ucontrol->value.iec958.status[3] = v & 0x3f; in onyx_spdif_get()
504 ucontrol->value.iec958.status[4] = v & 0x0f; in onyx_spdif_get()
505 mutex_unlock(&onyx->mutex); in onyx_spdif_get()
516 mutex_lock(&onyx->mutex); in onyx_spdif_put()
518 v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e); in onyx_spdif_put()
521 v = ucontrol->value.iec958.status[1]; in onyx_spdif_put()
525 v = (v & ~0x3f) | (ucontrol->value.iec958.status[3] & 0x3f); in onyx_spdif_put()
529 v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f); in onyx_spdif_put()
531 mutex_unlock(&onyx->mutex); in onyx_spdif_put()
570 (-1 /*dB*/ + 8) & 0xF, /* line in selected, -1 dB gain*/
585 if (!onyx->initialised) { in onyx_register_init()
588 return -1; in onyx_register_init()
594 regs[i] = onyx->cache[register_map[i]-FIRSTREGISTER]; in onyx_register_init()
599 return -1; in onyx_register_init()
601 onyx->initialised = 1; in onyx_register_init()
610 /* analog input */
620 /* if analog and digital are currently off, anything should go,
633 /* analog output */
643 /* digital pcm output, also possible for analog out */
673 struct onyx *onyx = cii->codec_data; in onyx_usable()
676 mutex_lock(&onyx->mutex); in onyx_usable()
683 mutex_unlock(&onyx->mutex); in onyx_usable()
685 switch (ti->tag) { in onyx_usable()
698 struct onyx *onyx = cii->codec_data; in onyx_prepare()
699 int err = -EBUSY; in onyx_prepare()
701 mutex_lock(&onyx->mutex); in onyx_prepare()
704 if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) { in onyx_prepare()
705 /* mute and lock analog output */ in onyx_prepare()
711 onyx->analog_locked = 1; in onyx_prepare()
716 switch (substream->runtime->rate) { in onyx_prepare()
728 onyx_read_register(cii->codec_data, ONYX_REG_DIG_INFO4, &v); in onyx_prepare()
733 onyx->spdif_locked = 1; in onyx_prepare()
739 mutex_unlock(&onyx->mutex); in onyx_prepare()
747 struct onyx *onyx = cii->codec_data; in onyx_open()
749 mutex_lock(&onyx->mutex); in onyx_open()
750 onyx->open_count++; in onyx_open()
751 mutex_unlock(&onyx->mutex); in onyx_open()
759 struct onyx *onyx = cii->codec_data; in onyx_close()
761 mutex_lock(&onyx->mutex); in onyx_close()
762 onyx->open_count--; in onyx_close()
763 if (!onyx->open_count) in onyx_close()
764 onyx->spdif_locked = onyx->analog_locked = 0; in onyx_close()
765 mutex_unlock(&onyx->mutex); in onyx_close()
773 struct onyx *onyx = cii->codec_data; in onyx_switch_clock()
775 mutex_lock(&onyx->mutex); in onyx_switch_clock()
779 onyx->codec.gpio->methods->all_amps_off(onyx->codec.gpio); in onyx_switch_clock()
782 onyx->codec.gpio->methods->all_amps_restore(onyx->codec.gpio); in onyx_switch_clock()
787 mutex_unlock(&onyx->mutex); in onyx_switch_clock()
796 struct onyx *onyx = cii->codec_data; in onyx_suspend()
798 int err = -ENXIO; in onyx_suspend()
800 mutex_lock(&onyx->mutex); in onyx_suspend()
807 mutex_unlock(&onyx->mutex); in onyx_suspend()
814 struct onyx *onyx = cii->codec_data; in onyx_resume()
816 int err = -ENXIO; in onyx_resume()
818 mutex_lock(&onyx->mutex); in onyx_resume()
820 /* reset codec */ in onyx_resume()
821 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); in onyx_resume()
823 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1); in onyx_resume()
825 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); in onyx_resume()
828 /* take codec out of suspend (if it still is after reset) */ in onyx_resume()
838 mutex_unlock(&onyx->mutex); in onyx_resume()
861 static int onyx_init_codec(struct aoa_codec *codec) in onyx_init_codec() argument
863 struct onyx *onyx = codec_to_onyx(codec); in onyx_init_codec()
869 if (!onyx->codec.gpio || !onyx->codec.gpio->methods) { in onyx_init_codec()
871 return -EINVAL; in onyx_init_codec()
874 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); in onyx_init_codec()
876 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1); in onyx_init_codec()
878 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); in onyx_init_codec()
883 return -ENODEV; in onyx_init_codec()
888 return -ENODEV; in onyx_init_codec()
892 if ((onyx->codec.connected & 0xF) == 0) in onyx_init_codec()
893 return -ENOTCONN; in onyx_init_codec()
896 if ((onyx->codec.connected & 0xC) == 0) { in onyx_init_codec()
897 if (!onyx->codec_info) in onyx_init_codec()
898 onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL); in onyx_init_codec()
899 if (!onyx->codec_info) in onyx_init_codec()
900 return -ENOMEM; in onyx_init_codec()
901 ci = onyx->codec_info; in onyx_init_codec()
903 ci->transfers++; in onyx_init_codec()
907 if ((onyx->codec.connected & 3) == 0) { in onyx_init_codec()
908 if (!onyx->codec_info) in onyx_init_codec()
909 onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL); in onyx_init_codec()
910 if (!onyx->codec_info) in onyx_init_codec()
911 return -ENOMEM; in onyx_init_codec()
912 ci = onyx->codec_info; in onyx_init_codec()
916 ci->transfers[1].formats = 0; in onyx_init_codec()
919 if (onyx->codec.soundbus_dev->attach_codec(onyx->codec.soundbus_dev, in onyx_init_codec()
923 return -ENODEV; in onyx_init_codec()
929 ctl->id.device = \ in onyx_init_codec()
930 onyx->codec.soundbus_dev->pcm->device; \ in onyx_init_codec()
937 if (onyx->codec.soundbus_dev->pcm) { in onyx_init_codec()
938 /* give the user appropriate controls in onyx_init_codec()
940 if ((onyx->codec.connected & 0xC) == 0xC) in onyx_init_codec()
942 else if (onyx->codec.connected & 4) in onyx_init_codec()
946 if (onyx->codec.connected & 0xC) in onyx_init_codec()
950 * give the user appropriate controls */ in onyx_init_codec()
951 if (onyx->codec.connected & 1) { in onyx_init_codec()
960 if (onyx->codec.connected & 2) { in onyx_init_codec()
964 if ((onyx->codec.connected & 3) == 3) in onyx_init_codec()
967 if ((onyx->codec.connected & 3) == 2) { in onyx_init_codec()
974 printk(KERN_INFO PFX "attached to onyx codec via i2c\n"); in onyx_init_codec()
978 onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx); in onyx_init_codec()
983 static void onyx_exit_codec(struct aoa_codec *codec) in onyx_exit_codec() argument
985 struct onyx *onyx = codec_to_onyx(codec); in onyx_exit_codec()
987 if (!onyx->codec.soundbus_dev) { in onyx_exit_codec()
991 onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx); in onyx_exit_codec()
996 struct device_node *node = client->dev.of_node; in onyx_i2c_probe()
1003 return -ENOMEM; in onyx_i2c_probe()
1005 mutex_init(&onyx->mutex); in onyx_i2c_probe()
1006 onyx->i2c = client; in onyx_i2c_probe()
1010 * to check if the codec is present */ in onyx_i2c_probe()
1016 strscpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN); in onyx_i2c_probe()
1017 onyx->codec.owner = THIS_MODULE; in onyx_i2c_probe()
1018 onyx->codec.init = onyx_init_codec; in onyx_i2c_probe()
1019 onyx->codec.exit = onyx_exit_codec; in onyx_i2c_probe()
1020 onyx->codec.node = of_node_get(node); in onyx_i2c_probe()
1022 if (aoa_codec_register(&onyx->codec)) { in onyx_i2c_probe()
1029 return -ENODEV; in onyx_i2c_probe()
1036 aoa_codec_unregister(&onyx->codec); in onyx_i2c_remove()
1037 of_node_put(onyx->codec.node); in onyx_i2c_remove()
1038 kfree(onyx->codec_info); in onyx_i2c_remove()