Esempio n. 1
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;
}
Esempio n. 2
0
int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
			   u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,
			   u16 drive)
{
	switch (isink) {
	case WM8350_ISINK_A:
		wm8350_reg_write(wm8350, WM8350_CSA_FLASH_CONTROL,
				 (mode ? WM8350_CS1_FLASH_MODE : 0) |
				 (trigger ? WM8350_CS1_TRIGSRC : 0) |
				 duration | on_ramp | off_ramp | drive);
		break;
	case WM8350_ISINK_B:
		wm8350_reg_write(wm8350, WM8350_CSB_FLASH_CONTROL,
				 (mode ? WM8350_CS2_FLASH_MODE : 0) |
				 (trigger ? WM8350_CS2_TRIGSRC : 0) |
				 duration | on_ramp | off_ramp | drive);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}
Esempio n. 3
0
static int wm8350_dcdc_set_suspend_disable(struct regulator_dev *rdev)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int dcdc = rdev_get_id(rdev);
	u16 val;

	switch (dcdc) {
	case WM8350_DCDC_1:
		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
		wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
				 val | WM8350_DCDC_HIB_MODE_DIS);
		break;
	case WM8350_DCDC_3:
		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
		wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
				 val | WM8350_DCDC_HIB_MODE_DIS);
		break;
	case WM8350_DCDC_4:
		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
		wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
				 val | WM8350_DCDC_HIB_MODE_DIS);
		break;
	case WM8350_DCDC_6:
		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
		wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
				 val | WM8350_DCDC_HIB_MODE_DIS);
		break;
	case WM8350_DCDC_2:
	case WM8350_DCDC_5:
	default:
		return -EINVAL;
	}

	return 0;
}
Esempio n. 4
0
static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
				  int max_uV, unsigned *selector)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
		max_mV = max_uV / 1000;
	u16 val;

	if (min_mV < 900 || min_mV > 3300)
		return -EINVAL;
	if (max_mV < 900 || max_mV > 3300)
		return -EINVAL;

	if (min_mV < 1800) {
		/* step size is 50mV < 1800mV */
		mV = (min_mV - 851) / 50;
		if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
			return -EINVAL;
		BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
	} else {
		/* step size is 100mV > 1800mV */
		mV = ((min_mV - 1701) / 100) + 16;
		if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
			return -EINVAL;
		BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
	}

	switch (ldo) {
	case WM8350_LDO_1:
		volt_reg = WM8350_LDO1_CONTROL;
		break;
	case WM8350_LDO_2:
		volt_reg = WM8350_LDO2_CONTROL;
		break;
	case WM8350_LDO_3:
		volt_reg = WM8350_LDO3_CONTROL;
		break;
	case WM8350_LDO_4:
		volt_reg = WM8350_LDO4_CONTROL;
		break;
	default:
		return -EINVAL;
	}

	*selector = mV;

	/* all LDOs have same mV bits */
	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
	wm8350_reg_write(wm8350, volt_reg, val | mV);
	return 0;
}
Esempio n. 5
0
static int wm8350_wdt_kick(struct wm8350 *wm8350)
{
	int ret;
	u16 reg;

	mutex_lock(&wdt_mutex);

	reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
	ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);

	mutex_unlock(&wdt_mutex);

	return ret;
}
Esempio n. 6
0
static int wm8350_wdt_ping(struct watchdog_device *wdt_dev)
{
	struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
	int ret;
	u16 reg;

	mutex_lock(&wdt_mutex);

	reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
	ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);

	mutex_unlock(&wdt_mutex);

	return ret;
}
Esempio n. 7
0
static int wm8350_dcdc25_set_suspend_disable(struct regulator_dev *rdev)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int dcdc = rdev_get_id(rdev);
	u16 val;

	switch (dcdc) {
	case WM8350_DCDC_2:
		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
		    & ~WM8350_DC2_HIB_MODE_MASK;
		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
		    (WM8350_DC2_HIB_MODE_DISABLE << WM8350_DC2_HIB_MODE_SHIFT));
		break;
	case WM8350_DCDC_5:
		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
		    & ~WM8350_DC5_HIB_MODE_MASK;
		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
		    (WM8350_DC5_HIB_MODE_DISABLE << WM8350_DC5_HIB_MODE_SHIFT));
		break;
	default:
		return -EINVAL;
	}
	return 0;
}
Esempio n. 8
0
static int wm8350_rtc_set_pie(struct wm8350_rtc *wm_rtc, unsigned long freq)
{
	struct wm8350 *wm8350 = to_wm8350_from_rtc(wm_rtc);
	int ret, power;
	u16 reg;

	power = ffs(freq);
	if ((power == fls(freq)) && freq < 1025) {
		wm_rtc->pie_freq = freq;
		reg = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
		reg &= ~WM8350_RTC_DSW_MASK;
		reg |= (power + 1) << WM8350_RTC_DSW_SHIFT;
		ret = wm8350_reg_write(wm8350, WM8350_RTC_TIME_CONTROL, reg);
		return ret;
	}
	return -EINVAL;
}
Esempio n. 9
0
int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
			 u16 stop, u16 fault)
{
	int slot_reg;
	u16 val;

	dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
		__func__, dcdc, start, stop);

	/* slot valid ? */
	if (start > 15 || stop > 15)
		return -EINVAL;

	switch (dcdc) {
	case WM8350_DCDC_1:
		slot_reg = WM8350_DCDC1_TIMEOUTS;
		break;
	case WM8350_DCDC_2:
		slot_reg = WM8350_DCDC2_TIMEOUTS;
		break;
	case WM8350_DCDC_3:
		slot_reg = WM8350_DCDC3_TIMEOUTS;
		break;
	case WM8350_DCDC_4:
		slot_reg = WM8350_DCDC4_TIMEOUTS;
		break;
	case WM8350_DCDC_5:
		slot_reg = WM8350_DCDC5_TIMEOUTS;
		break;
	case WM8350_DCDC_6:
		slot_reg = WM8350_DCDC6_TIMEOUTS;
		break;
	default:
		return -EINVAL;
	}

	val = wm8350_reg_read(wm8350, slot_reg) &
	    ~(WM8350_DC1_ENSLOT_MASK | WM8350_DC1_SDSLOT_MASK |
	      WM8350_DC1_ERRACT_MASK);
	wm8350_reg_write(wm8350, slot_reg,
			 val | (start << WM8350_DC1_ENSLOT_SHIFT) |
			 (stop << WM8350_DC1_SDSLOT_SHIFT) |
			 (fault << WM8350_DC1_ERRACT_SHIFT));

	return 0;
}
Esempio n. 10
0
static int wm8350_wdt_stop(struct wm8350 *wm8350)
{
	int ret;
	u16 reg;

	mutex_lock(&wdt_mutex);
	wm8350_reg_unlock(wm8350);

	reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
	reg &= ~WM8350_WDOG_MODE_MASK;
	ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);

	wm8350_reg_lock(wm8350);
	mutex_unlock(&wdt_mutex);

	return ret;
}
Esempio n. 11
0
static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
				   int max_uV, unsigned *selector)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int volt_reg, dcdc = rdev_get_id(rdev), mV,
		min_mV = min_uV / 1000, max_mV = max_uV / 1000;
	u16 val;

	if (min_mV < 850 || min_mV > 4025)
		return -EINVAL;
	if (max_mV < 850 || max_mV > 4025)
		return -EINVAL;

	/* step size is 25mV */
	mV = (min_mV - 826) / 25;
	if (wm8350_dcdc_val_to_mvolts(mV) > max_mV)
		return -EINVAL;
	BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV);

	switch (dcdc) {
	case WM8350_DCDC_1:
		volt_reg = WM8350_DCDC1_CONTROL;
		break;
	case WM8350_DCDC_3:
		volt_reg = WM8350_DCDC3_CONTROL;
		break;
	case WM8350_DCDC_4:
		volt_reg = WM8350_DCDC4_CONTROL;
		break;
	case WM8350_DCDC_6:
		volt_reg = WM8350_DCDC6_CONTROL;
		break;
	case WM8350_DCDC_2:
	case WM8350_DCDC_5:
	default:
		return -EINVAL;
	}

	*selector = mV;

	/* all DCDCs have same mV bits */
	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
	wm8350_reg_write(wm8350, volt_reg, val | mV);
	return 0;
}
Esempio n. 12
0
static int wm8350_wdt_set_timeout(struct wm8350 *wm8350, u16 value)
{
	int ret;
	u16 reg;

	mutex_lock(&wdt_mutex);
	wm8350_reg_unlock(wm8350);

	reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
	reg &= ~WM8350_WDOG_TO_MASK;
	reg |= value;
	ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);

	wm8350_reg_lock(wm8350);
	mutex_unlock(&wdt_mutex);

	return ret;
}
Esempio n. 13
0
static int wm8350_wdt_stop(struct watchdog_device *wdt_dev)
{
	struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
	int ret;
	u16 reg;

	mutex_lock(&wdt_mutex);
	wm8350_reg_unlock(wm8350);

	reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
	reg &= ~WM8350_WDOG_MODE_MASK;
	ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);

	wm8350_reg_lock(wm8350);
	mutex_unlock(&wdt_mutex);

	return ret;
}
Esempio n. 14
0
static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev);
	u16 val;

	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV);

	if (mV && (mV < 850 || mV > 4025)) {
		dev_err(wm8350->dev,
			"DCDC%d suspend voltage %d mV out of range\n",
			dcdc, mV);
		return -EINVAL;
	}
	if (mV == 0)
		mV = 850;

	switch (dcdc) {
	case WM8350_DCDC_1:
		volt_reg = WM8350_DCDC1_LOW_POWER;
		break;
	case WM8350_DCDC_3:
		volt_reg = WM8350_DCDC3_LOW_POWER;
		break;
	case WM8350_DCDC_4:
		volt_reg = WM8350_DCDC4_LOW_POWER;
		break;
	case WM8350_DCDC_6:
		volt_reg = WM8350_DCDC6_LOW_POWER;
		break;
	case WM8350_DCDC_2:
	case WM8350_DCDC_5:
	default:
		return -EINVAL;
	}

	/* all DCDCs have same mV bits */
	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
	wm8350_reg_write(wm8350, volt_reg,
			 val | wm8350_dcdc_mvolts_to_val(mV));
	return 0;
}
Esempio n. 15
0
static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev);
	u16 val;

	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV);

	if (mV < 900 || mV > 3300) {
		dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n",
			ldo, mV);
		return -EINVAL;
	}

	switch (ldo) {
	case WM8350_LDO_1:
		volt_reg = WM8350_LDO1_LOW_POWER;
		break;
	case WM8350_LDO_2:
		volt_reg = WM8350_LDO2_LOW_POWER;
		break;
	case WM8350_LDO_3:
		volt_reg = WM8350_LDO3_LOW_POWER;
		break;
	case WM8350_LDO_4:
		volt_reg = WM8350_LDO4_LOW_POWER;
		break;
	default:
		return -EINVAL;
	}

	/* all LDOs have same mV bits */
	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
	wm8350_reg_write(wm8350, volt_reg,
			 val | wm8350_ldo_mvolts_to_val(mV));
	return 0;
}
Esempio n. 16
0
static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
	int sel, volt_reg, dcdc = rdev_get_id(rdev);
	u16 val;

	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, uV / 1000);

	switch (dcdc) {
	case WM8350_DCDC_1:
		volt_reg = WM8350_DCDC1_LOW_POWER;
		break;
	case WM8350_DCDC_3:
		volt_reg = WM8350_DCDC3_LOW_POWER;
		break;
	case WM8350_DCDC_4:
		volt_reg = WM8350_DCDC4_LOW_POWER;
		break;
	case WM8350_DCDC_6:
		volt_reg = WM8350_DCDC6_LOW_POWER;
		break;
	case WM8350_DCDC_2:
	case WM8350_DCDC_5:
	default:
		return -EINVAL;
	}

	sel = regulator_map_voltage_linear(rdev, uV, uV);
	if (sel < 0)
		return sel;

	/* all DCDCs have same mV bits */
	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
	wm8350_reg_write(wm8350, volt_reg, val | sel);
	return 0;
}
Esempio n. 17
0
static  int wm8350_codec_probe(struct snd_soc_codec *codec)
{
	struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
	struct wm8350_data *priv;
	struct wm8350_output *out1;
	struct wm8350_output *out2;
	int ret, i;

	if (wm8350->codec.platform_data == NULL) {
		dev_err(codec->dev, "No audio platform data supplied\n");
		return -EINVAL;
	}

	priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
	if (priv == NULL)
		return -ENOMEM;
	snd_soc_codec_set_drvdata(codec, priv);

	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
		priv->supplies[i].supply = supply_names[i];

	ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
				 priv->supplies);
	if (ret != 0)
		goto err_priv;

	wm8350->codec.codec = codec;
	codec->control_data = wm8350;

	/* Put the codec into reset if it wasn't already */
	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);

	INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);

	/* Enable the codec */
	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);

	/* Enable robust clocking mode in ADC */
	wm8350_codec_write(codec, WM8350_SECURITY, 0xa7);
	wm8350_codec_write(codec, 0xde, 0x13);
	wm8350_codec_write(codec, WM8350_SECURITY, 0);

	/* read OUT1 & OUT2 volumes */
	out1 = &priv->out1;
	out2 = &priv->out2;
	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_reg_write(wm8350, WM8350_LOUT2_VOLUME, 0);
	wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, 0);

	/* Latch VU bits & mute */
	wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME,
			WM8350_OUT1_VU | WM8350_OUT1L_MUTE);
	wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME,
			WM8350_OUT2_VU | WM8350_OUT2L_MUTE);
	wm8350_set_bits(wm8350, WM8350_ROUT1_VOLUME,
			WM8350_OUT1_VU | WM8350_OUT1R_MUTE);
	wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME,
			WM8350_OUT2_VU | WM8350_OUT2R_MUTE);

	/* Make sure jack detect is disabled to start off with */
	wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
			  WM8350_JDL_ENA | WM8350_JDR_ENA);

	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
			    wm8350_hp_jack_handler, 0, "Left jack detect",
			    priv);
	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
			    wm8350_hp_jack_handler, 0, "Right jack detect",
			    priv);
	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD,
			    wm8350_mic_handler, 0, "Microphone short", priv);
	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
			    wm8350_mic_handler, 0, "Microphone detect", priv);


	snd_soc_add_controls(codec, wm8350_snd_controls,
				ARRAY_SIZE(wm8350_snd_controls));
	wm8350_add_widgets(codec);

	wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

	return 0;

