ARM: dts: rockchip: bump sd card pin drive strength up on rk3288-firefly
[firefly-linux-kernel-4.4.55.git] / sound / pci / oxygen / xonar_pcm179x.c
index e0260593166936a70c15f5e12cd0829e519fbbb1..24109d37ca09783e09b243044506c852d4cee94d 100644 (file)
 #define GPIO_ST_MAGIC          0x0040
 #define GPIO_ST_HP             0x0080
 
+#define GPIO_XENSE_OUTPUT_ENABLE       (0x0001 | 0x0010 | 0x0020)
+#define GPIO_XENSE_SPEAKERS            0x0080
+
 #define I2C_DEVICE_PCM1796(i)  (0x98 + ((i) << 1))     /* 10011, ii, /W=0 */
 #define I2C_DEVICE_CS2000      0x9c                    /* 100111, 0, /W=0 */
 
@@ -419,6 +422,7 @@ static void xonar_st_init_common(struct oxygen *chip)
 
        data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
        data->dacs = chip->model.dac_channels_mixer / 2;
+       data->h6 = chip->model.dac_channels_mixer > 2;
        data->hp_gain_offset = 2*-18;
 
        pcm1796_init(chip);
@@ -499,6 +503,51 @@ static void xonar_stx_init(struct oxygen *chip)
        xonar_st_init_common(chip);
 }
 
+static void xonar_xense_init(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       data->generic.ext_power_reg = OXYGEN_GPI_DATA;
+       data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+       data->generic.ext_power_bit = GPI_EXT_POWER;
+       xonar_init_ext_power(chip);
+
+       data->generic.anti_pop_delay = 100;
+       data->has_cs2000 = 1;
+       data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1;
+
+       oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
+               OXYGEN_RATE_48000 |
+               OXYGEN_I2S_FORMAT_I2S |
+               OXYGEN_I2S_MCLK(MCLK_512) |
+               OXYGEN_I2S_BITS_16 |
+               OXYGEN_I2S_MASTER |
+               OXYGEN_I2S_BCLK_64);
+
+       xonar_st_init_i2c(chip);
+       cs2000_registers_init(chip);
+
+       data->generic.output_enable_bit = GPIO_XENSE_OUTPUT_ENABLE;
+       data->dacs = 1;
+       data->hp_gain_offset = 2*-18;
+
+       pcm1796_init(chip);
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+               GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
+               GPIO_ST_MAGIC | GPIO_XENSE_SPEAKERS);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+               GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
+               GPIO_XENSE_SPEAKERS);
+
+       xonar_init_cs53x1(chip);
+       xonar_enable_output(chip);
+
+       snd_component_add(chip->card, "PCM1796");
+       snd_component_add(chip->card, "CS5381");
+       snd_component_add(chip->card, "CS2000");
+}
+
 static void xonar_d2_cleanup(struct oxygen *chip)
 {
        xonar_disable_output(chip);
@@ -795,11 +844,11 @@ static int st_output_switch_put(struct snd_kcontrol *ctl,
 static int st_hp_volume_offset_info(struct snd_kcontrol *ctl,
                                    struct snd_ctl_elem_info *info)
 {
-       static const char *const names[3] = {
-               "< 64 ohms", "64-300 ohms", "300-600 ohms"
+       static const char *const names[4] = {
+               "< 32 ohms", "32-64 ohms", "64-300 ohms", "300-600 ohms"
        };
 
-       return snd_ctl_enum_info(info, 1, 3, names);
+       return snd_ctl_enum_info(info, 1, 4, names);
 }
 
 static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
@@ -809,12 +858,14 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
        struct xonar_pcm179x *data = chip->model_data;
 
        mutex_lock(&chip->mutex);
-       if (data->hp_gain_offset < 2*-6)
+       if (data->hp_gain_offset < 2*-12)
                value->value.enumerated.item[0] = 0;
-       else if (data->hp_gain_offset < 0)
+       else if (data->hp_gain_offset < 2*-6)
                value->value.enumerated.item[0] = 1;
-       else
+       else if (data->hp_gain_offset < 0)
                value->value.enumerated.item[0] = 2;
+       else
+               value->value.enumerated.item[0] = 3;
        mutex_unlock(&chip->mutex);
        return 0;
 }
@@ -823,13 +874,13 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
 static int st_hp_volume_offset_put(struct snd_kcontrol *ctl,
                                   struct snd_ctl_elem_value *value)
 {
-       static const s8 offsets[] = { 2*-18, 2*-6, 0 };
+       static const s8 offsets[] = { 2*-18, 2*-12, 2*-6, 0 };
        struct oxygen *chip = ctl->private_data;
        struct xonar_pcm179x *data = chip->model_data;
        s8 offset;
        int changed;
 
-       if (value->value.enumerated.item[0] > 2)
+       if (value->value.enumerated.item[0] > 3)
                return -EINVAL;
        offset = offsets[value->value.enumerated.item[0]];
        mutex_lock(&chip->mutex);
@@ -859,6 +910,67 @@ static const struct snd_kcontrol_new st_controls[] = {
        },
 };
 
+static int xense_output_switch_get(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 gpio;
+
+       gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       if (gpio & GPIO_XENSE_SPEAKERS)
+               value->value.enumerated.item[0] = 0;
+       else if (!(gpio & GPIO_XENSE_SPEAKERS) && (gpio & GPIO_ST_HP_REAR))
+               value->value.enumerated.item[0] = 1;
+       else
+               value->value.enumerated.item[0] = 2;
+       return 0;
+}
+
+static int xense_output_switch_put(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_pcm179x *data = chip->model_data;
+       u16 gpio_old, gpio;
+
+       mutex_lock(&chip->mutex);
+       gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       gpio = gpio_old;
+       switch (value->value.enumerated.item[0]) {
+       case 0:
+               gpio |= GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR;
+               break;
+       case 1:
+               gpio = (gpio | GPIO_ST_HP_REAR) & ~GPIO_XENSE_SPEAKERS;
+               break;
+       case 2:
+               gpio &= ~(GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR);
+               break;
+       }
+       oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
+       data->hp_active = !(gpio & GPIO_XENSE_SPEAKERS);
+       update_pcm1796_volume(chip);
+       mutex_unlock(&chip->mutex);
+       return gpio != gpio_old;
+}
+
+static const struct snd_kcontrol_new xense_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Output",
+               .info = st_output_switch_info,
+               .get = xense_output_switch_get,
+               .put = xense_output_switch_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Headphones Impedance Playback Enum",
+               .info = st_hp_volume_offset_info,
+               .get = st_hp_volume_offset_get,
+               .put = st_hp_volume_offset_put,
+       },
+};
+
 static void xonar_line_mic_ac97_switch(struct oxygen *chip,
                                       unsigned int reg, unsigned int mute)
 {
@@ -946,6 +1058,23 @@ static int xonar_st_mixer_init(struct oxygen *chip)
        return 0;
 }
 
