Exemple #1
0
static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
		int clk_id, unsigned int freq, int dir)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct wm8350* wm8350 = codec->control_data;
	u16 fll_4;
	
	switch(clk_id) {
	case WM8350_MCLK_SEL_MCLK:
		wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_1, 
			WM8350_MCLK_SEL);
		break;
	case WM8350_MCLK_SEL_PLL_MCLK:
	case WM8350_MCLK_SEL_PLL_DAC:
	case WM8350_MCLK_SEL_PLL_ADC:
	case WM8350_MCLK_SEL_PLL_32K:
		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1, 
			WM8350_MCLK_SEL);
		fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) & 
			~WM8350_FLL_CLK_SRC_MASK;
		wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, 
			fll_4 | clk_id);
		break;
	}
		
	/* MCLK direction */
	if (dir == WM8350_MCLK_DIR_OUT)
		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2, 
			WM8350_MCLK_DIR);
	else 
		wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2, 
			WM8350_MCLK_DIR);
				
	return 0;
}
Exemple #2
0
static int wm8350_remove(struct platform_device *pdev)
{
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
	struct snd_soc_codec *codec = socdev->card->codec;
	struct wm8350 *wm8350 = codec->control_data;
	struct wm8350_data *priv = codec->private_data;
	int ret;

	wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
			  WM8350_JDL_ENA | WM8350_JDR_ENA);
	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);

	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);

	priv->hpl.jack = NULL;
	priv->hpr.jack = NULL;

	/* cancel any work waiting to be queued. */
	ret = cancel_delayed_work(&codec->delayed_work);

	/* if there was any work waiting then we run it now and
	 * wait for its completion */
	if (ret) {
		schedule_delayed_work(&codec->delayed_work, 0);
		flush_scheduled_work();
	}

	wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);

	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);

	return 0;
}
static int imx_3stack_startup(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_codec *codec = rtd->socdev->card->codec;
	struct wm8350 *wm8350 = codec->control_data;
	struct imx_3stack_priv *priv = &machine_priv;

	/* In master mode the LR clock can come from either the DAC or ADC.
	 * We use the LR clock from whatever stream is enabled first.
	 */

	if (!priv->lr_clk_active) {
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
			wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2,
					  WM8350_LRC_ADC_SEL);
		else
			wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2,
					WM8350_LRC_ADC_SEL);
	}
	priv->lr_clk_active++;
	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
		priv->capture_active = 1;
	else
		priv->playback_active = 1;
	return 0;
}
static void imx_3stack_shutdown(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_codec *codec = rtd->socdev->card->codec;
	struct snd_soc_dai_link *machine = rtd->dai;
	struct snd_soc_dai *codec_dai = machine->codec_dai;
	struct imx_3stack_priv *priv = &machine_priv;
	struct wm8350 *wm8350 = codec->control_data;

	/* disable the PLL if there are no active Tx or Rx channels */
	if (!codec_dai->active)
		snd_soc_dai_set_pll(codec_dai, 0, 0, 0);
	priv->lr_clk_active--;

	/*
	 * We need to keep track of active streams in master mode and
	 * switch LRC source if necessary.
	 */

	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
		priv->capture_active = 0;
	else
		priv->playback_active = 0;

	if (priv->capture_active)
		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2,
				WM8350_LRC_ADC_SEL);
	else if (priv->playback_active)
		wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2,
				  WM8350_LRC_ADC_SEL);
}
Exemple #5
0
static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
{
	int reg = 0, ret;

	switch (dcdc) {
	case WM8350_DCDC_1:
		reg = WM8350_DCDC1_FORCE_PWM;
		break;
	case WM8350_DCDC_3:
		reg = WM8350_DCDC3_FORCE_PWM;
		break;
	case WM8350_DCDC_4:
		reg = WM8350_DCDC4_FORCE_PWM;
		break;
	case WM8350_DCDC_6:
		reg = WM8350_DCDC6_FORCE_PWM;
		break;
	default:
		return -EINVAL;
	}

	if (enable)
		ret = wm8350_set_bits(wm8350, reg,
			WM8350_DCDC1_FORCE_PWM_ENA);
	else
		ret = wm8350_clear_bits(wm8350, reg,
			WM8350_DCDC1_FORCE_PWM_ENA);
	return ret;
}
Exemple #6
0
static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert)
{
	if (invert == WM8350_GPIO_INVERT_ON)
		return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio);
	else
		return wm8350_clear_bits(wm8350,
					 WM8350_GPIO_INT_MODE, 1 << gpio);
}
Exemple #7
0
static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
{
	if (db == WM8350_GPIO_DEBOUNCE_ON)
		return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
				       1 << gpio);
	else
		return wm8350_clear_bits(wm8350,
					 WM8350_GPIO_DEBOUNCE, 1 << gpio);
}
Exemple #8
0
static int wm8350_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int dcdc = rdev_get_id(rdev);
	u16 val;

	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
		return -EINVAL;

	if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
		return -EINVAL;

	val = 1 << (dcdc - WM8350_DCDC_1);

	switch (mode) {
	case REGULATOR_MODE_FAST:
		/* force continuous mode */
		wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
		force_continuous_enable(wm8350, dcdc, 1);
		break;
	case REGULATOR_MODE_NORMAL:
		/* active / pulse skipping */
		wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
		force_continuous_enable(wm8350, dcdc, 0);
		break;
	case REGULATOR_MODE_IDLE:
		/* standby mode */
		force_continuous_enable(wm8350, dcdc, 0);
		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
		wm8350_clear_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
		break;
	case REGULATOR_MODE_STANDBY:
		/* LDO mode */
		force_continuous_enable(wm8350, dcdc, 0);
		wm8350_set_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
		break;
	}

	return 0;
}
Exemple #9
0
static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down)
{
	if (down)
		return wm8350_set_bits(wm8350,
				       WM8350_GPIO_PULL_DOWN_CONTROL,
				       1 << gpio);
	else
		return wm8350_clear_bits(wm8350,
					 WM8350_GPIO_PULL_DOWN_CONTROL,
					 1 << gpio);
}
Exemple #10
0
static int wm8350_mute(struct snd_soc_dai *dai, int mute)
{
	struct snd_soc_codec *codec = dai->codec;
	struct wm8350* wm8350 = codec->control_data;

	if (mute)
		wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
	else
		wm8350_clear_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
	return 0;
}
Exemple #11
0
static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol)
{
	if (pol == WM8350_GPIO_ACTIVE_HIGH)
		return wm8350_set_bits(wm8350,
				       WM8350_GPIO_PIN_POLARITY_TYPE,
				       1 << gpio);
	else
		return wm8350_clear_bits(wm8350,
					 WM8350_GPIO_PIN_POLARITY_TYPE,
					 1 << gpio);
}
Exemple #12
0
static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up)
{
	if (up)
		return wm8350_set_bits(wm8350,
				       WM8350_GPIO_PIN_PULL_UP_CONTROL,
				       1 << gpio);
	else
		return wm8350_clear_bits(wm8350,
					 WM8350_GPIO_PIN_PULL_UP_CONTROL,
					 1 << gpio);
}
Exemple #13
0
static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
			  int pll_id, int source, unsigned int freq_in,
			  unsigned int freq_out)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct wm8350 *wm8350 = codec->control_data;
	struct wm8350_data *priv = codec->private_data;
	struct _fll_div fll_div;
	int ret = 0;
	u16 fll_1, fll_4;

	if (freq_in == priv->fll_freq_in && freq_out == priv->fll_freq_out)
		return 0;

	/* power down FLL - we need to do this for reconfiguration */
	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4,
			  WM8350_FLL_ENA | WM8350_FLL_OSC_ENA);

	if (freq_out == 0 || freq_in == 0)
		return ret;

	ret = fll_factors(&fll_div, freq_in, freq_out);
	if (ret < 0)
		return ret;
	dev_dbg(wm8350->dev,
		"FLL in %u FLL out %u N 0x%x K 0x%x div %d ratio %d",
		freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div,
		fll_div.ratio);

	/* set up N.K & dividers */
	fll_1 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_1) &
	    ~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000);
	wm8350_codec_write(codec, WM8350_FLL_CONTROL_1,
			   fll_1 | (fll_div.div << 8) | 0x50);
	wm8350_codec_write(codec, WM8350_FLL_CONTROL_2,
			   (fll_div.ratio << 11) | (fll_div.
						    n & WM8350_FLL_N_MASK));
	wm8350_codec_write(codec, WM8350_FLL_CONTROL_3, fll_div.k);
	fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) &
	    ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF);
	wm8350_codec_write(codec, WM8350_FLL_CONTROL_4,
			   fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) |
			   (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0));

	/* power FLL on */
	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA);
	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA);

	priv->fll_freq_out = freq_out;
	priv->fll_freq_in = freq_in;

	return 0;
}
static int wm8350_ldo_disable(struct regulator_dev *rdev)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int ldo = rdev_get_id(rdev);
	u16 shift;

	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
		return -EINVAL;

	shift = (ldo - WM8350_LDO_1) + 8;
	wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
	return 0;
}
Exemple #15
0
static int wm8350_isink_disable(struct regulator_dev *rdev)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int isink = rdev_get_id(rdev);

	switch (isink) {
	case WM8350_ISINK_A:
		switch (wm8350->pmic.isink_A_dcdc) {
		case WM8350_DCDC_2:
		case WM8350_DCDC_5:
			wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
					  1 << (wm8350->pmic.isink_A_dcdc -
						WM8350_DCDC_1));
			wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
					  WM8350_CS1_ENA);
			break;
		default:
			return -EINVAL;
		}
		break;
	case WM8350_ISINK_B:
		switch (wm8350->pmic.isink_B_dcdc) {
		case WM8350_DCDC_2:
		case WM8350_DCDC_5:
			wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
					  1 << (wm8350->pmic.isink_B_dcdc -
						WM8350_DCDC_1));
			wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
					  WM8350_CS2_ENA);
			break;
		default:
			return -EINVAL;
		}
		break;
	default:
		return -EINVAL;
	}
	return 0;
}
static int wm8350_dcdc_disable(struct regulator_dev *rdev)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int dcdc = rdev_get_id(rdev);
	u16 shift;

	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
		return -EINVAL;

	shift = dcdc - WM8350_DCDC_1;
	wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);

	return 0;
}
static int  wm8350_codec_remove(struct snd_soc_codec *codec)
{
	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
	struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
	int ret;

	wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
			  WM8350_JDL_ENA | WM8350_JDR_ENA);
	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);

	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICD, priv);
	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, priv);
	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv);
	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv);

	priv->hpl.jack = NULL;
	priv->hpr.jack = NULL;
	priv->mic.jack = NULL;

	/* cancel any work waiting to be queued. */
	ret = cancel_delayed_work(&codec->delayed_work);

	/* if there was any work waiting then we run it now and
	 * wait for its completion */
	if (ret) {
		schedule_delayed_work(&codec->delayed_work, 0);
		flush_scheduled_work();
	}

	wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);

	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);

	regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
	kfree(priv);
	return 0;
}
Exemple #18
0
static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
{
	int ret;

	wm8350_reg_unlock(wm8350);
	if (dir == WM8350_GPIO_DIR_OUT)
		ret = wm8350_clear_bits(wm8350,
					WM8350_GPIO_CONFIGURATION_I_O,
					1 << gpio);
	else
		ret = wm8350_set_bits(wm8350,
				      WM8350_GPIO_CONFIGURATION_I_O,
				      1 << gpio);
	wm8350_reg_lock(wm8350);
	return ret;
}
Exemple #19
0
/*
 * Set current time and date in RTC
 */