err_priv:
	kfree(priv);
	return ret;
}
Esempio n. 18
0
static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
{
	u16 reg;

	wm8350_reg_unlock(wm8350);
	switch (gpio) {
	case 0:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
		    & ~WM8350_GP0_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
				 reg | ((func & 0xf) << 0));
		break;
	case 1:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
		    & ~WM8350_GP1_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
				 reg | ((func & 0xf) << 4));
		break;
	case 2:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
		    & ~WM8350_GP2_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
				 reg | ((func & 0xf) << 8));
		break;
	case 3:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
		    & ~WM8350_GP3_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
				 reg | ((func & 0xf) << 12));
		break;
	case 4:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
		    & ~WM8350_GP4_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
				 reg | ((func & 0xf) << 0));
		break;
	case 5:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
		    & ~WM8350_GP5_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
				 reg | ((func & 0xf) << 4));
		break;
	case 6:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
		    & ~WM8350_GP6_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
				 reg | ((func & 0xf) << 8));
		break;
	case 7:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
		    & ~WM8350_GP7_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
				 reg | ((func & 0xf) << 12));
		break;
	case 8:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
		    & ~WM8350_GP8_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
				 reg | ((func & 0xf) << 0));
		break;
	case 9:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
		    & ~WM8350_GP9_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
				 reg | ((func & 0xf) << 4));
		break;
	case 10:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
		    & ~WM8350_GP10_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
				 reg | ((func & 0xf) << 8));
		break;
	case 11:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
		    & ~WM8350_GP11_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
				 reg | ((func & 0xf) << 12));
		break;
	case 12:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
		    & ~WM8350_GP12_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
				 reg | ((func & 0xf) << 0));
		break;
	default:
		wm8350_reg_lock(wm8350);
		return -EINVAL;
	}

	wm8350_reg_lock(wm8350);
	return 0;
}
Esempio n. 19
0
//static int wm8350_init(struct wm8350 *wm8350)
int wm8350_dev_init(struct wm8350 *wm8350)
{
	int i, ret;
	u16 data;

#if 0
	/* dont assert RTS when hibernating */
	wm8350_set_bits(wm8350, WM8350_SYSTEM_HIBERNATE, WM8350_RST_HIB_MODE);
#endif

	wm8350_reg_unlock(wm8350);
	wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, WM8350_IRQ_POL);
	wm8350_reg_lock(wm8350);

	s3c2410_gpio_pullup(S3C2410_GPF1, 0);
	s3c2410_gpio_cfgpin(S3C2410_GPF1, S3C2410_GPF1_EINT1);
