| /* |
| * intelmid_v2_control.c - Intel Sound card driver for MID |
| * |
| * Copyright (C) 2008-10 Intel Corp |
| * Authors: Vinod Koul <vinod.koul@intel.com> |
| * Harsha Priya <priya.harsha@intel.com> |
| * KP Jeeja <jeeja.kp@intel.com> |
| * Dharageswari R <dharageswari.r@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 vendor 3 |
| */ |
| |
| #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| |
| #include <linux/gpio.h> |
| #include <linux/pci.h> |
| #include <linux/delay.h> |
| #include <linux/file.h> |
| #include <sound/control.h> |
| #include "intel_sst.h" |
| #include "intelmid_snd_control.h" |
| #include "intelmid.h" |
| |
| enum reg_v3 { |
| VAUDIOCNT = 0x51, |
| VOICEPORT1 = 0x100, |
| VOICEPORT2 = 0x101, |
| AUDIOPORT1 = 0x102, |
| AUDIOPORT2 = 0x103, |
| ADCSAMPLERATE = 0x104, |
| DMICCTRL1 = 0x105, |
| DMICCTRL2 = 0x106, |
| MICCTRL = 0x107, |
| MICSELVOL = 0x108, |
| LILSEL = 0x109, |
| LIRSEL = 0x10a, |
| VOICEVOL = 0x10b, |
| AUDIOLVOL = 0x10c, |
| AUDIORVOL = 0x10d, |
| LMUTE = 0x10e, |
| RMUTE = 0x10f, |
| POWERCTRL1 = 0x110, |
| POWERCTRL2 = 0x111, |
| DRVPOWERCTRL = 0x112, |
| VREFPLL = 0x113, |
| PCMBUFCTRL = 0x114, |
| SOFTMUTE = 0x115, |
| DTMFPATH = 0x116, |
| DTMFVOL = 0x117, |
| DTMFFREQ = 0x118, |
| DTMFHFREQ = 0x119, |
| DTMFLFREQ = 0x11a, |
| DTMFCTRL = 0x11b, |
| DTMFASON = 0x11c, |
| DTMFASOFF = 0x11d, |
| DTMFASINUM = 0x11e, |
| CLASSDVOL = 0x11f, |
| VOICEDACAVOL = 0x120, |
| AUDDACAVOL = 0x121, |
| LOMUTEVOL = 0x122, |
| HPLVOL = 0x123, |
| HPRVOL = 0x124, |
| MONOVOL = 0x125, |
| LINEOUTMIXVOL = 0x126, |
| EPMIXVOL = 0x127, |
| LINEOUTLSEL = 0x128, |
| LINEOUTRSEL = 0x129, |
| EPMIXOUTSEL = 0x12a, |
| HPLMIXSEL = 0x12b, |
| HPRMIXSEL = 0x12c, |
| LOANTIPOP = 0x12d, |
| AUXDBNC = 0x12f, |
| }; |
| |
| static void nc_set_amp_power(int power) |
| { |
| if (snd_pmic_ops_nc.gpio_amp) |
| gpio_set_value(snd_pmic_ops_nc.gpio_amp, power); |
| } |
| |
| /**** |
| * nc_init_card - initialize the sound card |
| * |
| * This initializes the audio paths to know values in case of this sound card |
| */ |
| static int nc_init_card(void) |
| { |
| struct sc_reg_access sc_access[] = { |
| {VAUDIOCNT, 0x25, 0}, |
| {VOICEPORT1, 0x00, 0}, |
| {VOICEPORT2, 0x00, 0}, |
| {AUDIOPORT1, 0x98, 0}, |
| {AUDIOPORT2, 0x09, 0}, |
| {AUDIOLVOL, 0x00, 0}, |
| {AUDIORVOL, 0x00, 0}, |
| {LMUTE, 0x03, 0}, |
| {RMUTE, 0x03, 0}, |
| {POWERCTRL1, 0x00, 0}, |
| {POWERCTRL2, 0x00, 0}, |
| {DRVPOWERCTRL, 0x00, 0}, |
| {VREFPLL, 0x10, 0}, |
| {HPLMIXSEL, 0xee, 0}, |
| {HPRMIXSEL, 0xf6, 0}, |
| {PCMBUFCTRL, 0x0, 0}, |
| {VOICEVOL, 0x0e, 0}, |
| {HPLVOL, 0x06, 0}, |
| {HPRVOL, 0x06, 0}, |
| {MICCTRL, 0x51, 0x00}, |
| {ADCSAMPLERATE, 0x8B, 0x00}, |
| {MICSELVOL, 0x5B, 0x00}, |
| {LILSEL, 0x06, 0}, |
| {LIRSEL, 0x46, 0}, |
| {LOANTIPOP, 0x00, 0}, |
| {DMICCTRL1, 0x40, 0}, |
| {AUXDBNC, 0xff, 0}, |
| }; |
| snd_pmic_ops_nc.card_status = SND_CARD_INIT_DONE; |
| snd_pmic_ops_nc.master_mute = UNMUTE; |
| snd_pmic_ops_nc.mute_status = UNMUTE; |
| sst_sc_reg_access(sc_access, PMIC_WRITE, 27); |
| mutex_init(&snd_pmic_ops_nc.lock); |
| pr_debug("init complete!!\n"); |
| return 0; |
| } |
| |
| static int nc_enable_audiodac(int value) |
| { |
| struct sc_reg_access sc_access[3]; |
| int mute_val = 0; |
| |
| if (snd_pmic_ops_nc.mute_status == MUTE) |
| return 0; |
| |
| if (((snd_pmic_ops_nc.output_dev_id == MONO_EARPIECE) || |
| (snd_pmic_ops_nc.output_dev_id == INTERNAL_SPKR)) && |
| (value == UNMUTE)) |
| return 0; |
| if (value == UNMUTE) { |
| /* unmute the system, set the 7th bit to zero */ |
| mute_val = 0x00; |
| } else { |
| /* MUTE:Set the seventh bit */ |
| mute_val = 0x04; |
| |
| } |
| sc_access[0].reg_addr = LMUTE; |
| sc_access[1].reg_addr = RMUTE; |
| sc_access[0].mask = sc_access[1].mask = MASK2; |
| sc_access[0].value = sc_access[1].value = mute_val; |
| |
| if (snd_pmic_ops_nc.num_channel == 1) |
| sc_access[1].value = 0x04; |
| return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); |
| |
| } |
| |
| static int nc_power_up_pb(unsigned int port) |
| { |
| struct sc_reg_access sc_access[7]; |
| int retval = 0; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| if (port == 0xFF) |
| return 0; |
| mutex_lock(&snd_pmic_ops_nc.lock); |
| nc_enable_audiodac(MUTE); |
| msleep(30); |
| |
| pr_debug("powering up pb....\n"); |
| |
| sc_access[0].reg_addr = VAUDIOCNT; |
| sc_access[0].value = 0x27; |
| sc_access[0].mask = 0x27; |
| sc_access[1].reg_addr = VREFPLL; |
| if (port == 0) { |
| sc_access[1].value = 0x3A; |
| sc_access[1].mask = 0x3A; |
| } else if (port == 1) { |
| sc_access[1].value = 0x35; |
| sc_access[1].mask = 0x35; |
| } |
| retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); |
| |
| |
| |
| sc_access[0].reg_addr = POWERCTRL1; |
| if (port == 0) { |
| sc_access[0].value = 0x40; |
| sc_access[0].mask = 0x40; |
| } else if (port == 1) { |
| sc_access[0].value = 0x01; |
| sc_access[0].mask = 0x01; |
| } |
| sc_access[1].reg_addr = POWERCTRL2; |
| sc_access[1].value = 0x0C; |
| sc_access[1].mask = 0x0C; |
| |
| sc_access[2].reg_addr = DRVPOWERCTRL; |
| sc_access[2].value = 0x86; |
| sc_access[2].mask = 0x86; |
| |
| sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3); |
| |
| msleep(30); |
| |
| snd_pmic_ops_nc.pb_on = 1; |
| |
| /* |
| * There is a mismatch between Playback Sources and the enumerated |
| * values of output sources. This mismatch causes ALSA upper to send |
| * Item 1 for Internal Speaker, but the expected enumeration is 2! For |
| * now, treat MONO_EARPIECE and INTERNAL_SPKR identically and power up |
| * the needed resources |
| */ |
| if (snd_pmic_ops_nc.output_dev_id == MONO_EARPIECE || |
| snd_pmic_ops_nc.output_dev_id == INTERNAL_SPKR) |
| nc_set_amp_power(1); |
| nc_enable_audiodac(UNMUTE); |
| mutex_unlock(&snd_pmic_ops_nc.lock); |
| return 0; |
| } |
| |
| static int nc_power_up_cp(unsigned int port) |
| { |
| struct sc_reg_access sc_access[5]; |
| int retval = 0; |
| |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| |
| pr_debug("powering up cp....\n"); |
| |
| if (port == 0xFF) |
| return 0; |
| sc_access[0].reg_addr = VAUDIOCNT; |
| sc_access[0].value = 0x27; |
| sc_access[0].mask = 0x27; |
| sc_access[1].reg_addr = VREFPLL; |
| if (port == 0) { |
| sc_access[1].value = 0x3E; |
| sc_access[1].mask = 0x3E; |
| } else if (port == 1) { |
| sc_access[1].value = 0x35; |
| sc_access[1].mask = 0x35; |
| } |
| |
| retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); |
| |
| |
| sc_access[0].reg_addr = POWERCTRL1; |
| if (port == 0) { |
| sc_access[0].value = 0xB4; |
| sc_access[0].mask = 0xB4; |
| } else if (port == 1) { |
| sc_access[0].value = 0xBF; |
| sc_access[0].mask = 0xBF; |
| } |
| sc_access[1].reg_addr = POWERCTRL2; |
| if (port == 0) { |
| sc_access[1].value = 0x0C; |
| sc_access[1].mask = 0x0C; |
| } else if (port == 1) { |
| sc_access[1].value = 0x02; |
| sc_access[1].mask = 0x02; |
| } |
| |
| return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); |
| |
| } |
| |
| static int nc_power_down(void) |
| { |
| int retval = 0; |
| struct sc_reg_access sc_access[5]; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| nc_enable_audiodac(MUTE); |
| |
| |
| pr_debug("powering dn nc_power_down ....\n"); |
| |
| if (snd_pmic_ops_nc.output_dev_id == MONO_EARPIECE || |
| snd_pmic_ops_nc.output_dev_id == INTERNAL_SPKR) |
| nc_set_amp_power(0); |
| |
| msleep(30); |
| |
| sc_access[0].reg_addr = DRVPOWERCTRL; |
| sc_access[0].value = 0x00; |
| sc_access[0].mask = 0x00; |
| |
| sst_sc_reg_access(sc_access, PMIC_WRITE, 1); |
| |
| sc_access[0].reg_addr = POWERCTRL1; |
| sc_access[0].value = 0x00; |
| sc_access[0].mask = 0x00; |
| |
| sc_access[1].reg_addr = POWERCTRL2; |
| sc_access[1].value = 0x00; |
| sc_access[1].mask = 0x00; |
| |
| |
| |
| sst_sc_reg_access(sc_access, PMIC_WRITE, 2); |
| |
| msleep(30); |
| sc_access[0].reg_addr = VREFPLL; |
| sc_access[0].value = 0x10; |
| sc_access[0].mask = 0x10; |
| |
| sc_access[1].reg_addr = VAUDIOCNT; |
| sc_access[1].value = 0x25; |
| sc_access[1].mask = 0x25; |
| |
| |
| retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 2); |
| |
| msleep(30); |
| return nc_enable_audiodac(UNMUTE); |
| } |
| |
| static int nc_power_down_pb(unsigned int device) |
| { |
| |
| int retval = 0; |
| struct sc_reg_access sc_access[5]; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| pr_debug("powering dn pb....\n"); |
| mutex_lock(&snd_pmic_ops_nc.lock); |
| nc_enable_audiodac(MUTE); |
| |
| |
| msleep(30); |
| |
| |
| sc_access[0].reg_addr = DRVPOWERCTRL; |
| sc_access[0].value = 0x00; |
| sc_access[0].mask = 0x00; |
| |
| sst_sc_reg_access(sc_access, PMIC_WRITE, 1); |
| |
| msleep(30); |
| |
| sc_access[0].reg_addr = POWERCTRL1; |
| sc_access[0].value = 0x00; |
| sc_access[0].mask = 0x41; |
| |
| sc_access[1].reg_addr = POWERCTRL2; |
| sc_access[1].value = 0x00; |
| sc_access[1].mask = 0x0C; |
| |
| sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); |
| |
| msleep(30); |
| |
| snd_pmic_ops_nc.pb_on = 0; |
| |
| nc_enable_audiodac(UNMUTE); |
| mutex_unlock(&snd_pmic_ops_nc.lock); |
| return 0; |
| } |
| |
| static int nc_power_down_cp(unsigned int device) |
| { |
| struct sc_reg_access sc_access[] = { |
| {POWERCTRL1, 0x00, 0xBE}, |
| {POWERCTRL2, 0x00, 0x02}, |
| }; |
| int retval = 0; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| pr_debug("powering dn cp....\n"); |
| return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); |
| } |
| |
| static int nc_set_pcm_voice_params(void) |
| { |
| struct sc_reg_access sc_access[] = { |
| {0x100, 0xD5, 0}, |
| {0x101, 0x08, 0}, |
| {0x104, 0x03, 0}, |
| {0x107, 0x10, 0}, |
| {0x10B, 0x0E, 0}, |
| {0x10E, 0x03, 0}, |
| {0x10F, 0x03, 0}, |
| {0x114, 0x13, 0}, |
| {0x115, 0x00, 0}, |
| {0x128, 0xFE, 0}, |
| {0x129, 0xFE, 0}, |
| {0x12A, 0xFE, 0}, |
| {0x12B, 0xDE, 0}, |
| {0x12C, 0xDE, 0}, |
| }; |
| int retval = 0; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| sst_sc_reg_access(sc_access, PMIC_WRITE, 14); |
| pr_debug("Voice parameters set successfully!!\n"); |
| return 0; |
| } |
| |
| |
| static int nc_set_pcm_audio_params(int sfreq, int word_size, int num_channel) |
| { |
| int config2 = 0; |
| struct sc_reg_access sc_access; |
| int retval = 0; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| switch (sfreq) { |
| case 8000: |
| config2 = 0x00; |
| break; |
| case 11025: |
| config2 = 0x01; |
| break; |
| case 12000: |
| config2 = 0x02; |
| break; |
| case 16000: |
| config2 = 0x03; |
| break; |
| case 22050: |
| config2 = 0x04; |
| break; |
| case 24000: |
| config2 = 0x05; |
| break; |
| case 32000: |
| config2 = 0x07; |
| break; |
| case 44100: |
| config2 = 0x08; |
| break; |
| case 48000: |
| config2 = 0x09; |
| break; |
| } |
| |
| snd_pmic_ops_nc.num_channel = num_channel; |
| if (snd_pmic_ops_nc.num_channel == 1) { |
| |
| sc_access.value = 0x07; |
| sc_access.reg_addr = RMUTE; |
| pr_debug("RIGHT_HP_MUTE value%d\n", sc_access.value); |
| sc_access.mask = MASK2; |
| sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); |
| } else { |
| sc_access.value = 0x00; |
| sc_access.reg_addr = RMUTE; |
| pr_debug("RIGHT_HP_MUTE value %d\n", sc_access.value); |
| sc_access.mask = MASK2; |
| sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); |
| |
| |
| } |
| |
| pr_debug("word_size = %d\n", word_size); |
| |
| if (word_size == 24) { |
| sc_access.reg_addr = AUDIOPORT2; |
| sc_access.value = config2 | 0x10; |
| sc_access.mask = 0x1F; |
| } else { |
| sc_access.value = config2; |
| sc_access.mask = 0x1F; |
| sc_access.reg_addr = AUDIOPORT2; |
| } |
| sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); |
| |
| pr_debug("word_size = %d\n", word_size); |
| sc_access.reg_addr = AUDIOPORT1; |
| sc_access.mask = MASK5|MASK4|MASK1|MASK0; |
| if (word_size == 16) |
| sc_access.value = 0x98; |
| else if (word_size == 24) |
| sc_access.value = 0xAB; |
| |
| return sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); |
| |
| |
| |
| } |
| |
| static int nc_set_selected_output_dev(u8 value) |
| { |
| struct sc_reg_access sc_access_HP[] = { |
| {LMUTE, 0x02, 0x06}, |
| {RMUTE, 0x02, 0x06}, |
| {DRVPOWERCTRL, 0x06, 0x06}, |
| }; |
| struct sc_reg_access sc_access_IS[] = { |
| {LMUTE, 0x04, 0x06}, |
| {RMUTE, 0x04, 0x06}, |
| {DRVPOWERCTRL, 0x00, 0x06}, |
| }; |
| int retval = 0; |
| |
| snd_pmic_ops_nc.output_dev_id = value; |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| pr_debug("nc set selected output:%d\n", value); |
| mutex_lock(&snd_pmic_ops_nc.lock); |
| switch (value) { |
| case STEREO_HEADPHONE: |
| if (snd_pmic_ops_nc.pb_on) |
| sst_sc_reg_access(sc_access_HP+2, PMIC_WRITE, 1); |
| retval = sst_sc_reg_access(sc_access_HP, PMIC_WRITE, 2); |
| nc_set_amp_power(0); |
| break; |
| case MONO_EARPIECE: |
| case INTERNAL_SPKR: |
| retval = sst_sc_reg_access(sc_access_IS, PMIC_WRITE, 3); |
| if (snd_pmic_ops_nc.pb_on) |
| nc_set_amp_power(1); |
| break; |
| default: |
| pr_err("rcvd illegal request: %d\n", value); |
| mutex_unlock(&snd_pmic_ops_nc.lock); |
| return -EINVAL; |
| } |
| mutex_unlock(&snd_pmic_ops_nc.lock); |
| return retval; |
| } |
| |
| static int nc_audio_init(void) |
| { |
| struct sc_reg_access sc_acces, sc_access[] = { |
| {0x100, 0x00, 0}, |
| {0x101, 0x00, 0}, |
| {0x104, 0x8B, 0}, |
| {0x107, 0x11, 0}, |
| {0x10B, 0x0E, 0}, |
| {0x114, 0x00, 0}, |
| {0x115, 0x00, 0}, |
| {0x128, 0x00, 0}, |
| {0x129, 0x00, 0}, |
| {0x12A, 0x00, 0}, |
| {0x12B, 0xee, 0}, |
| {0x12C, 0xf6, 0}, |
| }; |
| |
| sst_sc_reg_access(sc_access, PMIC_WRITE, 12); |
| pr_debug("Audio Init successfully!!\n"); |
| |
| /*set output device */ |
| nc_set_selected_output_dev(snd_pmic_ops_nc.output_dev_id); |
| |
| if (snd_pmic_ops_nc.num_channel == 1) { |
| sc_acces.value = 0x07; |
| sc_acces.reg_addr = RMUTE; |
| pr_debug("RIGHT_HP_MUTE value%d\n", sc_acces.value); |
| sc_acces.mask = MASK2; |
| sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1); |
| } else { |
| sc_acces.value = 0x00; |
| sc_acces.reg_addr = RMUTE; |
| pr_debug("RIGHT_HP_MUTE value%d\n", sc_acces.value); |
| sc_acces.mask = MASK2; |
| sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1); |
| } |
| |
| return 0; |
| } |
| |
| static int nc_set_audio_port(int status) |
| { |
| struct sc_reg_access sc_access[2] = {{0,},}; |
| int retval = 0; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| if (status == DEACTIVATE) { |
| /* Deactivate audio port-tristate and power */ |
| sc_access[0].value = 0x00; |
| sc_access[0].mask = MASK4|MASK5; |
| sc_access[0].reg_addr = AUDIOPORT1; |
| return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); |
| } else if (status == ACTIVATE) { |
| /* activate audio port */ |
| nc_audio_init(); |
| sc_access[0].value = 0x10; |
| sc_access[0].mask = MASK4|MASK5 ; |
| sc_access[0].reg_addr = AUDIOPORT1; |
| return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); |
| } else |
| return -EINVAL; |
| |
| } |
| |
| static int nc_set_voice_port(int status) |
| { |
| struct sc_reg_access sc_access[2] = {{0,},}; |
| int retval = 0; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| if (status == DEACTIVATE) { |
| /* Activate Voice port */ |
| sc_access[0].value = 0x00; |
| sc_access[0].mask = MASK4; |
| sc_access[0].reg_addr = VOICEPORT1; |
| return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); |
| } else if (status == ACTIVATE) { |
| /* Deactivate voice port */ |
| nc_set_pcm_voice_params(); |
| sc_access[0].value = 0x10; |
| sc_access[0].mask = MASK4; |
| sc_access[0].reg_addr = VOICEPORT1; |
| return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); |
| } else |
| return -EINVAL; |
| } |
| |
| static int nc_set_mute(int dev_id, u8 value) |
| { |
| struct sc_reg_access sc_access[3]; |
| u8 mute_val, cap_mute; |
| int retval = 0; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| pr_debug("set device id::%d, value %d\n", dev_id, value); |
| |
| switch (dev_id) { |
| case PMIC_SND_MUTE_ALL: |
| pr_debug("PMIC_SND_MUTE_ALL value %d\n", value); |
| snd_pmic_ops_nc.mute_status = value; |
| snd_pmic_ops_nc.master_mute = value; |
| if (value == UNMUTE) { |
| /* unmute the system, set the 7th bit to zero */ |
| mute_val = cap_mute = 0x00; |
| } else { |
| /* MUTE:Set the seventh bit */ |
| mute_val = 0x80; |
| cap_mute = 0x40; |
| } |
| sc_access[0].reg_addr = AUDIOLVOL; |
| sc_access[1].reg_addr = AUDIORVOL; |
| sc_access[0].mask = sc_access[1].mask = MASK7; |
| sc_access[0].value = sc_access[1].value = mute_val; |
| if (snd_pmic_ops_nc.num_channel == 1) |
| sc_access[1].value = 0x80; |
| if (!sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2)) { |
| sc_access[0].reg_addr = 0x109; |
| sc_access[1].reg_addr = 0x10a; |
| sc_access[2].reg_addr = 0x105; |
| sc_access[0].mask = sc_access[1].mask = |
| sc_access[2].mask = MASK6; |
| sc_access[0].value = sc_access[1].value = |
| sc_access[2].value = cap_mute; |
| |
| if ((snd_pmic_ops_nc.input_dev_id == AMIC) || |
| (snd_pmic_ops_nc.input_dev_id == DMIC)) |
| sc_access[1].value = 0x40; |
| if (snd_pmic_ops_nc.input_dev_id == HS_MIC) |
| sc_access[0].value = 0x40; |
| retval = sst_sc_reg_access(sc_access, |
| PMIC_READ_MODIFY, 3); |
| } |
| break; |
| case PMIC_SND_HP_MIC_MUTE: |
| pr_debug("PMIC_SND_HPMIC_MUTE value %d\n", value); |
| if (value == UNMUTE) { |
| /* unmute the system, set the 6th bit to one */ |
| sc_access[0].value = 0x00; |
| } else { |
| /* mute the system, reset the 6th bit to zero */ |
| sc_access[0].value = 0x40; |
| } |
| sc_access[0].reg_addr = LIRSEL; |
| sc_access[0].mask = MASK6; |
| retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); |
| break; |
| case PMIC_SND_AMIC_MUTE: |
| pr_debug("PMIC_SND_AMIC_MUTE value %d\n", value); |
| if (value == UNMUTE) { |
| /* unmute the system, set the 6th bit to one */ |
| sc_access[0].value = 0x00; |
| } else { |
| /* mute the system, reset the 6th bit to zero */ |
| sc_access[0].value = 0x40; |
| } |
| sc_access[0].reg_addr = LILSEL; |
| sc_access[0].mask = MASK6; |
| retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); |
| break; |
| |
| case PMIC_SND_DMIC_MUTE: |
| pr_debug("INPUT_MUTE_DMIC value%d\n", value); |
| if (value == UNMUTE) { |
| /* unmute the system, set the 6th bit to one */ |
| sc_access[1].value = 0x00; |
| sc_access[0].value = 0x00; |
| } else { |
| /* mute the system, reset the 6th bit to zero */ |
| sc_access[1].value = 0x40; |
| sc_access[0].value = 0x40; |
| } |
| sc_access[0].reg_addr = DMICCTRL1; |
| sc_access[0].mask = MASK6; |
| sc_access[1].reg_addr = LILSEL; |
| sc_access[1].mask = MASK6; |
| retval = sst_sc_reg_access(sc_access, |
| PMIC_READ_MODIFY, 2); |
| break; |
| |
| case PMIC_SND_LEFT_HP_MUTE: |
| case PMIC_SND_RIGHT_HP_MUTE: |
| snd_pmic_ops_nc.mute_status = value; |
| if (value == UNMUTE) |
| sc_access[0].value = 0x0; |
| else |
| sc_access[0].value = 0x04; |
| |
| if (dev_id == PMIC_SND_LEFT_HP_MUTE) { |
| sc_access[0].reg_addr = LMUTE; |
| pr_debug("LEFT_HP_MUTE value %d\n", |
| sc_access[0].value); |
| } else { |
| if (snd_pmic_ops_nc.num_channel == 1) |
| sc_access[0].value = 0x04; |
| sc_access[0].reg_addr = RMUTE; |
| pr_debug("RIGHT_HP_MUTE value %d\n", |
| sc_access[0].value); |
| } |
| sc_access[0].mask = MASK2; |
| retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); |
| break; |
| case PMIC_SND_LEFT_SPEAKER_MUTE: |
| case PMIC_SND_RIGHT_SPEAKER_MUTE: |
| if (value == UNMUTE) |
| sc_access[0].value = 0x00; |
| else |
| sc_access[0].value = 0x03; |
| sc_access[0].reg_addr = LMUTE; |
| pr_debug("SPEAKER_MUTE %d\n", sc_access[0].value); |
| sc_access[0].mask = MASK1; |
| retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); |
| break; |
| default: |
| return -EINVAL; |
| } |
| return retval ; |
| |
| } |
| |
| static int nc_set_vol(int dev_id, int value) |
| { |
| struct sc_reg_access sc_access[3]; |
| int retval = 0, entries = 0; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| pr_debug("set volume:%d\n", dev_id); |
| switch (dev_id) { |
| case PMIC_SND_CAPTURE_VOL: |
| pr_debug("PMIC_SND_CAPTURE_VOL:value::%d\n", value); |
| sc_access[0].value = sc_access[1].value = |
| sc_access[2].value = -value; |
| sc_access[0].mask = sc_access[1].mask = sc_access[2].mask = |
| (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); |
| sc_access[0].reg_addr = 0x10a; |
| sc_access[1].reg_addr = 0x109; |
| sc_access[2].reg_addr = 0x105; |
| entries = 3; |
| break; |
| |
| case PMIC_SND_LEFT_PB_VOL: |
| pr_debug("PMIC_SND_LEFT_HP_VOL %d\n", value); |
| sc_access[0].value = -value; |
| sc_access[0].reg_addr = HPLVOL; |
| sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4); |
| entries = 1; |
| break; |
| |
| case PMIC_SND_RIGHT_PB_VOL: |
| pr_debug("PMIC_SND_RIGHT_HP_VOL value %d\n", value); |
| if (snd_pmic_ops_nc.num_channel == 1) { |
| sc_access[0].value = 0x04; |
| sc_access[0].reg_addr = RMUTE; |
| sc_access[0].mask = MASK2; |
| } else { |
| sc_access[0].value = -value; |
| sc_access[0].reg_addr = HPRVOL; |
| sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4); |
| } |
| entries = 1; |
| break; |
| |
| case PMIC_SND_LEFT_MASTER_VOL: |
| pr_debug("PMIC_SND_LEFT_MASTER_VOL value %d\n", value); |
| sc_access[0].value = -value; |
| sc_access[0].reg_addr = AUDIOLVOL; |
| sc_access[0].mask = |
| (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6); |
| entries = 1; |
| break; |
| |
| case PMIC_SND_RIGHT_MASTER_VOL: |
| pr_debug("PMIC_SND_RIGHT_MASTER_VOL value %d\n", value); |
| sc_access[0].value = -value; |
| sc_access[0].reg_addr = AUDIORVOL; |
| sc_access[0].mask = |
| (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6); |
| entries = 1; |
| break; |
| |
| default: |
| return -EINVAL; |
| |
| } |
| return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, entries); |
| } |
| |
| static int nc_set_selected_input_dev(u8 value) |
| { |
| struct sc_reg_access sc_access[6]; |
| u8 num_val; |
| int retval = 0; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| snd_pmic_ops_nc.input_dev_id = value; |
| |
| pr_debug("nc set selected input:%d\n", value); |
| |
| switch (value) { |
| case AMIC: |
| pr_debug("Selecting AMIC\n"); |
| sc_access[0].reg_addr = 0x107; |
| sc_access[0].value = 0x40; |
| sc_access[0].mask = MASK6|MASK3|MASK1|MASK0; |
| sc_access[1].reg_addr = 0x10a; |
| sc_access[1].value = 0x40; |
| sc_access[1].mask = MASK6; |
| sc_access[2].reg_addr = 0x109; |
| sc_access[2].value = 0x00; |
| sc_access[2].mask = MASK6; |
| sc_access[3].reg_addr = 0x105; |
| sc_access[3].value = 0x40; |
| sc_access[3].mask = MASK6; |
| num_val = 4; |
| break; |
| |
| case HS_MIC: |
| pr_debug("Selecting HS_MIC\n"); |
| sc_access[0].reg_addr = MICCTRL; |
| sc_access[0].mask = MASK6|MASK3|MASK1|MASK0; |
| sc_access[0].value = 0x00; |
| sc_access[1].reg_addr = 0x109; |
| sc_access[1].mask = MASK6; |
| sc_access[1].value = 0x40; |
| sc_access[2].reg_addr = 0x10a; |
| sc_access[2].mask = MASK6; |
| sc_access[2].value = 0x00; |
| sc_access[3].reg_addr = 0x105; |
| sc_access[3].value = 0x40; |
| sc_access[3].mask = MASK6; |
| sc_access[4].reg_addr = ADCSAMPLERATE; |
| sc_access[4].mask = MASK7|MASK6|MASK5|MASK4|MASK3; |
| sc_access[4].value = 0xc8; |
| num_val = 5; |
| break; |
| |
| case DMIC: |
| pr_debug("DMIC\n"); |
| sc_access[0].reg_addr = MICCTRL; |
| sc_access[0].mask = MASK6|MASK3|MASK1|MASK0; |
| sc_access[0].value = 0x0B; |
| sc_access[1].reg_addr = 0x105; |
| sc_access[1].value = 0x80; |
| sc_access[1].mask = MASK7|MASK6; |
| sc_access[2].reg_addr = 0x10a; |
| sc_access[2].value = 0x40; |
| sc_access[2].mask = MASK6; |
| sc_access[3].reg_addr = LILSEL; |
| sc_access[3].mask = MASK6; |
| sc_access[3].value = 0x00; |
| sc_access[4].reg_addr = ADCSAMPLERATE; |
| sc_access[4].mask = MASK7|MASK6|MASK5|MASK4|MASK3; |
| sc_access[4].value = 0x33; |
| num_val = 5; |
| break; |
| default: |
| return -EINVAL; |
| } |
| return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_val); |
| } |
| |
| static int nc_get_mute(int dev_id, u8 *value) |
| { |
| int retval = 0, mask = 0; |
| struct sc_reg_access sc_access = {0,}; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| pr_debug("get mute::%d\n", dev_id); |
| |
| switch (dev_id) { |
| case PMIC_SND_AMIC_MUTE: |
| pr_debug("PMIC_SND_INPUT_MUTE_MIC1\n"); |
| sc_access.reg_addr = LILSEL; |
| mask = MASK6; |
| break; |
| case PMIC_SND_HP_MIC_MUTE: |
| pr_debug("PMIC_SND_INPUT_MUTE_MIC2\n"); |
| sc_access.reg_addr = LIRSEL; |
| mask = MASK6; |
| break; |
| case PMIC_SND_LEFT_HP_MUTE: |
| case PMIC_SND_RIGHT_HP_MUTE: |
| mask = MASK2; |
| pr_debug("PMIC_SN_LEFT/RIGHT_HP_MUTE\n"); |
| if (dev_id == PMIC_SND_RIGHT_HP_MUTE) |
| sc_access.reg_addr = RMUTE; |
| else |
| sc_access.reg_addr = LMUTE; |
| break; |
| |
| case PMIC_SND_LEFT_SPEAKER_MUTE: |
| pr_debug("PMIC_MONO_EARPIECE_MUTE\n"); |
| sc_access.reg_addr = RMUTE; |
| mask = MASK1; |
| break; |
| case PMIC_SND_DMIC_MUTE: |
| pr_debug("PMIC_SND_INPUT_MUTE_DMIC\n"); |
| sc_access.reg_addr = 0x105; |
| mask = MASK6; |
| break; |
| default: |
| return -EINVAL; |
| |
| } |
| retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1); |
| pr_debug("reg value = %d\n", sc_access.value); |
| if (retval) |
| return retval; |
| *value = (sc_access.value) & mask; |
| pr_debug("masked value = %d\n", *value); |
| if (*value) |
| *value = 0; |
| else |
| *value = 1; |
| pr_debug("value returned = 0x%x\n", *value); |
| return retval; |
| } |
| |
| static int nc_get_vol(int dev_id, int *value) |
| { |
| int retval = 0, mask = 0; |
| struct sc_reg_access sc_access = {0,}; |
| |
| if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) |
| retval = nc_init_card(); |
| if (retval) |
| return retval; |
| |
| switch (dev_id) { |
| case PMIC_SND_CAPTURE_VOL: |
| pr_debug("PMIC_SND_INPUT_CAPTURE_VOL\n"); |
| sc_access.reg_addr = LILSEL; |
| mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); |
| break; |
| |
| case PMIC_SND_LEFT_MASTER_VOL: |
| pr_debug("GET_VOLUME_PMIC_LEFT_MASTER_VOL\n"); |
| sc_access.reg_addr = AUDIOLVOL; |
| mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6); |
| break; |
| |
| case PMIC_SND_RIGHT_MASTER_VOL: |
| pr_debug("GET_VOLUME_PMIC_RIGHT_MASTER_VOL\n"); |
| sc_access.reg_addr = AUDIORVOL; |
| mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6); |
| break; |
| |
| case PMIC_SND_RIGHT_PB_VOL: |
| pr_debug("GET_VOLUME_PMIC_RIGHT_HP_VOL\n"); |
| sc_access.reg_addr = HPRVOL; |
| mask = (MASK0|MASK1|MASK2|MASK3|MASK4); |
| break; |
| |
| case PMIC_SND_LEFT_PB_VOL: |
| pr_debug("GET_VOLUME_PMIC_LEFT_HP_VOL\n"); |
| sc_access.reg_addr = HPLVOL; |
| mask = (MASK0|MASK1|MASK2|MASK3|MASK4); |
| break; |
| |
| default: |
| return -EINVAL; |
| |
| } |
| retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1); |
| pr_debug("value read = 0x%x\n", sc_access.value); |
| *value = -((sc_access.value) & mask); |
| pr_debug("get vol value returned = %d\n", *value); |
| return retval; |
| } |
| |
| static void hp_automute(enum snd_jack_types type, int present) |
| { |
| u8 in = DMIC; |
| u8 out = INTERNAL_SPKR; |
| if (present) { |
| if (type == SND_JACK_HEADSET) |
| in = HS_MIC; |
| out = STEREO_HEADPHONE; |
| } |
| nc_set_selected_input_dev(in); |
| nc_set_selected_output_dev(out); |
| } |
| |
| static void nc_pmic_irq_cb(void *cb_data, u8 intsts) |
| { |
| u8 value = 0; |
| struct mad_jack *mjack = NULL; |
| unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0; |
| struct snd_intelmad *intelmaddata = cb_data; |
| struct sc_reg_access sc_access_read = {0,}; |
| |
| sc_access_read.reg_addr = 0x132; |
| sst_sc_reg_access(&sc_access_read, PMIC_READ, 1); |
| value = (sc_access_read.value); |
| pr_debug("value returned = 0x%x\n", value); |
| |
| mjack = &intelmaddata->jack[0]; |
| if (intsts & 0x1) { |
| pr_debug("SST DBG:MAD headset detected\n"); |
| /* send headset detect/undetect */ |
| present = (value == 0x1) ? 3 : 0; |
| jack_event_flag = 1; |
| mjack->jack.type = SND_JACK_HEADSET; |
| hp_automute(SND_JACK_HEADSET, present); |
| } |
| |
| if (intsts & 0x2) { |
| pr_debug(":MAD headphone detected\n"); |
| /* send headphone detect/undetect */ |
| present = (value == 0x2) ? 1 : 0; |
| jack_event_flag = 1; |
| mjack->jack.type = SND_JACK_HEADPHONE; |
| hp_automute(SND_JACK_HEADPHONE, present); |
| } |
| |
| if (intsts & 0x4) { |
| pr_debug("MAD short push detected\n"); |
| /* send short push */ |
| present = 1; |
| jack_event_flag = 1; |
| buttonpressflag = 1; |
| mjack->jack.type = MID_JACK_HS_SHORT_PRESS; |
| } |
| |
| if (intsts & 0x8) { |
| pr_debug(":MAD long push detected\n"); |
| /* send long push */ |
| present = 1; |
| jack_event_flag = 1; |
| buttonpressflag = 1; |
| mjack->jack.type = MID_JACK_HS_LONG_PRESS; |
| } |
| |
| if (jack_event_flag) |
| sst_mad_send_jack_report(&mjack->jack, |
| buttonpressflag, present); |
| } |
| static int nc_jack_enable(void) |
| { |
| return 0; |
| } |
| |
| struct snd_pmic_ops snd_pmic_ops_nc = { |
| .input_dev_id = DMIC, |
| .output_dev_id = INTERNAL_SPKR, |
| .set_input_dev = nc_set_selected_input_dev, |
| .set_output_dev = nc_set_selected_output_dev, |
| .set_mute = nc_set_mute, |
| .get_mute = nc_get_mute, |
| .set_vol = nc_set_vol, |
| .get_vol = nc_get_vol, |
| .init_card = nc_init_card, |
| .set_pcm_audio_params = nc_set_pcm_audio_params, |
| .set_pcm_voice_params = nc_set_pcm_voice_params, |
| .set_voice_port = nc_set_voice_port, |
| .set_audio_port = nc_set_audio_port, |
| .power_up_pmic_pb = nc_power_up_pb, |
| .power_up_pmic_cp = nc_power_up_cp, |
| .power_down_pmic_pb = nc_power_down_pb, |
| .power_down_pmic_cp = nc_power_down_cp, |
| .power_down_pmic = nc_power_down, |
| .pmic_irq_cb = nc_pmic_irq_cb, |
| .pmic_jack_enable = nc_jack_enable, |
| }; |