Merge "icnss: Vote for hardware resources"
This commit is contained in:
commit
2d20bbca35
3 changed files with 374 additions and 11 deletions
|
@ -12,9 +12,17 @@ Required properties:
|
||||||
- reg-names: Names of the memory regions defined in reg entry
|
- reg-names: Names of the memory regions defined in reg entry
|
||||||
- interrupts: Copy engine interrupt table
|
- interrupts: Copy engine interrupt table
|
||||||
- qcom,wlan-msa-memory: MSA memory size
|
- qcom,wlan-msa-memory: MSA memory size
|
||||||
|
- clocks: List of clock phandles
|
||||||
|
- clock-names: List of clock names corresponding to the "clocks" property
|
||||||
- iommus: SMMUs and corresponding Stream IDs needed by WLAN
|
- iommus: SMMUs and corresponding Stream IDs needed by WLAN
|
||||||
- qcom,wlan-smmu-iova-address: I/O virtual address range as <start length>
|
- qcom,wlan-smmu-iova-address: I/O virtual address range as <start length>
|
||||||
format to be used for allocations associated between WLAN and SMMU
|
format to be used for allocations associated between WLAN and SMMU
|
||||||
|
- <supply-name>-supply: phandle to the regulator device tree node
|
||||||
|
Required "supply-name" is "vdd-0.8-cx-mx".
|
||||||
|
- qcom,<supply>-config: Specifies voltage levels for supply. Should be
|
||||||
|
specified in pairs (min, max), units uV. There can
|
||||||
|
be optional load in uA and Regulator settle delay in
|
||||||
|
uS.
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- qcom,icnss-vadc: VADC handle for vph_pwr read APIs.
|
- qcom,icnss-vadc: VADC handle for vph_pwr read APIs.
|
||||||
|
@ -27,6 +35,8 @@ Example:
|
||||||
compatible = "qcom,icnss";
|
compatible = "qcom,icnss";
|
||||||
reg = <0x0a000000 0x1000000>;
|
reg = <0x0a000000 0x1000000>;
|
||||||
reg-names = "membase";
|
reg-names = "membase";
|
||||||
|
clocks = <&clock_gcc clk_aggre2_noc_clk>;
|
||||||
|
clock-names = "smmu_aggre2_noc_clk";
|
||||||
iommus = <&anoc2_smmu 0x1900>,
|
iommus = <&anoc2_smmu 0x1900>,
|
||||||
<&anoc2_smmu 0x1901>;
|
<&anoc2_smmu 0x1901>;
|
||||||
qcom,wlan-smmu-iova-address = <0 0x10000000>;
|
qcom,wlan-smmu-iova-address = <0 0x10000000>;
|
||||||
|
@ -45,4 +55,6 @@ Example:
|
||||||
<0 141 0 /* CE11 */ >;
|
<0 141 0 /* CE11 */ >;
|
||||||
qcom,wlan-msa-memory = <0x200000>;
|
qcom,wlan-msa-memory = <0x200000>;
|
||||||
qcom,smmu-s1-bypass;
|
qcom,smmu-s1-bypass;
|
||||||
|
vdd-0.8-cx-mx-supply = <&pm8998_l5>;
|
||||||
|
qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3079,6 +3079,8 @@
|
||||||
<0xa0000000 0x10000000>,
|
<0xa0000000 0x10000000>,
|
||||||
<0xb0000000 0x10000>;
|
<0xb0000000 0x10000>;
|
||||||
reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa";
|
reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa";
|
||||||
|
clocks = <&clock_gcc clk_rf_clk2_pin>;
|
||||||
|
clock-names = "cxo_ref_clk_pin";
|
||||||
iommus = <&anoc2_smmu 0x1900>,
|
iommus = <&anoc2_smmu 0x1900>,
|
||||||
<&anoc2_smmu 0x1901>;
|
<&anoc2_smmu 0x1901>;
|
||||||
interrupts = <0 413 0 /* CE0 */ >,
|
interrupts = <0 413 0 /* CE0 */ >,
|
||||||
|
@ -3094,6 +3096,12 @@
|
||||||
<0 424 0 /* CE10 */ >,
|
<0 424 0 /* CE10 */ >,
|
||||||
<0 425 0 /* CE11 */ >;
|
<0 425 0 /* CE11 */ >;
|
||||||
qcom,wlan-msa-memory = <0x100000>;
|
qcom,wlan-msa-memory = <0x100000>;
|
||||||
|
vdd-0.8-cx-mx-supply = <&pm8998_l5>;
|
||||||
|
vdd-1.8-xo-supply = <&pm8998_l7_pin_ctrl>;
|
||||||
|
vdd-1.3-rfa-supply = <&pm8998_l17_pin_ctrl>;
|
||||||
|
vdd-3.3-ch0-supply = <&pm8998_l25_pin_ctrl>;
|
||||||
|
qcom,vdd-0.8-cx-mx-config = <800000 800000>;
|
||||||
|
qcom,vdd-3.3-ch0-config = <3104000 3312000>;
|
||||||
qcom,icnss-vadc = <&pm8998_vadc>;
|
qcom,icnss-vadc = <&pm8998_vadc>;
|
||||||
qcom,icnss-adc_tm = <&pm8998_adc_tm>;
|
qcom,icnss-adc_tm = <&pm8998_adc_tm>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -195,6 +195,38 @@ struct ce_irq_list {
|
||||||
irqreturn_t (*handler)(int, void *);
|
irqreturn_t (*handler)(int, void *);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct icnss_vreg_info {
|
||||||
|
struct regulator *reg;
|
||||||
|
const char *name;
|
||||||
|
u32 min_v;
|
||||||
|
u32 max_v;
|
||||||
|
u32 load_ua;
|
||||||
|
unsigned long settle_delay;
|
||||||
|
bool required;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct icnss_clk_info {
|
||||||
|
struct clk *handle;
|
||||||
|
const char *name;
|
||||||
|
u32 freq;
|
||||||
|
bool required;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct icnss_vreg_info icnss_vreg_info[] = {
|
||||||
|
{NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, true},
|
||||||
|
{NULL, "vdd-1.8-xo", 1800000, 1800000, 0, 0, false},
|
||||||
|
{NULL, "vdd-1.3-rfa", 1304000, 1304000, 0, 0, false},
|
||||||
|
{NULL, "vdd-3.3-ch0", 3312000, 3312000, 0, 0, false},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ICNSS_VREG_INFO_SIZE ARRAY_SIZE(icnss_vreg_info)
|
||||||
|
|
||||||
|
static struct icnss_clk_info icnss_clk_info[] = {
|
||||||
|
{NULL, "cxo_ref_clk_pin", 0, false},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ICNSS_CLK_INFO_SIZE ARRAY_SIZE(icnss_clk_info)
|
||||||
|
|
||||||
struct icnss_stats {
|
struct icnss_stats {
|
||||||
struct {
|
struct {
|
||||||
uint32_t posted;
|
uint32_t posted;
|
||||||
|
@ -248,6 +280,7 @@ struct icnss_stats {
|
||||||
uint32_t rejuvenate_ack_req;
|
uint32_t rejuvenate_ack_req;
|
||||||
uint32_t rejuvenate_ack_resp;
|
uint32_t rejuvenate_ack_resp;
|
||||||
uint32_t rejuvenate_ack_err;
|
uint32_t rejuvenate_ack_err;
|
||||||
|
uint32_t trigger_recovery;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_NO_OF_MAC_ADDR 4
|
#define MAX_NO_OF_MAC_ADDR 4
|
||||||
|
@ -267,6 +300,8 @@ static struct icnss_priv {
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct icnss_driver_ops *ops;
|
struct icnss_driver_ops *ops;
|
||||||
struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS];
|
struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS];
|
||||||
|
struct icnss_vreg_info vreg_info[ICNSS_VREG_INFO_SIZE];
|
||||||
|
struct icnss_clk_info clk_info[ICNSS_CLK_INFO_SIZE];
|
||||||
u32 ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS];
|
u32 ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS];
|
||||||
phys_addr_t mem_base_pa;
|
phys_addr_t mem_base_pa;
|
||||||
void __iomem *mem_base_va;
|
void __iomem *mem_base_va;
|
||||||
|
@ -664,41 +699,220 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int icnss_vreg_on(struct icnss_priv *priv)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct icnss_vreg_info *vreg_info;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ICNSS_VREG_INFO_SIZE; i++) {
|
||||||
|
vreg_info = &priv->vreg_info[i];
|
||||||
|
|
||||||
|
if (!vreg_info->reg)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
icnss_pr_dbg("Regulator %s being enabled\n", vreg_info->name);
|
||||||
|
|
||||||
|
ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v,
|
||||||
|
vreg_info->max_v);
|
||||||
|
if (ret) {
|
||||||
|
icnss_pr_err("Regulator %s, can't set voltage: min_v: %u, max_v: %u, ret: %d\n",
|
||||||
|
vreg_info->name, vreg_info->min_v,
|
||||||
|
vreg_info->max_v, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vreg_info->load_ua) {
|
||||||
|
ret = regulator_set_load(vreg_info->reg,
|
||||||
|
vreg_info->load_ua);
|
||||||
|
if (ret < 0) {
|
||||||
|
icnss_pr_err("Regulator %s, can't set load: %u, ret: %d\n",
|
||||||
|
vreg_info->name,
|
||||||
|
vreg_info->load_ua, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regulator_enable(vreg_info->reg);
|
||||||
|
if (ret) {
|
||||||
|
icnss_pr_err("Regulator %s, can't enable: %d\n",
|
||||||
|
vreg_info->name, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vreg_info->settle_delay)
|
||||||
|
udelay(vreg_info->settle_delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (; i >= 0; i--) {
|
||||||
|
vreg_info = &priv->vreg_info[i];
|
||||||
|
|
||||||
|
if (!vreg_info->reg)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
regulator_disable(vreg_info->reg);
|
||||||
|
regulator_set_load(vreg_info->reg, 0);
|
||||||
|
regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int icnss_vreg_off(struct icnss_priv *priv)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct icnss_vreg_info *vreg_info;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = ICNSS_VREG_INFO_SIZE - 1; i >= 0; i--) {
|
||||||
|
vreg_info = &priv->vreg_info[i];
|
||||||
|
|
||||||
|
if (!vreg_info->reg)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
icnss_pr_dbg("Regulator %s being disabled\n", vreg_info->name);
|
||||||
|
|
||||||
|
ret = regulator_disable(vreg_info->reg);
|
||||||
|
if (ret)
|
||||||
|
icnss_pr_err("Regulator %s, can't disable: %d\n",
|
||||||
|
vreg_info->name, ret);
|
||||||
|
|
||||||
|
ret = regulator_set_load(vreg_info->reg, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
icnss_pr_err("Regulator %s, can't set load: %d\n",
|
||||||
|
vreg_info->name, ret);
|
||||||
|
|
||||||
|
ret = regulator_set_voltage(vreg_info->reg, 0,
|
||||||
|
vreg_info->max_v);
|
||||||
|
if (ret)
|
||||||
|
icnss_pr_err("Regulator %s, can't set voltage: %d\n",
|
||||||
|
vreg_info->name, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int icnss_clk_init(struct icnss_priv *priv)
|
||||||
|
{
|
||||||
|
struct icnss_clk_info *clk_info;
|
||||||
|
int i;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
|
||||||
|
clk_info = &priv->clk_info[i];
|
||||||
|
|
||||||
|
if (!clk_info->handle)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
icnss_pr_dbg("Clock %s being enabled\n", clk_info->name);
|
||||||
|
|
||||||
|
if (clk_info->freq) {
|
||||||
|
ret = clk_set_rate(clk_info->handle, clk_info->freq);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
icnss_pr_err("Clock %s, can't set frequency: %u, ret: %d\n",
|
||||||
|
clk_info->name, clk_info->freq,
|
||||||
|
ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(clk_info->handle);
|
||||||
|
if (ret) {
|
||||||
|
icnss_pr_err("Clock %s, can't enable: %d\n",
|
||||||
|
clk_info->name, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (; i >= 0; i--) {
|
||||||
|
clk_info = &priv->clk_info[i];
|
||||||
|
|
||||||
|
if (!clk_info->handle)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
clk_disable_unprepare(clk_info->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int icnss_clk_deinit(struct icnss_priv *priv)
|
||||||
|
{
|
||||||
|
struct icnss_clk_info *clk_info;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
|
||||||
|
clk_info = &priv->clk_info[i];
|
||||||
|
|
||||||
|
if (!clk_info->handle)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
icnss_pr_dbg("Clock %s being disabled\n", clk_info->name);
|
||||||
|
|
||||||
|
clk_disable_unprepare(clk_info->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int icnss_hw_power_on(struct icnss_priv *priv)
|
static int icnss_hw_power_on(struct icnss_priv *priv)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
icnss_pr_dbg("HW Power on: state: 0x%lx\n", priv->state);
|
icnss_pr_dbg("HW Power on: state: 0x%lx\n", priv->state);
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->on_off_lock, flags);
|
spin_lock(&priv->on_off_lock);
|
||||||
if (test_bit(ICNSS_POWER_ON, &priv->state)) {
|
if (test_bit(ICNSS_POWER_ON, &priv->state)) {
|
||||||
spin_unlock_irqrestore(&priv->on_off_lock, flags);
|
spin_unlock(&priv->on_off_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
set_bit(ICNSS_POWER_ON, &priv->state);
|
set_bit(ICNSS_POWER_ON, &priv->state);
|
||||||
spin_unlock_irqrestore(&priv->on_off_lock, flags);
|
spin_unlock(&priv->on_off_lock);
|
||||||
|
|
||||||
|
ret = icnss_vreg_on(priv);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = icnss_clk_init(priv);
|
||||||
|
if (ret)
|
||||||
|
goto vreg_off;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
vreg_off:
|
||||||
|
icnss_vreg_off(priv);
|
||||||
|
out:
|
||||||
|
clear_bit(ICNSS_POWER_ON, &priv->state);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int icnss_hw_power_off(struct icnss_priv *priv)
|
static int icnss_hw_power_off(struct icnss_priv *priv)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (test_bit(HW_ALWAYS_ON, &quirks))
|
if (test_bit(HW_ALWAYS_ON, &quirks))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
icnss_pr_dbg("HW Power off: 0x%lx\n", priv->state);
|
icnss_pr_dbg("HW Power off: 0x%lx\n", priv->state);
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->on_off_lock, flags);
|
spin_lock(&priv->on_off_lock);
|
||||||
if (!test_bit(ICNSS_POWER_ON, &priv->state)) {
|
if (!test_bit(ICNSS_POWER_ON, &priv->state)) {
|
||||||
spin_unlock_irqrestore(&priv->on_off_lock, flags);
|
spin_unlock(&priv->on_off_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
clear_bit(ICNSS_POWER_ON, &priv->state);
|
clear_bit(ICNSS_POWER_ON, &priv->state);
|
||||||
spin_unlock_irqrestore(&priv->on_off_lock, flags);
|
spin_unlock(&priv->on_off_lock);
|
||||||
|
|
||||||
|
icnss_clk_deinit(priv);
|
||||||
|
|
||||||
|
ret = icnss_vreg_off(priv);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1895,6 +2109,8 @@ static int icnss_call_driver_remove(struct icnss_priv *priv)
|
||||||
|
|
||||||
clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
|
clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
|
||||||
|
|
||||||
|
icnss_hw_power_off(penv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1947,8 +2163,6 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv,
|
||||||
icnss_call_driver_remove(priv);
|
icnss_call_driver_remove(priv);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
ret = icnss_hw_power_off(priv);
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -2923,11 +3137,16 @@ int icnss_trigger_recovery(struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!priv->service_notifier[0].handle) {
|
if (!priv->service_notifier[0].handle) {
|
||||||
icnss_pr_err("Invalid handle during recovery\n");
|
icnss_pr_err("Invalid handle during recovery, state: 0x%lx\n",
|
||||||
|
priv->state);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
icnss_pr_dbg("Initiate PD restart at WLAN FW, state: 0x%lx\n",
|
||||||
|
priv->state);
|
||||||
|
priv->stats.trigger_recovery++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initiate PDR, required only for the first instance
|
* Initiate PDR, required only for the first instance
|
||||||
*/
|
*/
|
||||||
|
@ -3005,6 +3224,114 @@ static void icnss_smmu_deinit(struct icnss_priv *priv)
|
||||||
priv->smmu_mapping = NULL;
|
priv->smmu_mapping = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int icnss_get_vreg_info(struct device *dev,
|
||||||
|
struct icnss_vreg_info *vreg_info)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
char prop_name[MAX_PROP_SIZE];
|
||||||
|
struct regulator *reg;
|
||||||
|
const __be32 *prop;
|
||||||
|
int len = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
reg = devm_regulator_get_optional(dev, vreg_info->name);
|
||||||
|
if (PTR_ERR(reg) == -EPROBE_DEFER) {
|
||||||
|
icnss_pr_err("EPROBE_DEFER for regulator: %s\n",
|
||||||
|
vreg_info->name);
|
||||||
|
ret = PTR_ERR(reg);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ERR(reg)) {
|
||||||
|
ret = PTR_ERR(reg);
|
||||||
|
|
||||||
|
if (vreg_info->required) {
|
||||||
|
icnss_pr_err("Regulator %s doesn't exist: %d\n",
|
||||||
|
vreg_info->name, ret);
|
||||||
|
goto out;
|
||||||
|
} else {
|
||||||
|
icnss_pr_dbg("Optional regulator %s doesn't exist: %d\n",
|
||||||
|
vreg_info->name, ret);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vreg_info->reg = reg;
|
||||||
|
|
||||||
|
snprintf(prop_name, MAX_PROP_SIZE,
|
||||||
|
"qcom,%s-config", vreg_info->name);
|
||||||
|
|
||||||
|
prop = of_get_property(dev->of_node, prop_name, &len);
|
||||||
|
|
||||||
|
icnss_pr_dbg("Got regulator config, prop: %s, len: %d\n",
|
||||||
|
prop_name, len);
|
||||||
|
|
||||||
|
if (!prop || len < (2 * sizeof(__be32))) {
|
||||||
|
icnss_pr_dbg("Property %s %s\n", prop_name,
|
||||||
|
prop ? "invalid format" : "doesn't exist");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; (i * sizeof(__be32)) < len; i++) {
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
vreg_info->min_v = be32_to_cpup(&prop[0]);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
vreg_info->max_v = be32_to_cpup(&prop[1]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
vreg_info->load_ua = be32_to_cpup(&prop[2]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
vreg_info->settle_delay = be32_to_cpup(&prop[3]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
icnss_pr_dbg("Property %s, ignoring value at %d\n",
|
||||||
|
prop_name, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
icnss_pr_dbg("Regulator: %s, min_v: %u, max_v: %u, load: %u, delay: %lu\n",
|
||||||
|
vreg_info->name, vreg_info->min_v, vreg_info->max_v,
|
||||||
|
vreg_info->load_ua, vreg_info->settle_delay);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int icnss_get_clk_info(struct device *dev,
|
||||||
|
struct icnss_clk_info *clk_info)
|
||||||
|
{
|
||||||
|
struct clk *handle;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
handle = devm_clk_get(dev, clk_info->name);
|
||||||
|
if (IS_ERR(handle)) {
|
||||||
|
ret = PTR_ERR(handle);
|
||||||
|
if (clk_info->required) {
|
||||||
|
icnss_pr_err("Clock %s isn't available: %d\n",
|
||||||
|
clk_info->name, ret);
|
||||||
|
goto out;
|
||||||
|
} else {
|
||||||
|
icnss_pr_dbg("Ignoring clock %s: %d\n", clk_info->name,
|
||||||
|
ret);
|
||||||
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
icnss_pr_dbg("Clock: %s, freq: %u\n", clk_info->name, clk_info->freq);
|
||||||
|
|
||||||
|
clk_info->handle = handle;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int icnss_fw_debug_show(struct seq_file *s, void *data)
|
static int icnss_fw_debug_show(struct seq_file *s, void *data)
|
||||||
{
|
{
|
||||||
struct icnss_priv *priv = s->private;
|
struct icnss_priv *priv = s->private;
|
||||||
|
@ -3370,6 +3697,7 @@ static int icnss_stats_show(struct seq_file *s, void *data)
|
||||||
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
|
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
|
||||||
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
|
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
|
||||||
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
|
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
|
||||||
|
ICNSS_STATS_DUMP(s, priv, trigger_recovery);
|
||||||
|
|
||||||
seq_puts(s, "\n<------------------ PM stats ------------------->\n");
|
seq_puts(s, "\n<------------------ PM stats ------------------->\n");
|
||||||
ICNSS_STATS_DUMP(s, priv, pm_suspend);
|
ICNSS_STATS_DUMP(s, priv, pm_suspend);
|
||||||
|
@ -3715,6 +4043,21 @@ static int icnss_probe(struct platform_device *pdev)
|
||||||
if (ret == -EPROBE_DEFER)
|
if (ret == -EPROBE_DEFER)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
memcpy(priv->vreg_info, icnss_vreg_info, sizeof(icnss_vreg_info));
|
||||||
|
for (i = 0; i < ICNSS_VREG_INFO_SIZE; i++) {
|
||||||
|
ret = icnss_get_vreg_info(dev, &priv->vreg_info[i]);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(priv->clk_info, icnss_clk_info, sizeof(icnss_clk_info));
|
||||||
|
for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
|
||||||
|
ret = icnss_get_clk_info(dev, &priv->clk_info[i]);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (of_property_read_bool(pdev->dev.of_node, "qcom,smmu-s1-bypass"))
|
if (of_property_read_bool(pdev->dev.of_node, "qcom,smmu-s1-bypass"))
|
||||||
priv->bypass_s1_smmu = true;
|
priv->bypass_s1_smmu = true;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue