]> Pileus Git - ~andy/linux/blobdiff - sound/soc/codecs/tlv320aic3x.c
ASoC: tlv320aic3x: Fix remaining output pin switch names
[~andy/linux] / sound / soc / codecs / tlv320aic3x.c
index 867bf1fb182567c5ad99f4ac854a94ba0d6a9a4b..6e4ed79d5eb9fb23d00ff103f3bff90a9ac0e5b1 100644 (file)
  *
  * Notes:
  *  The AIC3X is a driver for a low power stereo audio
- *  codecs aic31, aic32, aic33.
+ *  codecs aic31, aic32, aic33, aic3007.
  *
  *  It supports full aic33 codec functionality.
- *  The compatibility with aic32, aic31 is as follows:
- *        aic32        |        aic31
+ *  The compatibility with aic32, aic31 and aic3007 is as follows:
+ *    aic32/aic3007    |        aic31
  *  ---------------------------------------
  *   MONO_LOUT -> N/A  |  MONO_LOUT -> N/A
  *                     |  IN1L -> LINE1L
@@ -70,6 +70,10 @@ struct aic3x_priv {
        unsigned int sysclk;
        int master;
        int gpio_reset;
+#define AIC3X_MODEL_3X 0
+#define AIC3X_MODEL_33 1
+#define AIC3X_MODEL_3007 2
+       u16 model;
 };
 
 /*
@@ -310,7 +314,7 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
                         DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
+       SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
        SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume",
                         PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
@@ -321,7 +325,7 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_DOUBLE_R_TLV("HP DAC Playback Volume",
                         DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
+       SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
                     0x01, 0),
        SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume",
                         PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
@@ -337,7 +341,7 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume",
                         DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
+       SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
                     0x01, 0),
        SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume",
                       PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
@@ -361,6 +365,14 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
 };
 
+/*
+ * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
+       SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
+
 /* Left DAC Mux */
 static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
@@ -589,6 +601,15 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("LINE2R"),
 };
 
+static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
+       /* Class-D outputs */
+       SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("SPOP"),
+       SND_SOC_DAPM_OUTPUT("SPOM"),
+};
+
 static const struct snd_soc_dapm_route intercon[] = {
        /* Left Output */
        {"Left DAC Mux", "DAC_L1", "Left DAC"},
@@ -759,14 +780,30 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
 };
 
+static const struct snd_soc_dapm_route intercon_3007[] = {
+       /* Class-D outputs */
+       {"Left Class-D Out", NULL, "Left Line Out"},
+       {"Right Class-D Out", NULL, "Left Line Out"},
+       {"SPOP", NULL, "Left Class-D Out"},
+       {"SPOM", NULL, "Right Class-D Out"},
+};
+
 static int aic3x_add_widgets(struct snd_soc_codec *codec)
 {
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+
        snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
 
        /* set up audio path interconnects */
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
+       if (aic3x->model == AIC3X_MODEL_3007) {
+               snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets,
+                       ARRAY_SIZE(aic3007_dapm_widgets));
+               snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007));
+       }
+
        return 0;
 }
 
@@ -1151,6 +1188,7 @@ static int aic3x_resume(struct snd_soc_codec *codec)
  */
 static int aic3x_init(struct snd_soc_codec *codec)
 {
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
        int reg;
 
        aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
@@ -1219,6 +1257,17 @@ static int aic3x_init(struct snd_soc_codec *codec)
        aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
        aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
 
+       if (aic3x->model == AIC3X_MODEL_3007) {
+               /* Class-D speaker driver init; datasheet p. 46 */
+               aic3x_write(codec, AIC3X_PAGE_SELECT, 0x0D);
+               aic3x_write(codec, 0xD, 0x0D);
+               aic3x_write(codec, 0x8, 0x5C);
+               aic3x_write(codec, 0x8, 0x5D);
+               aic3x_write(codec, 0x8, 0x5C);
+               aic3x_write(codec, AIC3X_PAGE_SELECT, 0x00);
+               aic3x_write(codec, CLASSD_CTRL, 0);
+       }
+
        /* off, with power on */
        aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -1232,6 +1281,8 @@ static int aic3x_probe(struct snd_soc_codec *codec)
        codec->hw_write = (hw_write_t) i2c_master_send;
        codec->control_data = aic3x->control_data;
 
+       aic3x_init(codec);
+
        if (aic3x->setup) {
                /* setup GPIO functions */
                aic3x_write(codec, AIC3X_GPIO1_REG,
@@ -1240,10 +1291,10 @@ static int aic3x_probe(struct snd_soc_codec *codec)
                            (aic3x->setup->gpio_func[1] & 0xf) << 4);
        }
 
-       aic3x_init(codec);
-
        snd_soc_add_controls(codec, aic3x_snd_controls,
                             ARRAY_SIZE(aic3x_snd_controls));
+       if (aic3x->model == AIC3X_MODEL_3007)
+               snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
 
        aic3x_add_widgets(codec);
 
@@ -1275,6 +1326,14 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
  * 0x18, 0x19, 0x1A, 0x1B
  */
 
+static const struct i2c_device_id aic3x_i2c_id[] = {
+       [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 },
+       [AIC3X_MODEL_33] = { "tlv320aic33", 0 },
+       [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
+
 /*
  * If the i2c layer weren't so broken, we could pass this kind of data
  * around
@@ -1286,6 +1345,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
        struct aic3x_setup_data *setup = pdata->setup;
        struct aic3x_priv *aic3x;
        int ret, i;
+       const struct i2c_device_id *tbl;
 
        aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
        if (aic3x == NULL) {
@@ -1306,6 +1366,12 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
                gpio_direction_output(aic3x->gpio_reset, 0);
        }
 
+       for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) {
+               if (!strcmp(tbl->name, id->name))
+                       break;
+       }
+       aic3x->model = tbl - aic3x_i2c_id;
+
        for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
                aic3x->supplies[i].supply = aic3x_supply_names[i];
 
@@ -1360,13 +1426,6 @@ static int aic3x_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-static const struct i2c_device_id aic3x_i2c_id[] = {
-       { "tlv320aic3x", 0 },
-       { "tlv320aic33", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
-
 /* machine i2c codec control layer */
 static struct i2c_driver aic3x_i2c_driver = {
        .driver = {