//	set_irq_type(IRQ_EINT1, IRQT_BOTHEDGE);
	s3c2410_gpio_pullup(S3C2410_GPF2, 0);
	s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);

	/* Shutdown threshold value 3.1v off , 3.2v on */
	wm8350_reg_unlock(wm8350);
	data = wm8350_reg_read(wm8350, WM8350_POWER_CHECK_COMPARATOR)
		& ~(WM8350_PCCMP_OFF_THR_MASK | WM8350_PCCMP_ON_THR_MASK);
	wm8350_reg_write(wm8350, WM8350_POWER_CHECK_COMPARATOR, data | 0x23);
	wm8350_reg_lock(wm8350);

	data = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_2);
	wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_2, data | WM8350_AUXADC_CAL);

	config_s3c_wm8350_gpio(wm8350);

#if 0
	/* Sw1 --> PWR_ON */
	wm8350_register_irq(wm8350, WM8350_IRQ_WKUP_ONKEY,
			    imx32ads_switch_handler, NULL);
	wm8350_unmask_irq(wm8350, WM8350_IRQ_WKUP_ONKEY);
#endif

#ifndef CONFIG_MACH_CANOPUS
	for (i = 0; i < ARRAY_SIZE(wm8350_regulator_devices); i++) {
		platform_set_drvdata(&wm8350_regulator_devices[i], wm8350);
		ret = platform_device_register(&wm8350_regulator_devices[i]);
		if (ret < 0)
			goto unwind;
	}
