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

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

Merge "cnss2: Re-arch power related APIs"

parents 99638f95 90fde779
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -635,7 +635,7 @@ static int cnss_get_resources(struct cnss_plat_data *plat_priv)
{
	int ret = 0;

	ret = cnss_get_vreg(plat_priv);
	ret = cnss_get_vreg_type(plat_priv, CNSS_VREG_PRIM);
	if (ret) {
		cnss_pr_err("Failed to get vreg, err = %d\n", ret);
		goto out;
@@ -1698,6 +1698,7 @@ static int cnss_probe(struct platform_device *plat_dev)
	plat_priv->bus_type = cnss_get_bus_type(plat_priv->device_id);
	cnss_set_plat_priv(plat_dev, plat_priv);
	platform_set_drvdata(plat_dev, plat_priv);
	INIT_LIST_HEAD(&plat_priv->vreg_list);

	cnss_init_control_params(plat_priv);

+21 −4
Original line number Diff line number Diff line
@@ -29,8 +29,7 @@ enum cnss_dev_bus_type {
	CNSS_BUS_PCI,
};

struct cnss_vreg_info {
	struct regulator *reg;
struct cnss_vreg_cfg {
	const char *name;
	u32 min_uv;
	u32 max_uv;
@@ -38,6 +37,17 @@ struct cnss_vreg_info {
	u32 delay_us;
};

struct cnss_vreg_info {
	struct list_head list;
	struct regulator *reg;
	struct cnss_vreg_cfg cfg;
	u32 enabled;
};

enum cnss_vreg_type {
	CNSS_VREG_PRIM,
};

struct cnss_pinctrl_info {
	struct pinctrl *pinctrl;
	struct pinctrl_state *bootstrap_active;
@@ -238,7 +248,7 @@ struct cnss_plat_data {
	struct platform_device *plat_dev;
	void *bus_priv;
	enum cnss_dev_bus_type bus_type;
	struct cnss_vreg_info *vreg_info;
	struct list_head vreg_list;
	struct cnss_pinctrl_info pinctrl_info;
	struct cnss_subsys_info subsys_info;
	struct cnss_ramdump_info ramdump_info;
@@ -290,7 +300,14 @@ struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
			   enum cnss_driver_event_type type,
			   u32 flags, void *data);
int cnss_get_vreg(struct cnss_plat_data *plat_priv);
int cnss_get_vreg_type(struct cnss_plat_data *plat_priv,
		       enum cnss_vreg_type type);
void cnss_put_vreg_type(struct cnss_plat_data *plat_priv,
			enum cnss_vreg_type type);
int cnss_vreg_on_type(struct cnss_plat_data *plat_priv,
		      enum cnss_vreg_type type);
int cnss_vreg_off_type(struct cnss_plat_data *plat_priv,
		       enum cnss_vreg_type type);
int cnss_get_pinctrl(struct cnss_plat_data *plat_priv);
int cnss_power_on_device(struct cnss_plat_data *plat_priv);
void cnss_power_off_device(struct cnss_plat_data *plat_priv);
+283 −144
Original line number Diff line number Diff line
@@ -9,25 +9,25 @@
#include "main.h"
#include "debug.h"

static struct cnss_vreg_info cnss_vreg_info[] = {
	{NULL, "vdd-wlan-core", 1300000, 1300000, 0, 0},
	{NULL, "vdd-wlan-io", 1800000, 1800000, 0, 0},
	{NULL, "vdd-wlan-xtal-aon", 0, 0, 0, 0},
	{NULL, "vdd-wlan-xtal", 1800000, 1800000, 0, 2},
	{NULL, "vdd-wlan", 0, 0, 0, 0},
	{NULL, "vdd-wlan-ctrl1", 0, 0, 0, 0},
	{NULL, "vdd-wlan-ctrl2", 0, 0, 0, 0},
	{NULL, "vdd-wlan-sp2t", 2700000, 2700000, 0, 0},
	{NULL, "wlan-ant-switch", 1800000, 1800000, 0, 0},
	{NULL, "wlan-soc-swreg", 1200000, 1200000, 0, 0},
	{NULL, "vdd-wlan-aon", 950000, 950000, 0, 0},
	{NULL, "vdd-wlan-dig", 950000, 952000, 0, 0},
	{NULL, "vdd-wlan-rfa1", 1900000, 1900000, 0, 0},
	{NULL, "vdd-wlan-rfa2", 1350000, 1350000, 0, 0},
	{NULL, "vdd-wlan-en", 0, 0, 0, 10},
static struct cnss_vreg_cfg cnss_vreg_list[] = {
	{"vdd-wlan-core", 1300000, 1300000, 0, 0},
	{"vdd-wlan-io", 1800000, 1800000, 0, 0},
	{"vdd-wlan-xtal-aon", 0, 0, 0, 0},
	{"vdd-wlan-xtal", 1800000, 1800000, 0, 2},
	{"vdd-wlan", 0, 0, 0, 0},
	{"vdd-wlan-ctrl1", 0, 0, 0, 0},
	{"vdd-wlan-ctrl2", 0, 0, 0, 0},
	{"vdd-wlan-sp2t", 2700000, 2700000, 0, 0},
	{"wlan-ant-switch", 1800000, 1800000, 0, 0},
	{"wlan-soc-swreg", 1200000, 1200000, 0, 0},
	{"vdd-wlan-aon", 950000, 950000, 0, 0},
	{"vdd-wlan-dig", 950000, 952000, 0, 0},
	{"vdd-wlan-rfa1", 1900000, 1900000, 0, 0},
	{"vdd-wlan-rfa2", 1350000, 1350000, 0, 0},
	{"vdd-wlan-en", 0, 0, 0, 10},
};

#define CNSS_VREG_INFO_SIZE		ARRAY_SIZE(cnss_vreg_info)
#define CNSS_VREG_INFO_SIZE		ARRAY_SIZE(cnss_vreg_list)
#define MAX_PROP_SIZE			32

#define BOOTSTRAP_GPIO			"qcom,enable-bootstrap-gpio"
@@ -39,191 +39,330 @@ static struct cnss_vreg_info cnss_vreg_info[] = {
#define BOOTSTRAP_DELAY			1000
#define WLAN_ENABLE_DELAY		1000

int cnss_get_vreg(struct cnss_plat_data *plat_priv)
static int cnss_get_vreg_single(struct cnss_plat_data *plat_priv,
				struct cnss_vreg_info *vreg)
{
	int ret = 0;
	int i;
	struct cnss_vreg_info *vreg_info;
	struct device *dev;
	struct regulator *reg;
	const __be32 *prop;
	char prop_name[MAX_PROP_SIZE];
	char prop_name[MAX_PROP_SIZE] = {0};
	int len;

	dev = &plat_priv->plat_dev->dev;

	plat_priv->vreg_info = devm_kzalloc(dev, sizeof(cnss_vreg_info),
					    GFP_KERNEL);
	if (!plat_priv->vreg_info) {
		ret = -ENOMEM;
		goto out;
	}

	memcpy(plat_priv->vreg_info, cnss_vreg_info, sizeof(cnss_vreg_info));

	for (i = 0; i < CNSS_VREG_INFO_SIZE; i++) {
		vreg_info = &plat_priv->vreg_info[i];
		reg = devm_regulator_get_optional(dev, vreg_info->name);
	reg = devm_regulator_get_optional(dev, vreg->cfg.name);
	if (IS_ERR(reg)) {
		ret = PTR_ERR(reg);
		if (ret == -ENODEV)
				continue;
			return ret;
		else if (ret == -EPROBE_DEFER)
			cnss_pr_info("EPROBE_DEFER for regulator: %s\n",
					     vreg_info->name);
				     vreg->cfg.name);
		else
			cnss_pr_err("Failed to get regulator %s, err = %d\n",
					    vreg_info->name, ret);
			goto out;
				    vreg->cfg.name, ret);
		return ret;
	}

		vreg_info->reg = reg;
	vreg->reg = reg;

	snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-info",
			 vreg_info->name);
		 vreg->cfg.name);

	prop = of_get_property(dev->of_node, prop_name, &len);
		cnss_pr_dbg("Got regulator info, name: %s, len: %d\n",
			    prop_name, len);

	if (!prop || len != (4 * sizeof(__be32))) {
		cnss_pr_dbg("Property %s %s, use default\n", prop_name,
			    prop ? "invalid format" : "doesn't exist");
	} else {
			vreg_info->min_uv = be32_to_cpup(&prop[0]);
			vreg_info->max_uv = be32_to_cpup(&prop[1]);
			vreg_info->load_ua = be32_to_cpup(&prop[2]);
			vreg_info->delay_us = be32_to_cpup(&prop[3]);
		vreg->cfg.min_uv = be32_to_cpup(&prop[0]);
		vreg->cfg.max_uv = be32_to_cpup(&prop[1]);
		vreg->cfg.load_ua = be32_to_cpup(&prop[2]);
		vreg->cfg.delay_us = be32_to_cpup(&prop[3]);
	}

	cnss_pr_dbg("Got regulator: %s, min_uv: %u, max_uv: %u, load_ua: %u, delay_us: %u\n",
			    vreg_info->name, vreg_info->min_uv,
			    vreg_info->max_uv, vreg_info->load_ua,
			    vreg_info->delay_us);
	}
		    vreg->cfg.name, vreg->cfg.min_uv,
		    vreg->cfg.max_uv, vreg->cfg.load_ua,
		    vreg->cfg.delay_us);

	return 0;
out:
	return ret;
}

static int cnss_vreg_on(struct cnss_plat_data *plat_priv)
static void cnss_put_vreg_single(struct cnss_plat_data *plat_priv,
				 struct cnss_vreg_info *vreg)
{
	int ret = 0;
	struct cnss_vreg_info *vreg_info;
	int i;
	struct device *dev = &plat_priv->plat_dev->dev;

	if (!plat_priv) {
		cnss_pr_err("plat_priv is NULL!\n");
		return -ENODEV;
	cnss_pr_dbg("Put regulator: %s\n", vreg->cfg.name);
	devm_regulator_put(vreg->reg);
	devm_kfree(dev, vreg);
}

	for (i = 0; i < CNSS_VREG_INFO_SIZE; i++) {
		vreg_info = &plat_priv->vreg_info[i];
static cnss_vreg_on_single(struct cnss_vreg_info *vreg)
{
	int ret = 0;

		if (!vreg_info->reg)
			continue;
	if (vreg->enabled) {
		cnss_pr_dbg("Regulator %s is already enabled\n",
			    vreg->cfg.name);
		return 0;
	}

		cnss_pr_dbg("Regulator %s is being enabled\n", vreg_info->name);
	cnss_pr_dbg("Regulator %s is being enabled\n", vreg->cfg.name);

		if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0) {
			ret = regulator_set_voltage(vreg_info->reg,
						    vreg_info->min_uv,
						    vreg_info->max_uv);
	if (vreg->cfg.min_uv != 0 && vreg->cfg.max_uv != 0) {
		ret = regulator_set_voltage(vreg->reg,
					    vreg->cfg.min_uv,
					    vreg->cfg.max_uv);

		if (ret) {
			cnss_pr_err("Failed to set voltage for regulator %s, min_uv: %u, max_uv: %u, err = %d\n",
					    vreg_info->name, vreg_info->min_uv,
					    vreg_info->max_uv, ret);
				break;
				    vreg->cfg.name, vreg->cfg.min_uv,
				    vreg->cfg.max_uv, ret);
			goto out;
		}
	}

		if (vreg_info->load_ua) {
			ret = regulator_set_load(vreg_info->reg,
						 vreg_info->load_ua);
	if (vreg->cfg.load_ua) {
		ret = regulator_set_load(vreg->reg,
					 vreg->cfg.load_ua);

		if (ret < 0) {
			cnss_pr_err("Failed to set load for regulator %s, load: %u, err = %d\n",
					    vreg_info->name, vreg_info->load_ua,
				    vreg->cfg.name, vreg->cfg.load_ua,
				    ret);
				break;
			goto out;
		}
	}

		if (vreg_info->delay_us)
			udelay(vreg_info->delay_us);
	if (vreg->cfg.delay_us)
		udelay(vreg->cfg.delay_us);

		ret = regulator_enable(vreg_info->reg);
	ret = regulator_enable(vreg->reg);
	if (ret) {
		cnss_pr_err("Failed to enable regulator %s, err = %d\n",
				    vreg_info->name, ret);
			break;
			    vreg->cfg.name, ret);
		goto out;
	}
	vreg->enabled = true;

out:
	return ret;
}

	if (ret) {
		for (; i >= 0; i--) {
			vreg_info = &plat_priv->vreg_info[i];
static int cnss_vreg_off_single(struct cnss_vreg_info *vreg)
{
	int ret = 0;

			if (!vreg_info->reg)
				continue;
	if (!vreg->enabled) {
		cnss_pr_dbg("Regulator %s is already disabled\n",
			    vreg->cfg.name);
		return 0;
	}

	cnss_pr_dbg("Regulator %s is being disabled\n",
		    vreg->cfg.name);

			regulator_disable(vreg_info->reg);
			if (vreg_info->load_ua)
				regulator_set_load(vreg_info->reg, 0);
			if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0)
				regulator_set_voltage(vreg_info->reg, 0,
						      vreg_info->max_uv);
	ret = regulator_disable(vreg->reg);
	if (ret)
		cnss_pr_err("Failed to disable regulator %s, err = %d\n",
			    vreg->cfg.name, ret);

	if (vreg->cfg.load_ua) {
		ret = regulator_set_load(vreg->reg, 0);
		if (ret < 0)
			cnss_pr_err("Failed to set load for regulator %s, err = %d\n",
				    vreg->cfg.name, ret);
	}

	if (vreg->cfg.min_uv != 0 && vreg->cfg.max_uv != 0) {
		ret = regulator_set_voltage(vreg->reg, 0,
					    vreg->cfg.max_uv);
		if (ret)
			cnss_pr_err("Failed to set voltage for regulator %s, err = %d\n",
				    vreg->cfg.name, ret);
	}
	vreg->enabled = false;

	return ret;
}

	return 0;
static struct cnss_vreg_cfg *get_vreg_list(u32 *vreg_list_size,
					   enum cnss_vreg_type type)
{
	switch (type) {
	case CNSS_VREG_PRIM:
		*vreg_list_size = CNSS_VREG_INFO_SIZE;
		return cnss_vreg_list;
	default:
		cnss_pr_err("Unsupported vreg type 0x%x\n", type);
		*vreg_list_size = 0;
		return NULL;
	}
}

static int cnss_vreg_off(struct cnss_plat_data *plat_priv)
static int cnss_get_vreg(struct cnss_plat_data *plat_priv,
			 struct list_head *vreg_list,
			 struct cnss_vreg_cfg *vreg_cfg,
			 u32 vreg_list_size)
{

	int ret = 0;
	struct cnss_vreg_info *vreg_info;
	int i;
	struct cnss_vreg_info *vreg;
	struct device *dev = &plat_priv->plat_dev->dev;

	if (!plat_priv) {
		cnss_pr_err("plat_priv is NULL!\n");
		return -ENODEV;
	if (!list_empty(vreg_list)) {
		cnss_pr_dbg("Vregs have already been updated\n");
		return 0;
	}

	for (i = CNSS_VREG_INFO_SIZE - 1; i >= 0; i--) {
		vreg_info = &plat_priv->vreg_info[i];
	for (i = 0; i < vreg_list_size; i++) {
		vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
		if (!vreg)
			return -ENOMEM;

		if (!vreg_info->reg)
		memcpy(&vreg->cfg, &vreg_cfg[i], sizeof(vreg->cfg));
		ret = cnss_get_vreg_single(plat_priv, vreg);
		if (ret != 0) {
			if (ret == -ENODEV) {
				devm_kfree(dev, vreg);
				continue;
			} else {
				devm_kfree(dev, vreg);
				return ret;
			}
		}
		list_add_tail(&vreg->list, vreg_list);
	}

		cnss_pr_dbg("Regulator %s is being disabled\n",
			    vreg_info->name);
	return 0;
}

		ret = regulator_disable(vreg_info->reg);
		if (ret)
			cnss_pr_err("Failed to disable regulator %s, err = %d\n",
				    vreg_info->name, ret);
static void cnss_put_vreg(struct cnss_plat_data *plat_priv,
			  struct list_head *vreg_list)
{
	struct cnss_vreg_info *vreg;

		if (vreg_info->load_ua) {
			ret = regulator_set_load(vreg_info->reg, 0);
			if (ret < 0)
				cnss_pr_err("Failed to set load for regulator %s, err = %d\n",
					    vreg_info->name, ret);
	while (!list_empty(vreg_list)) {
		vreg = list_first_entry(vreg_list,
					struct cnss_vreg_info, list);
		list_del(&vreg->list);
		if (IS_ERR_OR_NULL(vreg->reg))
			continue;
		cnss_put_vreg_single(plat_priv, vreg);
	}
}

		if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0) {
			ret = regulator_set_voltage(vreg_info->reg, 0,
						    vreg_info->max_uv);
static int cnss_vreg_on(struct cnss_plat_data *plat_priv,
			struct list_head *vreg_list)
{
	struct cnss_vreg_info *vreg;
	int ret = 0;

	list_for_each_entry(vreg, vreg_list, list) {
		if (IS_ERR_OR_NULL(vreg->reg))
			continue;
		ret = cnss_vreg_on_single(vreg);
		if (ret)
				cnss_pr_err("Failed to set voltage for regulator %s, err = %d\n",
					    vreg_info->name, ret);
			break;
	}

	if (!ret)
		return 0;

	list_for_each_entry_continue_reverse(vreg, vreg_list, list) {
		if (IS_ERR_OR_NULL(vreg->reg) || !vreg->enabled)
			continue;

		cnss_vreg_off_single(vreg);
	}

	return ret;
}

static int cnss_vreg_off(struct cnss_plat_data *plat_priv,
			 struct list_head *vreg_list)
{
	struct cnss_vreg_info *vreg;

	list_for_each_entry_reverse(vreg, vreg_list, list) {
		if (IS_ERR_OR_NULL(vreg->reg))
			continue;

		cnss_vreg_off_single(vreg);
	}

	return 0;
}

int cnss_get_vreg_type(struct cnss_plat_data *plat_priv,
		       enum cnss_vreg_type type)
{
	struct cnss_vreg_cfg *vreg_cfg;
	u32 vreg_list_size = 0;
	int ret = 0;

	vreg_cfg = get_vreg_list(&vreg_list_size, type);
	if (!vreg_cfg)
		return -EINVAL;

	switch (type) {
	case CNSS_VREG_PRIM:
		ret = cnss_get_vreg(plat_priv, &plat_priv->vreg_list,
				    vreg_cfg, vreg_list_size);
		break;
	default:
		cnss_pr_err("Unsupported vreg type 0x%x\n", type);
		return -EINVAL;
	}

	return ret;
}

void cnss_put_vreg_type(struct cnss_plat_data *plat_priv,
			enum cnss_vreg_type type)
{
	switch (type) {
	case CNSS_VREG_PRIM:
		cnss_put_vreg(plat_priv, &plat_priv->vreg_list);
		break;
	default:
		return;
	}
}

int cnss_vreg_on_type(struct cnss_plat_data *plat_priv,
		      enum cnss_vreg_type type)
{
	int ret = 0;

	switch (type) {
	case CNSS_VREG_PRIM:
		ret = cnss_vreg_on(plat_priv, &plat_priv->vreg_list);
		break;
	default:
		cnss_pr_err("Unsupported vreg type 0x%x\n", type);
		return -EINVAL;
	}

	return ret;
}

int cnss_vreg_off_type(struct cnss_plat_data *plat_priv,
		       enum cnss_vreg_type type)
{
	int ret = 0;

	switch (type) {
	case CNSS_VREG_PRIM:
		ret = cnss_vreg_off(plat_priv, &plat_priv->vreg_list);
		break;
	default:
		cnss_pr_err("Unsupported vreg type 0x%x\n", type);
		return -EINVAL;
	}

	return ret;
}

@@ -346,7 +485,7 @@ int cnss_power_on_device(struct cnss_plat_data *plat_priv)
		return 0;
	}

	ret = cnss_vreg_on(plat_priv);
	ret = cnss_vreg_on_type(plat_priv, CNSS_VREG_PRIM);
	if (ret) {
		cnss_pr_err("Failed to turn on vreg, err = %d\n", ret);
		goto out;
@@ -361,7 +500,7 @@ int cnss_power_on_device(struct cnss_plat_data *plat_priv)

	return 0;
vreg_off:
	cnss_vreg_off(plat_priv);
	cnss_vreg_off_type(plat_priv, CNSS_VREG_PRIM);
out:
	return ret;
}
@@ -374,7 +513,7 @@ void cnss_power_off_device(struct cnss_plat_data *plat_priv)
	}

	cnss_select_pinctrl_state(plat_priv, false);
	cnss_vreg_off(plat_priv);
	cnss_vreg_off_type(plat_priv, CNSS_VREG_PRIM);
	plat_priv->powered_on = false;
}