]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/intel_sst/intelmid_msic_control.c
Merge tag 'v2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / staging / intel_sst / intelmid_msic_control.c
diff --git a/drivers/staging/intel_sst/intelmid_msic_control.c b/drivers/staging/intel_sst/intelmid_msic_control.c
new file mode 100644 (file)
index 0000000..4d1755e
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ *  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,
+};