#else	// CONFIG_MACH_CANOPUS
	struct regulator_init_data *reg_data = NULL;

	for (i = 0; i < ARRAY_SIZE(wm8350_regulator_devices); i++) {
		if (wm8350_regulator_devices[i].id == WM8350_DCDC_4) {
			// for LCD
			if (q_hw_ver(7800_ES2)
					|| q_hw_ver(7800_TP)
					|| q_hw_ver(7800_MP)) {
				reg_data = (struct regulator_init_data *)wm8350_regulator_devices[i].dev.platform_data;
				reg_data->constraints.min_uV = 3400000;
				reg_data->constraints.max_uV = 3400000;
				reg_data->constraints.state_mem.uV = 3400000;
			}
		} else if (wm8350_regulator_devices[i].id == WM8350_LDO_3) {
			// for PMIC LDO
			if (q_hw_ver(SWP2000)
					|| q_hw_ver(7800_MP2)
					|| q_hw_ver(KTQOOK_TP2)
					|| q_hw_ver(KTQOOK_MP)
					|| q_hw_ver(SKATM)) {
				reg_data = (struct regulator_init_data *)wm8350_regulator_devices[i].dev.platform_data;

				reg_data->constraints.min_uV = 1200000;
				reg_data->constraints.max_uV = 1200000;
				reg_data->num_consumer_supplies = ARRAY_SIZE(ldo4_consumers);
				reg_data->consumer_supplies = ldo4_consumers;
			}
		} else if (wm8350_regulator_devices[i].id == WM8350_LDO_4) {
			// for PMIC LDO
			if (q_hw_ver(SWP2000)
					|| q_hw_ver(7800_MP2)
					|| q_hw_ver(KTQOOK_TP2)
					|| q_hw_ver(KTQOOK_MP)
					|| q_hw_ver(SKATM)) {
				reg_data = (struct regulator_init_data *)wm8350_regulator_devices[i].dev.platform_data;
				reg_data->constraints.min_uV = 3300000;
				reg_data->constraints.max_uV = 3300000;
				reg_data->num_consumer_supplies = ARRAY_SIZE(ldo3_consumers);
				reg_data->consumer_supplies = ldo3_consumers;
			}
		}

		platform_set_drvdata(&wm8350_regulator_devices[i], wm8350);
		ret = platform_device_register(&wm8350_regulator_devices[i]);
		if (ret < 0)
			goto unwind;
	}
