^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * ALSA Driver for the PT2258 volume controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2006 Jochen Voss <voss@seehuhn.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <sound/control.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <sound/tlv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <sound/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <sound/pt2258.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) MODULE_AUTHOR("Jochen Voss <voss@seehuhn.de>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define PT2258_CMD_RESET 0xc0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define PT2258_CMD_UNMUTE 0xf8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define PT2258_CMD_MUTE 0xf9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static const unsigned char pt2258_channel_code[12] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) 0x80, 0x90, /* channel 1: -10dB, -1dB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) 0x40, 0x50, /* channel 2: -10dB, -1dB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) 0x00, 0x10, /* channel 3: -10dB, -1dB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) 0x20, 0x30, /* channel 4: -10dB, -1dB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) 0x60, 0x70, /* channel 5: -10dB, -1dB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) 0xa0, 0xb0 /* channel 6: -10dB, -1dB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) int snd_pt2258_reset(struct snd_pt2258 *pt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) unsigned char bytes[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* reset chip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) bytes[0] = PT2258_CMD_RESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) snd_i2c_lock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) goto __error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) snd_i2c_unlock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* mute all channels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) pt->mute = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) bytes[0] = PT2258_CMD_MUTE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) snd_i2c_lock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) goto __error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) snd_i2c_unlock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* set all channels to 0dB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) for (i = 0; i < 6; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) pt->volume[i] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) bytes[0] = 0xd0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) bytes[1] = 0xe0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) snd_i2c_lock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) goto __error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) snd_i2c_unlock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) __error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) snd_i2c_unlock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) snd_printk(KERN_ERR "PT2258 reset failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct snd_ctl_elem_info *uinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) uinfo->count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) uinfo->value.integer.min = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) uinfo->value.integer.max = 79;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct snd_pt2258 *pt = kcontrol->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int base = kcontrol->private_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /* chip does not support register reads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ucontrol->value.integer.value[0] = 79 - pt->volume[base];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct snd_pt2258 *pt = kcontrol->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int base = kcontrol->private_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) unsigned char bytes[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) int val0, val1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) val0 = 79 - ucontrol->value.integer.value[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) val1 = 79 - ucontrol->value.integer.value[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (val0 < 0 || val0 > 79 || val1 < 0 || val1 > 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (val0 == pt->volume[base] && val1 == pt->volume[base + 1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) pt->volume[base] = val0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) snd_i2c_lock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) goto __error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) snd_i2c_unlock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) pt->volume[base + 1] = val1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) snd_i2c_lock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) goto __error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) snd_i2c_unlock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) __error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) snd_i2c_unlock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) snd_printk(KERN_ERR "PT2258 access failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) #define pt2258_switch_info snd_ctl_boolean_mono_info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static int pt2258_switch_get(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct snd_pt2258 *pt = kcontrol->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ucontrol->value.integer.value[0] = !pt->mute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static int pt2258_switch_put(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct snd_pt2258 *pt = kcontrol->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) unsigned char bytes[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) val = !ucontrol->value.integer.value[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (pt->mute == val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) pt->mute = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) snd_i2c_lock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) goto __error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) snd_i2c_unlock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) __error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) snd_i2c_unlock(pt->i2c_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) snd_printk(KERN_ERR "PT2258 access failed 2\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static const DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) int snd_pt2258_build_controls(struct snd_pt2258 *pt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) struct snd_kcontrol_new knew;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) char *names[3] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) "Mic Loopback Playback Volume",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) "Line Loopback Playback Volume",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) "CD Loopback Playback Volume"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) int i, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) for (i = 0; i < 3; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) memset(&knew, 0, sizeof(knew));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) knew.name = names[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) knew.count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) SNDRV_CTL_ELEM_ACCESS_TLV_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) knew.private_value = 2 * i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) knew.info = pt2258_stereo_volume_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) knew.get = pt2258_stereo_volume_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) knew.put = pt2258_stereo_volume_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) knew.tlv.p = pt2258_db_scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) memset(&knew, 0, sizeof(knew));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) knew.name = "Loopback Switch";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) knew.info = pt2258_switch_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) knew.get = pt2258_switch_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) knew.put = pt2258_switch_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) knew.access = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) EXPORT_SYMBOL(snd_pt2258_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) EXPORT_SYMBOL(snd_pt2258_build_controls);