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

Commit 6757b96a authored by Xiao Li's avatar Xiao Li Committed by Gerrit - the friendly Code Review server
Browse files

ASoC: aw8896: add logic to handle regulator for DVDD



aw8896's DVDD is not powered by default, add logic to read regulator info
from device tree, and enable power for DVDD in the driver probe function.

Change-Id: I544ef3e8e7f273f868cefc6a3ff27b6e7f9ed768
Signed-off-by: default avatarXiao Li <lixiao@codeaurora.org>
parent 34f2473a
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -8,6 +8,12 @@ Required properties:

  - reset-gpio : gpio used for HW reset

  - dvdd-supply : Power supply for PA's dvdd

  - dvdd-voltage : Minimum and maximum voltage in uV to set for power supply

  - dvdd-current : dvdd's max current in uA

Optional properties:

  - irq-gpio: gpio used for irq indicator
@@ -18,4 +24,7 @@ Examples:
		compatible = "awinic,i2c_smartpa";
		reg = <0x34>;
		reset-gpio = <&tlmm 68 0>;
		dvdd-supply = <&pm660_l9>;
		dvdd-voltage = <1800000 1800000>;
		dvdd-current = <15000>;
	};
+84 −1
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#define AW_READ_CHIPID_RETRIES 5
#define AW_READ_CHIPID_RETRY_DELAY 5
#define AW8896_MAX_DSP_START_TRY_COUNT    10
#define DT_MAX_PROP_SIZE 80

static int aw8896_spk_control;
static int aw8896_rcv_control;
@@ -1068,6 +1069,14 @@ static irqreturn_t aw8896_irq(int irq, void *data)

static int aw8896_parse_dt(struct device *dev, struct aw8896 *aw8896,
		struct device_node *np) {
	int prop_val = 0;
	int ret = 0;
	int len = 0;
	const __be32 *prop = NULL;
	struct device_node *regnode = NULL;
	char *dvdd_supply = "dvdd";
	char prop_name[DT_MAX_PROP_SIZE] = {0};

	aw8896->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
	if (aw8896->reset_gpio < 0) {
		dev_err(dev,
@@ -1082,7 +1091,47 @@ static int aw8896_parse_dt(struct device *dev, struct aw8896 *aw8896,
	if (aw8896->irq_gpio < 0)
		dev_info(dev, "%s: no irq gpio provided.\n", __func__);

	snprintf(prop_name, DT_MAX_PROP_SIZE, "%s-supply", dvdd_supply);
	regnode = of_parse_phandle(np, prop_name, 0);
	if (!regnode) {
		dev_err(dev, "%s: no %s provided\n", __func__, prop_name);
		goto err_get_regulator;
	}

	aw8896->supply.regulator = devm_regulator_get(dev, dvdd_supply);
	if (IS_ERR(aw8896->supply.regulator)) {
		dev_err(dev, "%s: failed to get supply for %s\n", __func__,
			dvdd_supply);
		goto err_get_regulator;
	}

	snprintf(prop_name, DT_MAX_PROP_SIZE, "%s-voltage", dvdd_supply);
	prop = of_get_property(np, prop_name, &len);
	if (!prop || (len != (2 * sizeof(__be32)))) {
		dev_err(dev, "%s: no %s provided or format invalid\n",
			__func__, prop_name);
		goto err_get_voltage;
	}

	aw8896->supply.min_uv = be32_to_cpup(&prop[0]);
	aw8896->supply.max_uv = be32_to_cpup(&prop[1]);

	snprintf(prop_name, DT_MAX_PROP_SIZE, "%s-current", dvdd_supply);
	ret = of_property_read_u32(np, prop_name, &prop_val);
	if (ret) {
		dev_err(dev, "%s: no %s provided\n", __func__, prop_name);
		goto err_get_current;
	}
	aw8896->supply.ua = prop_val;

	return 0;

err_get_current:
err_get_voltage:
	devm_regulator_put(aw8896->supply.regulator);
	aw8896->supply.regulator = NULL;
err_get_regulator:
	return -EINVAL;
}

int aw8896_hw_reset(struct aw8896 *aw8896)
@@ -1354,7 +1403,7 @@ static int aw8896_i2c_probe(struct i2c_client *i2c,

	i2c_set_clientdata(i2c, aw8896);
	mutex_init(&aw8896->lock);
	/* aw8896 rst & int */

	if (np) {
		ret = aw8896_parse_dt(&i2c->dev, aw8896, np);
		if (ret) {
@@ -1388,6 +1437,30 @@ static int aw8896_i2c_probe(struct i2c_client *i2c,
		}
	}

	ret = regulator_set_voltage(aw8896->supply.regulator,
				    aw8896->supply.max_uv,
				    aw8896->supply.min_uv);
	if (ret) {
		dev_err(&i2c->dev, "%s: set voltage %d ~ %d failed\n",
				__func__,
				aw8896->supply.min_uv,
				aw8896->supply.max_uv);
		goto err_supply_set;
	}

	ret = regulator_set_load(aw8896->supply.regulator, aw8896->supply.ua);
	if (ret < 0) {
		dev_err(&i2c->dev, "%s: set current %d failed\n", __func__,
				aw8896->supply.ua);
		goto err_supply_set;
	}

	ret = regulator_enable(aw8896->supply.regulator);
	if (ret < 0) {
		dev_err(&i2c->dev, "%s: regulator enable failed\n", __func__);
		goto err_supply_set;
	}

	ret = aw8896_hw_reset(aw8896);
	if (ret < 0) {
		dev_err(&i2c->dev, "%s: aw8896_hw_reset failed\n", __func__);
@@ -1461,6 +1534,11 @@ static int aw8896_i2c_probe(struct i2c_client *i2c,
	if (gpio_is_valid(aw8896->irq_gpio))
		devm_gpio_free(&i2c->dev, aw8896->irq_gpio);
err_hw_rst:
	if (aw8896->supply.regulator)
		regulator_disable(aw8896->supply.regulator);
err_supply_set:
	if (aw8896->supply.regulator)
		devm_regulator_put(aw8896->supply.regulator);
err_irq_gpio_request:
	if (gpio_is_valid(aw8896->reset_gpio))
		devm_gpio_free(&i2c->dev, aw8896->reset_gpio);
@@ -1486,6 +1564,11 @@ static int aw8896_i2c_remove(struct i2c_client *i2c)
	if (gpio_is_valid(aw8896->reset_gpio))
		devm_gpio_free(&i2c->dev, aw8896->reset_gpio);

	if (aw8896->supply.regulator) {
		regulator_disable(aw8896->supply.regulator);
		devm_regulator_put(aw8896->supply.regulator);
	}

	devm_kfree(&i2c->dev, aw8896);
	aw8896 = NULL;

+9 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@

#ifndef _AW8896_H_
#define _AW8896_H_
#include <linux/regulator/driver.h>

/*
 * i2c transaction on Linux limited to 64k
@@ -81,10 +82,18 @@ enum aw8896_dsp_cfg_state {
	AW8896_DSP_CFG_OK,
};

struct dvdd_supply {
	struct regulator *regulator;
	int min_uv;
	int max_uv;
	int ua;
};

struct aw8896 {
	struct regmap *regmap;
	struct i2c_client *i2c;
	struct snd_soc_codec *codec;
	struct dvdd_supply supply;
	struct mutex lock;
	int dsp_init;
	int dsp_fw_state;