static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm)
{
	struct wm8350_rtc *wm_rtc = to_wm8350_rtc_device(dev);
	struct wm8350 *wm8350 = to_wm8350_from_rtc(wm_rtc);
	u16 time[4];
	u16 rtc_ctrl;
	int ret, retries = WM8350_SET_TIME_RETRIES;

	dbg("%s tm->tm_wday %d, tm->tm_mon %d",
	    __FUNCTION__, tm->tm_wday, tm->tm_mon);
	time[0] = tm->tm_sec;
	time[0] |= tm->tm_min << WM8350_RTC_MINS_SHIFT;
	time[1] = tm->tm_hour;
	time[1] |= (tm->tm_wday + 1) << WM8350_RTC_DAY_SHIFT;
	time[2] = tm->tm_mday;
	time[2] |= (tm->tm_mon + 1) << WM8350_RTC_MTH_SHIFT;
	time[3] = ((tm->tm_year + 1900) / 100) << WM8350_RTC_YHUNDREDS_SHIFT;
	time[3] |= (tm->tm_year + 1900) % 100;

	/* Set RTC_SET to stop the clock */
	ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_SET);
	if (ret < 0)
		return ret;

	/* Wait until confirmation of stopping */
	do {
		rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
		schedule_timeout_interruptible(msecs_to_jiffies(1));
	} while (retries-- && !(rtc_ctrl & WM8350_RTC_STS));

	if (!retries) {
		printk(KERN_ERR "wm8350-rtc time out on set confirmation\n");
		return -EIO;
	}

	/* Write time to RTC */
	ret = wm8350_block_write(wm8350, WM8350_RTC_SECONDS_MINUTES, 4, time);
	if (ret < 0)
		return ret;

	/* Clear RTC_SET to start the clock */
	ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL,
				WM8350_RTC_SET);
	return ret;
}
Exemple #20
0
/*
 * Set current time and date in RTC
 */
