dhd_custom_exynos.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*
  2. * Platform Dependent file for Samsung Exynos
  3. *
  4. * Copyright (C) 1999-2015, Broadcom Corporation
  5. *
  6. * Unless you and Broadcom execute a separate written software license
  7. * agreement governing use of this software, this software is licensed to you
  8. * under the terms of the GNU General Public License version 2 (the "GPL"),
  9. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  10. * following added to such license:
  11. *
  12. * As a special exception, the copyright holders of this software give you
  13. * permission to link this software with independent modules, and to copy and
  14. * distribute the resulting executable under terms of your choice, provided that
  15. * you also meet, for each linked independent module, the terms and conditions of
  16. * the license of that module. An independent module is a module which is not
  17. * derived from this software. The special exception does not apply to any
  18. * modifications of the software.
  19. *
  20. * Notwithstanding the above, under no circumstances may you combine this
  21. * software in any way with any other Broadcom software provided under a license
  22. * other than the GPL, without Broadcom's express prior written consent.
  23. *
  24. * $Id: dhd_custom_exynos.c 605818 2015-12-11 15:14:08Z $
  25. */
  26. #include <linux/device.h>
  27. #include <linux/gpio.h>
  28. #include <linux/of_gpio.h>
  29. #include <linux/delay.h>
  30. #include <linux/interrupt.h>
  31. #include <linux/irq.h>
  32. #include <linux/slab.h>
  33. #include <linux/workqueue.h>
  34. #include <linux/poll.h>
  35. #include <linux/miscdevice.h>
  36. #include <linux/sched.h>
  37. #include <linux/module.h>
  38. #include <linux/fs.h>
  39. #include <linux/list.h>
  40. #include <linux/io.h>
  41. #include <linux/workqueue.h>
  42. #include <linux/unistd.h>
  43. #include <linux/bug.h>
  44. #include <linux/skbuff.h>
  45. #include <linux/init.h>
  46. #include <linux/platform_device.h>
  47. #include <linux/wlan_plat.h>
  48. #if !defined(CONFIG_ARCH_SWA100)&& !defined(CONFIG_MACH_UNIVERSAL7580)
  49. #include <mach/gpio.h>
  50. #endif /* !CONFIG_ARCH_SWA100 && !CONFIG_MACH_UNIVERSAL7580 */
  51. #ifndef CONFIG_ARCH_SWA100
  52. #include <mach/irqs.h>
  53. #include <linux/sec_sysfs.h>
  54. #endif /* not CONFIG_ARCH_SWA100 */
  55. #include <plat/gpio-cfg.h>
  56. #ifdef CONFIG_MACH_A7LTE
  57. #define PINCTL_DELAY 150
  58. #endif /* CONFIG_MACH_A7LTE */
  59. #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
  60. #define WLAN_STATIC_SCAN_BUF0 5
  61. #define WLAN_STATIC_SCAN_BUF1 6
  62. #define WLAN_STATIC_DHD_INFO_BUF 7
  63. #define WLAN_STATIC_DHD_WLFC_INFO 8
  64. #define WLAN_STATIC_DHD_LOG_DUMP_BUF 9
  65. #define WLAN_SCAN_BUF_SIZE (64 * 1024)
  66. #define WLAN_DHD_INFO_BUF_SIZE (24 * 1024)
  67. #define WLAN_STATIC_DHD_WLFC_INFO_SIZE (64 * 1024)
  68. #define PREALLOC_WLAN_SEC_NUM 4
  69. #define PREALLOC_WLAN_BUF_NUM 160
  70. #define PREALLOC_WLAN_SECTION_HEADER 24
  71. #define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128)
  72. #define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128)
  73. #define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512)
  74. #define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024)
  75. #define DHD_SKB_HDRSIZE 336
  76. #define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE)
  77. #define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE)
  78. #define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE)
  79. #define WLAN_SKB_BUF_NUM 17
  80. #define DHD_LOG_DUMP_BUF_SIZE (1024 * 1024)
  81. #if defined(CONFIG_ARGOS)
  82. extern int argos_irq_affinity_setup_label(unsigned int irq, const char *label,
  83. struct cpumask *affinity_cpu_mask,
  84. struct cpumask *default_cpu_mask);
  85. #endif /* CONFIG_ARGOS */
  86. static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
  87. struct wlan_mem_prealloc {
  88. void *mem_ptr;
  89. unsigned long size;
  90. };
  91. static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = {
  92. {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)},
  93. {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)},
  94. {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)},
  95. {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)}
  96. };
  97. void *wlan_static_scan_buf0 = NULL;
  98. void *wlan_static_scan_buf1 = NULL;
  99. void *wlan_static_dhd_info_buf = NULL;
  100. void *wlan_static_dhd_wlfc_buf = NULL;
  101. void *wlan_static_dhd_log_dump_buf = NULL;
  102. static void *dhd_wlan_mem_prealloc(int section, unsigned long size)
  103. {
  104. if (section == PREALLOC_WLAN_SEC_NUM)
  105. return wlan_static_skb;
  106. if (section == WLAN_STATIC_SCAN_BUF0)
  107. return wlan_static_scan_buf0;
  108. if (section == WLAN_STATIC_SCAN_BUF1)
  109. return wlan_static_scan_buf1;
  110. if (section == WLAN_STATIC_DHD_INFO_BUF) {
  111. if (size > WLAN_DHD_INFO_BUF_SIZE) {
  112. pr_err("request DHD_INFO size(%lu) is bigger than"
  113. " static size(%d).\n", size,
  114. WLAN_DHD_INFO_BUF_SIZE);
  115. return NULL;
  116. }
  117. return wlan_static_dhd_info_buf;
  118. }
  119. if (section == WLAN_STATIC_DHD_WLFC_INFO) {
  120. if (size > WLAN_STATIC_DHD_WLFC_INFO_SIZE) {
  121. pr_err("request DHD_WLFC_INFO size(%lu) is bigger than"
  122. " static size(%d).\n",
  123. size, WLAN_STATIC_DHD_WLFC_INFO_SIZE);
  124. return NULL;
  125. }
  126. return wlan_static_dhd_wlfc_buf;
  127. }
  128. if (section == WLAN_STATIC_DHD_LOG_DUMP_BUF) {
  129. if (size > DHD_LOG_DUMP_BUF_SIZE) {
  130. pr_err("request DHD_LOG_DUMP_BUF size(%lu) is bigger then"
  131. " static size(%d).\n", size, DHD_LOG_DUMP_BUF_SIZE);
  132. return NULL;
  133. }
  134. return wlan_static_dhd_log_dump_buf;
  135. }
  136. if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM))
  137. return NULL;
  138. if (wlan_mem_array[section].size < size)
  139. return NULL;
  140. return wlan_mem_array[section].mem_ptr;
  141. }
  142. static int dhd_init_wlan_mem(void)
  143. {
  144. int i;
  145. int j;
  146. for (i = 0; i < 8; i++) {
  147. wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE);
  148. if (!wlan_static_skb[i])
  149. goto err_skb_alloc;
  150. }
  151. for (; i < 16; i++) {
  152. wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE);
  153. if (!wlan_static_skb[i])
  154. goto err_skb_alloc;
  155. }
  156. wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE);
  157. if (!wlan_static_skb[i])
  158. goto err_skb_alloc;
  159. for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) {
  160. wlan_mem_array[i].mem_ptr =
  161. kmalloc(wlan_mem_array[i].size, GFP_KERNEL);
  162. if (!wlan_mem_array[i].mem_ptr)
  163. goto err_mem_alloc;
  164. }
  165. wlan_static_scan_buf0 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL);
  166. if (!wlan_static_scan_buf0)
  167. goto err_mem_alloc;
  168. wlan_static_scan_buf1 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL);
  169. if (!wlan_static_scan_buf1)
  170. goto err_mem_alloc;
  171. wlan_static_dhd_info_buf = kmalloc(WLAN_DHD_INFO_BUF_SIZE, GFP_KERNEL);
  172. if (!wlan_static_dhd_info_buf)
  173. goto err_mem_alloc;
  174. wlan_static_dhd_wlfc_buf = kmalloc(WLAN_STATIC_DHD_WLFC_INFO_SIZE, GFP_KERNEL);
  175. if (!wlan_static_dhd_wlfc_buf) {
  176. goto err_mem_alloc;
  177. }
  178. wlan_static_dhd_log_dump_buf = kmalloc(DHD_LOG_DUMP_BUF_SIZE, GFP_KERNEL);
  179. if (!wlan_static_dhd_log_dump_buf) {
  180. pr_err("Failed to alloc wlan_static_dhd_log_dump_buf\n");
  181. goto err_mem_alloc;
  182. }
  183. pr_err("%s: WIFI MEM Allocated\n", __FUNCTION__);
  184. return 0;
  185. err_mem_alloc:
  186. pr_err("Failed to mem_alloc for WLAN\n");
  187. if (wlan_static_scan_buf0)
  188. kfree(wlan_static_scan_buf0);
  189. if (wlan_static_scan_buf1)
  190. kfree(wlan_static_scan_buf1);
  191. if (wlan_static_dhd_info_buf)
  192. kfree(wlan_static_dhd_info_buf);
  193. if (wlan_static_dhd_wlfc_buf)
  194. kfree(wlan_static_dhd_wlfc_buf);
  195. if (wlan_static_dhd_log_dump_buf)
  196. kfree(wlan_static_dhd_log_dump_buf);
  197. for (j = 0; j < i; j++)
  198. kfree(wlan_mem_array[j].mem_ptr);
  199. i = WLAN_SKB_BUF_NUM;
  200. err_skb_alloc:
  201. pr_err("Failed to skb_alloc for WLAN\n");
  202. for (j = 0; j < i; j++)
  203. dev_kfree_skb(wlan_static_skb[j]);
  204. return -ENOMEM;
  205. }
  206. #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
  207. static struct device *wlan_dev;
  208. static int wlan_pwr_on = -1;
  209. static int wlan_host_wake_irq = 0;
  210. #ifdef CONFIG_MACH_A7LTE
  211. extern struct device *mmc_dev_for_wlan;
  212. #endif /* CONFIG_MACH_A7LTE */
  213. #ifdef CONFIG_MACH_UNIVERSAL3475
  214. extern struct mmc_host *wlan_mmc;
  215. extern void mmc_ctrl_power(struct mmc_host *host, bool onoff);
  216. #endif /* CONFIG_MACH_UNIVERSAL3475 */
  217. static int dhd_wlan_power(int onoff)
  218. {
  219. #ifdef CONFIG_MACH_A7LTE
  220. struct pinctrl *pinctrl = NULL;
  221. #endif /* CONFIG_MACH_A7LTE */
  222. printk(KERN_INFO"------------------------------------------------");
  223. printk(KERN_INFO"------------------------------------------------\n");
  224. printk(KERN_INFO"%s Enter: power %s\n", __FUNCTION__, onoff ? "on" : "off");
  225. #ifdef CONFIG_MACH_A7LTE
  226. if (onoff) {
  227. pinctrl = devm_pinctrl_get_select(mmc_dev_for_wlan, "sdio_wifi_on");
  228. if (IS_ERR(pinctrl))
  229. printk(KERN_INFO "%s WLAN SDIO GPIO control error\n", __FUNCTION__);
  230. msleep(PINCTL_DELAY);
  231. }
  232. #endif /* CONFIG_MACH_A7LTE */
  233. if (gpio_direction_output(wlan_pwr_on, onoff)) {
  234. printk(KERN_ERR "%s failed to control WLAN_REG_ON to %s\n",
  235. __FUNCTION__, onoff ? "HIGH" : "LOW");
  236. return -EIO;
  237. }
  238. #ifdef CONFIG_MACH_A7LTE
  239. if (!onoff) {
  240. pinctrl = devm_pinctrl_get_select(mmc_dev_for_wlan, "sdio_wifi_off");
  241. if (IS_ERR(pinctrl))
  242. printk(KERN_INFO "%s WLAN SDIO GPIO control error\n", __FUNCTION__);
  243. }
  244. #endif /* CONFIG_MACH_A7LTE */
  245. #ifdef CONFIG_MACH_UNIVERSAL3475
  246. if (wlan_mmc)
  247. mmc_ctrl_power(wlan_mmc, onoff);
  248. #endif /* CONFIG_MACH_UNIVERSAL3475 */
  249. return 0;
  250. }
  251. static int dhd_wlan_reset(int onoff)
  252. {
  253. return 0;
  254. }
  255. extern void (*notify_func_callback)(void *dev_id, int state);
  256. extern void *mmc_host_dev;
  257. static int dhd_wlan_set_carddetect(int val)
  258. {
  259. pr_err("%s: notify_func=%p, mmc_host_dev=%p, val=%d\n",
  260. __FUNCTION__, notify_func_callback, mmc_host_dev, val);
  261. if (notify_func_callback)
  262. notify_func_callback(mmc_host_dev, val);
  263. else
  264. pr_warning("%s: Nobody to notify\n", __FUNCTION__);
  265. return 0;
  266. }
  267. int dhd_get_system_rev(void)
  268. {
  269. const char *wlan_node = "samsung,brcm-wlan";
  270. struct device_node *root_node = NULL;
  271. unsigned int base_system_rev_for_nv = 0;
  272. int ret;
  273. root_node = of_find_compatible_node(NULL, NULL, wlan_node);
  274. if (!root_node) {
  275. printk(KERN_ERR "couldn't get root node\n");
  276. return -ENODEV;
  277. }
  278. ret = of_property_read_u32(root_node, "base_system_rev_for_nv",
  279. &base_system_rev_for_nv);
  280. if (ret) {
  281. printk(KERN_INFO "couldn't get base_system_rev_for_nv\n");
  282. return -ENODEV;
  283. }
  284. return base_system_rev_for_nv;
  285. }
  286. int __init dhd_wlan_init_gpio(void)
  287. {
  288. const char *wlan_node = "samsung,brcm-wlan";
  289. unsigned int wlan_host_wake_up = -1;
  290. struct device_node *root_node = NULL;
  291. #ifndef CONFIG_ARCH_SWA100
  292. wlan_dev = sec_device_create(NULL, "wlan");
  293. BUG_ON(!wlan_dev);
  294. #endif /* not CONFIG_ARCH_SWA100 */
  295. root_node = of_find_compatible_node(NULL, NULL, wlan_node);
  296. if (!root_node) {
  297. WARN(1, "failed to get device node of bcm4354\n");
  298. return -ENODEV;
  299. }
  300. /* ========== WLAN_PWR_EN ============ */
  301. wlan_pwr_on = of_get_gpio(root_node, 0);
  302. if (!gpio_is_valid(wlan_pwr_on)) {
  303. WARN(1, "Invalied gpio pin : %d\n", wlan_pwr_on);
  304. return -ENODEV;
  305. }
  306. if (gpio_request(wlan_pwr_on, "WLAN_REG_ON")) {
  307. WARN(1, "fail to request gpio(WLAN_REG_ON)\n");
  308. return -ENODEV;
  309. }
  310. gpio_direction_output(wlan_pwr_on, 0);
  311. gpio_export(wlan_pwr_on, 1);
  312. #ifndef CONFIG_ARCH_SWA100
  313. gpio_export_link(wlan_dev, "WLAN_REG_ON", wlan_pwr_on);
  314. #endif /* not CONFIG_ARCH_SWA100 */
  315. /* ========== WLAN_HOST_WAKE ============ */
  316. wlan_host_wake_up = of_get_gpio(root_node, 1);
  317. if (!gpio_is_valid(wlan_host_wake_up)) {
  318. WARN(1, "Invalied gpio pin : %d\n", wlan_host_wake_up);
  319. return -ENODEV;
  320. }
  321. if (gpio_request(wlan_host_wake_up, "WLAN_HOST_WAKE")) {
  322. WARN(1, "fail to request gpio(WLAN_HOST_WAKE)\n");
  323. return -ENODEV;
  324. }
  325. gpio_direction_input(wlan_host_wake_up);
  326. gpio_export(wlan_host_wake_up, 1);
  327. #ifndef CONFIG_ARCH_SWA100
  328. gpio_export_link(wlan_dev, "WLAN_HOST_WAKE", wlan_host_wake_up);
  329. #endif /* not CONFIG_ARCH_SWA100 */
  330. wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up);
  331. return 0;
  332. }
  333. #if defined(CONFIG_ARGOS)
  334. void set_cpucore_for_interrupt(cpumask_var_t default_cpu_mask,
  335. cpumask_var_t affinity_cpu_mask) {
  336. #if defined(CONFIG_MACH_UNIVERSAL5430)
  337. argos_irq_affinity_setup_label(IRQ_SPI(226), "WIFI", affinity_cpu_mask, default_cpu_mask);
  338. argos_irq_affinity_setup_label(IRQ_SPI(2), "WIFI", affinity_cpu_mask, default_cpu_mask);
  339. #endif
  340. }
  341. #endif /* CONFIG_ARGOS */
  342. void interrupt_set_cpucore(int set, unsigned int dpc_cpucore, unsigned int primary_cpucore)
  343. {
  344. printk(KERN_INFO "%s: set: %d\n", __FUNCTION__, set);
  345. if (set)
  346. {
  347. #if defined(CONFIG_MACH_UNIVERSAL5422)
  348. irq_set_affinity(EXYNOS5_IRQ_HSMMC1, cpumask_of(dpc_cpucore));
  349. irq_set_affinity(EXYNOS_IRQ_EINT16_31, cpumask_of(dpc_cpucore));
  350. #elif defined(CONFIG_MACH_UNIVERSAL5430)
  351. irq_set_affinity(IRQ_SPI(226), cpumask_of(dpc_cpucore));
  352. irq_set_affinity(IRQ_SPI(2), cpumask_of(dpc_cpucore));
  353. #elif defined(CONFIG_MACH_UNIVERSAL7580)
  354. irq_set_affinity(IRQ_SPI(246), cpumask_of(dpc_cpucore));
  355. #endif
  356. } else {
  357. #if defined(CONFIG_MACH_UNIVERSAL5422)
  358. irq_set_affinity(EXYNOS5_IRQ_HSMMC1, cpumask_of(primary_cpucore));
  359. irq_set_affinity(EXYNOS_IRQ_EINT16_31, cpumask_of(primary_cpucore));
  360. #elif defined(CONFIG_MACH_UNIVERSAL5430)
  361. irq_set_affinity(IRQ_SPI(226), cpumask_of(primary_cpucore));
  362. irq_set_affinity(IRQ_SPI(2), cpumask_of(primary_cpucore));
  363. #elif defined(CONFIG_MACH_UNIVERSAL7580)
  364. irq_set_affinity(IRQ_SPI(246), cpumask_of(primary_cpucore));
  365. #endif
  366. }
  367. }
  368. struct resource dhd_wlan_resources = {
  369. .name = "bcmdhd_wlan_irq",
  370. .start = 0,
  371. .end = 0,
  372. .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL |
  373. IORESOURCE_IRQ_SHAREABLE,
  374. };
  375. struct wifi_platform_data dhd_wlan_control = {
  376. .set_power = dhd_wlan_power,
  377. .set_reset = dhd_wlan_reset,
  378. .set_carddetect = dhd_wlan_set_carddetect,
  379. #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
  380. .mem_prealloc = dhd_wlan_mem_prealloc,
  381. #endif
  382. };
  383. int __init dhd_wlan_init(void)
  384. {
  385. int ret;
  386. printk(KERN_INFO "%s: start\n", __FUNCTION__);
  387. ret = dhd_wlan_init_gpio();
  388. if (ret < 0) {
  389. printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n",
  390. __FUNCTION__, ret);
  391. return ret;
  392. }
  393. dhd_wlan_resources.start = wlan_host_wake_irq;
  394. dhd_wlan_resources.end = wlan_host_wake_irq;
  395. #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
  396. ret = dhd_init_wlan_mem();
  397. #endif
  398. return ret;
  399. }
  400. device_initcall(dhd_wlan_init);