/* interface to reset Riva by sending the reset interrupt */ void wcnss_reset_intr(void) { if (wcnss_hardware_type() == WCNSS_RIVA_HW) { wmb(); __raw_writel(1 << 24, MSM_APCS_GCC_BASE + 0x8); } else { pr_err("%s: reset interrupt not supported\n", __func__); } }
/* interface to reset wcnss by sending the reset interrupt */ void wcnss_reset_intr(void) { if (wcnss_hardware_type() == WCNSS_PRONTO_HW) { wcnss_pronto_log_debug_regs(); wmb(); __raw_writel(1 << 16, penv->fiq_reg); } else { wcnss_riva_log_debug_regs(); wmb(); __raw_writel(1 << 24, MSM_APCS_GCC_BASE + 0x8); } }
void wcnss_suspend_notify(void) { void __iomem *pmu_spare_reg; u32 reg = 0; unsigned long flags; if (!enable_wcnss_suspend_notify) return; if (wcnss_hardware_type() == WCNSS_PRONTO_HW) return; /* For Riva */ pmu_spare_reg = penv->msm_wcnss_base + RIVA_SPARE_OFFSET; spin_lock_irqsave(®_spinlock, flags); reg = readl_relaxed(pmu_spare_reg); reg |= RIVA_SUSPEND_BIT; writel_relaxed(reg, pmu_spare_reg); spin_unlock_irqrestore(®_spinlock, flags); }
static int wcnss_trigger_config(struct platform_device *pdev) { int ret; struct qcom_wcnss_opts *pdata; unsigned long wcnss_phys_addr; int size = 0; int has_pronto_hw = of_property_read_bool(pdev->dev.of_node, "qcom,has_pronto_hw"); /* make sure we are only triggered once */ if (penv->triggered) return 0; penv->triggered = 1; /* initialize the WCNSS device configuration */ pdata = pdev->dev.platform_data; if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) { if (has_pronto_hw) { has_48mhz_xo = of_property_read_bool(pdev->dev.of_node, "qcom,has_48mhz_xo"); penv->wcnss_hw_type = WCNSS_PRONTO_HW; } else { penv->wcnss_hw_type = WCNSS_RIVA_HW; has_48mhz_xo = pdata->has_48mhz_xo; } } penv->wlan_config.use_48mhz_xo = has_48mhz_xo; penv->thermal_mitigation = 0; strlcpy(penv->wcnss_version, "INVALID", WCNSS_VERSION_LEN); /* Configure 5 wire GPIOs */ if (!has_pronto_hw) { penv->gpios_5wire = platform_get_resource_byname(pdev, IORESOURCE_IO, "wcnss_gpios_5wire"); /* allocate 5-wire GPIO resources */ if (!penv->gpios_5wire) { dev_err(&pdev->dev, "insufficient IO resources\n"); ret = -ENOENT; goto fail_gpio_res; } ret = wcnss_gpios_config(penv->gpios_5wire, true); } else ret = wcnss_pronto_gpios_config(&pdev->dev, true); if (ret) { dev_err(&pdev->dev, "WCNSS gpios config failed.\n"); goto fail_gpio_res; } /* power up the WCNSS */ ret = wcnss_wlan_power(&pdev->dev, &penv->wlan_config, WCNSS_WLAN_SWITCH_ON); if (ret) { dev_err(&pdev->dev, "WCNSS Power-up failed.\n"); goto fail_power; } /* trigger initialization of the WCNSS */ penv->pil = pil_get(WCNSS_PIL_DEVICE); if (IS_ERR(penv->pil)) { dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n"); ret = PTR_ERR(penv->pil); penv->pil = NULL; goto fail_pil; } /* allocate resources */ penv->mmio_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wcnss_mmio"); penv->tx_irq_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "wcnss_wlantx_irq"); penv->rx_irq_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "wcnss_wlanrx_irq"); if (!(penv->mmio_res && penv->tx_irq_res && penv->rx_irq_res)) { dev_err(&pdev->dev, "insufficient resources\n"); ret = -ENOENT; goto fail_res; } INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler); INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req); wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss"); if (wcnss_hardware_type() == WCNSS_PRONTO_HW) { size = 0x3000; wcnss_phys_addr = MSM_PRONTO_PHYS; } else { wcnss_phys_addr = MSM_RIVA_PHYS; size = SZ_256; } penv->msm_wcnss_base = ioremap(wcnss_phys_addr, size); if (!penv->msm_wcnss_base) { ret = -ENOMEM; pr_err("%s: ioremap wcnss physical failed\n", __func__); goto fail_wake; } return 0; fail_wake: wake_lock_destroy(&penv->wcnss_wake_lock); fail_res: if (penv->pil) pil_put(penv->pil); fail_pil: wcnss_wlan_power(&pdev->dev, &penv->wlan_config, WCNSS_WLAN_SWITCH_OFF); fail_power: if (has_pronto_hw) wcnss_pronto_gpios_config(&pdev->dev, false); else wcnss_gpios_config(penv->gpios_5wire, false); fail_gpio_res: kfree(penv); penv = NULL; return ret; }
static void wcnssctrl_rx_handler(struct work_struct *worker) { int len = 0; int rc = 0; unsigned char buf[WCNSS_MAX_FRAME_SIZE]; struct smd_msg_hdr *phdr; struct wcnss_version *pversion; int hw_type; len = smd_read_avail(penv->smd_ch); if (len > WCNSS_MAX_FRAME_SIZE) { pr_err("wcnss: frame larger than the allowed size\n"); smd_read(penv->smd_ch, NULL, len); return; } if (len <= 0) return; rc = smd_read(penv->smd_ch, buf, len); if (rc < len) { pr_err("wcnss: incomplete data read from smd\n"); return; } phdr = (struct smd_msg_hdr *)buf; switch (phdr->msg_type) { case WCNSS_VERSION_RSP: pversion = (struct wcnss_version *)buf; if (len != sizeof(struct wcnss_version)) { pr_err("wcnss: invalid version data from wcnss %d\n", len); return; } snprintf(penv->wcnss_version, WCNSS_VERSION_LEN, "%02x%02x%02x%02x", pversion->major, pversion->minor, pversion->version, pversion->revision); pr_info("wcnss: version %s\n", penv->wcnss_version); /* schedule work to download nvbin to ccpu */ hw_type = wcnss_hardware_type(); switch (hw_type) { case WCNSS_RIVA_HW: /* supported only if riva major >= 1 and minor >= 4 */ if ((pversion->major >= 1) && (pversion->minor >= 4)) { pr_info("wcnss: schedule dnld work for riva\n"); schedule_work(&penv->wcnssctrl_nvbin_dnld_work); } break; case WCNSS_PRONTO_HW: /* supported only if pronto major >= 1 and minor >= 4 */ if ((pversion->major >= 1) && (pversion->minor >= 4)) { pr_info("wcnss: schedule dnld work for pronto\n"); schedule_work(&penv->wcnssctrl_nvbin_dnld_work); } break; default: pr_info("wcnss: unknown hw type (%d), will not schedule dnld work\n", hw_type); break; } break; case WCNSS_NVBIN_DNLD_RSP: pr_info("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu\n"); break; default: pr_err("wcnss: invalid message type %d\n", phdr->msg_type); } return; }