diff options
Diffstat (limited to 'drivers/staging/intel_sst/intelmid_msic_control.c')
-rw-r--r-- | drivers/staging/intel_sst/intelmid_msic_control.c | 254 |
1 files changed, 242 insertions, 12 deletions
diff --git a/drivers/staging/intel_sst/intelmid_msic_control.c b/drivers/staging/intel_sst/intelmid_msic_control.c index bbe9ab20f967..10073c5b5f64 100644 --- a/drivers/staging/intel_sst/intelmid_msic_control.c +++ b/drivers/staging/intel_sst/intelmid_msic_control.c @@ -54,11 +54,8 @@ 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}, @@ -80,14 +77,221 @@ static int msic_init_card(void) {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; 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}, + }; + 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); + 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}, + }; + 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); + 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); + 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); + 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); + break; + case NONE: + pr_debug("Selecting Lineout-NONE\n"); + retval = sst_sc_reg_access(lout_def, + PMIC_WRITE, 1); + break; + default: + return -EINVAL; + } + return retval; +} + static int msic_power_up_pb(unsigned int device) { @@ -161,12 +365,12 @@ static int msic_power_up_pb(unsigned int device) struct sc_reg_access vib1_en[] = { /* enable driver, ADC */ {0x25D, 0x10, 0x10}, - {0x264, 0x02, 0x02}, + {0x264, 0x02, 0x82}, }; struct sc_reg_access vib2_en[] = { /* enable driver, ADC */ {0x25D, 0x20, 0x20}, - {0x26A, 0x02, 0x02}, + {0x26A, 0x02, 0x82}, }; struct sc_reg_access pcm2_en[] = { /* enable pcm 2 */ @@ -187,6 +391,8 @@ static int msic_power_up_pb(unsigned int device) 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(vhs, PMIC_WRITE, 2); sst_sc_reg_access(hsdac, PMIC_READ_MODIFY, 2); @@ -197,22 +403,31 @@ static int msic_power_up_pb(unsigned int device) 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: + 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: + 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: + 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: @@ -310,6 +525,7 @@ static int msic_power_down(void) }; pr_debug("powering dn msic\n"); + snd_msic_ops.pbhs_on = 0; snd_msic_ops.pb_on = 0; snd_msic_ops.cap_on = 0; sst_sc_reg_access(power_dn, PMIC_WRITE, 3); @@ -348,15 +564,22 @@ static int msic_power_down_pb(unsigned int device) struct sc_reg_access vib2_off[] = { {0x26A, 0x00, 0x82}, }; + struct sc_reg_access lout_off[] = { + {0x25e, 0x66, 0x00}, + }; + + pr_debug("powering dn pb for device %d\n", device); switch (device) { case SND_SST_DEVICE_HEADSET: - snd_msic_ops.pb_on = 0; + 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, 2); + if (snd_msic_ops.lineout_dev_id == HEADSET) + sst_sc_reg_access(lout_off, PMIC_WRITE, 1); break; case SND_SST_DEVICE_IHF: @@ -364,18 +587,24 @@ static int msic_power_down_pb(unsigned int device) 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); break; case SND_SST_DEVICE_VIBRA: - sst_sc_reg_access(vib1_off, PMIC_READ_MODIFY, 2); + 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, 2); + 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; @@ -414,7 +643,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; } @@ -494,6 +723,7 @@ static int msic_get_vol(int dev_id, int *value) 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_mute = msic_set_mute, .get_mute = msic_get_mute, .set_vol = msic_set_vol, |