static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm)
{
	struct wm8350 *wm8350 = dev_get_drvdata(dev);
	u16 time[4];
	u16 rtc_ctrl;
	int ret, retries = WM8350_SET_TIME_RETRIES;

	time[0] = tm->tm_sec;
	time[0] |= tm->tm_min << WM8350_RTC_MINS_SHIFT;
	time[1] = tm->tm_hour;
	time[1] |= (tm->tm_wday + 1) << WM8350_RTC_DAY_SHIFT;
	time[2] = tm->tm_mday;
	time[2] |= (tm->tm_mon + 1) << WM8350_RTC_MTH_SHIFT;
	time[3] = ((tm->tm_year + 1900) / 100) << WM8350_RTC_YHUNDREDS_SHIFT;
	time[3] |= (tm->tm_year + 1900) % 100;

	dev_dbg(dev, "Setting: %04x %04x %04x %04x\n",
		time[0], time[1], time[2], time[3]);

	/* Set RTC_SET to stop the clock */
	ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_SET);
	if (ret < 0)
		return ret;

	/* Wait until confirmation of stopping */
	do {
		rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
		schedule_timeout_uninterruptible(msecs_to_jiffies(1));
	} while (--retries && !(rtc_ctrl & WM8350_RTC_STS));

	if (!retries) {
		dev_err(dev, "timed out on set confirmation\n");
		return -EIO;
	}

	/* Write time to RTC */
	ret = wm8350_block_write(wm8350, WM8350_RTC_SECONDS_MINUTES, 4, time);
	if (ret < 0)
		return ret;

	/* Clear RTC_SET to start the clock */
	ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL,
				WM8350_RTC_SET);
	return ret;
}
Exemple #21
0
static int wm8350_codec_io_probe(struct snd_soc_codec *codec,
	struct snd_soc_machine *machine)
{
	struct wm8350* wm8350 = codec->control_data;
	struct wm8350_out_ramp *or = codec->private_data;
	struct wm8350_output *out1 = &or->out1, *out2 = &or->out2;
	
