Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 403f8234 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drivers: iio: imu: asm330 regulators"

parents 00c0876d 6a5330cd
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -210,6 +210,8 @@ struct st_asm330lhh_hw {

	const struct st_asm330lhh_transfer_function *tf;
	struct st_asm330lhh_transfer_buffer tb;
	struct regulator *vdd;
	struct regulator *vio;
};

extern const struct dev_pm_ops st_asm330lhh_pm_ops;
+135 −7
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/pm.h>
#include <linux/version.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>

#include <linux/platform_data/st_sensors_pdata.h>

@@ -707,11 +708,115 @@ static struct iio_dev *st_asm330lhh_alloc_iiodev(struct st_asm330lhh_hw *hw,
	return iio_dev;
}

static void st_asm330lhh_regulator_power_down(struct st_asm330lhh_hw *hw)
{
	regulator_disable(hw->vdd);
	regulator_set_voltage(hw->vdd, 0, INT_MAX);
	regulator_set_load(hw->vdd, 0);
	regulator_disable(hw->vio);
	regulator_set_voltage(hw->vio, 0, INT_MAX);
	regulator_set_load(hw->vio, 0);
}

static int st_asm330lhh_regulator_init(struct st_asm330lhh_hw *hw)
{
	int err = 0;

	hw->vdd  = devm_regulator_get(hw->dev, "vdd");
	if (IS_ERR(hw->vdd)) {
		err = PTR_ERR(hw->vdd);
		if (err != -EPROBE_DEFER)
			dev_err(hw->dev, "Error %d to get vdd\n", err);
		return err;
	}

	hw->vio = devm_regulator_get(hw->dev, "vio");
	if (IS_ERR(hw->vio)) {
		err = PTR_ERR(hw->vio);
		if (err != -EPROBE_DEFER)
			dev_err(hw->dev, "Error %d to get vio\n", err);
		return err;
	}
	return err;
}

static int st_asm330lhh_regulator_power_up(struct st_asm330lhh_hw *hw)
{
	u32 vdd_voltage[2] = {3000000, 3600000};
	u32 vio_voltage[2] = {1620000, 3600000};
	u32 vdd_current = 30000;
	u32 vio_current = 30000;
	int err = 0;

	/* Enable VDD for ASM330 */
	if (vdd_voltage[0] > 0 && vdd_voltage[0] <= vdd_voltage[1]) {
		err = regulator_set_voltage(hw->vdd, vdd_voltage[0],
						vdd_voltage[1]);
		if (err) {
			pr_err("Error %d during vdd set_voltage\n", err);
			return err;
		}
	}

	if (vdd_current > 0) {
		err = regulator_set_load(hw->vdd, vdd_current);
		if (err < 0) {
			pr_err("vdd regulator_set_load failed,err=%d\n", err);
			goto remove_vdd_voltage;
		}
	}

	err = regulator_enable(hw->vdd);
	if (err) {
		dev_err(hw->dev, "vdd enable failed with error %d\n", err);
		goto remove_vdd_current;
	}

	/* Enable VIO for ASM330 */
	if (vio_voltage[0] > 0 && vio_voltage[0] <= vio_voltage[1]) {
		err = regulator_set_voltage(hw->vio, vio_voltage[0],
						vio_voltage[1]);
		if (err) {
			pr_err("Error %d during vio set_voltage\n", err);
			goto disable_vdd;
		}
	}

	if (vio_current > 0) {
		err = regulator_set_load(hw->vio, vio_current);
		if (err < 0) {
			pr_err("vio regulator_set_load failed,err=%d\n", err);
			goto remove_vio_voltage;
		}
	}

	err = regulator_enable(hw->vio);
	if (err) {
		dev_err(hw->dev, "vio enable failed with error %d\n", err);
		goto remove_vio_current;
	}

	return 0;

remove_vio_current:
	regulator_set_load(hw->vio, 0);
remove_vio_voltage:
	regulator_set_voltage(hw->vio, 0, INT_MAX);
disable_vdd:
	regulator_disable(hw->vdd);
remove_vdd_current:
	regulator_set_load(hw->vdd, 0);
remove_vdd_voltage:
	regulator_set_voltage(hw->vdd, 0, INT_MAX);

	return err;
}

int st_asm330lhh_probe(struct device *dev, int irq,
		       const struct st_asm330lhh_transfer_function *tf_ops)
{
	struct st_asm330lhh_hw *hw;
	int i, err;
	int i = 0, err = 0;

	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
	if (!hw)
@@ -727,24 +832,42 @@ int st_asm330lhh_probe(struct device *dev, int irq,
	hw->tf = tf_ops;

	dev_info(hw->dev, "Ver: %s\n", ST_ASM330LHH_VERSION);

	err = st_asm330lhh_regulator_init(hw);
	if (err < 0) {
		dev_err(hw->dev, "regulator init failed\n");
		return err;
	}

	err = st_asm330lhh_regulator_power_up(hw);
	if (err < 0) {
		dev_err(hw->dev, "regulator power up failed\n");
		return err;
	}

	/* allow time for enabling regulators */
	usleep_range(1000, 2000);

	err = st_asm330lhh_check_whoami(hw);
	if (err < 0)
		return err;
		goto regulator_shutdown;

	err = st_asm330lhh_init_device(hw);
	if (err < 0)
		return err;
		goto regulator_shutdown;

	for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) {
		hw->iio_devs[i] = st_asm330lhh_alloc_iiodev(hw, i);
		if (!hw->iio_devs[i])
			return -ENOMEM;
		if (!hw->iio_devs[i]) {
			err = -ENOMEM;
			goto regulator_shutdown;
		}
	}

	if (hw->irq > 0) {
		err = st_asm330lhh_fifo_setup(hw);
		if (err < 0)
			return err;
			goto regulator_shutdown;
	}

	for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) {
@@ -753,12 +876,17 @@ int st_asm330lhh_probe(struct device *dev, int irq,

		err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
		if (err)
			return err;
			goto regulator_shutdown;
	}

	dev_info(hw->dev, "probe ok\n");

	return 0;

regulator_shutdown:
	st_asm330lhh_regulator_power_down(hw);

	return err;
}
EXPORT_SYMBOL(st_asm330lhh_probe);