wcnss: modularize wcnss power up sequence and debug logs

Modularize the wcnss power up sequence like wcnss voltage
regulator enable/disable sequence and voltage regulator
current and voltage level parsing method. Remove hack code
from the power wcnss power process and enable/disable
the power resource if it's defined in the wcnss device node.

Update the debug logs to track the exact state of the power
state during device bootup. Remove the unnecessary logging
for the optional resource request fails during device bootup.

CRs-Fixed: 2086414
Change-Id: I30b1e2196eb9d1c933275f3db34ca0ff5664ea3b
Signed-off-by: Sarada Prasanna Garnayak <sgarna@codeaurora.org>
This commit is contained in:
Sarada Prasanna Garnayak 2017-08-02 17:47:19 +05:30 committed by Gerrit - the friendly Code Review server
parent a49bb61510
commit 5eebfeaa9c
4 changed files with 176 additions and 156 deletions

View file

@ -64,8 +64,6 @@ support for pronto hardware.
to use for VBATT feature.
- qcom,has-a2xb-split-reg: boolean flag to determine A2xb split timeout limit
register is available or not.
- qcom,wcn-external-gpio-support: boolean flag to determine 3.3v gpio support
for pronto hardware for a target.
Example:
@ -87,7 +85,6 @@ Example:
gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>,
<&msmgpio 39 0>, <&msmgpio 40 0>;
qcom,wcn-external-gpio-support;
qcom,has-48mhz-xo;
qcom,is-pronto-vt;
qcom,wlan-rx-buff-count = <512>;

View file