	snd_assert(wm8350 != NULL, return -EINVAL);
	
	/* reset codec */
	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
	
	/* enable clock gen - lg need to move in new silicon */
	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_SYSCLK_ENA);

	/* charge output caps */
	codec->dapm_state = SNDRV_CTL_POWER_D3cold;
	wm8350_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
	
	wm8350_add_controls(codec, machine->card);
	wm8350_add_widgets(codec, machine);
	
	/* read OUT1 & OUT2 volumes */
	out1->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME) &
		WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
	out1->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME) &
		WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
	out2->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME) &
		WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
	out2->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME) &
		WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
	wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, 0);
	wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, 0);
	wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME, WM8350_OUT1_VU);
	wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, 0);
	wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, 0);
	wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME, WM8350_OUT2_VU);
	
	return 0;
}
Exemple #22
0
static int __exit wm8350_rtc_remove(struct platform_device *pdev)
{
	struct wm8350 *wm8350 = platform_get_drvdata(pdev);
	struct wm8350_rtc *wm_rtc = &wm8350->rtc;
	int ret;

	if (wm_rtc->per_irq)
		free_irq(wm_rtc->per_irq, wm8350);
	wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
	wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_ALM);
	wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC);
	wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM);
	rtc_device_unregister(wm_rtc->rtc);

	ret = wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5,
				WM8350_RTC_TICK_ENA);
	if (ret < 0)
		printk(KERN_ERR "wm8350-rtc: failed to enable RTC\n");

	return 0;
}
Exemple #23
0
static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
		int pll_id, unsigned int freq_in, unsigned int freq_out)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct wm8350* wm8350 = codec->control_data;
	struct _fll_div fll_div;
	int ret = 0;
	u16 fll_1, fll_4;
	
	if (freq_out == 0 || freq_in == 0) {
		/* power down FLL */
		wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, 
			WM8350_FLL_ENA | WM8350_FLL_OSC_ENA);
		return ret;
	}
	
	ret = fll_factors(&fll_div, freq_in, freq_out);
	if (ret < 0)
		return ret;
		
	/* set up N.K & dividers */
	fll_1 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_1) & 
		~(WM8350_FLL_OUTDIV_MASK | 0xc000);
	wm8350_codec_write(codec, WM8350_FLL_CONTROL_1, 
		fll_1 | (fll_div.div << 8));
	wm8350_codec_write(codec, WM8350_FLL_CONTROL_2, 
		 (fll_div.ratio << 11) | (fll_div.n & WM8350_FLL_N_MASK));
	wm8350_codec_write(codec, WM8350_FLL_CONTROL_3, fll_div.k);
	fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) & 
		~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF);
	wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, 
		fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) | 
		(fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0));
		
	/* power FLL on */
	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA);
	/* do we need to wait here ? */
	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA);
	return 0;	
}
Exemple #24
0
static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params,
				struct snd_soc_dai *codec_dai)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct wm8350 *wm8350 = codec->control_data;
	u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
	    ~WM8350_AIF_WL_MASK;

	/* bit size */
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
		iface |= 0x1 << 10;
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		iface |= 0x2 << 10;
		break;
	case SNDRV_PCM_FORMAT_S32_LE:
		iface |= 0x3 << 10;
		break;
	}

	wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);

	/* The sloping stopband filter is recommended for use with
	 * lower sample rates to improve performance.
	 */
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		if (params_rate(params) < 24000)
			wm8350_set_bits(wm8350, WM8350_DAC_MUTE_VOLUME,
					WM8350_DAC_SB_FILT);
		else
			wm8350_clear_bits(wm8350, WM8350_DAC_MUTE_VOLUME,
					  WM8350_DAC_SB_FILT);
	}

	return 0;
}
Exemple #25
0
static int wm8350_rtc_start_alarm(struct wm8350 *wm8350)
{
	int ret;
	int retries = WM8350_SET_ALM_RETRIES;
	u16 rtc_ctrl;

	ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL,
				WM8350_RTC_ALMSET);
	if (ret < 0)
		return ret;

	/* Wait until confirmation */
	do {
		rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
		schedule_timeout_uninterruptible(msecs_to_jiffies(1));
	} while (retries-- && rtc_ctrl & WM8350_RTC_ALMSTS);

	if (rtc_ctrl & WM8350_RTC_ALMSTS)
		return -ETIMEDOUT;

	return 0;
}
/**
 * wm8350_mic_jack_detect - Enable microphone jack detection.
 *
 * @codec:         WM8350 codec
 * @jack:          jack to report detection events on
 * @detect_report: value to report when presence detected
 * @short_report:  value to report when microphone short detected
 *
 * Enables the microphone jack detection of the WM8350.  If both reports
 * are specified as zero then detection is disabled.
 */