+static int xonar_xense_mixer_init(struct oxygen *chip)
+{
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(xense_controls); ++i) {
+               err = snd_ctl_add(chip->card,
+               snd_ctl_new1(&xense_controls[i], chip));
+               if (err < 0)
+                       return err;
+       }
+       err = add_pcm1796_controls(chip);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
 static void dump_pcm1796_registers(struct oxygen *chip,
                                   struct snd_info_buffer *buffer)
 {
@@ -1140,12 +1269,29 @@ int get_xonar_pcm179x_model(struct oxygen *chip,
                break;
        case 0x85f4:
                chip->model = model_xonar_st;
-               /* TODO: daughterboard support */
-               chip->model.shortname = "Xonar STX II";
+               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
+               switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
+               default:
+                       chip->model.shortname = "Xonar STX II";
+                       break;
+               case GPIO_DB_H6:
+                       chip->model.shortname = "Xonar STX II+H6";
+                       chip->model.dac_channels_pcm = 8;
+                       chip->model.dac_channels_mixer = 8;
+                       chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
+                       break;
+               }
                chip->model.init = xonar_stx_init;
                chip->model.resume = xonar_stx_resume;
                chip->model.set_dac_params = set_pcm1796_params;
                break;
+       case 0x8428:
+               chip->model = model_xonar_st;
+               chip->model.shortname = "Xonar Xense";
+               chip->model.chip = "AV100";
+               chip->model.init = xonar_xense_init;
+               chip->model.mixer_init = xonar_xense_mixer_init;
+               break;
        default:
                return -EINVAL;
        }