static void vib_set(int const new_power_state)
{
	struct twl6040 *twl6040 = misc_data->twl6040;
	u8 speed = misc_data->pdata->voltage_raise_speed;
	int ret;

	mutex_lock(&misc_data->io_mutex);

	/* already in requested state */
	if (new_power_state == misc_data->vib_power_state)
		goto out;

	/**
	 * @warning  VIBDATx registers MUST be setted BEFORE VIBENAx bit
	 *           setted in corresponding VIBCTLx registers
	 */
	if (new_power_state) {
		ret = twl6040_vib_power(true);
		if (ret)
			goto out;

		if (speed == 0x00)
			speed = 0x32;

		twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, speed);
		twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, speed);

		/*
		 * ERRATA: Disable overcurrent protection for at least
		 * 2.5ms when enabling vibrator drivers to avoid false
		 * overcurrent detection
		 */
		twl6040_set_bits(twl6040, TWL6040_REG_VIBCTLL,
				 TWL6040_VIBENAL | TWL6040_VIBCTRLLP);
		twl6040_set_bits(twl6040, TWL6040_REG_VIBCTLR,
				 TWL6040_VIBENAR | TWL6040_VIBCTRLRP);

		mdelay(4);

		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
				 TWL6040_VIBCTRLLP);
		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
				 TWL6040_VIBCTRLRP);
	} else {
		twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, 0x00);
		twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, 0x00);

		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
				   TWL6040_VIBENAL);
		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
				   TWL6040_VIBENAR);

		twl6040_vib_power(false);
	}
	misc_data->vib_power_state = new_power_state;

out:
	mutex_unlock(&misc_data->io_mutex);
}
Esempio n. 2
0
static void vib_set(int on)
{
	struct twl6040_codec *twl6040 = misc_data->twl6040;

	mutex_lock(&misc_data->io_mutex);

	/* already in requested state */
	if (misc_data->vib_power_state == on)
		goto out;

	if (on) {
		/*
		 * ERRATA: Disable overcurrent protection for at least
		 * 2.5ms when enabling vibrator drivers to avoid false
		 * overcurrent detection
		 */
		twl6040_set_bits(twl6040, TWL6040_REG_VIBCTLL,
				 TWL6040_VIBENAL | TWL6040_VIBCTRLR);
		twl6040_set_bits(twl6040, TWL6040_REG_VIBCTLR,
				 TWL6040_VIBENAR | TWL6040_VIBCTRLR);

		mdelay(4);
		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
				 TWL6040_VIBCTRLL);
		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
				 TWL6040_VIBCTRLR);
		twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, 0x26);
		twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, 0x26);

	} else {
		twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, 0x00);
		twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, 0x00);
		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
				   TWL6040_VIBENAL);
		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
				   TWL6040_VIBENAR);
	}
	misc_data->vib_power_state = on;

