Commit eb02c700 authored by Sitanshu Nanavati's avatar Sitanshu Nanavati Committed by Greg Kroah-Hartman
Browse files

intel_sst: DMIC routing



This patch adds support for configuring and routing the
DMICs (assigned HW route to DMICs)

Signed-off-by: default avatarSitanshu Nanavati <sitanshu.nanavati@intel.com>
Signed-off-by: default avatarRamesh Babu K V <ramesh.babu@intel.com>
Signed-off-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 2784a80c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@

#define SST_CARD_NAMES "intel_mid_card"

#define MFLD_MAX_HW_CH 4
/* control list Pmic & Lpe */
/* Input controls */
enum port_status {
@@ -108,6 +109,9 @@ struct snd_pmic_ops {
	int (*power_down_pmic_pb) (unsigned int device);
	int (*power_down_pmic_cp) (unsigned int device);
	int (*power_down_pmic) (void);
	unsigned int hw_dmic_map[MFLD_MAX_HW_CH];
	unsigned int available_dmics;
	int (*set_hw_dmic_route) (u8 index);
};

struct intel_sst_pcm_control {
+1 −1
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@
 */
int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot)
{
	if (device > MAX_NUM_STREAMS_MFLD) {
	if (device >= MAX_NUM_STREAMS_MFLD) {
		pr_debug("device type invalid %d\n", device);
		return -EINVAL;
	}
+9 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#define __INTELMID_H

#include <linux/time.h>
#include <sound/jack.h>

#define DRIVER_NAME_MFLD "msic_audio"
#define DRIVER_NAME_MRST "pmic_audio"
@@ -43,7 +44,7 @@
#define MAX_BUFFER		(800*1024) /* for PCM */
#define MIN_BUFFER		(800*1024)
#define MAX_PERIODS		(1024*2)
#define MIN_PERIODS		1
#define MIN_PERIODS		2
#define MAX_PERIOD_BYTES MAX_BUFFER
#define MIN_PERIOD_BYTES 32
/*#define MIN_PERIOD_BYTES 160*/
@@ -57,7 +58,7 @@
#define FIFO_SIZE		0 /* fifo not being used */
#define INTEL_MAD		"Intel MAD"
#define MAX_CTRL_MRST		7
#define MAX_CTRL_MFLD		3
#define MAX_CTRL_MFLD		7
#define MAX_CTRL		7
#define MAX_VENDORS		4
/* TODO +6 db */
@@ -167,6 +168,12 @@ enum _widget_ctrl {
enum _widget_ctrl_mfld {
	LINEOUT_SEL_MFLD = 3,
};
enum hw_chs {
	HW_CH0 = 0,
	HW_CH1,
	HW_CH2,
	HW_CH3
};

void period_elapsed(void *mad_substream);
int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream);
+198 −0
Original line number Diff line number Diff line
@@ -35,6 +35,22 @@
#include "intelmid_snd_control.h"
#include "intelmid.h"

#define HW_CH_BASE 4


#define HW_CH_0	"Hw1"
#define HW_CH_1	"Hw2"
#define HW_CH_2	"Hw3"
#define HW_CH_3	"Hw4"

static char *router_dmics[] = {	"DMIC1",
				"DMIC2",
				"DMIC3",
				"DMIC4",
				"DMIC5",
				"DMIC6"
				};

static char *out_names_mrst[] = {"Headphones",
				"Internal speakers"};
static char *in_names_mrst[] = {"AMIC",
@@ -574,6 +590,152 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol,
	return ret_val;
}

static int snd_intelmad_device_dmic_get(struct snd_kcontrol *kcontrol,
					struct snd_ctl_elem_value *uval)
{
	struct snd_intelmad *intelmaddata;
	struct snd_pmic_ops *scard_ops;

	WARN_ON(!uval);
	WARN_ON(!kcontrol);

	intelmaddata = kcontrol->private_data;
	scard_ops = intelmaddata->sstdrv_ops->scard_ops;

	if (scard_ops->input_dev_id != DMIC) {
		pr_debug("input dev = 0x%x\n", scard_ops->input_dev_id);
		return 0;
	}

	if (intelmaddata->cpu_id == CPU_CHIP_PENWELL)
		uval->value.enumerated.item[0] = kcontrol->private_value;
	else
		pr_debug(" CPU id = 0x%xis invalid.\n",
			intelmaddata->cpu_id);
	return 0;
}

void msic_set_bit(u8 index, unsigned int *available_dmics)
{
	*available_dmics |= (1 << index);
}

void msic_clear_bit(u8 index, unsigned int *available_dmics)
{
	*available_dmics &= ~(1 << index);
}

int msic_is_set_bit(u8 index, unsigned int *available_dmics)
{
	int ret_val;

	ret_val = (*available_dmics & (1 << index));
	return ret_val;
}

static int snd_intelmad_device_dmic_set(struct snd_kcontrol *kcontrol,
					struct snd_ctl_elem_value *uval)
{
	struct snd_intelmad *intelmaddata;
	struct snd_pmic_ops *scard_ops;
	int i, dmic_index;
	unsigned int available_dmics;
	int jump_count;
	int max_dmics = ARRAY_SIZE(router_dmics);

	WARN_ON(!uval);
	WARN_ON(!kcontrol);

	intelmaddata = kcontrol->private_data;
	WARN_ON(!intelmaddata->sstdrv_ops);

	scard_ops = intelmaddata->sstdrv_ops->scard_ops;
	WARN_ON(!scard_ops);

	if (scard_ops->input_dev_id != DMIC) {
		pr_debug("input dev = 0x%x\n", scard_ops->input_dev_id);
		return 0;
	}

	available_dmics = scard_ops->available_dmics;

	if (kcontrol->private_value > uval->value.enumerated.item[0]) {
		pr_debug("jump count -1.\n");
		jump_count = -1;
	} else {
		pr_debug("jump count 1.\n");
		jump_count = 1;
	}

	dmic_index =  uval->value.enumerated.item[0];
	pr_debug("set function. dmic_index = %d, avl_dmic = 0x%x\n",
			 dmic_index, available_dmics);
	for (i = 0; i < max_dmics; i++) {
		pr_debug("set function. loop index = 0x%x.  dmic_index = 0x%x\n",
			 i, dmic_index);
		if (!msic_is_set_bit(dmic_index, &available_dmics)) {
			msic_clear_bit(kcontrol->private_value,
						&available_dmics);
			msic_set_bit(dmic_index, &available_dmics);
			kcontrol->private_value = dmic_index;
			scard_ops->available_dmics = available_dmics;
			scard_ops->hw_dmic_map[kcontrol->id.numid-HW_CH_BASE] =
				kcontrol->private_value;
			scard_ops->set_hw_dmic_route
				(kcontrol->id.numid-HW_CH_BASE);
			return 0;
		}

		dmic_index += jump_count;

		if (dmic_index > (max_dmics - 1) && jump_count == 1) {
			pr_debug("Resettingthe dmic index to 0.\n");
			dmic_index = 0;
		} else if (dmic_index == -1 && jump_count == -1) {
			pr_debug("Resetting the dmic index to 5.\n");
			dmic_index = max_dmics - 1;
		}
	}

	return -EINVAL;
}

static int snd_intelmad_device_dmic_info_mfld(struct snd_kcontrol *kcontrol,
					struct snd_ctl_elem_info *uinfo)
{
	struct snd_intelmad *intelmaddata;
	struct snd_pmic_ops *scard_ops;

	uinfo->count                  = MONO_CNTL;
	uinfo->type                   = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
	uinfo->value.enumerated.items = ARRAY_SIZE(router_dmics);

	intelmaddata = kcontrol->private_data;
	WARN_ON(!intelmaddata->sstdrv_ops);

	scard_ops = intelmaddata->sstdrv_ops->scard_ops;
	WARN_ON(!scard_ops);

	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
		uinfo->value.enumerated.item =
			uinfo->value.enumerated.items - 1;

	strncpy(uinfo->value.enumerated.name,
	router_dmics[uinfo->value.enumerated.item],
	sizeof(uinfo->value.enumerated.name)-1);


	msic_set_bit(kcontrol->private_value, &scard_ops->available_dmics);
	pr_debug("info function. avl_dmic = 0x%x",
		scard_ops->available_dmics);

	scard_ops->hw_dmic_map[kcontrol->id.numid-HW_CH_BASE] =
		kcontrol->private_value;

	return 0;
}


struct snd_kcontrol_new snd_intelmad_controls_mrst[MAX_CTRL] __devinitdata = {
{
	.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -669,5 +831,41 @@ snd_intelmad_controls_mfld[MAX_CTRL_MFLD] __devinitdata = {
	.put		=	snd_intelmad_device_set,
	.private_value	=	0,
},
{
	.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,
	.name		=	HW_CH_0,
	.access		=	SNDRV_CTL_ELEM_ACCESS_READWRITE,
	.info		=	snd_intelmad_device_dmic_info_mfld,
	.get		=	snd_intelmad_device_dmic_get,
	.put		=	snd_intelmad_device_dmic_set,
	.private_value	=	0
},
{
	.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,
	.name		=	HW_CH_1,
	.access		=	SNDRV_CTL_ELEM_ACCESS_READWRITE,
	.info		=	snd_intelmad_device_dmic_info_mfld,
	.get		=	snd_intelmad_device_dmic_get,
	.put		=	snd_intelmad_device_dmic_set,
	.private_value	=	1
},
{
	.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,
	.name		=	HW_CH_2,
	.access		=	SNDRV_CTL_ELEM_ACCESS_READWRITE,
	.info		=	snd_intelmad_device_dmic_info_mfld,
	.get		=	snd_intelmad_device_dmic_get,
	.put		=	snd_intelmad_device_dmic_set,
	.private_value	=	2
},
{
	.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,
	.name		=	HW_CH_3,
	.access		=	SNDRV_CTL_ELEM_ACCESS_READWRITE,
	.info		=	snd_intelmad_device_dmic_info_mfld,
	.get		=	snd_intelmad_device_dmic_get,
	.put		=	snd_intelmad_device_dmic_set,
	.private_value	=	3
}
};
+58 −0
Original line number Diff line number Diff line
@@ -29,8 +29,14 @@
#include <linux/pci.h>
#include <linux/file.h>
#include <linux/delay.h>
#include <sound/control.h>
#include "intel_sst.h"
#include <linux/input.h>
#include "intelmid_snd_control.h"
#include "intelmid.h"

#define AUDIOMUX12  0x24c
#define AUDIOMUX34  0x24d

static int msic_init_card(void)
{
@@ -680,6 +686,57 @@ static int msic_set_selected_input_dev(u8 value)
	return retval;
}

static int msic_set_hw_dmic_route(u8 hw_ch_index)
{
	struct sc_reg_access sc_access_router;
	int    retval = -EINVAL;

	switch (hw_ch_index) {
	case HW_CH0:
		sc_access_router.reg_addr = AUDIOMUX12;
		sc_access_router.value    = snd_msic_ops.hw_dmic_map[0];
		sc_access_router.mask     = (MASK2 | MASK1 | MASK0);
		pr_debug("hw_ch0.  value = 0x%x\n",
				sc_access_router.value);
		retval = sst_sc_reg_access(&sc_access_router,
				PMIC_READ_MODIFY, 1);
		break;

	case HW_CH1:
		sc_access_router.reg_addr = AUDIOMUX12;
		sc_access_router.value    = (snd_msic_ops.hw_dmic_map[1]) << 4;
		sc_access_router.mask     = (MASK6 | MASK5 | MASK4);
		pr_debug("### hw_ch1.  value = 0x%x\n",
				sc_access_router.value);
		retval = sst_sc_reg_access(&sc_access_router,
				PMIC_READ_MODIFY, 1);
		break;

	case HW_CH2:
		sc_access_router.reg_addr = AUDIOMUX34;
		sc_access_router.value    = snd_msic_ops.hw_dmic_map[2];
		sc_access_router.mask     = (MASK2 | MASK1 | MASK0);
		pr_debug("hw_ch2.  value = 0x%x\n",
				sc_access_router.value);
		retval = sst_sc_reg_access(&sc_access_router,
				PMIC_READ_MODIFY, 1);
		break;

	case HW_CH3:
		sc_access_router.reg_addr = AUDIOMUX34;
		sc_access_router.value    = (snd_msic_ops.hw_dmic_map[3]) << 4;
		sc_access_router.mask     = (MASK6 | MASK5 | MASK4);
		pr_debug("hw_ch3.  value = 0x%x\n",
				sc_access_router.value);
		retval = sst_sc_reg_access(&sc_access_router,
				PMIC_READ_MODIFY, 1);
		break;
	}

	return retval;
}


static int msic_set_pcm_voice_params(void)
{
	return 0;
@@ -724,6 +781,7 @@ struct snd_pmic_ops snd_msic_ops = {
	.set_input_dev	=	msic_set_selected_input_dev,
	.set_output_dev =	msic_set_selected_output_dev,
	.set_lineout_dev =	msic_set_selected_lineout_dev,
	.set_hw_dmic_route =    msic_set_hw_dmic_route,
	.set_mute	=	msic_set_mute,
	.get_mute	=	msic_get_mute,
	.set_vol	=	msic_set_vol,