int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
			   struct snd_soc_jack *jack,
			   int detect_report, int short_report)
{
	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
	struct wm8350 *wm8350 = codec->control_data;

	priv->mic.jack = jack;
	priv->mic.report = detect_report;
	priv->mic.short_report = short_report;

	if (detect_report || short_report) {
		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_1,
				WM8350_MIC_DET_ENA);
	} else {
		wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_1,
				  WM8350_MIC_DET_ENA);
	}

	return 0;
}
Exemple #27
0
/*
 * Set alarm time and date in RTC
 */
static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	struct wm8350_rtc *wm_rtc = to_wm8350_rtc_device(dev);
	struct wm8350 *wm8350 = to_wm8350_from_rtc(wm_rtc);
	struct rtc_time *tm = &alrm->time;
	u16 rtc_ctrl;
	u16 time[3];
	int ret, retries = WM8350_SET_ALM_RETRIES;

	time[0] = tm->tm_sec;
	time[0] |= tm->tm_min << WM8350_RTC_ALMMINS_SHIFT;
	time[1] = tm->tm_hour;
	time[1] |= WM8350_RTC_ALMDAY_MASK;
	time[2] = WM8350_RTC_ALMDATE_MASK;
	time[2] |= WM8350_RTC_ALMMTH_MASK;

	/* Set RTC_SET to stop the clock */
	ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL,
			      WM8350_RTC_ALMSET);
	if (ret < 0)
		return ret;

	/* Wait until confirmation of stopping */
	do {
		rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
		schedule_timeout_interruptible(msecs_to_jiffies(1));
	} while (retries-- && !(rtc_ctrl & WM8350_RTC_ALMSTS));

	/* Write time to RTC */
	ret = wm8350_block_write(wm8350, WM8350_ALARM_SECONDS_MINUTES,
				 3, time);
	if (ret < 0)
		return ret;

	/* Clear RTC_ALMSET to enable the alarm */
	ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL,
				WM8350_RTC_ALMSET);
	return ret;
}
/**
 * wm8350_hp_jack_detect - Enable headphone jack detection.
 *
 * @codec:  WM8350 codec
 * @which:  left or right jack detect signal
 * @jack:   jack to report detection events on
 * @report: value to report
 *
 * Enables the headphone jack detection of the WM8350.  If no report
 * is specified then detection is disabled.
 */
