static int wm8994_device_suspend(struct device *dev) { struct wm8994 *wm8994 = dev_get_drvdata(dev); int ret; /* GPIO configuration state is saved here since we may be configuring * the GPIO alternate functions even if we're not using the gpiolib * driver for them. */ ret = wm8994_read(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2, &wm8994->gpio_regs); if (ret < 0) dev_err(dev, "Failed to save GPIO registers: %d\n", ret); /* For similar reasons we also stash the regulator states */ ret = wm8994_read(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2, &wm8994->ldo_regs); if (ret < 0) dev_err(dev, "Failed to save LDO registers: %d\n", ret); ret = regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies); if (ret != 0) { dev_err(dev, "Failed to disable supplies: %d\n", ret); return ret; } return 0; }
static void set_headphones(void) { unsigned int val; /* get current headphones level value and force setting it, soundlevel mod will be handled on wm8994.c */ val = wm8994_read(soundlevel_codec, WM8994_LEFT_OUTPUT_VOLUME); wm8994_write(soundlevel_codec, WM8994_LEFT_OUTPUT_VOLUME, val); val = wm8994_read(soundlevel_codec, WM8994_RIGHT_OUTPUT_VOLUME); wm8994_write(soundlevel_codec, WM8994_RIGHT_OUTPUT_VOLUME, val | WM8994_HPOUT1_VU); /* Set the update flag to actually apply the new setting */ }
static void set_speaker(void) { unsigned int val; /* get current headphones level value and force setting it, soundlevel mod will be handled on wm8994.c */ val = wm8994_read(soundlevel_codec, WM8994_SPEAKER_VOLUME_LEFT); wm8994_write(soundlevel_codec, WM8994_SPEAKER_VOLUME_LEFT, val); val = wm8994_read(soundlevel_codec, WM8994_SPEAKER_VOLUME_RIGHT); wm8994_write(soundlevel_codec, WM8994_SPEAKER_VOLUME_RIGHT, val | WM8994_SPKOUT_VU); /* Set the update flag to actually apply the new setting */ }
void update_fm_radio_headset_restore_freqs(bool with_mute) { unsigned short val; DECLARE_WM8994(codec); bypass_write_extension = true; // apply only when FM radio is active if (wm8994->fmradio_path == FMR_OFF) return; if (with_mute) { wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, WM8994_AIF2DAC_MUTE | WM8994_AIF2DAC_MUTERATE | WM8994_AIF2DAC_UNMUTE_RAMP | WM8994_AIF2DAC_DEEMP_MASK); msleep(180); } if (fm_radio_headset_restore_bass) { // disable Sidetone high-pass filter // was designed for voice and not FM radio wm8994_write(codec, WM8994_SIDETONE, 0x0000); // disable 4FS ultrasonic mode and // restore the hi-fi <4Hz hi pass filter wm8994_write(codec, WM8994_AIF2_ADC_FILTERS, WM8994_AIF2ADCL_HPF | WM8994_AIF2ADCR_HPF); } else { // default settings in GT-I9000 Froyo XXJPX kernel sources wm8994_write(codec, WM8994_SIDETONE, 0x01c0); wm8994_write(codec, WM8994_AIF2_ADC_FILTERS, 0xF800); } if (fm_radio_headset_restore_highs) { val = wm8994_read(codec, WM8994_AIF2_DAC_FILTERS_1); val &= ~(WM8994_AIF2DAC_DEEMP_MASK); wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, val); } else { wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, 0x0036); } // un-mute if (with_mute) { val = wm8994_read(codec, WM8994_AIF2_DAC_FILTERS_1); val &= ~(WM8994_AIF2DAC_MUTE_MASK); wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, val); } bypass_write_extension = false; }
void update_fm_radio_headset_restore_freqs(bool with_mute) { unsigned short val; // apply only when FM radio is active DECLARE_WM8994(codec_) if (wm8994->fmradio_path == FMR_OFF) return; if (with_mute) { wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, 0x236); msleep(180); } if (fm_radio_headset_restore_bass) { // disable Sidetone high-pass filter designed for voice and not FM radio // Sidetone(621H): 0000 ST_HPF_CUT=000, ST_HPF=0, ST2_SEL=0, ST1_SEL=0 wm8994_write(codec_, WM8994_SIDETONE, 0x0000); // disable 4FS ultrasonic mode and restore the hi-fi <4Hz hi pass filter // AIF2 ADC Filters(510H): 1800 AIF2ADC_4FS=0, AIF2ADC_HPF_CUT=00, AIF2ADCL_HPF=1, AIF2ADCR_HPF=1 wm8994_write(codec_, WM8994_AIF2_ADC_FILTERS, 0x1800); } else { // default settings in GT-I9000 Froyo XXJPX kernel sources wm8994_write(codec_, WM8994_SIDETONE, 0x01c0); wm8994_write(codec_, WM8994_AIF2_ADC_FILTERS, 0xF800); } if (fm_radio_headset_restore_highs) { val = wm8994_read(codec_, WM8994_AIF2_DAC_FILTERS_1); val &= ~(WM8994_AIF2DAC_DEEMP_MASK); wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, val); } else wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, 0x0036); // un-mute if (with_mute) { val = wm8994_read(codec_, WM8994_AIF2_DAC_FILTERS_1); val &= ~(WM8994_AIF2DAC_MUTE_MASK); wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, val); } }
/** * wm8994_set_bits: Set the value of a bitfield in a WM8994 register * * @wm8994: Device to write to. * @reg: Register to write to. * @mask: Mask of bits to set. * @val: Value to set (unshifted) */ int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg, unsigned short mask, unsigned short val) { int ret; u16 r; mutex_lock(&wm8994->io_lock); ret = wm8994_read(wm8994, reg, 2, &r); if (ret < 0) goto out; r = be16_to_cpu(r); r &= ~mask; r |= val; r = cpu_to_be16(r); ret = wm8994_write(wm8994, reg, 2, &r); out: mutex_unlock(&wm8994->io_lock); return ret; }
void update_osr128(bool with_mute) { unsigned short val; val = osr128_get_value(wm8994_read(codec, WM8994_OVERSAMPLING)); bypass_write_hook = true; wm8994_write(codec, WM8994_OVERSAMPLING, val); bypass_write_hook = false; }
static int wm8994_suspend(struct device *dev) { struct wm8994 *wm8994 = dev_get_drvdata(dev); int ret; /* Don't actually go through with the suspend if the CODEC is * still active (eg, for audio passthrough from CP. */ ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_1); if (ret < 0) { dev_err(dev, "Failed to read power status: %d\n", ret); } else if (ret & WM8994_VMID_SEL_MASK) { dev_dbg(dev, "CODEC still active, ignoring suspend\n"); return 0; } /* GPIO configuration state is saved here since we may be configuring * the GPIO alternate functions even if we're not using the gpiolib * driver for them. */ ret = wm8994_read(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2, &wm8994->gpio_regs); if (ret < 0) dev_err(dev, "Failed to save GPIO registers: %d\n", ret); /* For similar reasons we also stash the regulator states */ ret = wm8994_read(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2, &wm8994->ldo_regs); if (ret < 0) dev_err(dev, "Failed to save LDO registers: %d\n", ret); /* Explicitly put the device into reset in case regulators * don't get disabled in order to ensure consistent restart. */ wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, 0x8994); wm8994->suspended = true; ret = regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(dev, "Failed to disable supplies: %d\n", ret); return ret; } return 0; }
/** * wm8994_bulk_read: Read multiple WM8994 registers * * @wm8994: Device to read from * @reg: First register * @count: Number of registers * @buf: Buffer to fill. The data will be returned big endian. */ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, int count, u16 *buf) { int ret; mutex_lock(&wm8994->io_lock); ret = wm8994_read(wm8994, reg, count * 2, buf); mutex_unlock(&wm8994->io_lock); return ret; }
/** * wm8994_reg_read: Read a single WM8994 register. * * @wm8994: Device to read from. * @reg: Register to read. */ int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg) { unsigned short val; int ret; mutex_lock(&wm8994->io_lock); ret = wm8994_read(wm8994, reg, 2, &val); mutex_unlock(&wm8994->io_lock); if (ret < 0) return ret; else return be16_to_cpu(val); }
/** * wm8994_reg_read: Read a single WM8994 register. * * @wm8994: Device to read from. * @reg: Register to read. */ int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg) { unsigned short val; int ret; mutex_lock(&wm8994->io_lock); ret = wm8994_read(wm8994, reg, 2, &val); mutex_unlock(&wm8994->io_lock); #if 1 dev_vdbg(wm8994->dev, "wm8994_reg_read ADRESS is %x, VALUE is %x\n", reg, val); #else printk("wm8994_reg_read ADRESS is %x, VALUE is %x\n", reg, val); #endif if (ret < 0) return ret; else return val; }
void update_hpvol(bool with_fade) { unsigned short val; unsigned short i; short steps; int hp_level_old[2]; unsigned short hp_level_registers[2] = { WM8994_LEFT_OUTPUT_VOLUME, WM8994_RIGHT_OUTPUT_VOLUME }; DECLARE_WM8994(codec); // don't affect headphone amplifier volume // when not on heapdhones or if call is active if (!is_path(HEADPHONES) || (wm8994->codec_state & CALL_ACTIVE)) return; if (!with_fade) { bypass_write_extension = true; write_hpvol(hpvol(0), hpvol(1)); bypass_write_extension = false; return; } // read previous levels for (i = 0; i < 2; i++) { val = wm8994_read(codec, hp_level_registers[i]); val &= ~(WM8994_HPOUT1_VU_MASK); val &= ~(WM8994_HPOUT1L_ZC_MASK); val &= ~(WM8994_HPOUT1L_MUTE_N_MASK); hp_level_old[i] = val + (digital_gain / 1000); if (hp_level_old[i] < 0) hp_level_old[i] = 0; if (debug_log(LOG_INFOS)) printk("wm8994_extensions: previous hp_level[%hu]: %d\n", i, hp_level_old[i]); } // calculate number of steps for volume fade steps = hp_level[0] - hp_level_old[0]; if (debug_log(LOG_INFOS)) printk("wm8994_extensions: volume change steps: %hd " "start: %hu, end: %hu\n", steps, hp_level_old[0], hp_level[0]); while (steps != 0) { if (hp_level[0] < hp_level_old[0]) steps++; else steps--; if (debug_log(LOG_INFOS)) printk("wm8994_extensions: volume: %hu\n", (hpvol(0) - steps)); bypass_write_extension = true; write_hpvol(hpvol(0) - steps, hpvol(1) - steps); bypass_write_extension = false; if (steps != 0) udelay(1000); } }
static int wm8994_device_suspend(struct device *dev) { struct wm8994 *wm8994 = dev_get_drvdata(dev); int ret; /* Don't actually go through with the suspend if the CODEC is * still active (eg, for audio passthrough from CP. */ ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_1); if (ret < 0) { dev_err(dev, "Failed to read power status: %d\n", ret); } else if (ret & WM8994_VMID_SEL_MASK) { dev_dbg(dev, "CODEC still active, ignoring suspend\n"); return 0; } ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_4); if (ret < 0) { dev_err(dev, "Failed to read power status: %d\n", ret); } else if (ret & (WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA | WM8994_AIF1ADC2L_ENA | WM8994_AIF1ADC2R_ENA | WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC1R_ENA)) { dev_dbg(dev, "CODEC still active, ignoring suspend\n"); return 0; } ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_5); if (ret < 0) { dev_err(dev, "Failed to read power status: %d\n", ret); } else if (ret & (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA | WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA)) { dev_dbg(dev, "CODEC still active, ignoring suspend\n"); return 0; } switch (wm8994->type) { case WM8958: case WM1811: ret = wm8994_reg_read(wm8994, WM8958_MIC_DETECT_1); if (ret < 0) { dev_err(dev, "Failed to read power status: %d\n", ret); } else if (ret & WM8958_MICD_ENA) { dev_dbg(dev, "CODEC still active, ignoring suspend\n"); return 0; } break; default: break; } switch (wm8994->type) { case WM1811: ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2); if (ret < 0) { dev_err(dev, "Failed to read jackdet: %d\n", ret); } else if (ret & WM1811_JACKDET_MODE_MASK) { dev_dbg(dev, "CODEC still active, ignoring suspend\n"); return 0; } break; default: break; } /* Disable LDO pulldowns while the device is suspended if we * don't know that something will be driving them. */ if (!wm8994->ldo_ena_always_driven) wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2, WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD, WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD); /* GPIO configuration state is saved here since we may be configuring * the GPIO alternate functions even if we're not using the gpiolib * driver for them. */ ret = wm8994_read(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2, &wm8994->gpio_regs); if (ret < 0) dev_err(dev, "Failed to save GPIO registers: %d\n", ret); /* For similar reasons we also stash the regulator states */ ret = wm8994_read(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2, &wm8994->ldo_regs); if (ret < 0) dev_err(dev, "Failed to save LDO registers: %d\n", ret); /* Explicitly put the device into reset in case regulators * don't get disabled in order to ensure consistent restart. */ wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, 0x8994); wm8994->suspended = true; ret = regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(dev, "Failed to disable supplies: %d\n", ret); return ret; } set_mclk(0); return 0; }