#endif	// CONFIG_MACH_CANOPUS

	/* now register other clients */
	return s3c_wm8350_device_register(wm8350);
unwind:
	for (i--; i >= 0; i--)
		platform_device_unregister(&wm8350_regulator_devices[i]);

	return ret;
}
Esempio n. 20
0
int wm8350_device_init(struct wm8350 *wm8350, int irq,
		       struct wm8350_platform_data *pdata)
{
	int ret;
	u16 id1, id2, mask_rev;
	u16 cust_id, mode, chip_rev;

	/* get WM8350 revision and config mode */
	ret = wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
	if (ret != 0) {
		dev_err(wm8350->dev, "Failed to read ID: %d\n", ret);
		goto err;
	}

	ret = wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
	if (ret != 0) {
		dev_err(wm8350->dev, "Failed to read ID: %d\n", ret);
		goto err;
	}

	ret = wm8350->read_dev(wm8350, WM8350_REVISION, sizeof(mask_rev),
			       &mask_rev);
	if (ret != 0) {
		dev_err(wm8350->dev, "Failed to read revision: %d\n", ret);
		goto err;
	}

	id1 = be16_to_cpu(id1);
	id2 = be16_to_cpu(id2);
	mask_rev = be16_to_cpu(mask_rev);

	if (id1 != 0x6143) {
		dev_err(wm8350->dev,
			"Device with ID %x is not a WM8350\n", id1);
		ret = -ENODEV;
		goto err;
	}

	mode = (id2 & WM8350_CONF_STS_MASK) >> 10;
	cust_id = id2 & WM8350_CUST_ID_MASK;
	chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12;
	dev_info(wm8350->dev,
		 "CONF_STS %d, CUST_ID %d, MASK_REV %d, CHIP_REV %d\n",
		 mode, cust_id, mask_rev, chip_rev);

	if (cust_id != 0) {
		dev_err(wm8350->dev, "Unsupported CUST_ID\n");
		ret = -ENODEV;
		goto err;
	}

