/* * Platform Dependent file for Samsung Exynos * * Copyright (C) 2020, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that * you also meet, for each linked independent module, the terms and conditions of * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. * * * <> * * $Id$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \ defined(CONFIG_SOC_EXYNOS9820) || defined(CONFIG_SOC_EXYNOS9830) || \ defined(CONFIG_SOC_EXYNOS2100) || defined(CONFIG_SOC_EXYNOS1000) #include #endif /* CONFIG_SOC_EXYNOS8895 || CONFIG_SOC_EXYNOS9810 || * CONFIG_SOC_EXYNOS9820 || CONFIG_SOC_EXYNOS9830 || * CONFIG_SOC_EXYNOS2100 || CONFIG_SOC_EXYNOS1000 */ #if defined(CONFIG_64BIT) #include #endif /* CONFIG_64BIT */ #ifdef BCMDHD_MODULAR #if IS_ENABLED(CONFIG_SEC_SYSFS) #include #endif /* CONFIG_SEC_SYSFS */ #if IS_ENABLED(CONFIG_DRV_SAMSUNG) #include #endif /* CONFIG_SEC_SYSFS */ #else #if defined(CONFIG_SEC_SYSFS) #include #elif defined(CONFIG_DRV_SAMSUNG) #include #endif /* CONFIG_SEC_SYSFS */ #endif /* BCMDHD_MODULAR */ #include #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) #define PINCTL_DELAY 150 #endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */ #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM extern void dhd_exit_wlan_mem(void); extern int dhd_init_wlan_mem(void); extern void *dhd_wlan_mem_prealloc(int section, unsigned long size); #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ #define WIFI_TURNON_DELAY 200 static int wlan_pwr_on = -1; #ifdef CONFIG_BCMDHD_OOB_HOST_WAKE static int wlan_host_wake_irq = 0; static unsigned int wlan_host_wake_up = -1; #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) extern struct device *mmc_dev_for_wlan; #endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */ #ifdef CONFIG_BCMDHD_PCIE extern int pcie_ch_num; extern void exynos_pcie_pm_resume(int); extern void exynos_pcie_pm_suspend(int); #endif /* CONFIG_BCMDHD_PCIE */ #if defined(CONFIG_SOC_EXYNOS7870) || defined(CONFIG_SOC_EXYNOS9110) extern struct mmc_host *wlan_mmc; extern void mmc_ctrl_power(struct mmc_host *host, bool onoff); #endif /* SOC_EXYNOS7870 || CONFIG_SOC_EXYNOS9110 */ static int dhd_wlan_power(int onoff) { #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) struct pinctrl *pinctrl = NULL; #endif /* CONFIG_MACH_A7LTE || ONFIG_NOBLESSE */ printk(KERN_INFO"%s Enter: power %s\n", __FUNCTION__, onoff ? "on" : "off"); #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) if (onoff) { pinctrl = devm_pinctrl_get_select(mmc_dev_for_wlan, "sdio_wifi_on"); if (IS_ERR(pinctrl)) printk(KERN_INFO "%s WLAN SDIO GPIO control error\n", __FUNCTION__); msleep(PINCTL_DELAY); } #endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */ if (gpio_direction_output(wlan_pwr_on, onoff)) { printk(KERN_ERR "%s failed to control WLAN_REG_ON to %s\n", __FUNCTION__, onoff ? "HIGH" : "LOW"); return -EIO; } #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) if (!onoff) { pinctrl = devm_pinctrl_get_select(mmc_dev_for_wlan, "sdio_wifi_off"); if (IS_ERR(pinctrl)) printk(KERN_INFO "%s WLAN SDIO GPIO control error\n", __FUNCTION__); } #endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */ #if defined(CONFIG_SOC_EXYNOS7870) || defined(CONFIG_SOC_EXYNOS9110) if (wlan_mmc) mmc_ctrl_power(wlan_mmc, onoff); #endif /* SOC_EXYNOS7870 || CONFIG_SOC_EXYNOS9110 */ return 0; } static int dhd_wlan_reset(int onoff) { return 0; } #ifndef CONFIG_BCMDHD_PCIE extern void (*notify_func_callback)(void *dev_id, int state); extern void *mmc_host_dev; #endif /* !CONFIG_BCMDHD_PCIE */ static int dhd_wlan_set_carddetect(int val) { #ifndef CONFIG_BCMDHD_PCIE pr_err("%s: notify_func=%p, mmc_host_dev=%p, val=%d\n", __FUNCTION__, notify_func_callback, mmc_host_dev, val); if (notify_func_callback) { notify_func_callback(mmc_host_dev, val); } else { pr_warning("%s: Nobody to notify\n", __FUNCTION__); } #else if (val) { exynos_pcie_pm_resume(pcie_ch_num); } else { exynos_pcie_pm_suspend(pcie_ch_num); } #endif /* CONFIG_BCMDHD_PCIE */ return 0; } int __init dhd_wlan_init_gpio(void) { const char *wlan_node = "samsung,brcm-wlan"; struct device_node *root_node = NULL; struct device *wlan_dev; wlan_dev = sec_device_create(NULL, "wlan"); root_node = of_find_compatible_node(NULL, NULL, wlan_node); if (!root_node) { WARN(1, "failed to get device node of bcm4354\n"); return -ENODEV; } /* ========== WLAN_PWR_EN ============ */ wlan_pwr_on = of_get_gpio(root_node, 0); if (!gpio_is_valid(wlan_pwr_on)) { WARN(1, "Invalied gpio pin : %d\n", wlan_pwr_on); return -ENODEV; } if (gpio_request(wlan_pwr_on, "WLAN_REG_ON")) { WARN(1, "fail to request gpio(WLAN_REG_ON)\n"); return -ENODEV; } #ifdef CONFIG_BCMDHD_PCIE gpio_direction_output(wlan_pwr_on, 1); msleep(WIFI_TURNON_DELAY); #else gpio_direction_output(wlan_pwr_on, 0); #endif /* CONFIG_BCMDHD_PCIE */ gpio_export(wlan_pwr_on, 1); if (wlan_dev) gpio_export_link(wlan_dev, "WLAN_REG_ON", wlan_pwr_on); #ifdef CONFIG_BCMDHD_PCIE exynos_pcie_pm_resume(pcie_ch_num); #endif /* CONFIG_BCMDHD_PCIE */ #ifdef CONFIG_BCMDHD_OOB_HOST_WAKE /* ========== WLAN_HOST_WAKE ============ */ wlan_host_wake_up = of_get_gpio(root_node, 1); if (!gpio_is_valid(wlan_host_wake_up)) { WARN(1, "Invalied gpio pin : %d\n", wlan_host_wake_up); return -ENODEV; } if (gpio_request(wlan_host_wake_up, "WLAN_HOST_WAKE")) { WARN(1, "fail to request gpio(WLAN_HOST_WAKE)\n"); return -ENODEV; } gpio_direction_input(wlan_host_wake_up); gpio_export(wlan_host_wake_up, 1); if (wlan_dev) gpio_export_link(wlan_dev, "WLAN_HOST_WAKE", wlan_host_wake_up); wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up); #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ return 0; } #if defined(CONFIG_BCMDHD_OOB_HOST_WAKE) && defined(CONFIG_BCMDHD_GET_OOB_STATE) int dhd_get_wlan_oob_gpio(void) { return gpio_is_valid(wlan_host_wake_up) ? gpio_get_value(wlan_host_wake_up) : -1; } EXPORT_SYMBOL(dhd_get_wlan_oob_gpio); #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE && CONFIG_BCMDHD_GET_OOB_STATE */ struct resource dhd_wlan_resources = { .name = "bcmdhd_wlan_irq", .start = 0, .end = 0, .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE | #ifdef CONFIG_BCMDHD_PCIE IORESOURCE_IRQ_HIGHEDGE, #else IORESOURCE_IRQ_HIGHLEVEL, #endif /* CONFIG_BCMDHD_PCIE */ }; EXPORT_SYMBOL(dhd_wlan_resources); struct wifi_platform_data dhd_wlan_control = { .set_power = dhd_wlan_power, .set_reset = dhd_wlan_reset, .set_carddetect = dhd_wlan_set_carddetect, #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM .mem_prealloc = dhd_wlan_mem_prealloc, #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ }; EXPORT_SYMBOL(dhd_wlan_control); int __init dhd_wlan_init(void) { int ret; printk(KERN_INFO "%s: START.......\n", __FUNCTION__); ret = dhd_wlan_init_gpio(); if (ret < 0) { printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n", __FUNCTION__, ret); goto fail; } #ifdef CONFIG_BCMDHD_OOB_HOST_WAKE dhd_wlan_resources.start = wlan_host_wake_irq; dhd_wlan_resources.end = wlan_host_wake_irq; #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM ret = dhd_init_wlan_mem(); if (ret < 0) { printk(KERN_ERR "%s: failed to alloc reserved memory," " ret=%d\n", __FUNCTION__, ret); } #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ fail: return ret; } int dhd_wlan_deinit(void) { #ifdef CONFIG_BCMDHD_OOB_HOST_WAKE gpio_free(wlan_host_wake_up); #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ gpio_free(wlan_pwr_on); #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM dhd_exit_wlan_mem(); #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ return 0; } #ifndef BCMDHD_MODULAR #if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS8890) || \ defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \ defined(CONFIG_SOC_EXYNOS9820) || defined(CONFIG_SOC_EXYNOS9830) #if defined(CONFIG_DEFERRED_INITCALLS) deferred_module_init(dhd_wlan_init); #else late_initcall(dhd_wlan_init); #endif /* CONFIG_DEFERRED_INITCALLS */ #else device_initcall(dhd_wlan_init); #endif /* CONFIG Exynos PCIE Platforms */ #endif /* !BCMDHD_MODULAR */