Loading drivers/net/wireless/cnss2/main.c +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading drivers/net/wireless/cnss2/main.h +21 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading drivers/net/wireless/cnss2/power.c +283 −144 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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; } Loading @@ -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; } Loading Loading
drivers/net/wireless/cnss2/main.c +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading
drivers/net/wireless/cnss2/main.h +21 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading
drivers/net/wireless/cnss2/power.c +283 −144 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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; } Loading @@ -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; } Loading