	switch (mask_rev) {
	case 0:
		wm8350->pmic.max_dcdc = WM8350_DCDC_6;
		wm8350->pmic.max_isink = WM8350_ISINK_B;

		switch (chip_rev) {
		case WM8350_REV_E:
			dev_info(wm8350->dev, "WM8350 Rev E\n");
			break;
		case WM8350_REV_F:
			dev_info(wm8350->dev, "WM8350 Rev F\n");
			break;
		case WM8350_REV_G:
			dev_info(wm8350->dev, "WM8350 Rev G\n");
			wm8350->power.rev_g_coeff = 1;
			break;
		case WM8350_REV_H:
			dev_info(wm8350->dev, "WM8350 Rev H\n");
			wm8350->power.rev_g_coeff = 1;
			wm8350->power.policy = &pavo_charger_policy;
			break;
		default:
			/* For safety we refuse to run on unknown hardware */
			dev_err(wm8350->dev, "Unknown WM8350 CHIP_REV\n");
			ret = -ENODEV;
			goto err;
		}
		break;

	case 1:
		wm8350->pmic.max_dcdc = WM8350_DCDC_4;
		wm8350->pmic.max_isink = WM8350_ISINK_A;

		switch (chip_rev) {
		case 0:
			dev_info(wm8350->dev, "WM8351 Rev A\n");
			wm8350->power.rev_g_coeff = 1;
			break;

		case 1:
			dev_info(wm8350->dev, "WM8351 Rev B\n");
			wm8350->power.rev_g_coeff = 1;
			break;

		default:
			dev_err(wm8350->dev, "Unknown WM8351 CHIP_REV\n");
			ret = -ENODEV;
			goto err;
		}
		break;

	case 2:
		wm8350->pmic.max_dcdc = WM8350_DCDC_6;
		wm8350->pmic.max_isink = WM8350_ISINK_B;

		switch (chip_rev) {
		case 0:
			dev_info(wm8350->dev, "WM8352 Rev A\n");
			wm8350->power.rev_g_coeff = 1;
			break;

		default:
			dev_err(wm8350->dev, "Unknown WM8352 CHIP_REV\n");
			ret = -ENODEV;
			goto err;
		}
		break;

	default:
		dev_err(wm8350->dev, "Unknown MASK_REV\n");
		ret = -ENODEV;
		goto err;
	}

	ret = wm8350_create_cache(wm8350, mask_rev, mode);
	if (ret < 0) {
		dev_err(wm8350->dev, "Failed to create register cache\n");
		return ret;
	}

	wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
	wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
	wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
	wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
	wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
	wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
	
	wm8350_set_bits(wm8350,0xb0,0x1<<0x1);
        wm8350_set_bits(wm8350,0xb8,0x1<<10);

	mutex_init(&wm8350->auxadc_mutex);
	mutex_init(&wm8350->irq_mutex);
	INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
	if (irq) {
		ret = request_irq(irq, wm8350_irq, 0,
				  "wm8350", wm8350);
		if (ret != 0) {
			dev_err(wm8350->dev, "Failed to request IRQ: %d\n",
				ret);
			goto err;
		}
	} else {
		dev_err(wm8350->dev, "No IRQ configured\n");
		goto err;
	}
	wm8350->chip_irq = irq;

	if (pdata && pdata->init) {
		ret = pdata->init(wm8350);
		if (ret != 0) {
			dev_err(wm8350->dev, "Platform init() failed: %d\n",
				ret);
			goto err;
		}
	}

	wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0);

	wm8350_client_dev_register(wm8350, "wm8350-codec",
				   &(wm8350->codec.pdev));
	wm8350_client_dev_register(wm8350, "wm8350-gpio",
				   &(wm8350->gpio.pdev));
	wm8350_client_dev_register(wm8350, "wm8350-power",
				   &(wm8350->power.pdev));
	wm8350_client_dev_register(wm8350, "wm8350-rtc", &(wm8350->rtc.pdev));
	wm8350_client_dev_register(wm8350, "wm8350-wdt", &(wm8350->wdt.pdev));

	return 0;