@ -71,23 +71,33 @@ static int is_power_on;
struct vregs_info {
const char * const name;
const char * const curr;
const char * const volt;
int state;
bool required;
struct regulator *regulator;
};
/* IRIS regulators for Pronto hardware */
static struct vregs_info iris_vregs_pronto[] = {
{"qcom,iris-vddxo", VREG_NULL_CONFIG, NULL},
{"qcom,iris-vddrfa", VREG_NULL_CONFIG, NULL},
{"qcom,iris-vddpa", VREG_NULL_CONFIG, NULL},
{"qcom,iris-vdddig", VREG_NULL_CONFIG, NULL},
static struct vregs_info iris_vregs[] = {
{"qcom,iris-vddxo", "qcom,iris-vddxo-current",
"qcom,iris-vddxo-voltage-level", VREG_NULL_CONFIG, true, NULL},
{"qcom,iris-vddrfa", "qcom,iris-vddrfa-current",
"qcom,iris-vddrfa-voltage-level", VREG_NULL_CONFIG, true, NULL},
{"qcom,iris-vddpa", "qcom,iris-vddpa-current",
"qcom,iris-vddpa-voltage-level", VREG_NULL_CONFIG, false, NULL},
{"qcom,iris-vdddig", "qcom,iris-vdddig-current",
"qcom,iris-vdddig-voltage-level", VREG_NULL_CONFIG, true, NULL},
};
/* WCNSS regulators for Pronto hardware */
static struct vregs_info pronto_vregs[] = {
{"qcom,pronto-vddmx", VREG_NULL_CONFIG, NULL},
{"qcom,pronto-vddcx", VREG_NULL_CONFIG, NULL},
{"qcom,pronto-vddpx", VREG_NULL_CONFIG, NULL},
{"qcom,pronto-vddmx", "qcom,pronto-vddmx-current",
"qcom,vddmx-voltage-level", VREG_NULL_CONFIG, true, NULL},
{"qcom,pronto-vddcx", "qcom,pronto-vddcx-current",
"qcom,vddcx-voltage-level", VREG_NULL_CONFIG, true, NULL},
{"qcom,pronto-vddpx", "qcom,pronto-vddpx-current",
"qcom,vddpx-voltage-level", VREG_NULL_CONFIG, true, NULL},
};
struct host_driver {
@ -184,6 +194,129 @@ int validate_iris_chip_id(u32 reg)
}
}
static void wcnss_free_regulator(void)
{
int vreg_i;
/* Free pronto voltage regulators from device node */
for (vreg_i = 0; vreg_i < PRONTO_REGULATORS; vreg_i++) {
if (pronto_vregs[vreg_i].state) {
regulator_put(pronto_vregs[vreg_i].regulator);
pronto_vregs[vreg_i].state = VREG_NULL_CONFIG;
}
}
/* Free IRIS voltage regulators from device node */
for (vreg_i = 0; vreg_i < IRIS_REGULATORS; vreg_i++) {
if (iris_vregs[vreg_i].state) {
regulator_put(iris_vregs[vreg_i].regulator);
iris_vregs[vreg_i].state = VREG_NULL_CONFIG;
}
}
}
static int
wcnss_dt_parse_vreg_level(struct device *dev, int index,
const char *current_vreg_name, const char *vreg_name,
struct vregs_level *vlevel)
{
int ret = 0;
/* array used to store nominal, low and high voltage values */
u32 voltage_levels[3], current_vreg;
ret = of_property_read_u32_array(dev->of_node, vreg_name,
voltage_levels,
ARRAY_SIZE(voltage_levels));
if (ret) {
dev_err(dev, "error reading %s property\n", vreg_name);
return ret;
}
vlevel[index].nominal_min = voltage_levels[0];
vlevel[index].low_power_min = voltage_levels[1];
vlevel[index].max_voltage = voltage_levels[2];
ret = of_property_read_u32(dev->of_node, current_vreg_name,
&current_vreg);
if (ret) {
dev_err(dev, "error reading %s property\n", current_vreg_name);
return ret;
}
vlevel[index].uA_load = current_vreg;
return ret;
}
int
wcnss_parse_voltage_regulator(struct wcnss_wlan_config *wlan_config,
struct device *dev)
{
int rc, vreg_i;
/* Parse pronto voltage regulators from device node */
for (vreg_i = 0; vreg_i < PRONTO_REGULATORS; vreg_i++) {
pronto_vregs[vreg_i].regulator =
regulator_get(dev, pronto_vregs[vreg_i].name);
if (IS_ERR(pronto_vregs[vreg_i].regulator)) {
if (pronto_vregs[vreg_i].required) {
rc = PTR_ERR(pronto_vregs[vreg_i].regulator);
dev_err(dev, "regulator get of %s failed (%d)\n",
pronto_vregs[vreg_i].name, rc);
goto wcnss_vreg_get_err;
} else {
dev_dbg(dev, "Skip optional regulator configuration: %s\n",
pronto_vregs[vreg_i].name);
continue;
}
}
pronto_vregs[vreg_i].state |= VREG_GET_REGULATOR_MASK;
rc = wcnss_dt_parse_vreg_level(dev, vreg_i,
pronto_vregs[vreg_i].curr,
pronto_vregs[vreg_i].volt,
wlan_config->pronto_vlevel);
if (rc) {
dev_err(dev, "error reading voltage-level property\n");
goto wcnss_vreg_get_err;
}
}
/* Parse iris voltage regulators from device node */
for (vreg_i = 0; vreg_i < IRIS_REGULATORS; vreg_i++) {
iris_vregs[vreg_i].regulator =
regulator_get(dev, iris_vregs[vreg_i].name);
if (IS_ERR(iris_vregs[vreg_i].regulator)) {
if (iris_vregs[vreg_i].required) {
rc = PTR_ERR(iris_vregs[vreg_i].regulator);
dev_err(dev, "regulator get of %s failed (%d)\n",
iris_vregs[vreg_i].name, rc);
goto wcnss_vreg_get_err;
} else {
dev_dbg(dev, "Skip optional regulator configuration: %s\n",
iris_vregs[vreg_i].name);
continue;
}
}
iris_vregs[vreg_i].state |= VREG_GET_REGULATOR_MASK;
rc = wcnss_dt_parse_vreg_level(dev, vreg_i,
iris_vregs[vreg_i].curr,
iris_vregs[vreg_i].volt,
wlan_config->iris_vlevel);
if (rc) {
dev_err(dev, "error reading voltage-level property\n");
goto wcnss_vreg_get_err;
}
}
return 0;
wcnss_vreg_get_err:
wcnss_free_regulator();
return rc;
}
void wcnss_iris_reset(u32 reg, void __iomem *pmu_conf_reg)
{
/* Reset IRIS */
@ -417,11 +550,6 @@ static void wcnss_vregs_off(struct vregs_info regulators[], uint size,
if (regulators[i].state == VREG_NULL_CONFIG)
continue;
if (cfg->wcn_external_gpio_support) {
if (!memcmp(regulators[i].name, VDD_PA, sizeof(VDD_PA)))
continue;
}
/* Remove PWM mode */
if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
rc = regulator_set_load(regulators[i].regulator, 0);
@ -483,23 +611,10 @@ static int wcnss_vregs_on(struct device *dev,
}
for (i = 0; i < size; i++) {
if (cfg->wcn_external_gpio_support) {
if (!memcmp(regulators[i].name, VDD_PA, sizeof(VDD_PA)))
continue;
}
if (regulators[i].state == VREG_NULL_CONFIG)
continue;
/* Get regulator source */
regulators[i].regulator =
regulator_get(dev, regulators[i].name);
if (IS_ERR(regulators[i].regulator)) {
rc = PTR_ERR(regulators[i].regulator);
pr_err("regulator get of %s failed (%d)\n",
regulators[i].name, rc);
goto fail;
}
regulators[i].state |= VREG_GET_REGULATOR_MASK;
reg_cnt = regulator_count_voltages(regulators[i].regulator);
/* Set voltage to nominal. Exclude swtiches e.g. LVS */
if ((voltage_level[i].nominal_min ||
voltage_level[i].max_voltage) && (reg_cnt > 0)) {
@ -561,8 +676,7 @@ static void wcnss_iris_vregs_off(enum wcnss_hw_type hw_type,
{
switch (hw_type) {
case WCNSS_PRONTO_HW:
wcnss_vregs_off(iris_vregs_pronto,
ARRAY_SIZE(iris_vregs_pronto),
wcnss_vregs_off(iris_vregs, ARRAY_SIZE(iris_vregs),
cfg->iris_vlevel);
break;
default:
@ -579,8 +693,7 @@ static int wcnss_iris_vregs_on(struct device *dev,
switch (hw_type) {
case WCNSS_PRONTO_HW:
ret = wcnss_vregs_on(dev, iris_vregs_pronto,
ARRAY_SIZE(iris_vregs_pronto),
ret = wcnss_vregs_on(dev, iris_vregs, ARRAY_SIZE(iris_vregs),
cfg->iris_vlevel);
break;
default:

View file

@ -63,6 +63,21 @@
#define WCNSS_CONFIG_UNSPECIFIED (-1)
#define UINT32_MAX (0xFFFFFFFFU)
#define SUBSYS_NOTIF_MIN_INDEX 0
#define SUBSYS_NOTIF_MAX_INDEX 9
char *wcnss_subsys_notif_type[] = {
"SUBSYS_BEFORE_SHUTDOWN",
"SUBSYS_AFTER_SHUTDOWN",
"SUBSYS_BEFORE_POWERUP",
"SUBSYS_AFTER_POWERUP",
"SUBSYS_RAMDUMP_NOTIFICATION",
"SUBSYS_POWERUP_FAILURE",
"SUBSYS_PROXY_VOTE",
"SUBSYS_PROXY_UNVOTE",
"SUBSYS_SOC_RESET",
"SUBSYS_NOTIF_TYPE_COUNT"
};
static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED;
module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present");
@ -2713,51 +2728,16 @@ static struct miscdevice wcnss_usr_ctrl = {
.fops = &wcnss_ctrl_fops,
};
static int
wcnss_dt_parse_vreg_level(struct device *dev, int index,
const char *current_vreg_name, const char *vreg_name,
struct vregs_level *vlevel)
{
int ret = 0;
/* array used to store nominal, low and high voltage values
*/
u32 voltage_levels[3], current_vreg;
ret = of_property_read_u32_array(dev->of_node, vreg_name,
voltage_levels,
ARRAY_SIZE(voltage_levels));
if (ret) {
dev_err(dev, "error reading %s property\n", vreg_name);
return ret;
}
vlevel[index].nominal_min = voltage_levels[0];
vlevel[index].low_power_min = voltage_levels[1];
vlevel[index].max_voltage = voltage_levels[2];
ret = of_property_read_u32(dev->of_node, current_vreg_name,
&current_vreg);
if (ret) {
dev_err(dev, "error reading %s property\n", current_vreg_name);
return ret;
}
vlevel[index].uA_load = current_vreg;
return ret;
}
static int
wcnss_trigger_config(struct platform_device *pdev)
{
int ret;
int rc, index = 0;
int rc;
struct qcom_wcnss_opts *pdata;
struct resource *res;
int is_pronto_vadc;
int is_pronto_v3;
int pil_retry = 0;
struct wcnss_wlan_config *wlan_cfg = &penv->wlan_config;
struct device_node *node = (&pdev->dev)->of_node;
int has_pronto_hw = of_property_read_bool(node, "qcom,has-pronto-hw");
@ -2769,93 +2749,14 @@ wcnss_trigger_config(struct platform_device *pdev)
penv->is_a2xb_split_reg =
of_property_read_bool(node, "qcom,has-a2xb-split-reg");
wlan_cfg->wcn_external_gpio_support =
of_property_read_bool(node, "qcom,wcn-external-gpio-support");
if (of_property_read_u32(node, "qcom,wlan-rx-buff-count",
&penv->wlan_rx_buff_count)) {
penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT;
}
ret = wcnss_dt_parse_vreg_level(&pdev->dev, index,
"qcom,pronto-vddmx-current",
"qcom,vddmx-voltage-level",
penv->wlan_config.pronto_vlevel);
if (ret) {
dev_err(&pdev->dev, "error reading voltage-level property\n");
goto fail;
}
index++;
ret = wcnss_dt_parse_vreg_level(&pdev->dev, index,
"qcom,pronto-vddcx-current",
"qcom,vddcx-voltage-level",
penv->wlan_config.pronto_vlevel);
if (ret) {
dev_err(&pdev->dev, "error reading voltage-level property\n");
goto fail;
}
index++;
ret = wcnss_dt_parse_vreg_level(&pdev->dev, index,
"qcom,pronto-vddpx-current",
"qcom,vddpx-voltage-level",
penv->wlan_config.pronto_vlevel);
if (ret) {
dev_err(&pdev->dev, "error reading voltage-level property\n");
goto fail;
}
/* assign 0 to index now onwards, index variable re used to
* represent iris regulator index
*/
index = 0;
ret = wcnss_dt_parse_vreg_level(&pdev->dev, index,
"qcom,iris-vddxo-current",
"qcom,iris-vddxo-voltage-level",
penv->wlan_config.iris_vlevel);
if (ret) {
dev_err(&pdev->dev, "error reading voltage-level property\n");
goto fail;
}
index++;
ret = wcnss_dt_parse_vreg_level(&pdev->dev, index,
"qcom,iris-vddrfa-current",
"qcom,iris-vddrfa-voltage-level",
penv->wlan_config.iris_vlevel);
if (ret) {
dev_err(&pdev->dev, "error reading voltage-level property\n");
goto fail;
}
if (!wlan_cfg->wcn_external_gpio_support) {
index++;
ret = wcnss_dt_parse_vreg_level(
&pdev->dev, index,
"qcom,iris-vddpa-current",
"qcom,iris-vddpa-voltage-level",
penv->wlan_config.iris_vlevel);
if (ret) {
dev_err(&pdev->dev,
"error reading voltage-level property\n");
goto fail;
}
}
index++;
ret = wcnss_dt_parse_vreg_level(&pdev->dev, index,
"qcom,iris-vdddig-current",
"qcom,iris-vdddig-voltage-level",
penv->wlan_config.iris_vlevel);
if (ret) {
dev_err(&pdev->dev, "error reading voltage-level property\n");
rc = wcnss_parse_voltage_regulator(&penv->wlan_config, &pdev->dev);
if (rc) {
dev_err(&pdev->dev, "Failed to parse voltage regulators\n");
goto fail;
}
@ -3201,7 +3102,7 @@ wcnss_trigger_config(struct platform_device *pdev)
penv->vadc_dev = qpnp_get_vadc(&penv->pdev->dev, "wcnss");
if (IS_ERR(penv->vadc_dev)) {
pr_err("%s: vadc get failed\n", __func__);
pr_debug("%s: vadc get failed\n", __func__);
penv->vadc_dev = NULL;
} else {
rc = wcnss_get_battery_volt(&penv->wlan_config.vbatt);
@ -3477,7 +3378,15 @@ static int wcnss_notif_cb(struct notifier_block *this, unsigned long code,
struct notif_data *data = (struct notif_data *)ss_handle;
int ret, xo_mode;
pr_info("%s: wcnss notification event: %lu\n", __func__, code);
if (!(code >= SUBSYS_NOTIF_MIN_INDEX) &&
(code <= SUBSYS_NOTIF_MAX_INDEX)) {
pr_debug("%s: Invaild subsystem notification code: %lu\n",
__func__, code);
return NOTIFY_DONE;
}
pr_debug("%s: wcnss notification event: %lu : %s\n",
__func__, code, wcnss_subsys_notif_type[code]);
if (code == SUBSYS_PROXY_VOTE) {
if (pdev && pwlanconfig) {

View file

@ -38,7 +38,6 @@ struct vregs_level {
};
struct wcnss_wlan_config {
bool wcn_external_gpio_support;
int use_48mhz_xo;
int is_pronto_vadc;
int is_pronto_v3;
@ -143,6 +142,8 @@ void wcnss_init_delayed_work(struct delayed_work *dwork , void *callbackptr);
int wcnss_get_iris_name(char *iris_version);
void wcnss_dump_stack(struct task_struct *task);
void wcnss_snoc_vote(bool clk_chk_en);
int wcnss_parse_voltage_regulator(struct wcnss_wlan_config *wlan_config,
struct device *dev);
#ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE
void wcnss_log_debug_regs_on_bite(void);