ALSA: oxygen: merge HiFier driver into snd-oxygen

The snd-hifier driver contains more duplicated code than model-specific
code, so it does not make sense for it to be a separate driver.
Handling the two-channel output restriction can be easily done in the
generic driver.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index d0eb696..f1a1787 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -974,13 +974,6 @@
 
     See hdspm.txt for details.
 
-  Module snd-hifier
-  -----------------
-
-    Module for the MediaTek/TempoTec HiFier Fantasia sound card.
-
-    This module supports autoprobe and multiple cards.
-
   Module snd-ice1712
   ------------------
 
@@ -1531,7 +1524,7 @@
   Module snd-oxygen
   -----------------
 
-    Module for sound cards based on the C-Media CMI8788 chip:
+    Module for sound cards based on the C-Media CMI8787/8788 chip:
     * Asound A-8788
     * AuzenTech X-Meridian
     * Bgears b-Enspirer
@@ -1540,6 +1533,7 @@
     * HT-Omega Claro halo (XT)
     * Razer Barracuda AC-1
     * Sondigo Inferno
+    * TempoTec HiFier Fantasia
 
     This module supports autoprobe and multiple cards.
 
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 12e3465..dfe406d 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -209,7 +209,7 @@
         tristate
 
 config SND_OXYGEN
-	tristate "C-Media 8788 (Oxygen)"
+	tristate "C-Media 8787, 8788 (Oxygen)"
 	select SND_OXYGEN_LIB
 	select SND_PCM
 	select SND_MPU401_UART
@@ -224,6 +224,7 @@
 	   * HT-Omega Claro halo (XT)
 	   * Razer Barracuda AC-1
 	   * Sondigo Inferno
+	   * TempoTec/MediaTek HiFier Fantasia
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-oxygen.
@@ -578,18 +579,6 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-hdspm.
 
-config SND_HIFIER
-	tristate "TempoTec HiFier Fantasia"
-	select SND_OXYGEN_LIB
-	select SND_PCM
-	select SND_MPU401_UART
-	help
-	  Say Y here to include support for the MediaTek/TempoTec HiFier
-	  Fantasia sound card.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-hifier.
-
 config SND_ICE1712
 	tristate "ICEnsemble ICE1712 (Envy24)"
 	select SND_MPU401_UART
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile
index acd8f15..bd67c0d 100644
--- a/sound/pci/oxygen/Makefile
+++ b/sound/pci/oxygen/Makefile
@@ -1,10 +1,8 @@
 snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
-snd-hifier-objs := hifier.o
 snd-oxygen-objs := oxygen.o
 snd-virtuoso-objs := virtuoso.o xonar_lib.o \
 	xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
 
 obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
-obj-$(CONFIG_SND_HIFIER) += snd-hifier.o
 obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o
 obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c