err:
	kfree(wm8350->reg_cache);
	return ret;
}
Esempio n. 21
0
static int wm8350_probe(struct platform_device *pdev)
{
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
	struct snd_soc_codec *codec;
	struct wm8350 *wm8350;
	struct wm8350_data *priv;
	int ret;
	struct wm8350_output *out1;
	struct wm8350_output *out2;

	BUG_ON(!wm8350_codec);

	socdev->card->codec = wm8350_codec;
	codec = socdev->card->codec;
	wm8350 = codec->control_data;
	priv = codec->private_data;

	/* Enable the codec */
	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);

	/* Enable robust clocking mode in ADC */
	wm8350_codec_write(codec, WM8350_SECURITY, 0xa7);
	wm8350_codec_write(codec, 0xde, 0x13);
	wm8350_codec_write(codec, WM8350_SECURITY, 0);

	/* read OUT1 & OUT2 volumes */
	out1 = &priv->out1;
	out2 = &priv->out2;
	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_reg_write(wm8350, WM8350_LOUT2_VOLUME, 0);
	wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, 0);

	/* Latch VU bits & mute */
	wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME,
			WM8350_OUT1_VU | WM8350_OUT1L_MUTE);
	wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME,
			WM8350_OUT2_VU | WM8350_OUT2L_MUTE);
	wm8350_set_bits(wm8350, WM8350_ROUT1_VOLUME,
			WM8350_OUT1_VU | WM8350_OUT1R_MUTE);
	wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME,
			WM8350_OUT2_VU | WM8350_OUT2R_MUTE);

	wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
	wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
			    wm8350_hp_jack_handler, priv);
	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
			    wm8350_hp_jack_handler, priv);

	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to create pcms\n");
		return ret;
	}

	snd_soc_add_controls(codec, wm8350_snd_controls,
				ARRAY_SIZE(wm8350_snd_controls));
	wm8350_add_widgets(codec);

	wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

	return 0;
}
Esempio n. 22
0
static int wm8350_set_bias_level(struct snd_soc_codec *codec,
				 enum snd_soc_bias_level level)
{
	struct wm8350 *wm8350 = codec->control_data;
	struct wm8350_data *priv = codec->private_data;
	struct wm8350_audio_platform_data *platform =
		wm8350->codec.platform_data;
	u16 pm1;
	int ret;

	switch (level) {
	case SND_SOC_BIAS_ON:
		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_50K |
				 platform->codec_current_on << 14);
		break;

