Loading drivers/net/wireless/cnss2/main.c +15 −1 Original line number Diff line number Diff line Loading @@ -722,19 +722,32 @@ static int cnss_get_resources(struct cnss_plat_data *plat_priv) goto out; } ret = cnss_get_clk(plat_priv); if (ret) { cnss_pr_err("Failed to get clocks, err = %d\n", ret); goto put_vreg; } ret = cnss_get_pinctrl(plat_priv); if (ret) { cnss_pr_err("Failed to get pinctrl, err = %d\n", ret); goto out; goto put_clk; } return 0; put_clk: cnss_put_clk(plat_priv); put_vreg: cnss_put_vreg_type(plat_priv, CNSS_VREG_PRIM); out: return ret; } static void cnss_put_resources(struct cnss_plat_data *plat_priv) { cnss_put_clk(plat_priv); cnss_put_vreg_type(plat_priv, CNSS_VREG_PRIM); } static int cnss_modem_notifier_nb(struct notifier_block *nb, Loading Loading @@ -1929,6 +1942,7 @@ static int cnss_probe(struct platform_device *plat_dev) cnss_set_plat_priv(plat_dev, plat_priv); platform_set_drvdata(plat_dev, plat_priv); INIT_LIST_HEAD(&plat_priv->vreg_list); INIT_LIST_HEAD(&plat_priv->clk_list); cnss_get_cpr_info(plat_priv); cnss_init_control_params(plat_priv); Loading drivers/net/wireless/cnss2/main.h +16 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,19 @@ enum cnss_vreg_type { CNSS_VREG_PRIM, }; struct cnss_clk_cfg { const char *name; u32 freq; u32 required; }; struct cnss_clk_info { struct list_head list; struct clk *clk; struct cnss_clk_cfg cfg; u32 enabled; }; struct cnss_pinctrl_info { struct pinctrl *pinctrl; struct pinctrl_state *bootstrap_active; Loading Loading @@ -269,6 +282,7 @@ struct cnss_plat_data { void *bus_priv; enum cnss_dev_bus_type bus_type; struct list_head vreg_list; struct list_head clk_list; struct cnss_pinctrl_info pinctrl_info; struct cnss_subsys_info subsys_info; struct cnss_ramdump_info ramdump_info; Loading Loading @@ -355,6 +369,8 @@ 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_clk(struct cnss_plat_data *plat_priv); void cnss_put_clk(struct cnss_plat_data *plat_priv); 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 +224 −1 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include <linux/clk.h> #include <linux/delay.h> #include <linux/of.h> #include <linux/pinctrl/consumer.h> Loading Loading @@ -28,7 +29,12 @@ static struct cnss_vreg_cfg cnss_vreg_list[] = { {"vdd-wlan-en", 0, 0, 0, 10}, }; static struct cnss_clk_cfg cnss_clk_list[] = { {"rf_clk", 0, 0}, }; #define CNSS_VREG_INFO_SIZE ARRAY_SIZE(cnss_vreg_list) #define CNSS_CLK_INFO_SIZE ARRAY_SIZE(cnss_clk_list) #define MAX_PROP_SIZE 32 #define BOOTSTRAP_GPIO "qcom,enable-bootstrap-gpio" Loading Loading @@ -374,6 +380,212 @@ int cnss_vreg_off_type(struct cnss_plat_data *plat_priv, return ret; } static int cnss_get_clk_single(struct cnss_plat_data *plat_priv, struct cnss_clk_info *clk_info) { struct device *dev = &plat_priv->plat_dev->dev; struct clk *clk; int ret; clk = devm_clk_get(dev, clk_info->cfg.name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); if (clk_info->cfg.required) cnss_pr_err("Failed to get clock %s, err = %d\n", clk_info->cfg.name, ret); else cnss_pr_dbg("Failed to get optional clock %s, err = %d\n", clk_info->cfg.name, ret); return ret; } clk_info->clk = clk; cnss_pr_dbg("Got clock: %s, freq: %u\n", clk_info->cfg.name, clk_info->cfg.freq); return 0; } static void cnss_put_clk_single(struct cnss_plat_data *plat_priv, struct cnss_clk_info *clk_info) { struct device *dev = &plat_priv->plat_dev->dev; cnss_pr_dbg("Put clock: %s\n", clk_info->cfg.name); devm_clk_put(dev, clk_info->clk); } static int cnss_clk_on_single(struct cnss_clk_info *clk_info) { int ret; if (clk_info->enabled) { cnss_pr_dbg("Clock %s is already enabled\n", clk_info->cfg.name); return 0; } cnss_pr_dbg("Clock %s is being enabled\n", clk_info->cfg.name); if (clk_info->cfg.freq) { ret = clk_set_rate(clk_info->clk, clk_info->cfg.freq); if (ret) { cnss_pr_err("Failed to set frequency %u for clock %s, err = %d\n", clk_info->cfg.freq, clk_info->cfg.name, ret); return ret; } } ret = clk_prepare_enable(clk_info->clk); if (ret) { cnss_pr_err("Failed to enable clock %s, err = %d\n", clk_info->cfg.name, ret); return ret; } clk_info->enabled = true; return 0; } static int cnss_clk_off_single(struct cnss_clk_info *clk_info) { if (!clk_info->enabled) { cnss_pr_dbg("Clock %s is already disabled\n", clk_info->cfg.name); return 0; } cnss_pr_dbg("Clock %s is being disabled\n", clk_info->cfg.name); clk_disable_unprepare(clk_info->clk); clk_info->enabled = false; return 0; } int cnss_get_clk(struct cnss_plat_data *plat_priv) { struct device *dev; struct list_head *clk_list; struct cnss_clk_info *clk_info; int ret, i; if (!plat_priv) return -ENODEV; dev = &plat_priv->plat_dev->dev; clk_list = &plat_priv->clk_list; if (!list_empty(clk_list)) { cnss_pr_dbg("Clocks have already been updated\n"); return 0; } for (i = 0; i < CNSS_CLK_INFO_SIZE; i++) { clk_info = devm_kzalloc(dev, sizeof(*clk_info), GFP_KERNEL); if (!clk_info) { ret = -ENOMEM; goto cleanup; } memcpy(&clk_info->cfg, &cnss_clk_list[i], sizeof(clk_info->cfg)); ret = cnss_get_clk_single(plat_priv, clk_info); if (ret != 0) { if (clk_info->cfg.required) { devm_kfree(dev, clk_info); goto cleanup; } else { devm_kfree(dev, clk_info); continue; } } list_add_tail(&clk_info->list, clk_list); } return 0; cleanup: while (!list_empty(clk_list)) { clk_info = list_first_entry(clk_list, struct cnss_clk_info, list); list_del(&clk_info->list); if (IS_ERR_OR_NULL(clk_info->clk)) continue; cnss_put_clk_single(plat_priv, clk_info); devm_kfree(dev, clk_info); } return ret; } void cnss_put_clk(struct cnss_plat_data *plat_priv) { struct device *dev; struct list_head *clk_list; struct cnss_clk_info *clk_info; if (!plat_priv) return; dev = &plat_priv->plat_dev->dev; clk_list = &plat_priv->clk_list; while (!list_empty(clk_list)) { clk_info = list_first_entry(clk_list, struct cnss_clk_info, list); list_del(&clk_info->list); if (IS_ERR_OR_NULL(clk_info->clk)) continue; cnss_put_clk_single(plat_priv, clk_info); devm_kfree(dev, clk_info); } } static int cnss_clk_on(struct cnss_plat_data *plat_priv, struct list_head *clk_list) { struct cnss_clk_info *clk_info; int ret = 0; list_for_each_entry(clk_info, clk_list, list) { if (IS_ERR_OR_NULL(clk_info->clk)) continue; ret = cnss_clk_on_single(clk_info); if (ret) break; } if (!ret) return 0; list_for_each_entry_continue_reverse(clk_info, clk_list, list) { if (IS_ERR_OR_NULL(clk_info->clk)) continue; cnss_clk_off_single(clk_info); } return ret; } static int cnss_clk_off(struct cnss_plat_data *plat_priv, struct list_head *clk_list) { struct cnss_clk_info *clk_info; list_for_each_entry_reverse(clk_info, clk_list, list) { if (IS_ERR_OR_NULL(clk_info->clk)) continue; cnss_clk_off_single(clk_info); } return 0; } int cnss_get_pinctrl(struct cnss_plat_data *plat_priv) { int ret = 0; Loading Loading @@ -499,14 +711,24 @@ int cnss_power_on_device(struct cnss_plat_data *plat_priv) goto out; } ret = cnss_clk_on(plat_priv, &plat_priv->clk_list); if (ret) { cnss_pr_err("Failed to turn on clocks, err = %d\n", ret); goto vreg_off; } ret = cnss_select_pinctrl_state(plat_priv, true); if (ret) { cnss_pr_err("Failed to select pinctrl state, err = %d\n", ret); goto vreg_off; goto clk_off; } plat_priv->powered_on = true; return 0; clk_off: cnss_clk_off(plat_priv, &plat_priv->clk_list); vreg_off: cnss_vreg_off_type(plat_priv, CNSS_VREG_PRIM); out: Loading @@ -521,6 +743,7 @@ void cnss_power_off_device(struct cnss_plat_data *plat_priv) } cnss_select_pinctrl_state(plat_priv, false); cnss_clk_off(plat_priv, &plat_priv->clk_list); cnss_vreg_off_type(plat_priv, CNSS_VREG_PRIM); plat_priv->powered_on = false; } Loading Loading
drivers/net/wireless/cnss2/main.c +15 −1 Original line number Diff line number Diff line Loading @@ -722,19 +722,32 @@ static int cnss_get_resources(struct cnss_plat_data *plat_priv) goto out; } ret = cnss_get_clk(plat_priv); if (ret) { cnss_pr_err("Failed to get clocks, err = %d\n", ret); goto put_vreg; } ret = cnss_get_pinctrl(plat_priv); if (ret) { cnss_pr_err("Failed to get pinctrl, err = %d\n", ret); goto out; goto put_clk; } return 0; put_clk: cnss_put_clk(plat_priv); put_vreg: cnss_put_vreg_type(plat_priv, CNSS_VREG_PRIM); out: return ret; } static void cnss_put_resources(struct cnss_plat_data *plat_priv) { cnss_put_clk(plat_priv); cnss_put_vreg_type(plat_priv, CNSS_VREG_PRIM); } static int cnss_modem_notifier_nb(struct notifier_block *nb, Loading Loading @@ -1929,6 +1942,7 @@ static int cnss_probe(struct platform_device *plat_dev) cnss_set_plat_priv(plat_dev, plat_priv); platform_set_drvdata(plat_dev, plat_priv); INIT_LIST_HEAD(&plat_priv->vreg_list); INIT_LIST_HEAD(&plat_priv->clk_list); cnss_get_cpr_info(plat_priv); cnss_init_control_params(plat_priv); Loading
drivers/net/wireless/cnss2/main.h +16 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,19 @@ enum cnss_vreg_type { CNSS_VREG_PRIM, }; struct cnss_clk_cfg { const char *name; u32 freq; u32 required; }; struct cnss_clk_info { struct list_head list; struct clk *clk; struct cnss_clk_cfg cfg; u32 enabled; }; struct cnss_pinctrl_info { struct pinctrl *pinctrl; struct pinctrl_state *bootstrap_active; Loading Loading @@ -269,6 +282,7 @@ struct cnss_plat_data { void *bus_priv; enum cnss_dev_bus_type bus_type; struct list_head vreg_list; struct list_head clk_list; struct cnss_pinctrl_info pinctrl_info; struct cnss_subsys_info subsys_info; struct cnss_ramdump_info ramdump_info; Loading Loading @@ -355,6 +369,8 @@ 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_clk(struct cnss_plat_data *plat_priv); void cnss_put_clk(struct cnss_plat_data *plat_priv); 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 +224 −1 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include <linux/clk.h> #include <linux/delay.h> #include <linux/of.h> #include <linux/pinctrl/consumer.h> Loading Loading @@ -28,7 +29,12 @@ static struct cnss_vreg_cfg cnss_vreg_list[] = { {"vdd-wlan-en", 0, 0, 0, 10}, }; static struct cnss_clk_cfg cnss_clk_list[] = { {"rf_clk", 0, 0}, }; #define CNSS_VREG_INFO_SIZE ARRAY_SIZE(cnss_vreg_list) #define CNSS_CLK_INFO_SIZE ARRAY_SIZE(cnss_clk_list) #define MAX_PROP_SIZE 32 #define BOOTSTRAP_GPIO "qcom,enable-bootstrap-gpio" Loading Loading @@ -374,6 +380,212 @@ int cnss_vreg_off_type(struct cnss_plat_data *plat_priv, return ret; } static int cnss_get_clk_single(struct cnss_plat_data *plat_priv, struct cnss_clk_info *clk_info) { struct device *dev = &plat_priv->plat_dev->dev; struct clk *clk; int ret; clk = devm_clk_get(dev, clk_info->cfg.name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); if (clk_info->cfg.required) cnss_pr_err("Failed to get clock %s, err = %d\n", clk_info->cfg.name, ret); else cnss_pr_dbg("Failed to get optional clock %s, err = %d\n", clk_info->cfg.name, ret); return ret; } clk_info->clk = clk; cnss_pr_dbg("Got clock: %s, freq: %u\n", clk_info->cfg.name, clk_info->cfg.freq); return 0; } static void cnss_put_clk_single(struct cnss_plat_data *plat_priv, struct cnss_clk_info *clk_info) { struct device *dev = &plat_priv->plat_dev->dev; cnss_pr_dbg("Put clock: %s\n", clk_info->cfg.name); devm_clk_put(dev, clk_info->clk); } static int cnss_clk_on_single(struct cnss_clk_info *clk_info) { int ret; if (clk_info->enabled) { cnss_pr_dbg("Clock %s is already enabled\n", clk_info->cfg.name); return 0; } cnss_pr_dbg("Clock %s is being enabled\n", clk_info->cfg.name); if (clk_info->cfg.freq) { ret = clk_set_rate(clk_info->clk, clk_info->cfg.freq); if (ret) { cnss_pr_err("Failed to set frequency %u for clock %s, err = %d\n", clk_info->cfg.freq, clk_info->cfg.name, ret); return ret; } } ret = clk_prepare_enable(clk_info->clk); if (ret) { cnss_pr_err("Failed to enable clock %s, err = %d\n", clk_info->cfg.name, ret); return ret; } clk_info->enabled = true; return 0; } static int cnss_clk_off_single(struct cnss_clk_info *clk_info) { if (!clk_info->enabled) { cnss_pr_dbg("Clock %s is already disabled\n", clk_info->cfg.name); return 0; } cnss_pr_dbg("Clock %s is being disabled\n", clk_info->cfg.name); clk_disable_unprepare(clk_info->clk); clk_info->enabled = false; return 0; } int cnss_get_clk(struct cnss_plat_data *plat_priv) { struct device *dev; struct list_head *clk_list; struct cnss_clk_info *clk_info; int ret, i; if (!plat_priv) return -ENODEV; dev = &plat_priv->plat_dev->dev; clk_list = &plat_priv->clk_list; if (!list_empty(clk_list)) { cnss_pr_dbg("Clocks have already been updated\n"); return 0; } for (i = 0; i < CNSS_CLK_INFO_SIZE; i++) { clk_info = devm_kzalloc(dev, sizeof(*clk_info), GFP_KERNEL); if (!clk_info) { ret = -ENOMEM; goto cleanup; } memcpy(&clk_info->cfg, &cnss_clk_list[i], sizeof(clk_info->cfg)); ret = cnss_get_clk_single(plat_priv, clk_info); if (ret != 0) { if (clk_info->cfg.required) { devm_kfree(dev, clk_info); goto cleanup; } else { devm_kfree(dev, clk_info); continue; } } list_add_tail(&clk_info->list, clk_list); } return 0; cleanup: while (!list_empty(clk_list)) { clk_info = list_first_entry(clk_list, struct cnss_clk_info, list); list_del(&clk_info->list); if (IS_ERR_OR_NULL(clk_info->clk)) continue; cnss_put_clk_single(plat_priv, clk_info); devm_kfree(dev, clk_info); } return ret; } void cnss_put_clk(struct cnss_plat_data *plat_priv) { struct device *dev; struct list_head *clk_list; struct cnss_clk_info *clk_info; if (!plat_priv) return; dev = &plat_priv->plat_dev->dev; clk_list = &plat_priv->clk_list; while (!list_empty(clk_list)) { clk_info = list_first_entry(clk_list, struct cnss_clk_info, list); list_del(&clk_info->list); if (IS_ERR_OR_NULL(clk_info->clk)) continue; cnss_put_clk_single(plat_priv, clk_info); devm_kfree(dev, clk_info); } } static int cnss_clk_on(struct cnss_plat_data *plat_priv, struct list_head *clk_list) { struct cnss_clk_info *clk_info; int ret = 0; list_for_each_entry(clk_info, clk_list, list) { if (IS_ERR_OR_NULL(clk_info->clk)) continue; ret = cnss_clk_on_single(clk_info); if (ret) break; } if (!ret) return 0; list_for_each_entry_continue_reverse(clk_info, clk_list, list) { if (IS_ERR_OR_NULL(clk_info->clk)) continue; cnss_clk_off_single(clk_info); } return ret; } static int cnss_clk_off(struct cnss_plat_data *plat_priv, struct list_head *clk_list) { struct cnss_clk_info *clk_info; list_for_each_entry_reverse(clk_info, clk_list, list) { if (IS_ERR_OR_NULL(clk_info->clk)) continue; cnss_clk_off_single(clk_info); } return 0; } int cnss_get_pinctrl(struct cnss_plat_data *plat_priv) { int ret = 0; Loading Loading @@ -499,14 +711,24 @@ int cnss_power_on_device(struct cnss_plat_data *plat_priv) goto out; } ret = cnss_clk_on(plat_priv, &plat_priv->clk_list); if (ret) { cnss_pr_err("Failed to turn on clocks, err = %d\n", ret); goto vreg_off; } ret = cnss_select_pinctrl_state(plat_priv, true); if (ret) { cnss_pr_err("Failed to select pinctrl state, err = %d\n", ret); goto vreg_off; goto clk_off; } plat_priv->powered_on = true; return 0; clk_off: cnss_clk_off(plat_priv, &plat_priv->clk_list); vreg_off: cnss_vreg_off_type(plat_priv, CNSS_VREG_PRIM); out: Loading @@ -521,6 +743,7 @@ void cnss_power_off_device(struct cnss_plat_data *plat_priv) } cnss_select_pinctrl_state(plat_priv, false); cnss_clk_off(plat_priv, &plat_priv->clk_list); cnss_vreg_off_type(plat_priv, CNSS_VREG_PRIM); plat_priv->powered_on = false; } Loading