int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
			  struct snd_soc_jack *jack, int report)
{
	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
	struct wm8350 *wm8350 = codec->control_data;
	int irq;
	int ena;

	switch (which) {
	case WM8350_JDL:
		priv->hpl.jack = jack;
		priv->hpl.report = report;
		irq = WM8350_IRQ_CODEC_JCK_DET_L;
		ena = WM8350_JDL_ENA;
		break;

	case WM8350_JDR:
		priv->hpr.jack = jack;
		priv->hpr.report = report;
		irq = WM8350_IRQ_CODEC_JCK_DET_R;
		ena = WM8350_JDR_ENA;
		break;

	default:
		return -EINVAL;
	}

	if (report) {
		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
		wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena);
	} else {
		wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, ena);
	}

	/* Sync status */
	wm8350_hp_jack_handler(irq + wm8350->irq_base, priv);

	return 0;
}
Exemple #29
0
static int wm8350_rtc_probe(struct platform_device *pdev)
{
	struct wm8350 *wm8350 = platform_get_drvdata(pdev);
	struct wm8350_rtc *wm_rtc = &wm8350->rtc;
	int ret = 0;
	u16 timectl, power5;

	timectl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
	if (timectl & WM8350_RTC_BCD) {
		dev_err(&pdev->dev, "RTC BCD mode not supported\n");
		return -EINVAL;
	}
	if (timectl & WM8350_RTC_12HR) {
		dev_err(&pdev->dev, "RTC 12 hour mode not supported\n");
		return -EINVAL;
	}

	/* enable the RTC if it's not already enabled */
	power5 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
	if (!(power5 &  WM8350_RTC_TICK_ENA)) {
		dev_info(wm8350->dev, "Starting RTC\n");

		wm8350_reg_unlock(wm8350);

		ret = wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5,
				      WM8350_RTC_TICK_ENA);
		if (ret < 0) {
			dev_err(&pdev->dev, "failed to enable RTC: %d\n", ret);
			return ret;
		}

		wm8350_reg_lock(wm8350);
	}

	if (timectl & WM8350_RTC_STS) {
		int retries;

		ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL,
					WM8350_RTC_SET);
		if (ret < 0) {
			dev_err(&pdev->dev, "failed to start: %d\n", ret);
			return ret;
		}

		retries = WM8350_SET_TIME_RETRIES;
		do {
			timectl = wm8350_reg_read(wm8350,
						  WM8350_RTC_TIME_CONTROL);
		} while (timectl & WM8350_RTC_STS && --retries);

		if (retries == 0) {
			dev_err(&pdev->dev, "failed to start: timeout\n");
			return -ENODEV;
		}
	}

	device_init_wakeup(&pdev->dev, 1);

	wm_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm8350",
					&wm8350_rtc_ops, THIS_MODULE);
	if (IS_ERR(wm_rtc->rtc)) {
		ret = PTR_ERR(wm_rtc->rtc);
		dev_err(&pdev->dev, "failed to register RTC: %d\n", ret);
		return ret;
	}

	wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC,
			    wm8350_rtc_update_handler, 0,
			    "RTC Seconds", wm8350);
	wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);

	wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM,
			    wm8350_rtc_alarm_handler, 0,
			    "RTC Alarm", wm8350);

	return 0;
}
Exemple #30
0
static int wm8350_dapm_event(struct snd_soc_codec *codec, int event)
{
	struct wm8350 *wm8350 = codec->control_data;
	struct wm8350_audio_platform_data *platform = codec->platform_data;
	u16 pm1;
	
	snd_assert(wm8350 != NULL, return -EINVAL);
	snd_assert(platform != NULL, return -EINVAL);

	switch (event) {
	case SNDRV_CTL_POWER_D0: /* full On */
		/* set vmid to 10k and current to 1.0x */
		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & 
			~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, 
			pm1 | WM8350_VMID_10K | 
			platform->codec_current_d0 << 14);
		break;
	case SNDRV_CTL_POWER_D1: /* partial On */
	case SNDRV_CTL_POWER_D2: /* partial On */
		/* set vmid to 40k for quick power up */
		if (codec->dapm_state == SNDRV_CTL_POWER_D3hot) {
			/* D3hot --> D0 */
			/* enable bias */
			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1);
			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, 
				pm1 | WM8350_BIASEN); 
		}
		break;
	case SNDRV_CTL_POWER_D3hot: /* Off, with power */
		if (codec->dapm_state == SNDRV_CTL_POWER_D3cold) {
			/* D3cold --> D3hot */
			/* mute DAC & outputs */
			wm8350_set_bits(wm8350, WM8350_DAC_MUTE, 
				WM8350_DAC_MUTE_ENA);
	
			/* discharge cap memory */
			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 
				platform->dis_out1 | 
				(platform->dis_out2 << 2) |
				(platform->dis_out3 << 4) | 
				(platform->dis_out4 << 6));
			
			/* wait for discharge */
			schedule_timeout_interruptible(msecs_to_jiffies(
				platform->cap_discharge_msecs));
			
			/* enable antipop */
			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 
				(platform->vmid_s_curve << 8)); 
		
			/* ramp up vmid */
			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, 
				(platform->codec_current_charge << 14) |
				WM8350_VMID_10K | WM8350_VMIDEN | WM8350_VBUFEN);
			
			/* wait for vmid */
			schedule_timeout_interruptible(msecs_to_jiffies(
				platform->vmid_charge_msecs));
			
			/* turn on vmid 500k  */
			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & 
				~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, 
				pm1 | WM8350_VMID_500K | 
				(platform->codec_current_d3 << 14));
						
			/* disable antipop */
			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0);

		} else {
			/* D1,D2 --> D3hot */
			/* turn on vmid 500k and reduce current */
			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & 
			~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, 
				pm1 | WM8350_VMID_500K | 
				(platform->codec_current_d3 << 14));
				
			/* disable bias */
			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & 
				~WM8350_BIASEN;
			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, 
				pm1); 
		}
	
		break;
	case SNDRV_CTL_POWER_D3cold: /* Off, without power */

		/* mute DAC & enable outputs */
		wm8350_set_bits(wm8350, WM8350_DAC_MUTE, 
			WM8350_DAC_MUTE_ENA);

		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_3, 
			WM8350_OUT1L_ENA | WM8350_OUT1R_ENA | 
			WM8350_OUT2L_ENA | WM8350_OUT2R_ENA);

		/* enable anti pop S curve */ 
		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
			(platform->vmid_s_curve << 8));
			
		/* turn off vmid  */
		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & 
				~WM8350_VMIDEN;
		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);		

		/* wait */
		schedule_timeout_interruptible(msecs_to_jiffies(
			platform->vmid_discharge_msecs));

		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
			(platform->vmid_s_curve << 8) | 
			platform->dis_out1 | 
			(platform->dis_out2 << 2) |
			(platform->dis_out3 << 4) | 
			(platform->dis_out4 << 6));

		/* turn off VBuf and drain */
		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & 
				~(WM8350_VBUFEN | WM8350_VMID_MASK);
		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, 
			pm1 | WM8350_OUTPUT_DRAIN_EN);
			
		/* wait */
		schedule_timeout_interruptible(msecs_to_jiffies(
			platform->drain_msecs));
		
		/* disable anti-pop */	
		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0);
		
		wm8350_clear_bits(wm8350, WM8350_LOUT1_VOLUME, 
			WM8350_OUT1L_ENA);
		wm8350_clear_bits(wm8350, WM8350_ROUT1_VOLUME, 
			WM8350_OUT1R_ENA);
		wm8350_clear_bits(wm8350, WM8350_LOUT2_VOLUME, 
			WM8350_OUT2L_ENA);
		wm8350_clear_bits(wm8350, WM8350_ROUT2_VOLUME, 
			WM8350_OUT2R_ENA);
	
		/* disable clock gen */
		wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_SYSCLK_ENA);
				
		break;
	}
	codec->dapm_state = event;
	return 0;
}