	case SND_SOC_BIAS_PREPARE:
		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1);
		pm1 &= ~WM8350_VMID_MASK;
		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
				 pm1 | WM8350_VMID_50K);
		break;

	case SND_SOC_BIAS_STANDBY:
		if (codec->bias_level == SND_SOC_BIAS_OFF) {
			ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
						    priv->supplies);
			if (ret != 0)
				return ret;

			/* Enable the system clock */
			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4,
					WM8350_SYSCLK_ENA);

			/* 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_5K | WM8350_VMIDEN |
					 WM8350_VBUFEN);

			/* wait for vmid */
			schedule_timeout_interruptible(msecs_to_jiffies
						       (platform->
							vmid_charge_msecs));

			/* turn on vmid 300k  */
			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
			    ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
			pm1 |= WM8350_VMID_300K |
				(platform->codec_current_standby << 14);
			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
					 pm1);


			/* enable analogue bias */
			pm1 |= WM8350_BIASEN;
			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);

			/* disable antipop */
			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0);

		} else {
			/* turn on vmid 300k 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_300K |
					 (platform->
					  codec_current_standby << 14));

		}
		break;

	case SND_SOC_BIAS_OFF:

		/* 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));

		pm1 &= ~WM8350_BIASEN;
		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);

		/* 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);

		regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
				       priv->supplies);
		break;
	}
	codec->bias_level = level;
	return 0;
}
Esempio n. 23
0
/*
 * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown.
 */
static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec)
{
	struct wm8350_out_ramp *or = codec->private_data;
	struct wm8350_output *output = &or->out1;
	struct wm8350 *wm8350 = codec->control_data;
	int left_complete = 0, right_complete = 0;
	u16 reg, val;
		
	/* left channel */
	reg = wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME);
	val = (reg & WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;

	if (output->ramp == WM8350_RAMP_UP) {
		/* ramp step up */
		if (val < output->left_vol) {
			val++;
			reg &= ~WM8350_OUT1L_VOL_MASK;
			wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, 
				reg | (val << WM8350_OUT1L_VOL_SHIFT));
		} else
			left_complete = 1;
	} else if (output->ramp == WM8350_RAMP_DOWN) {
		/* ramp step down */
		if (val > 0) {
			val--;
			reg &= ~WM8350_OUT1L_VOL_MASK;
			wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, 
				reg | (val << WM8350_OUT1L_VOL_SHIFT));
		} else
			left_complete = 1;
	} else
		return 1;

	/* right channel */
	reg = wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME);
	val = (reg & WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
	if (output->ramp == WM8350_RAMP_UP) {
		/* ramp step up */
		if (val < output->right_vol) {
			val++;
			reg &= ~WM8350_OUT1R_VOL_MASK;
			wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, 
				reg | (val << WM8350_OUT1R_VOL_SHIFT));
		} else
			right_complete = 1;
	} else if (output->ramp == WM8350_RAMP_DOWN) {
		/* ramp step down */
		if (val > 0) {
			val--;
			reg &= ~WM8350_OUT1R_VOL_MASK;
			wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, 
				reg | (val << WM8350_OUT1R_VOL_SHIFT));
		} else
			right_complete = 1;
	}
	
	/* only hit the update bit if either volume has changed this step */
	if (!left_complete || !right_complete) 
		wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME, WM8350_OUT1_VU);
	
	return left_complete & right_complete; 
}
Esempio n. 24
0
static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg,
	unsigned int value)
{
	struct wm8350* wm8350 = codec->control_data;
	return wm8350_reg_write(wm8350, reg, value);
}
int wm8350_init(struct wm8350 *wm8350)
{
    int ret = 0;

    /* register regulator and set constraints */
    wm8350_device_register_pmic(wm8350);
    set_regulator_constraints(wm8350);
#ifdef NOT_PORTED_TO_IMX37
    wm8350_device_register_rtc(wm8350);
    wm8350_device_register_wdg(wm8350);
    wm8350_device_register_power(wm8350);
#endif
    mxc_init_wm8350();

    /*Note: Needs to be moved into a regulator function. */
    /* Configuring -- GPIO 7 pin */
    if (wm8350_gpio_config(wm8350, 7, WM8350_GPIO_DIR_OUT, 0,
                           WM8350_GPIO_ACTIVE_LOW, WM8350_GPIO_PULL_NONE,
                           WM8350_GPIO_INVERT_OFF,
                           WM8350_GPIO_DEBOUNCE_OFF) == 0)
        wm8350_gpio_set_status(wm8350, 7, 1);
    else
        printk(KERN_ERR "Error in setting Wolfson GPIO pin 7 \n");
    /* enable gpio4:USB_VBUS_EN */
    ret =
        wm8350_gpio_config(wm8350, 4, WM8350_GPIO_DIR_IN,
                           WM8350_GPIO4_MR_IN, WM8350_GPIO_ACTIVE_HIGH,
                           WM8350_GPIO_PULL_UP, WM8350_GPIO_INVERT_OFF,
                           WM8350_GPIO_DEBOUNCE_OFF);
    if (ret)
        printk(KERN_ERR "Error in setting USB VBUS enable pin\n");

    /*PMIC RDY*/
    if (wm8350_gpio_config(wm8350, 9, WM8350_GPIO_DIR_OUT, WM8350_GPIO9_GPIO_OUT,
                           WM8350_GPIO_ACTIVE_LOW, WM8350_GPIO_PULL_NONE,
                           WM8350_GPIO_INVERT_OFF, WM8350_GPIO_DEBOUNCE_OFF) == 0)
        wm8350_gpio_set_status(wm8350, 9, 1);
    else
        printk(KERN_ERR "Error in setting Wolfson GPIO pin 9 \n");

    /* register sound */
    printk("Registering imx37_snd_device");
    imx_snd_device = platform_device_alloc("wm8350-imx-3stack-audio", -1);
    if (!imx_snd_device) {
        ret = -ENOMEM;
        goto err;
    }
    imx_snd_device->dev.platform_data = &imx_3stack_audio_platform_data;
    platform_set_drvdata(imx_snd_device, &wm8350->audio);
    ret = platform_device_add(imx_snd_device);
    if (ret)
        goto snd_err;

    /* set up PMIC IRQ (active high) to i.MX32ADS */
    printk("Registering PMIC INT");
    INIT_WORK(&wm8350->work, wm8350_irq_work);
    wm8350_reg_unlock(wm8350);
    wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, WM8350_IRQ_POL);
    wm8350_reg_lock(wm8350);
    set_irq_type(MXC_PMIC_INT_LINE, IRQT_RISING);
    ret = request_irq(MXC_PMIC_INT_LINE, wm8350_irq_handler,
                      IRQF_DISABLED, "wm8350-pmic", wm8350);
    if (ret != 0) {
        printk(KERN_ERR "wm8350: cant request irq %d\n",
               MXC_PMIC_INT_LINE);
        goto err;
    }
    wm8350->nirq = MXC_PMIC_INT_LINE;

    set_irq_wake(MXC_PMIC_INT_LINE, 1);

#ifdef NOT_PORTED_TO_IMX37
    printk("Configuring WM8350 GPIOS");
    config_gpios(wm8350);
    config_hibernate(wm8350);
#endif

    /* Sw1 --> PWR_ON */
    printk("Registering and unmasking the WM8350 wakeup key\n");
    wm8350_register_irq(wm8350, WM8350_IRQ_WKUP_ONKEY,
                        imx37_3stack_switch_handler, NULL);
    wm8350_unmask_irq(wm8350, WM8350_IRQ_WKUP_ONKEY);

    /* unmask all & clear sticky */
    printk("Unmasking WM8350 local interrupts\n");
    wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x3ffe);
    schedule_work(&wm8350->work);

#if BATTERY
    /* not much use without a battery atm */
    wm8350_init_battery(wm8350);
#endif

    printk("Exiting normally from wm8350_init()");
    return ret;
snd_err:
    platform_device_put(imx_snd_device);

err:
    printk("wm8350_init() FAILED");
    kfree(wm8350->reg_cache);
    return ret;
}
Esempio n. 26
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;
}