Loading Documentation/devicetree/bindings/cnss/icnss.txt +6 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,10 @@ Required properties: - reg-names: Names of the memory regions defined in reg entry - interrupts: Copy engine interrupt table - qcom,wlan-msa-memory: MSA memory size - <supply-name>-supply: phandle to the regulator device tree node Required "supply-name" is "vdd-io". - qcom,<supply>-voltage-level - specifies voltage levels for supply. Should be specified in pairs (min, max), units uV. Optional properties: - qcom,skip-qmi: Boolean property to decide whether to use QMI or not Loading @@ -37,4 +41,6 @@ Example: <0 141 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x200000>; qcom,skip-qmi; vdd-io-supply = <&pmcobalt_l5>; qcom,vdd-io-voltage-level = <800000 800000>; }; arch/arm/boot/dts/qcom/msmcobalt-rumi.dtsi +2 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,8 @@ <0 424 0 /* CE10 */ >, <0 425 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x100000>; vdd-io-supply = <&pmcobalt_l5>; qcom,vdd-io-voltage-level = <800000 800000>; }; msm_cpufreq: qcom,msm-cpufreq { Loading drivers/soc/qcom/icnss.c +262 −21 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/dma-mapping.h> Loading Loading @@ -44,11 +45,14 @@ struct icnss_qmi_event { #define WLFW_SERVICE_INS_ID_V01 0 #define ICNSS_WLFW_QMI_CONNECTED BIT(0) #define ICNSS_FW_READY BIT(1) #define MAX_PROP_SIZE 32 #define MAX_VOLTAGE_LEVEL 2 #define VREG_ON 1 #define VREG_OFF 0 #define ICNSS_IS_WLFW_QMI_CONNECTED(_state) \ ((_state) & ICNSS_WLFW_QMI_CONNECTED) #define ICNSS_IS_FW_READY(_state) ((_state) & ICNSS_FW_READY) #ifdef ICNSS_PANIC #define ICNSS_ASSERT(_condition) do { \ if (!(_condition)) { \ Loading @@ -72,10 +76,19 @@ struct ce_irq_list { irqreturn_t (*handler)(int, void *); }; struct icnss_vreg_info { struct regulator *reg; const char *name; u32 nominal_min; u32 max_voltage; bool state; }; static struct { struct platform_device *pdev; struct icnss_driver_ops *ops; struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS]; struct icnss_vreg_info vreg_info; u32 ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS]; phys_addr_t mem_base_pa; void __iomem *mem_base_va; Loading Loading @@ -161,19 +174,121 @@ out: return ret; } static int icnss_vreg_on(struct icnss_vreg_info *vreg_info) { int ret = 0; if (!vreg_info->reg) { pr_err("%s: regulator is not initialized\n", __func__); return -ENOENT; } if (!vreg_info->max_voltage || !vreg_info->nominal_min) { pr_err("%s: %s invalid constraints specified\n", __func__, vreg_info->name); return -EINVAL; } ret = regulator_set_voltage(vreg_info->reg, vreg_info->nominal_min, vreg_info->max_voltage); if (ret < 0) { pr_err("%s: regulator_set_voltage failed for (%s). min_uV=%d,max_uV=%d,ret=%d\n", __func__, vreg_info->name, vreg_info->nominal_min, vreg_info->max_voltage, ret); return ret; } ret = regulator_enable(vreg_info->reg); if (ret < 0) { pr_err("%s: Fail to enable regulator (%s) ret=%d\n", __func__, vreg_info->name, ret); } return ret; } static int icnss_vreg_off(struct icnss_vreg_info *vreg_info) { int ret = 0; int min_uV = 0; if (!vreg_info->reg) { pr_err("%s: regulator is not initialized\n", __func__); return -ENOENT; } ret = regulator_disable(vreg_info->reg); if (ret < 0) { pr_err("%s: Fail to disable regulator (%s) ret=%d\n", __func__, vreg_info->name, ret); return ret; } ret = regulator_set_voltage(vreg_info->reg, min_uV, vreg_info->max_voltage); if (ret < 0) { pr_err("%s: regulator_set_voltage failed for (%s). min_uV=%d,max_uV=%d,ret=%d\n", __func__, vreg_info->name, min_uV, vreg_info->max_voltage, ret); } return ret; } static int icnss_vreg_set(bool state) { int ret = 0; struct icnss_vreg_info *vreg_info = &penv->vreg_info; if (vreg_info->state == state) { pr_debug("Already %s state is %s\n", vreg_info->name, state ? "enabled" : "disabled"); return ret; } if (state) ret = icnss_vreg_on(vreg_info); else ret = icnss_vreg_off(vreg_info); if (ret < 0) goto out; pr_debug("%s: %s is now %s\n", __func__, vreg_info->name, state ? "enabled" : "disabled"); vreg_info->state = state; out: return ret; } static int icnss_adrastea_power_on(void) { int ret = 0; ret = icnss_vreg_set(VREG_ON); if (ret < 0) { pr_err("%s: Failed to turn on voltagre regulator: %d\n", __func__, ret); goto out; } /* TZ API of power on adrastea */ out: return ret; } void icnss_adrastea_power_off(void) static int icnss_adrastea_power_off(void) { int ret = 0; ret = icnss_vreg_set(VREG_OFF); if (ret < 0) { pr_err("%s: Failed to turn off voltagre regulator: %d\n", __func__, ret); goto out; } /* TZ API of power off adrastea */ out: return ret; } static int wlfw_msa_mem_info_send_sync_msg(void) Loading Loading @@ -629,7 +744,7 @@ static int icnss_qmi_event_server_arrive(void *data) if (ret < 0) { pr_err("%s: Failed to send indication message: %d\n", __func__, ret); goto fail; goto err_power_on; } if (penv->msa_va) { Loading @@ -637,27 +752,33 @@ static int icnss_qmi_event_server_arrive(void *data) if (ret < 0) { pr_err("%s: Failed to send MSA info: %d\n", __func__, ret); goto fail; goto err_power_on; } ret = wlfw_msa_ready_send_sync_msg(); if (ret < 0) { pr_err("%s: Failed to send MSA ready : %d\n", __func__, ret); goto fail; } goto err_power_on; } else { pr_err("%s: Invalid MSA address\n", __func__); ret = -EINVAL; goto fail; goto err_power_on; } ret = wlfw_cap_send_sync_msg(); if (ret < 0) { pr_err("%s: Failed to get capability: %d\n", __func__, ret); goto fail; goto err_power_on; } return ret; err_power_on: ret = icnss_vreg_set(VREG_OFF); if (ret < 0) { pr_err("%s: Failed to turn off voltagre regulator: %d\n", __func__, ret); } fail: qmi_handle_destroy(penv->wlfw_clnt); penv->wlfw_clnt = NULL; Loading Loading @@ -696,7 +817,12 @@ static int icnss_qmi_event_fw_ready_ind(void *data) goto out; } icnss_adrastea_power_off(); ret = icnss_adrastea_power_off(); if (ret < 0) { pr_err("%s: Failed to power off hardware: %d\n", __func__, ret); goto out; } if (!penv->ops || !penv->ops->probe) { pr_err("%s: WLAN driver is not registed yet\n", __func__); Loading Loading @@ -803,12 +929,17 @@ int icnss_register_driver(struct icnss_driver_ops *ops) /* check for all conditions before invoking probe */ if (ICNSS_IS_FW_READY(penv->state) && penv->ops->probe) { ret = icnss_vreg_set(VREG_ON); if (ret < 0) { pr_err("%s: Failed to turn on voltagre regulator: %d\n", __func__, ret); goto out; } ret = penv->ops->probe(&pdev->dev); } else { pr_err("icnss: FW is not ready\n"); ret = -ENOENT; } out: return ret; } Loading Loading @@ -838,6 +969,11 @@ int icnss_unregister_driver(struct icnss_driver_ops *ops) penv->ops->remove(&pdev->dev); penv->ops = NULL; ret = icnss_vreg_set(VREG_OFF); if (ret < 0) pr_err("%s: Failed to turn off voltagre regulator: %d\n", __func__, ret); out: return ret; } Loading Loading @@ -1150,6 +1286,79 @@ static ssize_t icnss_wlan_mode_store(struct device *dev, static DEVICE_ATTR(icnss_wlan_mode, S_IWUSR, NULL, icnss_wlan_mode_store); static int icnss_dt_parse_vreg_info(struct device *dev, struct icnss_vreg_info *vreg_info, const char *vreg_name) { int ret = 0; u32 voltage_levels[MAX_VOLTAGE_LEVEL] char prop_name[MAX_PROP_SIZE]; struct device_node *np = dev->of_node; snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name); if (!of_parse_phandle(np, prop_name, 0)) { pr_err("%s: No vreg data found for %s\n", __func__, vreg_name); ret = -EINVAL; return ret; } vreg_info->name = vreg_name; snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-voltage-level", vreg_name); ret = of_property_read_u32_array(np, prop_name, voltage_levels, ARRAY_SIZE(voltage_levels)); if (ret) { pr_err("%s: error reading %s property\n", __func__, prop_name); return ret; } vreg_info->nominal_min = voltage_levels[0]; vreg_info->max_voltage = voltage_levels[1]; return ret; } static int icnss_get_resources(struct device *dev) { int ret = 0; struct icnss_vreg_info *vreg_info; vreg_info = &penv->vreg_info; if (vreg_info->reg) { pr_err("%s: %s regulator is already initialized\n", __func__, vreg_info->name); return ret; } vreg_info->reg = devm_regulator_get(dev, vreg_info->name); if (IS_ERR(vreg_info->reg)) { ret = PTR_ERR(vreg_info->reg); if (ret == -EPROBE_DEFER) { pr_err("%s: %s probe deferred!\n", __func__, vreg_info->name); } else { pr_err("%s: Get %s failed!\n", __func__, vreg_info->name); } } return ret; } static int icnss_release_resources(void) { int ret = 0; struct icnss_vreg_info *vreg_info = &penv->vreg_info; if (!vreg_info->reg) { pr_err("%s: regulator is not initialized\n", __func__); return -ENOENT; } devm_regulator_put(vreg_info->reg); return ret; } static int icnss_probe(struct platform_device *pdev) { int ret = 0; Loading @@ -1157,8 +1366,10 @@ static int icnss_probe(struct platform_device *pdev) int i; struct device *dev = &pdev->dev; if (penv) if (penv) { pr_err("%s: penv is already initialized\n", __func__); return -EEXIST; } penv = devm_kzalloc(&pdev->dev, sizeof(*penv), GFP_KERNEL); if (!penv) Loading @@ -1166,26 +1377,38 @@ static int icnss_probe(struct platform_device *pdev) penv->pdev = pdev; ret = icnss_dt_parse_vreg_info(dev, &penv->vreg_info, "vdd-io"); if (ret < 0) { pr_err("%s: failed parsing vdd io data\n", __func__); goto out; } ret = icnss_get_resources(dev); if (ret < 0) { pr_err("%s: Regulator setup failed (%d)\n", __func__, ret); goto out; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase"); if (!res) { pr_err("icnss: Memory base not found\n"); pr_err("%s: Memory base not found\n", __func__); ret = -EINVAL; goto out; goto release_regulator; } penv->mem_base_pa = res->start; penv->mem_base_va = ioremap(penv->mem_base_pa, resource_size(res)); if (!penv->mem_base_va) { pr_err("icnss: ioremap failed\n"); pr_err("%s: ioremap failed\n", __func__); ret = -EINVAL; goto out; goto release_regulator; } for (i = 0; i < ICNSS_MAX_IRQ_REGISTRATIONS; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { pr_err("icnss: Fail to get IRQ-%d\n", i); pr_err("%s: Fail to get IRQ-%d\n", __func__, i); ret = -ENODEV; goto out; goto release_regulator; } else { penv->ce_irqs[i] = res->start; } Loading @@ -1201,7 +1424,7 @@ static int icnss_probe(struct platform_device *pdev) if (!penv->msa_va) { pr_err("%s: DMA alloc failed\n", __func__); ret = -EINVAL; goto out; goto release_regulator; } pr_debug("%s: MAS va: %p, MSA pa: %pa\n", __func__, penv->msa_va, &penv->msa_pa); Loading @@ -1209,7 +1432,7 @@ static int icnss_probe(struct platform_device *pdev) } else { pr_err("%s: Fail to get MSA Memory Size\n", __func__); ret = -ENODEV; goto out; goto release_regulator; } penv->skip_qmi = of_property_read_bool(dev->of_node, Loading Loading @@ -1255,12 +1478,21 @@ err_wlan_mode: if (penv->msa_va) dma_free_coherent(&pdev->dev, penv->msa_mem_size, penv->msa_va, penv->msa_pa); release_regulator: ret = icnss_release_resources(); if (ret < 0) pr_err("%s: fail to release the platform resource\n", __func__); out: devm_kfree(&pdev->dev, penv); penv = NULL; return ret; } static int icnss_remove(struct platform_device *pdev) { int ret = 0; qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01, WLFW_SERVICE_VERS_V01, WLFW_SERVICE_INS_ID_V01, Loading @@ -1272,7 +1504,16 @@ static int icnss_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, penv->msa_mem_size, penv->msa_va, penv->msa_pa); return 0; ret = icnss_vreg_set(VREG_OFF); if (ret < 0) pr_err("%s: Failed to turn off voltagre regulator: %d\n", __func__, ret); ret = icnss_release_resources(); if (ret < 0) pr_err("%s: fail to release the platform resource\n", __func__); return ret; } Loading Loading
Documentation/devicetree/bindings/cnss/icnss.txt +6 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,10 @@ Required properties: - reg-names: Names of the memory regions defined in reg entry - interrupts: Copy engine interrupt table - qcom,wlan-msa-memory: MSA memory size - <supply-name>-supply: phandle to the regulator device tree node Required "supply-name" is "vdd-io". - qcom,<supply>-voltage-level - specifies voltage levels for supply. Should be specified in pairs (min, max), units uV. Optional properties: - qcom,skip-qmi: Boolean property to decide whether to use QMI or not Loading @@ -37,4 +41,6 @@ Example: <0 141 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x200000>; qcom,skip-qmi; vdd-io-supply = <&pmcobalt_l5>; qcom,vdd-io-voltage-level = <800000 800000>; };
arch/arm/boot/dts/qcom/msmcobalt-rumi.dtsi +2 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,8 @@ <0 424 0 /* CE10 */ >, <0 425 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x100000>; vdd-io-supply = <&pmcobalt_l5>; qcom,vdd-io-voltage-level = <800000 800000>; }; msm_cpufreq: qcom,msm-cpufreq { Loading
drivers/soc/qcom/icnss.c +262 −21 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/dma-mapping.h> Loading Loading @@ -44,11 +45,14 @@ struct icnss_qmi_event { #define WLFW_SERVICE_INS_ID_V01 0 #define ICNSS_WLFW_QMI_CONNECTED BIT(0) #define ICNSS_FW_READY BIT(1) #define MAX_PROP_SIZE 32 #define MAX_VOLTAGE_LEVEL 2 #define VREG_ON 1 #define VREG_OFF 0 #define ICNSS_IS_WLFW_QMI_CONNECTED(_state) \ ((_state) & ICNSS_WLFW_QMI_CONNECTED) #define ICNSS_IS_FW_READY(_state) ((_state) & ICNSS_FW_READY) #ifdef ICNSS_PANIC #define ICNSS_ASSERT(_condition) do { \ if (!(_condition)) { \ Loading @@ -72,10 +76,19 @@ struct ce_irq_list { irqreturn_t (*handler)(int, void *); }; struct icnss_vreg_info { struct regulator *reg; const char *name; u32 nominal_min; u32 max_voltage; bool state; }; static struct { struct platform_device *pdev; struct icnss_driver_ops *ops; struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS]; struct icnss_vreg_info vreg_info; u32 ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS]; phys_addr_t mem_base_pa; void __iomem *mem_base_va; Loading Loading @@ -161,19 +174,121 @@ out: return ret; } static int icnss_vreg_on(struct icnss_vreg_info *vreg_info) { int ret = 0; if (!vreg_info->reg) { pr_err("%s: regulator is not initialized\n", __func__); return -ENOENT; } if (!vreg_info->max_voltage || !vreg_info->nominal_min) { pr_err("%s: %s invalid constraints specified\n", __func__, vreg_info->name); return -EINVAL; } ret = regulator_set_voltage(vreg_info->reg, vreg_info->nominal_min, vreg_info->max_voltage); if (ret < 0) { pr_err("%s: regulator_set_voltage failed for (%s). min_uV=%d,max_uV=%d,ret=%d\n", __func__, vreg_info->name, vreg_info->nominal_min, vreg_info->max_voltage, ret); return ret; } ret = regulator_enable(vreg_info->reg); if (ret < 0) { pr_err("%s: Fail to enable regulator (%s) ret=%d\n", __func__, vreg_info->name, ret); } return ret; } static int icnss_vreg_off(struct icnss_vreg_info *vreg_info) { int ret = 0; int min_uV = 0; if (!vreg_info->reg) { pr_err("%s: regulator is not initialized\n", __func__); return -ENOENT; } ret = regulator_disable(vreg_info->reg); if (ret < 0) { pr_err("%s: Fail to disable regulator (%s) ret=%d\n", __func__, vreg_info->name, ret); return ret; } ret = regulator_set_voltage(vreg_info->reg, min_uV, vreg_info->max_voltage); if (ret < 0) { pr_err("%s: regulator_set_voltage failed for (%s). min_uV=%d,max_uV=%d,ret=%d\n", __func__, vreg_info->name, min_uV, vreg_info->max_voltage, ret); } return ret; } static int icnss_vreg_set(bool state) { int ret = 0; struct icnss_vreg_info *vreg_info = &penv->vreg_info; if (vreg_info->state == state) { pr_debug("Already %s state is %s\n", vreg_info->name, state ? "enabled" : "disabled"); return ret; } if (state) ret = icnss_vreg_on(vreg_info); else ret = icnss_vreg_off(vreg_info); if (ret < 0) goto out; pr_debug("%s: %s is now %s\n", __func__, vreg_info->name, state ? "enabled" : "disabled"); vreg_info->state = state; out: return ret; } static int icnss_adrastea_power_on(void) { int ret = 0; ret = icnss_vreg_set(VREG_ON); if (ret < 0) { pr_err("%s: Failed to turn on voltagre regulator: %d\n", __func__, ret); goto out; } /* TZ API of power on adrastea */ out: return ret; } void icnss_adrastea_power_off(void) static int icnss_adrastea_power_off(void) { int ret = 0; ret = icnss_vreg_set(VREG_OFF); if (ret < 0) { pr_err("%s: Failed to turn off voltagre regulator: %d\n", __func__, ret); goto out; } /* TZ API of power off adrastea */ out: return ret; } static int wlfw_msa_mem_info_send_sync_msg(void) Loading Loading @@ -629,7 +744,7 @@ static int icnss_qmi_event_server_arrive(void *data) if (ret < 0) { pr_err("%s: Failed to send indication message: %d\n", __func__, ret); goto fail; goto err_power_on; } if (penv->msa_va) { Loading @@ -637,27 +752,33 @@ static int icnss_qmi_event_server_arrive(void *data) if (ret < 0) { pr_err("%s: Failed to send MSA info: %d\n", __func__, ret); goto fail; goto err_power_on; } ret = wlfw_msa_ready_send_sync_msg(); if (ret < 0) { pr_err("%s: Failed to send MSA ready : %d\n", __func__, ret); goto fail; } goto err_power_on; } else { pr_err("%s: Invalid MSA address\n", __func__); ret = -EINVAL; goto fail; goto err_power_on; } ret = wlfw_cap_send_sync_msg(); if (ret < 0) { pr_err("%s: Failed to get capability: %d\n", __func__, ret); goto fail; goto err_power_on; } return ret; err_power_on: ret = icnss_vreg_set(VREG_OFF); if (ret < 0) { pr_err("%s: Failed to turn off voltagre regulator: %d\n", __func__, ret); } fail: qmi_handle_destroy(penv->wlfw_clnt); penv->wlfw_clnt = NULL; Loading Loading @@ -696,7 +817,12 @@ static int icnss_qmi_event_fw_ready_ind(void *data) goto out; } icnss_adrastea_power_off(); ret = icnss_adrastea_power_off(); if (ret < 0) { pr_err("%s: Failed to power off hardware: %d\n", __func__, ret); goto out; } if (!penv->ops || !penv->ops->probe) { pr_err("%s: WLAN driver is not registed yet\n", __func__); Loading Loading @@ -803,12 +929,17 @@ int icnss_register_driver(struct icnss_driver_ops *ops) /* check for all conditions before invoking probe */ if (ICNSS_IS_FW_READY(penv->state) && penv->ops->probe) { ret = icnss_vreg_set(VREG_ON); if (ret < 0) { pr_err("%s: Failed to turn on voltagre regulator: %d\n", __func__, ret); goto out; } ret = penv->ops->probe(&pdev->dev); } else { pr_err("icnss: FW is not ready\n"); ret = -ENOENT; } out: return ret; } Loading Loading @@ -838,6 +969,11 @@ int icnss_unregister_driver(struct icnss_driver_ops *ops) penv->ops->remove(&pdev->dev); penv->ops = NULL; ret = icnss_vreg_set(VREG_OFF); if (ret < 0) pr_err("%s: Failed to turn off voltagre regulator: %d\n", __func__, ret); out: return ret; } Loading Loading @@ -1150,6 +1286,79 @@ static ssize_t icnss_wlan_mode_store(struct device *dev, static DEVICE_ATTR(icnss_wlan_mode, S_IWUSR, NULL, icnss_wlan_mode_store); static int icnss_dt_parse_vreg_info(struct device *dev, struct icnss_vreg_info *vreg_info, const char *vreg_name) { int ret = 0; u32 voltage_levels[MAX_VOLTAGE_LEVEL] char prop_name[MAX_PROP_SIZE]; struct device_node *np = dev->of_node; snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name); if (!of_parse_phandle(np, prop_name, 0)) { pr_err("%s: No vreg data found for %s\n", __func__, vreg_name); ret = -EINVAL; return ret; } vreg_info->name = vreg_name; snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-voltage-level", vreg_name); ret = of_property_read_u32_array(np, prop_name, voltage_levels, ARRAY_SIZE(voltage_levels)); if (ret) { pr_err("%s: error reading %s property\n", __func__, prop_name); return ret; } vreg_info->nominal_min = voltage_levels[0]; vreg_info->max_voltage = voltage_levels[1]; return ret; } static int icnss_get_resources(struct device *dev) { int ret = 0; struct icnss_vreg_info *vreg_info; vreg_info = &penv->vreg_info; if (vreg_info->reg) { pr_err("%s: %s regulator is already initialized\n", __func__, vreg_info->name); return ret; } vreg_info->reg = devm_regulator_get(dev, vreg_info->name); if (IS_ERR(vreg_info->reg)) { ret = PTR_ERR(vreg_info->reg); if (ret == -EPROBE_DEFER) { pr_err("%s: %s probe deferred!\n", __func__, vreg_info->name); } else { pr_err("%s: Get %s failed!\n", __func__, vreg_info->name); } } return ret; } static int icnss_release_resources(void) { int ret = 0; struct icnss_vreg_info *vreg_info = &penv->vreg_info; if (!vreg_info->reg) { pr_err("%s: regulator is not initialized\n", __func__); return -ENOENT; } devm_regulator_put(vreg_info->reg); return ret; } static int icnss_probe(struct platform_device *pdev) { int ret = 0; Loading @@ -1157,8 +1366,10 @@ static int icnss_probe(struct platform_device *pdev) int i; struct device *dev = &pdev->dev; if (penv) if (penv) { pr_err("%s: penv is already initialized\n", __func__); return -EEXIST; } penv = devm_kzalloc(&pdev->dev, sizeof(*penv), GFP_KERNEL); if (!penv) Loading @@ -1166,26 +1377,38 @@ static int icnss_probe(struct platform_device *pdev) penv->pdev = pdev; ret = icnss_dt_parse_vreg_info(dev, &penv->vreg_info, "vdd-io"); if (ret < 0) { pr_err("%s: failed parsing vdd io data\n", __func__); goto out; } ret = icnss_get_resources(dev); if (ret < 0) { pr_err("%s: Regulator setup failed (%d)\n", __func__, ret); goto out; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase"); if (!res) { pr_err("icnss: Memory base not found\n"); pr_err("%s: Memory base not found\n", __func__); ret = -EINVAL; goto out; goto release_regulator; } penv->mem_base_pa = res->start; penv->mem_base_va = ioremap(penv->mem_base_pa, resource_size(res)); if (!penv->mem_base_va) { pr_err("icnss: ioremap failed\n"); pr_err("%s: ioremap failed\n", __func__); ret = -EINVAL; goto out; goto release_regulator; } for (i = 0; i < ICNSS_MAX_IRQ_REGISTRATIONS; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { pr_err("icnss: Fail to get IRQ-%d\n", i); pr_err("%s: Fail to get IRQ-%d\n", __func__, i); ret = -ENODEV; goto out; goto release_regulator; } else { penv->ce_irqs[i] = res->start; } Loading @@ -1201,7 +1424,7 @@ static int icnss_probe(struct platform_device *pdev) if (!penv->msa_va) { pr_err("%s: DMA alloc failed\n", __func__); ret = -EINVAL; goto out; goto release_regulator; } pr_debug("%s: MAS va: %p, MSA pa: %pa\n", __func__, penv->msa_va, &penv->msa_pa); Loading @@ -1209,7 +1432,7 @@ static int icnss_probe(struct platform_device *pdev) } else { pr_err("%s: Fail to get MSA Memory Size\n", __func__); ret = -ENODEV; goto out; goto release_regulator; } penv->skip_qmi = of_property_read_bool(dev->of_node, Loading Loading @@ -1255,12 +1478,21 @@ err_wlan_mode: if (penv->msa_va) dma_free_coherent(&pdev->dev, penv->msa_mem_size, penv->msa_va, penv->msa_pa); release_regulator: ret = icnss_release_resources(); if (ret < 0) pr_err("%s: fail to release the platform resource\n", __func__); out: devm_kfree(&pdev->dev, penv); penv = NULL; return ret; } static int icnss_remove(struct platform_device *pdev) { int ret = 0; qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01, WLFW_SERVICE_VERS_V01, WLFW_SERVICE_INS_ID_V01, Loading @@ -1272,7 +1504,16 @@ static int icnss_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, penv->msa_mem_size, penv->msa_va, penv->msa_pa); return 0; ret = icnss_vreg_set(VREG_OFF); if (ret < 0) pr_err("%s: Failed to turn off voltagre regulator: %d\n", __func__, ret); ret = icnss_release_resources(); if (ret < 0) pr_err("%s: fail to release the platform resource\n", __func__); return ret; } Loading