Merge "wcnss: Add support to auto detect Iris XO"
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index c130b26..6df1efe 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -21,6 +21,10 @@
- qcom,has_48mhz_xo: boolean flag to determine the usage of 24MHz XO from RF
- qcom,has_pronto_hw: boolean flag to determine the revId of the WLAN subsystem
+Optional properties:
+- qcom,has_autodetect_xo: boolean flag to determine whether Iris XO auto detect
+should be performed during boot up.
+
Example:
qcom,wcnss-wlan@fb000000 {
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 59a6b68..c02daa4 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -31,6 +31,7 @@
static LIST_HEAD(power_on_lock_list);
static DEFINE_MUTEX(list_lock);
static DEFINE_SEMAPHORE(wcnss_power_on_lock);
+static int auto_detect;
#define MSM_RIVA_PHYS 0x03204000
#define MSM_PRONTO_PHYS 0xfb21b000
@@ -42,11 +43,17 @@
#define PRONTO_SPARE_OFFSET 0x1088
#define NVBIN_DLND_BIT BIT(25)
+#define PRONTO_IRIS_REG_READ_OFFSET 0x1134
+#define PRONTO_IRIS_REG_CHIP_ID 0x04
+
#define WCNSS_PMU_CFG_IRIS_XO_CFG BIT(3)
#define WCNSS_PMU_CFG_IRIS_XO_EN BIT(4)
#define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP BIT(5)
#define WCNSS_PMU_CFG_IRIS_XO_CFG_STS BIT(6) /* 1: in progress, 0: done */
+#define WCNSS_PMU_CFG_IRIS_XO_READ BIT(9)
+#define WCNSS_PMU_CFG_IRIS_XO_READ_STS BIT(10)
+
#define WCNSS_PMU_CFG_IRIS_XO_MODE 0x6
#define WCNSS_PMU_CFG_IRIS_XO_MODE_48 (3 << 1)
@@ -56,6 +63,8 @@
#define VREG_OPTIMUM_MODE_MASK 0x0004
#define VREG_ENABLE_MASK 0x0008
+#define WCNSS_INVALID_IRIS_REG 0xbaadbaad
+
struct vregs_info {
const char * const name;
int state;
@@ -110,10 +119,38 @@
struct list_head list;
};
+enum {
+ WCNSS_XO_48MHZ = 1,
+ WCNSS_XO_19MHZ,
+ WCNSS_XO_INVALID,
+};
+
+enum {
+ IRIS_3660, /* also 3660A and 3680 */
+ IRIS_3620
+};
+
+
+int xo_auto_detect(u32 reg)
+{
+ reg >>= 30;
+
+ switch (reg) {
+ case IRIS_3660:
+ return WCNSS_XO_48MHZ;
+
+ case IRIS_3620:
+ return WCNSS_XO_19MHZ;
+
+ default:
+ return WCNSS_XO_INVALID;
+ }
+}
static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
{
u32 reg = 0;
+ u32 iris_reg = WCNSS_INVALID_IRIS_REG;
int rc = 0;
int size = 0;
int pmu_offset = 0;
@@ -121,6 +158,7 @@
unsigned long wcnss_phys_addr;
void __iomem *pmu_conf_reg;
void __iomem *spare_reg;
+ void __iomem *iris_read_reg;
struct clk *clk;
struct clk *clk_rf = NULL;
@@ -136,14 +174,6 @@
return PTR_ERR(clk);
}
- if (!use_48mhz_xo) {
- clk_rf = clk_get(dev, "rf_clk");
- if (IS_ERR(clk_rf)) {
- pr_err("Couldn't get rf_clk\n");
- clk_put(clk);
- return PTR_ERR(clk_rf);
- }
- }
} else {
wcnss_phys_addr = MSM_RIVA_PHYS;
pmu_offset = RIVA_PMU_OFFSET;
@@ -187,10 +217,44 @@
WCNSS_PMU_CFG_IRIS_XO_EN;
writel_relaxed(reg, pmu_conf_reg);
+ if (wcnss_xo_auto_detect_enabled()) {
+ iris_read_reg = msm_wcnss_base +
+ PRONTO_IRIS_REG_READ_OFFSET;
+ iris_reg = readl_relaxed(iris_read_reg);
+ }
+
+ if (iris_reg != WCNSS_INVALID_IRIS_REG) {
+ iris_reg &= 0xffff;
+ iris_reg |= PRONTO_IRIS_REG_CHIP_ID;
+ writel_relaxed(iris_reg, iris_read_reg);
+
+ /* Iris read */
+ reg = readl_relaxed(pmu_conf_reg);
+ reg |= WCNSS_PMU_CFG_IRIS_XO_READ;
+ writel_relaxed(reg, pmu_conf_reg);
+
+ /* Wait for PMU_CFG.iris_reg_read_sts */
+ while (readl_relaxed(pmu_conf_reg) &
+ WCNSS_PMU_CFG_IRIS_XO_READ_STS)
+ cpu_relax();
+
+ iris_reg = readl_relaxed(iris_read_reg);
+ auto_detect = xo_auto_detect(iris_reg);
+
+ /* Reset iris read bit */
+ reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
+
+ } else if (wcnss_xo_auto_detect_enabled())
+ /* Default to 48 MHZ */
+ auto_detect = WCNSS_XO_48MHZ;
+ else
+ auto_detect = WCNSS_XO_INVALID;
+
/* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
- if (use_48mhz_xo)
+ if ((use_48mhz_xo && auto_detect == WCNSS_XO_INVALID)
+ || auto_detect == WCNSS_XO_48MHZ)
reg |= WCNSS_PMU_CFG_IRIS_XO_MODE_48;
writel_relaxed(reg, pmu_conf_reg);
@@ -210,30 +274,41 @@
writel_relaxed(reg, pmu_conf_reg);
clk_disable_unprepare(clk);
- if (!use_48mhz_xo) {
+ if ((!use_48mhz_xo && auto_detect == WCNSS_XO_INVALID)
+ || auto_detect == WCNSS_XO_19MHZ) {
+
+ clk_rf = clk_get(dev, "rf_clk");
+ if (IS_ERR(clk_rf)) {
+ pr_err("Couldn't get rf_clk\n");
+ goto fail;
+ }
+
rc = clk_prepare_enable(clk_rf);
if (rc) {
pr_err("clk_rf enable failed\n");
goto fail;
}
}
- } else if (clk_rf != NULL && !use_48mhz_xo)
- clk_disable_unprepare(clk_rf);
+
+ } else if ((!use_48mhz_xo && auto_detect == WCNSS_XO_INVALID)
+ || auto_detect == WCNSS_XO_19MHZ) {
+ clk_rf = clk_get(dev, "rf_clk");
+ if (IS_ERR(clk_rf)) {
+ pr_err("Couldn't get rf_clk\n");
+ goto fail;
+ }
+ clk_disable_unprepare(clk_rf);
+ }
+
/* Add some delay for XO to settle */
msleep(20);
+fail:
clk_put(clk);
- if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
- if (!use_48mhz_xo)
- clk_put(clk_rf);
- }
-
- return rc;
-fail:
if (clk_rf != NULL)
clk_put(clk_rf);
- clk_put(clk);
+
return rc;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index c30f46f..a75687b 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -56,6 +56,10 @@
module_param(has_calibrated_data, int, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(has_calibrated_data, "whether calibrated data file available");
+static int has_autodetect_xo = WCNSS_CONFIG_UNSPECIFIED;
+module_param(has_autodetect_xo, int, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(has_autodetect_xo, "Perform auto detect to configure IRIS XO");
+
static int do_not_cancel_vote = WCNSS_CONFIG_UNSPECIFIED;
module_param(do_not_cancel_vote, int, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(do_not_cancel_vote, "Do not cancel votes for wcnss");
@@ -873,6 +877,11 @@
module_param_call(enable_wcnss_suspend_notify, enable_wcnss_suspend_notify_set,
param_get_int, &enable_wcnss_suspend_notify, S_IRUGO | S_IWUSR);
+int wcnss_xo_auto_detect_enabled(void)
+{
+ return (has_autodetect_xo == 1 ? 1 : 0);
+}
+
void wcnss_suspend_notify(void)
{
@@ -1507,6 +1516,11 @@
penv->wcnss_hw_type = (has_pronto_hw) ? WCNSS_PRONTO_HW : WCNSS_RIVA_HW;
penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
+ if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) {
+ has_autodetect_xo = of_property_read_bool(pdev->dev.of_node,
+ "qcom,has_autodetect_xo");
+ }
+
penv->thermal_mitigation = 0;
strlcpy(penv->wcnss_version, "INVALID", WCNSS_VERSION_LEN);
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 4711ec8..2a53114 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -68,6 +68,7 @@
void wcnss_pronto_log_debug_regs(void);
int wcnss_device_ready(void);
void wcnss_riva_dump_pmic_regs(void);
+int wcnss_xo_auto_detect_enabled(void);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))