summaryrefslogtreecommitdiff
path: root/drivers/staging/intel_sst/intelmid_msic_control.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/intel_sst/intelmid_msic_control.c')
-rw-r--r--drivers/staging/intel_sst/intelmid_msic_control.c833
1 files changed, 734 insertions, 99 deletions
diff --git a/drivers/staging/intel_sst/intelmid_msic_control.c b/drivers/staging/intel_sst/intelmid_msic_control.c
index da093ed0cd88..70cdb1697815 100644
--- a/drivers/staging/intel_sst/intelmid_msic_control.c
+++ b/drivers/staging/intel_sst/intelmid_msic_control.c
@@ -28,9 +28,15 @@
#include <linux/pci.h>
#include <linux/file.h>
+#include <linux/delay.h>
+#include <sound/control.h>
#include "intel_sst.h"
-#include "intel_sst_ioctl.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)
{
@@ -54,116 +60,359 @@ static int msic_init_card(void)
/*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},
+ {0x259, 0x08, 0},
+ {0x25A, 0x08, 0},
+ {0x25B, 0x08, 0},
+ {0x25C, 0x08, 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},
+ {0x249, 0x01, 0x0},
+ {0x24A, 0x01, 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);
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 28);
snd_msic_ops.pb_on = 0;
+ snd_msic_ops.pbhs_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;
+ snd_msic_ops.jack_interrupt_status = false;
pr_debug("msic init complete!!\n");
return 0;
}
+static int msic_line_out_restore(u8 value)
+{
+ struct sc_reg_access hs_drv_en[] = {
+ {0x25d, 0x03, 0x03},
+ };
+ struct sc_reg_access ep_drv_en[] = {
+ {0x25d, 0x40, 0x40},
+ };
+ struct sc_reg_access ihf_drv_en[] = {
+ {0x25d, 0x0c, 0x0c},
+ };
+ struct sc_reg_access vib1_drv_en[] = {
+ {0x25d, 0x10, 0x10},
+ };
+ struct sc_reg_access vib2_drv_en[] = {
+ {0x25d, 0x20, 0x20},
+ };
+ struct sc_reg_access pmode_enable[] = {
+ {0x381, 0x10, 0x10},
+ };
+ int retval = 0;
+
+ pr_debug("msic_lineout_restore_lineout_dev:%d\n", value);
+
+ switch (value) {
+ case HEADSET:
+ pr_debug("Selecting Lineout-HEADSET-restore\n");
+ if (snd_msic_ops.output_dev_id == STEREO_HEADPHONE)
+ retval = sst_sc_reg_access(hs_drv_en,
+ PMIC_READ_MODIFY, 1);
+ else
+ retval = sst_sc_reg_access(ep_drv_en,
+ PMIC_READ_MODIFY, 1);
+ break;
+ case IHF:
+ pr_debug("Selecting Lineout-IHF-restore\n");
+ retval = sst_sc_reg_access(ihf_drv_en, PMIC_READ_MODIFY, 1);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_enable, PMIC_READ_MODIFY, 1);
+ break;
+ case VIBRA1:
+ pr_debug("Selecting Lineout-Vibra1-restore\n");
+ retval = sst_sc_reg_access(vib1_drv_en, PMIC_READ_MODIFY, 1);
+ break;
+ case VIBRA2:
+ pr_debug("Selecting Lineout-VIBRA2-restore\n");
+ retval = sst_sc_reg_access(vib2_drv_en, PMIC_READ_MODIFY, 1);
+ break;
+ case NONE:
+ pr_debug("Selecting Lineout-NONE-restore\n");
+ break;
+ default:
+ return -EINVAL;
+ }
+ return retval;
+}
+static int msic_get_lineout_prvstate(void)
+{
+ struct sc_reg_access hs_ihf_drv[2] = {
+ {0x257, 0x0, 0x0},
+ {0x25d, 0x0, 0x0},
+ };
+ struct sc_reg_access vib1drv[2] = {
+ {0x264, 0x0, 0x0},
+ {0x25D, 0x0, 0x0},
+ };
+ struct sc_reg_access vib2drv[2] = {
+ {0x26A, 0x0, 0x0},
+ {0x25D, 0x0, 0x0},
+ };
+ int retval = 0, drv_en, dac_en, dev_id, mask;
+ for (dev_id = 0; dev_id < snd_msic_ops.line_out_names_cnt; dev_id++) {
+ switch (dev_id) {
+ case HEADSET:
+ pr_debug("msic_get_lineout_prvs_state: HEADSET\n");
+ sst_sc_reg_access(hs_ihf_drv, PMIC_READ, 2);
+
+ mask = (MASK0|MASK1);
+ dac_en = (hs_ihf_drv[0].value) & mask;
+
+ mask = ((MASK0|MASK1)|MASK6);
+ drv_en = (hs_ihf_drv[1].value) & mask;
+
+ if (dac_en && (!drv_en)) {
+ snd_msic_ops.prev_lineout_dev_id = HEADSET;
+ return retval;
+ }
+ break;
+ case IHF:
+ pr_debug("msic_get_lineout_prvstate: IHF\n");
+ sst_sc_reg_access(hs_ihf_drv, PMIC_READ, 2);
+
+ mask = (MASK2 | MASK3);
+ dac_en = (hs_ihf_drv[0].value) & mask;
+
+ mask = (MASK2 | MASK3);
+ drv_en = (hs_ihf_drv[1].value) & mask;
+
+ if (dac_en && (!drv_en)) {
+ snd_msic_ops.prev_lineout_dev_id = IHF;
+ return retval;
+ }
+ break;
+ case VIBRA1:
+ pr_debug("msic_get_lineout_prvstate: vibra1\n");
+ sst_sc_reg_access(vib1drv, PMIC_READ, 2);
+
+ mask = MASK1;
+ dac_en = (vib1drv[0].value) & mask;
+
+ mask = MASK4;
+ drv_en = (vib1drv[1].value) & mask;
+
+ if (dac_en && (!drv_en)) {
+ snd_msic_ops.prev_lineout_dev_id = VIBRA1;
+ return retval;
+ }
+ break;
+ case VIBRA2:
+ pr_debug("msic_get_lineout_prvstate: vibra2\n");
+ sst_sc_reg_access(vib2drv, PMIC_READ, 2);
+
+ mask = MASK1;
+ dac_en = (vib2drv[0].value) & mask;
+
+ mask = MASK5;
+ drv_en = ((vib2drv[1].value) & mask);
+
+ if (dac_en && (!drv_en)) {
+ snd_msic_ops.prev_lineout_dev_id = VIBRA2;
+ return retval;
+ }
+ break;
+ case NONE:
+ pr_debug("msic_get_lineout_prvstate: NONE\n");
+ snd_msic_ops.prev_lineout_dev_id = NONE;
+ return retval;
+ default:
+ pr_debug("Invalid device id\n");
+ snd_msic_ops.prev_lineout_dev_id = NONE;
+ return -EINVAL;
+ }
+ }
+ return retval;
+}
+static int msic_set_selected_lineout_dev(u8 value)
+{
+ struct sc_reg_access lout_hs[] = {
+ {0x25e, 0x33, 0xFF},
+ {0x25d, 0x0, 0x43},
+ };
+ struct sc_reg_access lout_ihf[] = {
+ {0x25e, 0x55, 0xff},
+ {0x25d, 0x0, 0x0c},
+ };
+ struct sc_reg_access lout_vibra1[] = {
+
+ {0x25e, 0x61, 0xff},
+ {0x25d, 0x0, 0x10},
+ };
+ struct sc_reg_access lout_vibra2[] = {
+
+ {0x25e, 0x16, 0xff},
+ {0x25d, 0x0, 0x20},
+ };
+ struct sc_reg_access lout_def[] = {
+ {0x25e, 0x66, 0x0},
+ };
+ struct sc_reg_access pmode_disable[] = {
+ {0x381, 0x00, 0x10},
+ };
+ struct sc_reg_access pmode_enable[] = {
+ {0x381, 0x10, 0x10},
+ };
+ int retval = 0;
+
+ pr_debug("msic_set_selected_lineout_dev:%d\n", value);
+ msic_get_lineout_prvstate();
+ msic_line_out_restore(snd_msic_ops.prev_lineout_dev_id);
+ snd_msic_ops.lineout_dev_id = value;
+
+ switch (value) {
+ case HEADSET:
+ pr_debug("Selecting Lineout-HEADSET\n");
+ if (snd_msic_ops.pb_on)
+ retval = sst_sc_reg_access(lout_hs,
+ PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_disable,
+ PMIC_READ_MODIFY, 1);
+ break;
+ case IHF:
+ pr_debug("Selecting Lineout-IHF\n");
+ if (snd_msic_ops.pb_on)
+ retval = sst_sc_reg_access(lout_ihf,
+ PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_enable,
+ PMIC_READ_MODIFY, 1);
+ break;
+ case VIBRA1:
+ pr_debug("Selecting Lineout-Vibra1\n");
+ if (snd_msic_ops.pb_on)
+ retval = sst_sc_reg_access(lout_vibra1,
+ PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_disable,
+ PMIC_READ_MODIFY, 1);
+ break;
+ case VIBRA2:
+ pr_debug("Selecting Lineout-VIBRA2\n");
+ if (snd_msic_ops.pb_on)
+ retval = sst_sc_reg_access(lout_vibra2,
+ PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_disable,
+ PMIC_READ_MODIFY, 1);
+ break;
+ case NONE:
+ pr_debug("Selecting Lineout-NONE\n");
+ retval = sst_sc_reg_access(lout_def,
+ PMIC_WRITE, 1);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_disable,
+ PMIC_READ_MODIFY, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return retval;
+}
+
static int msic_power_up_pb(unsigned int device)
{
- struct sc_reg_access sc_access1[] = {
+ struct sc_reg_access vaud[] = {
/* turn on the audio power supplies */
- {0x0DB, 0x05, 0},
+ {0x0DB, 0x07, 0},
+ };
+ struct sc_reg_access pll[] = {
+ /* turn on PLL */
+ {0x240, 0x20, 0},
+ };
+ struct sc_reg_access vhs[] = {
/* VHSP */
- {0x0DC, 0xFF, 0},
+ {0x0DC, 0x3D, 0},
/* VHSN */
{0x0DD, 0x3F, 0},
- /* turn on PLL */
- {0x240, 0x21, 0},
};
- struct sc_reg_access sc_access2[] = {
+ struct sc_reg_access hsdac[] = {
+ {0x382, 0x40, 0x40},
/* disable driver */
{0x25D, 0x0, 0x43},
/* DAC CONFIG ; both HP, LP on */
{0x257, 0x03, 0x03},
};
- struct sc_reg_access sc_access3[] = {
+ struct sc_reg_access hs_filter[] = {
/* HSEPRXCTRL Enable the headset left and right FIR filters */
{0x250, 0x30, 0},
/* HSMIXER */
{0x256, 0x11, 0},
};
- struct sc_reg_access sc_access4[] = {
+ struct sc_reg_access hs_enable[] = {
/* enable driver */
{0x25D, 0x3, 0x3},
+ {0x26C, 0x0, 0x2},
/* unmute the headset */
{ 0x259, 0x80, 0x80},
{ 0x25A, 0x80, 0x80},
};
- struct sc_reg_access sc_access_vihf[] = {
+ struct sc_reg_access vihf[] = {
/* VIHF ON */
- {0x0C9, 0x2D, 0x00},
+ {0x0C9, 0x27, 0x00},
};
- struct sc_reg_access sc_access22[] = {
+ struct sc_reg_access ihf_filter[] = {
/* disable driver */
{0x25D, 0x00, 0x0C},
/*Filer DAC enable*/
{0x251, 0x03, 0x03},
{0x257, 0x0C, 0x0C},
};
- struct sc_reg_access sc_access32[] = {
+ struct sc_reg_access ihf_en[] = {
/*enable drv*/
{0x25D, 0x0C, 0x0c},
};
- struct sc_reg_access sc_access42[] = {
+ struct sc_reg_access ihf_unmute[] = {
/*unmute headset*/
{0x25B, 0x80, 0x80},
{0x25C, 0x80, 0x80},
};
- struct sc_reg_access sc_access23[] = {
+ struct sc_reg_access epdac[] = {
/* disable driver */
{0x25D, 0x0, 0x43},
/* DAC CONFIG ; both HP, LP on */
{0x257, 0x03, 0x03},
};
- struct sc_reg_access sc_access43[] = {
+ struct sc_reg_access ep_enable[] = {
/* enable driver */
{0x25D, 0x40, 0x40},
/* unmute the headset */
{ 0x259, 0x80, 0x80},
{ 0x25A, 0x80, 0x80},
};
- struct sc_reg_access sc_access_vib[] = {
+ struct sc_reg_access vib1_en[] = {
/* enable driver, ADC */
{0x25D, 0x10, 0x10},
- {0x264, 0x02, 0x02},
+ {0x264, 0x02, 0x82},
};
- struct sc_reg_access sc_access_hap[] = {
+ struct sc_reg_access vib2_en[] = {
/* enable driver, ADC */
{0x25D, 0x20, 0x20},
- {0x26A, 0x02, 0x02},
+ {0x26A, 0x02, 0x82},
};
- struct sc_reg_access sc_access_pcm2[] = {
+ struct sc_reg_access pcm2_en[] = {
/* enable pcm 2 */
{0x27C, 0x1, 0x1},
};
@@ -176,89 +425,95 @@ static int msic_power_up_pb(unsigned int device)
}
pr_debug("powering up pb.... Device %d\n", device);
- sst_sc_reg_access(sc_access1, PMIC_WRITE, 4);
+ sst_sc_reg_access(vaud, PMIC_WRITE, 1);
+ msleep(1);
+ sst_sc_reg_access(pll, PMIC_WRITE, 1);
+ msleep(1);
switch (device) {
case SND_SST_DEVICE_HEADSET:
+ snd_msic_ops.pb_on = 1;
+ snd_msic_ops.pbhs_on = 1;
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);
+ sst_sc_reg_access(vhs, PMIC_WRITE, 2);
+ sst_sc_reg_access(hsdac, PMIC_READ_MODIFY, 3);
+ sst_sc_reg_access(hs_filter, PMIC_WRITE, 2);
+ sst_sc_reg_access(hs_enable, PMIC_READ_MODIFY, 4);
} 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);
+ sst_sc_reg_access(epdac, PMIC_READ_MODIFY, 2);
+ sst_sc_reg_access(hs_filter, PMIC_WRITE, 2);
+ sst_sc_reg_access(ep_enable, PMIC_READ_MODIFY, 3);
}
- snd_msic_ops.pb_on = 1;
+ if (snd_msic_ops.lineout_dev_id == HEADSET)
+ msic_set_selected_lineout_dev(HEADSET);
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);
+ snd_msic_ops.pb_on = 1;
+ sst_sc_reg_access(vihf, PMIC_WRITE, 1);
+ sst_sc_reg_access(ihf_filter, PMIC_READ_MODIFY, 3);
+ sst_sc_reg_access(ihf_en, PMIC_READ_MODIFY, 1);
+ sst_sc_reg_access(ihf_unmute, PMIC_READ_MODIFY, 2);
+ if (snd_msic_ops.lineout_dev_id == IHF)
+ msic_set_selected_lineout_dev(IHF);
break;
case SND_SST_DEVICE_VIBRA:
- sst_sc_reg_access(sc_access_vib, PMIC_READ_MODIFY, 2);
+ snd_msic_ops.pb_on = 1;
+ sst_sc_reg_access(vib1_en, PMIC_READ_MODIFY, 2);
+ if (snd_msic_ops.lineout_dev_id == VIBRA1)
+ msic_set_selected_lineout_dev(VIBRA1);
break;
case SND_SST_DEVICE_HAPTIC:
- sst_sc_reg_access(sc_access_hap, PMIC_READ_MODIFY, 2);
+ snd_msic_ops.pb_on = 1;
+ sst_sc_reg_access(vib2_en, PMIC_READ_MODIFY, 2);
+ if (snd_msic_ops.lineout_dev_id == VIBRA2)
+ msic_set_selected_lineout_dev(VIBRA2);
break;
default:
pr_warn("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);
+ return sst_sc_reg_access(pcm2_en, PMIC_READ_MODIFY, 1);
}
static int msic_power_up_cp(unsigned int device)
{
- struct sc_reg_access sc_access[] = {
+ struct sc_reg_access vaud[] = {
/* turn on the audio power supplies */
- {0x0DB, 0x05, 0},
- /* VHSP */
- {0x0DC, 0xFF, 0},
- /* VHSN */
- {0x0DD, 0x3F, 0},
+ {0x0DB, 0x07, 0},
+ };
+ struct sc_reg_access pll[] = {
/* turn on PLL */
- {0x240, 0x21, 0},
-
- /* Turn on DMIC supply */
- {0x247, 0xA0, 0x0},
- {0x240, 0x21, 0x0},
- {0x24C, 0x10, 0x0},
-
+ {0x240, 0x20, 0},
+ };
+ struct sc_reg_access dmic_bias[] = {
+ /* Turn on AMIC supply */
+ {0x247, 0xA0, 0xA0},
+ };
+ struct sc_reg_access dmic[] = {
/* mic demux enable */
- {0x245, 0x3F, 0x0},
- {0x246, 0x7, 0x0},
+ {0x245, 0x3F, 0x3F},
+ {0x246, 0x07, 0x07},
};
- 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},
+ struct sc_reg_access amic_bias[] = {
/* Turn on AMIC supply */
- {0x247, 0xFC, 0x0},
+ {0x247, 0xFC, 0xFC},
+ };
+ struct sc_reg_access amic[] = {
+ /*MIC EN*/
+ {0x249, 0x01, 0x01},
+ {0x24A, 0x01, 0x01},
+ /*ADC EN*/
+ {0x248, 0x05, 0x0F},
};
- struct sc_reg_access sc_access2[] = {
+ struct sc_reg_access pcm2[] = {
/* enable pcm 2 */
{0x27C, 0x1, 0x1},
};
- struct sc_reg_access sc_access3[] = {
+ struct sc_reg_access tx_on[] = {
/*wait for mic to stabalize before turning on audio channels*/
{0x24F, 0x3C, 0x0},
};
@@ -271,42 +526,161 @@ static int msic_power_up_cp(unsigned int device)
}
pr_debug("powering up cp....%d\n", snd_msic_ops.input_dev_id);
- sst_sc_reg_access(sc_access2, PMIC_READ_MODIFY, 1);
+ sst_sc_reg_access(vaud, PMIC_WRITE, 1);
+ msleep(500);/*FIXME need optimzed value here*/
+ sst_sc_reg_access(pll, PMIC_WRITE, 1);
+ msleep(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);
-
+ if (snd_msic_ops.input_dev_id == AMIC) {
+ sst_sc_reg_access(amic_bias, PMIC_READ_MODIFY, 1);
+ msleep(1);
+ sst_sc_reg_access(amic, PMIC_READ_MODIFY, 3);
+ } else {
+ sst_sc_reg_access(dmic_bias, PMIC_READ_MODIFY, 1);
+ msleep(1);
+ sst_sc_reg_access(dmic, PMIC_READ_MODIFY, 2);
+ }
+ msleep(1);
+ sst_sc_reg_access(tx_on, PMIC_WRITE, 1);
+ return sst_sc_reg_access(pcm2, PMIC_READ_MODIFY, 1);
}
static int msic_power_down(void)
{
- int retval = 0;
+ struct sc_reg_access power_dn[] = {
+ /* VHSP */
+ {0x0DC, 0xC4, 0},
+ /* VHSN */
+ {0x0DD, 0x04, 0},
+ /* VIHF */
+ {0x0C9, 0x24, 0},
+ };
+ struct sc_reg_access pll[] = {
+ /* turn off PLL*/
+ {0x240, 0x00, 0x0},
+ };
+ struct sc_reg_access vaud[] = {
+ /* turn off VAUD*/
+ {0x0DB, 0x04, 0},
+ };
pr_debug("powering dn msic\n");
+ snd_msic_ops.pbhs_on = 0;
snd_msic_ops.pb_on = 0;
snd_msic_ops.cap_on = 0;
- return retval;
+ sst_sc_reg_access(power_dn, PMIC_WRITE, 3);
+ msleep(1);
+ sst_sc_reg_access(pll, PMIC_WRITE, 1);
+ msleep(1);
+ sst_sc_reg_access(vaud, PMIC_WRITE, 1);
+ return 0;
}
-static int msic_power_down_pb(void)
+static int msic_power_down_pb(unsigned int device)
{
- int retval = 0;
+ struct sc_reg_access drv_enable[] = {
+ {0x25D, 0x00, 0x00},
+ };
+ struct sc_reg_access hs_mute[] = {
+ {0x259, 0x80, 0x80},
+ {0x25A, 0x80, 0x80},
+ {0x26C, 0x02, 0x02},
+ };
+ struct sc_reg_access hs_off[] = {
+ {0x257, 0x00, 0x03},
+ {0x250, 0x00, 0x30},
+ {0x382, 0x00, 0x40},
+ };
+ struct sc_reg_access ihf_mute[] = {
+ {0x25B, 0x80, 0x80},
+ {0x25C, 0x80, 0x80},
+ };
+ struct sc_reg_access ihf_off[] = {
+ {0x257, 0x00, 0x0C},
+ {0x251, 0x00, 0x03},
+ };
+ struct sc_reg_access vib1_off[] = {
+ {0x264, 0x00, 0x82},
+ };
+ struct sc_reg_access vib2_off[] = {
+ {0x26A, 0x00, 0x82},
+ };
+ struct sc_reg_access lout_off[] = {
+ {0x25e, 0x66, 0x00},
+ };
+ struct sc_reg_access pmode_disable[] = {
+ {0x381, 0x00, 0x10},
+ };
- pr_debug("powering dn pb....\n");
- snd_msic_ops.pb_on = 0;
- return retval;
+
+
+ pr_debug("powering dn pb for device %d\n", device);
+ switch (device) {
+ case SND_SST_DEVICE_HEADSET:
+ snd_msic_ops.pbhs_on = 0;
+ sst_sc_reg_access(hs_mute, PMIC_READ_MODIFY, 3);
+ drv_enable[0].mask = 0x43;
+ sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1);
+ sst_sc_reg_access(hs_off, PMIC_READ_MODIFY, 3);
+ if (snd_msic_ops.lineout_dev_id == HEADSET)
+ sst_sc_reg_access(lout_off, PMIC_WRITE, 1);
+ break;
+
+ case SND_SST_DEVICE_IHF:
+ sst_sc_reg_access(ihf_mute, PMIC_READ_MODIFY, 2);
+ drv_enable[0].mask = 0x0C;
+ sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1);
+ sst_sc_reg_access(ihf_off, PMIC_READ_MODIFY, 2);
+ if (snd_msic_ops.lineout_dev_id == IHF) {
+ sst_sc_reg_access(lout_off, PMIC_WRITE, 1);
+ sst_sc_reg_access(pmode_disable, PMIC_READ_MODIFY, 1);
+ }
+ break;
+
+ case SND_SST_DEVICE_VIBRA:
+ sst_sc_reg_access(vib1_off, PMIC_READ_MODIFY, 1);
+ drv_enable[0].mask = 0x10;
+ sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1);
+ if (snd_msic_ops.lineout_dev_id == VIBRA1)
+ sst_sc_reg_access(lout_off, PMIC_WRITE, 1);
+ break;
+
+ case SND_SST_DEVICE_HAPTIC:
+ sst_sc_reg_access(vib2_off, PMIC_READ_MODIFY, 1);
+ drv_enable[0].mask = 0x20;
+ sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1);
+ if (snd_msic_ops.lineout_dev_id == VIBRA2)
+ sst_sc_reg_access(lout_off, PMIC_WRITE, 1);
+ break;
+ }
+ return 0;
}
-static int msic_power_down_cp(void)
+static int msic_power_down_cp(unsigned int device)
{
- int retval = 0;
+ struct sc_reg_access dmic[] = {
+ {0x247, 0x00, 0xA0},
+ {0x245, 0x00, 0x38},
+ {0x246, 0x00, 0x07},
+ };
+ struct sc_reg_access amic[] = {
+ {0x248, 0x00, 0x05},
+ {0x249, 0x00, 0x01},
+ {0x24A, 0x00, 0x01},
+ {0x247, 0x00, 0xA3},
+ };
+ struct sc_reg_access tx_off[] = {
+ {0x24F, 0x00, 0x3C},
+ };
pr_debug("powering dn cp....\n");
snd_msic_ops.cap_on = 0;
- return retval;
+ sst_sc_reg_access(tx_off, PMIC_READ_MODIFY, 1);
+ if (snd_msic_ops.input_dev_id == DMIC)
+ sst_sc_reg_access(dmic, PMIC_READ_MODIFY, 3);
+ else
+ sst_sc_reg_access(amic, PMIC_READ_MODIFY, 4);
+ return 0;
}
static int msic_set_selected_output_dev(u8 value)
@@ -315,7 +689,7 @@ static int msic_set_selected_output_dev(u8 value)
pr_debug("msic set selected output:%d\n", value);
snd_msic_ops.output_dev_id = value;
- if (snd_msic_ops.pb_on)
+ if (snd_msic_ops.pbhs_on)
msic_power_up_pb(SND_SST_DEVICE_HEADSET);
return retval;
}
@@ -352,6 +726,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;
@@ -392,9 +817,215 @@ static int msic_get_vol(int dev_id, int *value)
return 0;
}
+static int msic_set_headset_state(int state)
+{
+ struct sc_reg_access hs_enable[] = {
+ {0x25D, 0x03, 0x03},
+ };
+
+ if (state)
+ /*enable*/
+ sst_sc_reg_access(hs_enable, PMIC_READ_MODIFY, 1);
+ else {
+ hs_enable[0].value = 0;
+ sst_sc_reg_access(hs_enable, PMIC_READ_MODIFY, 1);
+ }
+ return 0;
+}
+
+static int msic_enable_mic_bias(void)
+{
+ struct sc_reg_access jack_interrupt_reg[] = {
+ {0x0DB, 0x07, 0x00},
+
+ };
+ struct sc_reg_access jack_bias_reg[] = {
+ {0x247, 0x0C, 0x0C},
+ };
+
+ sst_sc_reg_access(jack_interrupt_reg, PMIC_WRITE, 1);
+ sst_sc_reg_access(jack_bias_reg, PMIC_READ_MODIFY, 1);
+ return 0;
+}
+
+static int msic_disable_mic_bias(void)
+{
+ if (snd_msic_ops.jack_interrupt_status == true)
+ return 0;
+ if (!(snd_msic_ops.pb_on || snd_msic_ops.cap_on))
+ msic_power_down();
+ return 0;
+}
+
+static int msic_disable_jack_btn(void)
+{
+ struct sc_reg_access btn_disable[] = {
+ {0x26C, 0x00, 0x01}
+ };
+
+ if (!(snd_msic_ops.pb_on || snd_msic_ops.cap_on))
+ msic_power_down();
+ snd_msic_ops.jack_interrupt_status = false;
+ return sst_sc_reg_access(btn_disable, PMIC_READ_MODIFY, 1);
+}
+
+static int msic_enable_jack_btn(void)
+{
+ struct sc_reg_access btn_enable[] = {
+ {0x26b, 0x77, 0x00},
+ {0x26C, 0x01, 0x00},
+ };
+ return sst_sc_reg_access(btn_enable, PMIC_WRITE, 2);
+}
+static int msic_convert_adc_to_mvolt(unsigned int mic_bias)
+{
+ return (ADC_ONE_LSB_MULTIPLIER * mic_bias) / 1000;
+}
+int msic_get_headset_state(int mic_bias)
+{
+ struct sc_reg_access msic_hs_toggle[] = {
+ {0x070, 0x00, 0x01},
+ };
+ if (mic_bias >= 0 && mic_bias < 400) {
+
+ pr_debug("Detected Headphone!!!\n");
+ sst_sc_reg_access(msic_hs_toggle, PMIC_READ_MODIFY, 1);
+
+ } else if (mic_bias > 400 && mic_bias < 650) {
+
+ pr_debug("Detected American headset\n");
+ msic_hs_toggle[0].value = 0x01;
+ sst_sc_reg_access(msic_hs_toggle, PMIC_READ_MODIFY, 1);
+
+ } else if (mic_bias >= 650 && mic_bias < 2000) {
+
+ pr_debug("Detected Headset!!!\n");
+ sst_sc_reg_access(msic_hs_toggle, PMIC_READ_MODIFY, 1);
+ /*power on jack and btn*/
+ snd_msic_ops.jack_interrupt_status = true;
+ msic_enable_jack_btn();
+ msic_enable_mic_bias();
+ return SND_JACK_HEADSET;
+
+ } else
+ pr_debug("Detected Open Cable!!!\n");
+
+ return SND_JACK_HEADPHONE;
+}
+
+static int msic_get_mic_bias(void *arg)
+{
+ struct snd_intelmad *intelmad_drv = (struct snd_intelmad *)arg;
+ u16 adc_adr = intelmad_drv->adc_address;
+ u16 adc_val;
+ int ret;
+ struct sc_reg_access adc_ctrl3[2] = {
+ {0x1C2, 0x05, 0x0},
+ };
+
+ struct sc_reg_access audio_adc_reg1 = {0,};
+ struct sc_reg_access audio_adc_reg2 = {0,};
+
+ msic_enable_mic_bias();
+ /* Enable the msic for conversion before reading */
+ ret = sst_sc_reg_access(adc_ctrl3, PMIC_WRITE, 1);
+ if (ret)
+ return ret;
+ adc_ctrl3[0].value = 0x04;
+ /* Re-toggle the RRDATARD bit */
+ ret = sst_sc_reg_access(adc_ctrl3, PMIC_WRITE, 1);
+ if (ret)
+ return ret;
+
+ audio_adc_reg1.reg_addr = adc_adr;
+ /* Read the higher bits of data */
+ msleep(1000);
+ ret = sst_sc_reg_access(&audio_adc_reg1, PMIC_READ, 1);
+ if (ret)
+ return ret;
+ pr_debug("adc read value %x", audio_adc_reg1.value);
+
+ /* Shift bits to accomodate the lower two data bits */
+ adc_val = (audio_adc_reg1.value << 2);
+ adc_adr++;
+ audio_adc_reg2. reg_addr = adc_adr;
+ ret = sst_sc_reg_access(&audio_adc_reg2, PMIC_READ, 1);
+ if (ret)
+ return ret;
+ pr_debug("adc read value %x", audio_adc_reg2.value);
+
+ /* Adding lower two bits to the higher bits */
+ audio_adc_reg2.value &= 03;
+ adc_val += audio_adc_reg2.value;
+
+ pr_debug("ADC value 0x%x", adc_val);
+ msic_disable_mic_bias();
+ return adc_val;
+}
+
+static void msic_pmic_irq_cb(void *cb_data, u8 intsts)
+{
+ struct mad_jack *mjack = NULL;
+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
+ struct snd_intelmad *intelmaddata = cb_data;
+ int retval = 0;
+
+ pr_debug("value returned = 0x%x\n", intsts);
+
+ if (snd_msic_ops.card_status == SND_CARD_UN_INIT) {
+ retval = msic_init_card();
+ if (retval)
+ return;
+ }
+
+ mjack = &intelmaddata->jack[0];
+ if (intsts & 0x1) {
+ pr_debug("MAD short_push detected\n");
+ present = SND_JACK_BTN_0;
+ jack_event_flag = buttonpressflag = 1;
+ mjack->jack.type = SND_JACK_BTN_0;
+ mjack->jack.key[0] = BTN_0 ;
+ }
+
+ if (intsts & 0x2) {
+ pr_debug(":MAD long_push detected\n");
+ jack_event_flag = buttonpressflag = 1;
+ mjack->jack.type = present = SND_JACK_BTN_1;
+ mjack->jack.key[1] = BTN_1;
+ }
+
+ if (intsts & 0x4) {
+ unsigned int mic_bias;
+ jack_event_flag = 1;
+ buttonpressflag = 0;
+ mic_bias = msic_get_mic_bias(intelmaddata);
+ pr_debug("mic_bias = %d\n", mic_bias);
+ mic_bias = msic_convert_adc_to_mvolt(mic_bias);
+ pr_debug("mic_bias after conversion = %d mV\n", mic_bias);
+ mjack->jack_dev_state = msic_get_headset_state(mic_bias);
+ mjack->jack.type = present = mjack->jack_dev_state;
+ }
+
+ if (intsts & 0x8) {
+ mjack->jack.type = mjack->jack_dev_state;
+ present = 0;
+ jack_event_flag = 1;
+ buttonpressflag = 0;
+ msic_disable_jack_btn();
+ msic_disable_mic_bias();
+ }
+ if (jack_event_flag)
+ sst_mad_send_jack_report(&mjack->jack,
+ buttonpressflag, present);
+}
+
+
+
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,
@@ -408,5 +1039,9 @@ struct snd_pmic_ops snd_msic_ops = {
.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,
+ .power_down_pmic = msic_power_down,
+ .pmic_irq_cb = msic_pmic_irq_cb,
+ .pmic_jack_enable = msic_enable_mic_bias,
+ .pmic_get_mic_bias = msic_get_mic_bias,
+ .pmic_set_headset_state = msic_set_headset_state,
};