/* * Copyright (c) 2015 South Silicon Valley Microelectronics Inc. * Copyright (c) 2015 iComm Corporation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) #include #include #else #include #endif #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0) #include #else struct wifi_platform_data { int (*set_power)(int val); int (*set_reset)(int val); int (*set_carddetect)(int val); void *(*mem_prealloc)(int section, unsigned long size); int (*get_mac_addr)(unsigned char *buf); void *(*get_country_code)(char *ccode); }; #endif #define GPIO_REG_WRITEL(val,reg) \ do { \ __raw_writel(val, CTL_PIN_BASE + (reg)); \ } while (0) static int g_wifidev_registered = 0; static struct semaphore wifi_control_sem; static struct wifi_platform_data *wifi_control_data = NULL; static struct resource *wifi_irqres = NULL; static int g_wifi_irq_rc = 0; #define SDIO_ID 1 #define IRQ_RES_NAME "ssv_wlan_irq" #define WIFI_HOST_WAKE 0xFFFF extern void sunxi_mci_rescan_card(unsigned id, unsigned insert); extern int wifi_pm_gpio_ctrl(char *name, int level); static int ssv_wifi_power(int on) { printk("ssv pwr on=%d\n", on); if (on) { wifi_pm_gpio_ctrl("wl_reg_on", 0); mdelay(50); wifi_pm_gpio_ctrl("wl_reg_on", 1); } else { wifi_pm_gpio_ctrl("wl_reg_on", 0); } return 0; } static int ssv_wifi_reset(int on) { return 0; } int ssv_wifi_set_carddetect(int val) { sunxi_mci_rescan_card(SDIO_ID, val); return 0; } static struct wifi_platform_data ssv_wifi_control = { .set_power = ssv_wifi_power, .set_reset = ssv_wifi_reset, .set_carddetect = ssv_wifi_set_carddetect, }; static struct resource resources[] = { { .start = WIFI_HOST_WAKE, .flags = IORESOURCE_IRQ, .name = IRQ_RES_NAME, }, }; void ssv_wifi_device_release(struct device *dev) { printk(KERN_INFO "ssv_wifi_device_release\n"); } static struct platform_device ssv_wifi_device = { .name = "ssv_wlan", .id = 1, .num_resources = ARRAY_SIZE(resources), .resource = resources, .dev = { .platform_data = &ssv_wifi_control, .release = ssv_wifi_device_release, }, }; int wifi_set_power(int on, unsigned long msec) { if (wifi_control_data && wifi_control_data->set_power) { wifi_control_data->set_power(on); } if (msec) msleep(msec); return 0; } int wifi_set_reset(int on, unsigned long msec) { if (wifi_control_data && wifi_control_data->set_reset) { wifi_control_data->set_reset(on); } if (msec) msleep(msec); return 0; } static int wifi_set_carddetect(int on) { if (wifi_control_data && wifi_control_data->set_carddetect) { wifi_control_data->set_carddetect(on); } return 0; } static irqreturn_t wifi_wakeup_irq_handler(int irq, void *dev) { printk("sdhci_wakeup_irq_handler\n"); disable_irq_nosync(irq); return IRQ_HANDLED; } void setup_wifi_wakeup_BB(struct platform_device *pdev, bool bEnable) { int rc = 0, ret = 0; if (bEnable) { wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, IRQ_RES_NAME); rc = (int)wifi_irqres->start; g_wifi_irq_rc = rc; ret = request_threaded_irq( rc, NULL, (void *)wifi_wakeup_irq_handler, #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 0, 0) IRQ_TYPE_LEVEL_HIGH | IRQF_ONESHOT | IRQF_FORCE_RESUME, #else IRQ_TYPE_LEVEL_HIGH | IRQF_ONESHOT, #endif "wlan_wakeup_irq", NULL); enable_irq_wake(g_wifi_irq_rc); } else { if (g_wifi_irq_rc) { free_irq(g_wifi_irq_rc, NULL); g_wifi_irq_rc = 0; } } } static int wifi_probe(struct platform_device *pdev) { struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); printk(KERN_ALERT "wifi_probe\n"); wifi_control_data = wifi_ctrl; wifi_set_power(0, 40); wifi_set_power(1, 50); wifi_set_carddetect(1); up(&wifi_control_sem); return 0; } static int wifi_remove(struct platform_device *pdev) { struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); wifi_control_data = wifi_ctrl; wifi_set_power(0, 0); wifi_set_power(0, 0); wifi_set_power(0, 0); wifi_set_power(0, 0); wifi_set_carddetect(0); return 0; } static int wifi_suspend(struct platform_device *pdev, pm_message_t state) { return 0; } static int wifi_resume(struct platform_device *pdev) { return 0; } static struct platform_driver wifi_driver = { .probe = wifi_probe, .remove = wifi_remove, .suspend = wifi_suspend, .resume = wifi_resume, .driver = { .name = "ssv_wlan", } }; extern int ssvdevice_init(void); extern void ssvdevice_exit(void); #ifdef CONFIG_SSV_SUPPORT_AES_ASM extern int aes_init(void); extern void aes_fini(void); extern int sha1_mod_init(void); extern void sha1_mod_fini(void); #endif int initWlan(void) { int ret = 0; sema_init(&wifi_control_sem, 0); #ifdef CONFIG_SSV_SUPPORT_AES_ASM sha1_mod_init(); aes_init(); #endif platform_device_register(&ssv_wifi_device); platform_driver_register(&wifi_driver); g_wifidev_registered = 1; if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { ret = -EINVAL; printk(KERN_ALERT "%s: platform_driver_register timeout\n", __FUNCTION__); } ret = ssvdevice_init(); return ret; } void exitWlan(void) { if (g_wifidev_registered) { ssvdevice_exit(); #ifdef CONFIG_SSV_SUPPORT_AES_ASM aes_fini(); sha1_mod_fini(); #endif platform_driver_unregister(&wifi_driver); platform_device_unregister(&ssv_wifi_device); g_wifidev_registered = 0; } return; } static int generic_wifi_init_module(void) { return initWlan(); } static void generic_wifi_exit_module(void) { exitWlan(); } EXPORT_SYMBOL(generic_wifi_init_module); EXPORT_SYMBOL(generic_wifi_exit_module); module_init(generic_wifi_init_module); module_exit(generic_wifi_exit_module); MODULE_LICENSE("Dual BSD/GPL");