deleted file mode 100644
index 5a87d68..0000000
--- a/sound/pci/oxygen/hifier.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- *
- *
- *  This driver is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License, version 2.
- *
- *  This driver is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this driver; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-/*
- * CMI8788:
- *
- * SPI 0 -> AK4396
- */
-
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <sound/control.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/tlv.h>
-#include "oxygen.h"
-#include "ak4396.h"
-
-MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_DESCRIPTION("TempoTec HiFier driver");
-MODULE_LICENSE("GPL v2");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "card index");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string");
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "enable card");
-
-static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = {
-	{ OXYGEN_PCI_SUBID(0x14c3, 0x1710) },
-	{ OXYGEN_PCI_SUBID(0x14c3, 0x1711) },
-	{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
-	{ }
-};
-MODULE_DEVICE_TABLE(pci, hifier_ids);
-
-struct hifier_data {
-	u8 ak4396_regs[5];
-};
-
-static void ak4396_write(struct oxygen *chip, u8 reg, u8 value)
-{
-	struct hifier_data *data = chip->model_data;
-
-	oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER  |
-			 OXYGEN_SPI_DATA_LENGTH_2 |
-			 OXYGEN_SPI_CLOCK_160 |
-			 (0 << OXYGEN_SPI_CODEC_SHIFT) |
-			 OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
-			 AK4396_WRITE | (reg << 8) | value);
-	data->ak4396_regs[reg] = value;
-}
-
-static void ak4396_write_cached(struct oxygen *chip, u8 reg, u8 value)
-{
-	struct hifier_data *data = chip->model_data;
-
-	if (value != data->ak4396_regs[reg])
-		ak4396_write(chip, reg, value);
-}
-
-static void hifier_registers_init(struct oxygen *chip)
-{
-	struct hifier_data *data = chip->model_data;
-
-	ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
-	ak4396_write(chip, AK4396_CONTROL_2,
-		     data->ak4396_regs[AK4396_CONTROL_2]);
-	ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM);
-	ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
-	ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
-}
-
-static void hifier_init(struct oxygen *chip)
-{
-	struct hifier_data *data = chip->model_data;
-
-	data->ak4396_regs[AK4396_CONTROL_2] =
-		AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
-	hifier_registers_init(chip);
-
-	snd_component_add(chip->card, "AK4396");
-	snd_component_add(chip->card, "CS5340");
-}
-
-static void hifier_cleanup(struct oxygen *chip)
-{
-}
-
-static void hifier_resume(struct oxygen *chip)
-{
-	hifier_registers_init(chip);
-}
-
-static void set_ak4396_params(struct oxygen *chip,
-			       struct snd_pcm_hw_params *params)
-{
-	struct hifier_data *data = chip->model_data;
-	u8 value;
-
-	value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_DFS_MASK;
-	if (params_rate(params) <= 54000)
-		value |= AK4396_DFS_NORMAL;
-	else if (params_rate(params) <= 108000)
-		value |= AK4396_DFS_DOUBLE;
-	else
-		value |= AK4396_DFS_QUAD;
-
-	msleep(1); /* wait for the new MCLK to become stable */
-
-	if (value != data->ak4396_regs[AK4396_CONTROL_2]) {
-		ak4396_write(chip, AK4396_CONTROL_1,
-			     AK4396_DIF_24_MSB);
-		ak4396_write(chip, AK4396_CONTROL_2, value);
-		ak4396_write(chip, AK4396_CONTROL_1,
-			     AK4396_DIF_24_MSB | AK4396_RSTN);
-	}
-}
-
-static void update_ak4396_volume(struct oxygen *chip)
-{
-	ak4396_write_cached(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
-	ak4396_write_cached(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
-}
-
-static void update_ak4396_mute(struct oxygen *chip)
-{
-	struct hifier_data *data = chip->model_data;
-	u8 value;
-
-	value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_SMUTE;
-	if (chip->dac_mute)
-		value |= AK4396_SMUTE;
-	ak4396_write_cached(chip, AK4396_CONTROL_2, value);
-}
-
-static void set_cs5340_params(struct oxygen *chip,
-			      struct snd_pcm_hw_params *params)
-{
-}
-
-static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
-
-static const struct oxygen_model model_hifier = {
-	.shortname = "C-Media CMI8787",
-	.longname = "C-Media Oxygen HD Audio",
-	.chip = "CMI8788",
-	.init = hifier_init,
-	.cleanup = hifier_cleanup,
-	.resume = hifier_resume,
-	.get_i2s_mclk = oxygen_default_i2s_mclk,
-	.set_dac_params = set_ak4396_params,
-	.set_adc_params = set_cs5340_params,
-	.update_dac_volume = update_ak4396_volume,
-	.update_dac_mute = update_ak4396_mute,
-	.dac_tlv = ak4396_db_scale,
-	.model_data_size = sizeof(struct hifier_data),
-	.device_config = PLAYBACK_0_TO_I2S |
-			 PLAYBACK_1_TO_SPDIF |
-			 CAPTURE_0_FROM_I2S_1,
-	.dac_channels = 2,
-	.dac_volume_min = 0,
-	.dac_volume_max = 255,
-	.function_flags = OXYGEN_FUNCTION_SPI,
-	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
-static int __devinit get_hifier_model(struct oxygen *chip,
-				      const struct pci_device_id *id)
-{
-	chip->model = model_hifier;
-	return 0;
-}
-
-static int __devinit hifier_probe(struct pci_dev *pci,
-				  const struct pci_device_id *pci_id)
-{
-	static int dev;
-	int err;
-
-	if (dev >= SNDRV_CARDS)
-		return -ENODEV;
-	if (!enable[dev]) {
-		++dev;
-		return -ENOENT;
-	}
-	err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
-			       hifier_ids, get_hifier_model);
-	if (err >= 0)
-		++dev;
-	return err;
-}
-
-static struct pci_driver hifier_driver = {
-	.name = "CMI8787HiFier",
-	.id_table = hifier_ids,
-	.probe = hifier_probe,
-	.remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
-	.suspend = oxygen_pci_suspend,
-	.resume = oxygen_pci_resume,
-#endif
-};
-
-static int __init alsa_card_hifier_init(void)
-{
-	return pci_register_driver(&hifier_driver);
-}
-
-static void __exit alsa_card_hifier_exit(void)
-{
-	pci_unregister_driver(&hifier_driver);
-}
-
-module_init(alsa_card_hifier_init)
-module_exit(alsa_card_hifier_exit)
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 98a8eb3..5e258b2 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -70,6 +70,7 @@
 	MODEL_MERIDIAN,		/* AuzenTech X-Meridian */
 	MODEL_CLARO,		/* HT-Omega Claro */
 	MODEL_CLARO_HALO,	/* HT-Omega Claro halo */
+	MODEL_HIFIER,		/* TempoTec HiFier Fantasia */
 };
 
 static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
@@ -81,6 +82,8 @@
 	{ OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
 	{ OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF },
 	{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_HIFIER },
+	{ OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_HIFIER },
 	{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
 	{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
 	{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO },
@@ -98,6 +101,7 @@
 #define GPIO_CLARO_HP		0x0100
 
 struct generic_data {
+	unsigned int dacs;
 	u8 ak4396_regs[4][5];
 	u16 wm8785_regs[3];
 };
@@ -148,7 +152,7 @@
 	struct generic_data *data = chip->model_data;
 	unsigned int i;
 
-	for (i = 0; i < 4; ++i) {
+	for (i = 0; i < data->dacs; ++i) {
 		ak4396_write(chip, i, AK4396_CONTROL_1,
 			     AK4396_DIF_24_MSB | AK4396_RSTN);
 		ak4396_write(chip, i, AK4396_CONTROL_2,
@@ -166,6 +170,7 @@
 {
 	struct generic_data *data = chip->model_data;
 
+	data->dacs = chip->model.dac_channels / 2;
 	data->ak4396_regs[0][AK4396_CONTROL_2] =
 		AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
 	ak4396_registers_init(chip);
@@ -232,6 +237,12 @@
 	claro_enable_hp(chip);
 }
 
+static void hifier_init(struct oxygen *chip)
+{
+	ak4396_init(chip);
+	snd_component_add(chip->card, "CS5340");
+}
+
 static void generic_cleanup(struct oxygen *chip)
 {
 }
@@ -268,6 +279,11 @@
 	claro_enable_hp(chip);
 }
 
+static void stereo_resume(struct oxygen *chip)
+{
+	ak4396_registers_init(chip);
+}
+
 static void set_ak4396_params(struct oxygen *chip,
 			      struct snd_pcm_hw_params *params)
 {
@@ -286,7 +302,7 @@
 	msleep(1); /* wait for the new MCLK to become stable */
 
 	if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) {
-		for (i = 0; i < 4; ++i) {
+		for (i = 0; i < data->dacs; ++i) {
 			ak4396_write(chip, i, AK4396_CONTROL_1,
 				     AK4396_DIF_24_MSB);
 			ak4396_write(chip, i, AK4396_CONTROL_2, value);
@@ -298,9 +314,10 @@
 
 static void update_ak4396_volume(struct oxygen *chip)
 {
+	struct generic_data *data = chip->model_data;
 	unsigned int i;
 
-	for (i = 0; i < 4; ++i) {
+	for (i = 0; i < data->dacs; ++i) {
 		ak4396_write_cached(chip, i, AK4396_LCH_ATT,
 				    chip->dac_volume[i * 2]);
 		ak4396_write_cached(chip, i, AK4396_RCH_ATT,
@@ -317,7 +334,7 @@
 	value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE;
 	if (chip->dac_mute)
 		value |= AK4396_SMUTE;
-	for (i = 0; i < 4; ++i)
+	for (i = 0; i < data->dacs; ++i)
 		ak4396_write_cached(chip, i, AK4396_CONTROL_2, value);
 }
 
@@ -356,6 +373,10 @@
 			      value, GPIO_AK5385_DFS_MASK);
 }
 
+static void set_no_params(struct oxygen *chip, struct snd_pcm_hw_params *params)
+{
+}
+
 static int rolloff_info(struct snd_kcontrol *ctl,
 			struct snd_ctl_elem_info *info)
 {
@@ -400,7 +421,7 @@
 		reg &= ~AK4396_SLOW;
 	changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2];
 	if (changed) {
-		for (i = 0; i < 4; ++i)
+		for (i = 0; i < data->dacs; ++i)
 			ak4396_write(chip, i, AK4396_CONTROL_2, reg);
 	}
 	mutex_unlock(&chip->mutex);
@@ -550,6 +571,18 @@
 					    CAPTURE_0_FROM_I2S_2 |
 					    CAPTURE_1_FROM_SPDIF;
 		break;
+	case MODEL_HIFIER:
+		chip->model.shortname = "C-Media CMI8787";
+		chip->model.chip = "CMI8787";
+		chip->model.init = hifier_init;
+		chip->model.resume = stereo_resume;
+		chip->model.mixer_init = generic_mixer_init;
+		chip->model.set_adc_params = set_no_params;
+		chip->model.device_config = PLAYBACK_0_TO_I2S |
+					    PLAYBACK_1_TO_SPDIF |
+					    CAPTURE_0_FROM_I2S_1;
+		chip->model.dac_channels = 2;
+		break;
 	}
 	if (id->driver_data == MODEL_MERIDIAN ||
 	    id->driver_data == MODEL_CLARO_HALO) {