411 lines
9.6 KiB
C
411 lines
9.6 KiB
C
|
/*
|
||
|
* intelmid_vm_control.c - Intel Sound card driver for MID
|
||
|
*
|
||
|
* Copyright (C) 2010 Intel Corp
|
||
|
* Authors: Vinod Koul <vinod.koul@intel.com>
|
||
|
*
|
||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; version 2 of the License.
|
||
|
*
|
||
|
* This program 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 program; if not, write to the Free Software Foundation, Inc.,
|
||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||
|
*
|
||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
*
|
||
|
* This file contains the control operations of msic vendors
|
||
|
*/
|
||
|
|
||
|
#include <linux/pci.h>
|
||
|
#include <linux/file.h>
|
||
|
#include "intel_sst.h"
|
||
|
#include "intel_sst_ioctl.h"
|
||
|
#include "intelmid_snd_control.h"
|
||
|
|
||
|
static int msic_init_card(void)
|
||
|
{
|
||
|
struct sc_reg_access sc_access[] = {
|
||
|
/* dmic configuration */
|
||
|
{0x241, 0x85, 0},
|
||
|
{0x242, 0x02, 0},
|
||
|
/* audio paths config */
|
||
|
{0x24C, 0x10, 0},
|
||
|
{0x24D, 0x32, 0},
|
||
|
/* PCM2 interface slots */
|
||
|
/* preconfigured slots for 0-5 both tx, rx */
|
||
|
{0x272, 0x10, 0},
|
||
|
{0x273, 0x32, 0},
|
||
|
{0x274, 0xFF, 0},
|
||
|
{0x275, 0x10, 0},
|
||
|
{0x276, 0x32, 0},
|
||
|
{0x277, 0x54, 0},
|
||
|
/*Sinc5 decimator*/
|
||
|
{0x24E, 0x28, 0},
|
||
|
/*TI vibra w/a settings*/
|
||
|
{0x384, 0x80, 0},
|
||
|
{0x385, 0x80, 0},
|
||
|
/*vibra settings*/
|
||
|
{0x267, 0x00, 0},
|
||
|
{0x26A, 0x10, 0},
|
||
|
{0x261, 0x00, 0},
|
||
|
{0x264, 0x10, 0},
|
||
|
/* pcm port setting */
|
||
|
{0x278, 0x00, 0},
|
||
|
{0x27B, 0x01, 0},
|
||
|
{0x27C, 0x0a, 0},
|
||
|
/* Set vol HSLRVOLCTRL, IHFVOL */
|
||
|
{0x259, 0x04, 0},
|
||
|
{0x25A, 0x04, 0},
|
||
|
{0x25B, 0x04, 0},
|
||
|
{0x25C, 0x04, 0},
|
||
|
/* HSEPRXCTRL Enable the headset left and right FIR filters */
|
||
|
{0x250, 0x30, 0},
|
||
|
/* HSMIXER */
|
||
|
{0x256, 0x11, 0},
|
||
|
/* amic configuration */
|
||
|
{0x249, 0x09, 0x0},
|
||
|
{0x24A, 0x09, 0x0},
|
||
|
/* unmask ocaudio/accdet interrupts */
|
||
|
{0x1d, 0x00, 0x00},
|
||
|
{0x1e, 0x00, 0x00},
|
||
|
};
|
||
|
snd_msic_ops.card_status = SND_CARD_INIT_DONE;
|
||
|
sst_sc_reg_access(sc_access, PMIC_WRITE, 30);
|
||
|
snd_msic_ops.pb_on = 0;
|
||
|
snd_msic_ops.cap_on = 0;
|
||
|
snd_msic_ops.input_dev_id = DMIC; /*def dev*/
|
||
|
snd_msic_ops.output_dev_id = STEREO_HEADPHONE;
|
||
|
pr_debug("sst: msic init complete!!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msic_power_up_pb(unsigned int device)
|
||
|
{
|
||
|
struct sc_reg_access sc_access1[] = {
|
||
|
/* turn on the audio power supplies */
|
||
|
{0x0DB, 0x05, 0},
|
||
|
/* VHSP */
|
||
|
{0x0DC, 0xFF, 0},
|
||
|
/* VHSN */
|
||
|
{0x0DD, 0x3F, 0},
|
||
|
/* turn on PLL */
|
||
|
{0x240, 0x21, 0},
|
||
|
};
|
||
|
struct sc_reg_access sc_access2[] = {
|
||
|
/* disable driver */
|
||
|
{0x25D, 0x0, 0x43},
|
||
|
/* DAC CONFIG ; both HP, LP on */
|
||
|
{0x257, 0x03, 0x03},
|
||
|
};
|
||
|
struct sc_reg_access sc_access3[] = {
|
||
|
/* HSEPRXCTRL Enable the headset left and right FIR filters */
|
||
|
{0x250, 0x30, 0},
|
||
|
/* HSMIXER */
|
||
|
{0x256, 0x11, 0},
|
||
|
};
|
||
|
struct sc_reg_access sc_access4[] = {
|
||
|
/* enable driver */
|
||
|
{0x25D, 0x3, 0x3},
|
||
|
/* unmute the headset */
|
||
|
{ 0x259, 0x80, 0x80},
|
||
|
{ 0x25A, 0x80, 0x80},
|
||
|
};
|
||
|
struct sc_reg_access sc_access_vihf[] = {
|
||
|
/* VIHF ON */
|
||
|
{0x0C9, 0x2D, 0x00},
|
||
|
};
|
||
|
struct sc_reg_access sc_access22[] = {
|
||
|
/* disable driver */
|
||
|
{0x25D, 0x00, 0x0C},
|
||
|
/*Filer DAC enable*/
|
||
|
{0x251, 0x03, 0x03},
|
||
|
{0x257, 0x0C, 0x0C},
|
||
|
};
|
||
|
struct sc_reg_access sc_access32[] = {
|
||
|
/*enable drv*/
|
||
|
{0x25D, 0x0C, 0x0c},
|
||
|
};
|
||
|
struct sc_reg_access sc_access42[] = {
|
||
|
/*unmute headset*/
|
||
|
{0x25B, 0x80, 0x80},
|
||
|
{0x25C, 0x80, 0x80},
|
||
|
};
|
||
|
struct sc_reg_access sc_access23[] = {
|
||
|
/* disable driver */
|
||
|
{0x25D, 0x0, 0x43},
|
||
|
/* DAC CONFIG ; both HP, LP on */
|
||
|
{0x257, 0x03, 0x03},
|
||
|
};
|
||
|
struct sc_reg_access sc_access43[] = {
|
||
|
/* enable driver */
|
||
|
{0x25D, 0x40, 0x40},
|
||
|
/* unmute the headset */
|
||
|
{ 0x259, 0x80, 0x80},
|
||
|
{ 0x25A, 0x80, 0x80},
|
||
|
};
|
||
|
struct sc_reg_access sc_access_vib[] = {
|
||
|
/* enable driver, ADC */
|
||
|
{0x25D, 0x10, 0x10},
|
||
|
{0x264, 0x02, 0x02},
|
||
|
};
|
||
|
struct sc_reg_access sc_access_hap[] = {
|
||
|
/* enable driver, ADC */
|
||
|
{0x25D, 0x20, 0x20},
|
||
|
{0x26A, 0x02, 0x02},
|
||
|
};
|
||
|
struct sc_reg_access sc_access_pcm2[] = {
|
||
|
/* enable pcm 2 */
|
||
|
{0x27C, 0x1, 0x1},
|
||
|
};
|
||
|
int retval = 0;
|
||
|
|
||
|
if (snd_msic_ops.card_status == SND_CARD_UN_INIT) {
|
||
|
retval = msic_init_card();
|
||
|
if (retval)
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
pr_debug("sst: powering up pb.... Device %d\n", device);
|
||
|
sst_sc_reg_access(sc_access1, PMIC_WRITE, 4);
|
||
|
switch (device) {
|
||
|
case SND_SST_DEVICE_HEADSET:
|
||
|
if (snd_msic_ops.output_dev_id == STEREO_HEADPHONE) {
|
||
|
sst_sc_reg_access(sc_access2, PMIC_READ_MODIFY, 2);
|
||
|
sst_sc_reg_access(sc_access3, PMIC_WRITE, 2);
|
||
|
sst_sc_reg_access(sc_access4, PMIC_READ_MODIFY, 3);
|
||
|
} else {
|
||
|
sst_sc_reg_access(sc_access23, PMIC_READ_MODIFY, 2);
|
||
|
sst_sc_reg_access(sc_access3, PMIC_WRITE, 2);
|
||
|
sst_sc_reg_access(sc_access43, PMIC_READ_MODIFY, 3);
|
||
|
}
|
||
|
snd_msic_ops.pb_on = 1;
|
||
|
break;
|
||
|
|
||
|
case SND_SST_DEVICE_IHF:
|
||
|
sst_sc_reg_access(sc_access_vihf, PMIC_WRITE, 1);
|
||
|
sst_sc_reg_access(sc_access22, PMIC_READ_MODIFY, 3);
|
||
|
sst_sc_reg_access(sc_access32, PMIC_READ_MODIFY, 1);
|
||
|
sst_sc_reg_access(sc_access42, PMIC_READ_MODIFY, 2);
|
||
|
break;
|
||
|
|
||
|
case SND_SST_DEVICE_VIBRA:
|
||
|
sst_sc_reg_access(sc_access_vib, PMIC_READ_MODIFY, 2);
|
||
|
break;
|
||
|
|
||
|
case SND_SST_DEVICE_HAPTIC:
|
||
|
sst_sc_reg_access(sc_access_hap, PMIC_READ_MODIFY, 2);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
pr_warn("sst: Wrong Device %d, selected %d\n",
|
||
|
device, snd_msic_ops.output_dev_id);
|
||
|
}
|
||
|
return sst_sc_reg_access(sc_access_pcm2, PMIC_READ_MODIFY, 1);
|
||
|
}
|
||
|
|
||
|
static int msic_power_up_cp(unsigned int device)
|
||
|
{
|
||
|
struct sc_reg_access sc_access[] = {
|
||
|
/* turn on the audio power supplies */
|
||
|
{0x0DB, 0x05, 0},
|
||
|
/* VHSP */
|
||
|
{0x0DC, 0xFF, 0},
|
||
|
/* VHSN */
|
||
|
{0x0DD, 0x3F, 0},
|
||
|
/* turn on PLL */
|
||
|
{0x240, 0x21, 0},
|
||
|
|
||
|
/* Turn on DMIC supply */
|
||
|
{0x247, 0xA0, 0x0},
|
||
|
{0x240, 0x21, 0x0},
|
||
|
{0x24C, 0x10, 0x0},
|
||
|
|
||
|
/* mic demux enable */
|
||
|
{0x245, 0x3F, 0x0},
|
||
|
{0x246, 0x7, 0x0},
|
||
|
|
||
|
};
|
||
|
struct sc_reg_access sc_access_amic[] = {
|
||
|
/* turn on the audio power supplies */
|
||
|
{0x0DB, 0x05, 0},
|
||
|
/* VHSP */
|
||
|
{0x0DC, 0xFF, 0},
|
||
|
/* VHSN */
|
||
|
{0x0DD, 0x3F, 0},
|
||
|
/* turn on PLL */
|
||
|
{0x240, 0x21, 0},
|
||
|
/*ADC EN*/
|
||
|
{0x248, 0x05, 0x0},
|
||
|
{0x24C, 0x76, 0x0},
|
||
|
/*MIC EN*/
|
||
|
{0x249, 0x09, 0x0},
|
||
|
{0x24A, 0x09, 0x0},
|
||
|
/* Turn on AMIC supply */
|
||
|
{0x247, 0xFC, 0x0},
|
||
|
|
||
|
};
|
||
|
struct sc_reg_access sc_access2[] = {
|
||
|
/* enable pcm 2 */
|
||
|
{0x27C, 0x1, 0x1},
|
||
|
};
|
||
|
struct sc_reg_access sc_access3[] = {
|
||
|
/*wait for mic to stabalize before turning on audio channels*/
|
||
|
{0x24F, 0x3C, 0x0},
|
||
|
};
|
||
|
int retval = 0;
|
||
|
|
||
|
if (snd_msic_ops.card_status == SND_CARD_UN_INIT) {
|
||
|
retval = msic_init_card();
|
||
|
if (retval)
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
pr_debug("sst: powering up cp....%d\n", snd_msic_ops.input_dev_id);
|
||
|
sst_sc_reg_access(sc_access2, PMIC_READ_MODIFY, 1);
|
||
|
snd_msic_ops.cap_on = 1;
|
||
|
if (snd_msic_ops.input_dev_id == AMIC)
|
||
|
sst_sc_reg_access(sc_access_amic, PMIC_WRITE, 9);
|
||
|
else
|
||
|
sst_sc_reg_access(sc_access, PMIC_WRITE, 9);
|
||
|
return sst_sc_reg_access(sc_access3, PMIC_WRITE, 1);
|
||
|
|
||
|
}
|
||
|
|
||
|
static int msic_power_down(void)
|
||
|
{
|
||
|
int retval = 0;
|
||
|
|
||
|
pr_debug("sst: powering dn msic\n");
|
||
|
snd_msic_ops.pb_on = 0;
|
||
|
snd_msic_ops.cap_on = 0;
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
static int msic_power_down_pb(void)
|
||
|
{
|
||
|
int retval = 0;
|
||
|
|
||
|
pr_debug("sst: powering dn pb....\n");
|
||
|
snd_msic_ops.pb_on = 0;
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
static int msic_power_down_cp(void)
|
||
|
{
|
||
|
int retval = 0;
|
||
|
|
||
|
pr_debug("sst: powering dn cp....\n");
|
||
|
snd_msic_ops.cap_on = 0;
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
static int msic_set_selected_output_dev(u8 value)
|
||
|
{
|
||
|
int retval = 0;
|
||
|
|
||
|
pr_debug("sst: msic set selected output:%d\n", value);
|
||
|
snd_msic_ops.output_dev_id = value;
|
||
|
if (snd_msic_ops.pb_on)
|
||
|
msic_power_up_pb(SND_SST_DEVICE_HEADSET);
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
static int msic_set_selected_input_dev(u8 value)
|
||
|
{
|
||
|
|
||
|
struct sc_reg_access sc_access_dmic[] = {
|
||
|
{0x24C, 0x10, 0x0},
|
||
|
};
|
||
|
struct sc_reg_access sc_access_amic[] = {
|
||
|
{0x24C, 0x76, 0x0},
|
||
|
|
||
|
};
|
||
|
int retval = 0;
|
||
|
|
||
|
pr_debug("sst: msic_set_selected_input_dev:%d\n", value);
|
||
|
snd_msic_ops.input_dev_id = value;
|
||
|
switch (value) {
|
||
|
case AMIC:
|
||
|
pr_debug("sst: Selecting AMIC1\n");
|
||
|
retval = sst_sc_reg_access(sc_access_amic, PMIC_WRITE, 1);
|
||
|
break;
|
||
|
case DMIC:
|
||
|
pr_debug("sst: Selecting DMIC1\n");
|
||
|
retval = sst_sc_reg_access(sc_access_dmic, PMIC_WRITE, 1);
|
||
|
break;
|
||
|
default:
|
||
|
return -EINVAL;
|
||
|
|
||
|
}
|
||
|
if (snd_msic_ops.cap_on)
|
||
|
retval = msic_power_up_cp(SND_SST_DEVICE_CAPTURE);
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
static int msic_set_pcm_voice_params(void)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msic_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msic_set_audio_port(int status)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msic_set_voice_port(int status)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msic_set_mute(int dev_id, u8 value)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msic_set_vol(int dev_id, int value)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msic_get_mute(int dev_id, u8 *value)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msic_get_vol(int dev_id, int *value)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
struct snd_pmic_ops snd_msic_ops = {
|
||
|
.set_input_dev = msic_set_selected_input_dev,
|
||
|
.set_output_dev = msic_set_selected_output_dev,
|
||
|
.set_mute = msic_set_mute,
|
||
|
.get_mute = msic_get_mute,
|
||
|
.set_vol = msic_set_vol,
|
||
|
.get_vol = msic_get_vol,
|
||
|
.init_card = msic_init_card,
|
||
|
.set_pcm_audio_params = msic_set_pcm_audio_params,
|
||
|
.set_pcm_voice_params = msic_set_pcm_voice_params,
|
||
|
.set_voice_port = msic_set_voice_port,
|
||
|
.set_audio_port = msic_set_audio_port,
|
||
|
.power_up_pmic_pb = msic_power_up_pb,
|
||
|
.power_up_pmic_cp = msic_power_up_cp,
|
||
|
.power_down_pmic_pb = msic_power_down_pb,
|
||
|
.power_down_pmic_cp = msic_power_down_cp,
|
||
|
.power_down_pmic = msic_power_down,
|
||
|
};
|