out:
	mutex_unlock(&misc_data->io_mutex);
}
Esempio n. 3
0
static irqreturn_t twl6040_vib_irq_handler(int irq, void *data)
{
	struct vibra_info *info = data;
	struct twl6040 *twl6040 = info->twl6040;
	u8 status;

	status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
	if (status & TWL6040_VIBLOCDET) {
		dev_warn(info->dev, "Left Vibrator overcurrent detected\n");
		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
				   TWL6040_VIBENA);
	}
	if (status & TWL6040_VIBROCDET) {
		dev_warn(info->dev, "Right Vibrator overcurrent detected\n");
		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
				   TWL6040_VIBENA);
	}

	return IRQ_HANDLED;
}
Esempio n. 4
0
static irqreturn_t twl6040_vib_irq_handler(int irq, void *data)
{
	struct vib_data *misc_data = data;
	struct twl6040_codec *twl6040 = misc_data->twl6040;
	u8 intid = 0, status = 0;

	intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);

	if (intid & TWL6040_VIBINT) {
		status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
		if (status & TWL6040_VIBLOCDET) {
			pr_warn("Vibra left overcurrent detected\n");
			twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
					   TWL6040_VIBENAL);
		}
		if (status & TWL6040_VIBROCDET) {
			pr_warn("Vibra right overcurrent detected\n");
			twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
					   TWL6040_VIBENAR);
		}
	}

	return IRQ_HANDLED;
}
Esempio n. 5
0
static int sdp4430_mcpdm_twl6040_pre(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_codec *codec = rtd->codec;
	struct twl6040 *twl6040 = codec->control_data;
	int ret;

	/* enable external 32kHz clock */
	ret = regulator_enable(twl6040_clk32kreg);
	if (ret) {
		printk(KERN_ERR "failed to enable TWL6040 CLK32K\n");
		return ret;
	}

	/* disable internal 32kHz oscillator */
	twl6040_clear_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_CLK32KSEL);

	/* TWL6040 supplies McPDM PAD_CLKS */
	return twl6040_enable(twl6040);
}
static int twl6040_power(struct twl6040 *twl6040, int enable)
{
	struct twl4030_codec_data *pdata = dev_get_platdata(twl6040->dev);
	int audpwron = twl6040->audpwron;
	int naudint = twl6040->irq;
	int ret = 0;

	if (enable) {
		/* enable 32kHz external clock */
		if (pdata->set_ext_clk32k) {
			ret = pdata->set_ext_clk32k(true);
			if (ret) {
				dev_err(twl6040->dev,
					"failed to enable CLK32K %d\n", ret);
				return ret;
			}
		}

		/* disable internal 32kHz oscillator */
		twl6040_clear_bits(twl6040, TWL6040_REG_ACCCTL,
				TWL6040_CLK32KSEL);

		if (gpio_is_valid(audpwron)) {
			/* wait for power-up completion */
			ret = twl6040_power_up_completion(twl6040, naudint);
			if (ret) {
				dev_err(twl6040->dev,
					"automatic power-down failed\n");
				return ret;
			}
		} else {
			/* use manual power-up sequence */
			ret = twl6040_power_up(twl6040);
			if (ret) {
				dev_err(twl6040->dev,
					"manual power-up failed\n");
				return ret;
			}
		}

		/* Errata: PDMCLK can fail to generate at cold temperatures
		 * The workaround consists of resetting HPPLL and LPPLL
		 * after Sleep/Deep-Sleep mode and before application mode.
		 */
		twl6040_set_bits(twl6040, TWL6040_REG_HPPLLCTL,
				TWL6040_HPLLRST);
		twl6040_clear_bits(twl6040, TWL6040_REG_HPPLLCTL,
				TWL6040_HPLLRST);
		twl6040_set_bits(twl6040, TWL6040_REG_LPPLLCTL,
				TWL6040_LPLLRST);
		twl6040_clear_bits(twl6040, TWL6040_REG_LPPLLCTL,
				TWL6040_LPLLRST);

		twl6040->pll = TWL6040_LPPLL_ID;
		twl6040->sysclk = 19200000;
	} else {
		if (gpio_is_valid(audpwron)) {
			/* use AUDPWRON line */
			gpio_set_value(audpwron, 0);

			/* power-down sequence latency */
			udelay(500);
		} else {
			/* use manual power-down sequence */
			ret = twl6040_power_down(twl6040);
			if (ret) {
				dev_err(twl6040->dev,
					"manual power-down failed\n");
				return ret;
			}
		}

		/* enable internal 32kHz oscillator */
		twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL,
				TWL6040_CLK32KSEL);

		/* disable 32kHz external clock */
		if (pdata->set_ext_clk32k) {
			ret = pdata->set_ext_clk32k(false);
			if (ret)
				dev_err(twl6040->dev,
					"failed to disable CLK32K %d\n", ret);
		}

		twl6040->pll = TWL6040_NOPLL_ID;
		twl6040->sysclk = 0;
	}

	twl6040->powered = enable;

	return ret;
}