blob: 9072de43bcd9f1b717434c799d937ab5480daaf4 [file] [log] [blame]
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001#include "wilc_wfi_netdevice.h"
2
3#include <linux/mmc/sdio_func.h>
4#include <linux/mmc/card.h>
5#include <linux/mmc/sdio_ids.h>
6#include <linux/mmc/sdio.h>
7#include <linux/mmc/host.h>
Arnd Bergmannc4d139c2015-11-16 15:05:04 +01008#include <linux/of_gpio.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +09009
Arnd Bergmann5547c1f2015-11-16 15:05:06 +010010#include "linux_wlan_sdio.h"
Johnny Kimc5c77ba2015-05-11 14:30:56 +090011
Johnny Kimc5c77ba2015-05-11 14:30:56 +090012#define SDIO_MODALIAS "wilc1000_sdio"
Johnny Kimc5c77ba2015-05-11 14:30:56 +090013
Kim, Leoe89419b2015-09-08 17:08:02 +090014#if defined(CUSTOMER_PLATFORM)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090015/* TODO : User have to stable bus clock as user's environment. */
16 #ifdef MAX_BUS_SPEED
17 #define MAX_SPEED MAX_BUS_SPEED
18 #else
19 #define MAX_SPEED 50000000
20 #endif
21#else
22 #define MAX_SPEED (6 * 1000000) /* Max 50M */
23#endif
24
Arnd Bergmann2e7d5372015-11-16 15:05:03 +010025static struct sdio_func *wilc_sdio_func;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090026static unsigned int sdio_default_speed;
27
28#define SDIO_VENDOR_ID_WILC 0x0296
29#define SDIO_DEVICE_ID_WILC 0x5347
30
31static const struct sdio_device_id wilc_sdio_ids[] = {
32 { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) },
Axel Linf9db3852015-09-12 22:02:12 +080033 { },
Johnny Kimc5c77ba2015-05-11 14:30:56 +090034};
35
36
37static void wilc_sdio_interrupt(struct sdio_func *func)
38{
Johnny Kimc5c77ba2015-05-11 14:30:56 +090039 sdio_release_host(func);
Arnd Bergmannb03314e2015-11-16 15:05:01 +010040 wilc_handle_isr(sdio_get_drvdata(func));
Johnny Kimc5c77ba2015-05-11 14:30:56 +090041 sdio_claim_host(func);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090042}
Johnny Kimc5c77ba2015-05-11 14:30:56 +090043
Arnd Bergmann0e1af732015-11-16 15:04:54 +010044int wilc_sdio_cmd52(sdio_cmd52_t *cmd)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090045{
Arnd Bergmannb03314e2015-11-16 15:05:01 +010046 struct sdio_func *func = container_of(wilc_dev->dev, struct sdio_func, dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090047 int ret;
48 u8 data;
49
50 sdio_claim_host(func);
51
52 func->num = cmd->function;
53 if (cmd->read_write) { /* write */
54 if (cmd->raw) {
55 sdio_writeb(func, cmd->data, cmd->address, &ret);
56 data = sdio_readb(func, cmd->address, &ret);
57 cmd->data = data;
58 } else {
59 sdio_writeb(func, cmd->data, cmd->address, &ret);
60 }
61 } else { /* read */
62 data = sdio_readb(func, cmd->address, &ret);
63 cmd->data = data;
64 }
65
66 sdio_release_host(func);
67
68 if (ret < 0) {
69 PRINT_ER("wilc_sdio_cmd52..failed, err(%d)\n", ret);
70 return 0;
71 }
72 return 1;
73}
74
75
Arnd Bergmann0e1af732015-11-16 15:04:54 +010076int wilc_sdio_cmd53(sdio_cmd53_t *cmd)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090077{
Arnd Bergmannb03314e2015-11-16 15:05:01 +010078 struct sdio_func *func = container_of(wilc_dev->dev, struct sdio_func, dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090079 int size, ret;
80
81 sdio_claim_host(func);
82
83 func->num = cmd->function;
84 func->cur_blksize = cmd->block_size;
85 if (cmd->block_mode)
86 size = cmd->count * cmd->block_size;
87 else
88 size = cmd->count;
89
90 if (cmd->read_write) { /* write */
91 ret = sdio_memcpy_toio(func, cmd->address, (void *)cmd->buffer, size);
92 } else { /* read */
93 ret = sdio_memcpy_fromio(func, (void *)cmd->buffer, cmd->address, size);
94 }
95
96 sdio_release_host(func);
97
98
99 if (ret < 0) {
100 PRINT_ER("wilc_sdio_cmd53..failed, err(%d)\n", ret);
101 return 0;
102 }
103
104 return 1;
105}
106
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900107static int linux_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
108{
Tony Cho12ba5412015-10-20 14:26:56 +0900109 struct wilc *wilc;
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100110 int gpio;
Tony Cho75ce07d2015-10-20 14:26:55 +0900111
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100112 gpio = -1;
113 if (IS_ENABLED(CONFIG_WILC1000_HW_OOB_INTR)) {
114 gpio = of_get_gpio(func->dev.of_node, 0);
115 if (gpio < 0)
116 gpio = GPIO_NUM;
117 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900118
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900119 PRINT_D(INIT_DBG, "Initializing netdev\n");
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100120 wilc_sdio_func = func;
Arnd Bergmann7d37a4a2015-11-16 15:05:05 +0100121 if (wilc_netdev_init(&wilc, &func->dev, HIF_SDIO, gpio,
122 &wilc_hif_sdio)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900123 PRINT_ER("Couldn't initialize netdev\n");
124 return -1;
125 }
Arnd Bergmannb03314e2015-11-16 15:05:01 +0100126 sdio_set_drvdata(func, wilc);
127 wilc->dev = &func->dev;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900128
129 printk("Driver Initializing success\n");
130 return 0;
131}
132
133static void linux_sdio_remove(struct sdio_func *func)
134{
Arnd Bergmannb03314e2015-11-16 15:05:01 +0100135 wilc_netdev_cleanup(sdio_get_drvdata(func));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900136}
137
Arnd Bergmann857c7b02015-11-16 15:05:00 +0100138static struct sdio_driver wilc_bus = {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900139 .name = SDIO_MODALIAS,
140 .id_table = wilc_sdio_ids,
141 .probe = linux_sdio_probe,
142 .remove = linux_sdio_remove,
143};
144
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100145int wilc_sdio_enable_interrupt(struct wilc *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900146{
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100147 struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900148 int ret = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900149
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100150 sdio_claim_host(func);
151 ret = sdio_claim_irq(func, wilc_sdio_interrupt);
152 sdio_release_host(func);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900153
154 if (ret < 0) {
155 PRINT_ER("can't claim sdio_irq, err(%d)\n", ret);
156 ret = -EIO;
157 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900158 return ret;
159}
160
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100161void wilc_sdio_disable_interrupt(struct wilc *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900162{
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100163 struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900164 int ret;
165
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100166 PRINT_D(INIT_DBG, "wilc_sdio_disable_interrupt IN\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900167
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100168 sdio_claim_host(func);
169 ret = sdio_release_irq(func);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900170 if (ret < 0) {
171 PRINT_ER("can't release sdio_irq, err(%d)\n", ret);
172 }
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100173 sdio_release_host(func);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900174
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100175 PRINT_D(INIT_DBG, "wilc_sdio_disable_interrupt OUT\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900176}
177
178static int linux_sdio_set_speed(int speed)
179{
180 struct mmc_ios ios;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900181
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100182 sdio_claim_host(wilc_sdio_func);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900183
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100184 memcpy((void *)&ios, (void *)&wilc_sdio_func->card->host->ios, sizeof(struct mmc_ios));
185 wilc_sdio_func->card->host->ios.clock = speed;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900186 ios.clock = speed;
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100187 wilc_sdio_func->card->host->ops->set_ios(wilc_sdio_func->card->host, &ios);
188 sdio_release_host(wilc_sdio_func);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900189 PRINT_INFO(INIT_DBG, "@@@@@@@@@@@@ change SDIO speed to %d @@@@@@@@@\n", speed);
190
191 return 1;
192}
193
194static int linux_sdio_get_speed(void)
195{
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100196 return wilc_sdio_func->card->host->ios.clock;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900197}
198
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100199int wilc_sdio_init(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900200{
201
202 /**
203 * TODO :
204 **/
205
206
207 sdio_default_speed = linux_sdio_get_speed();
208 return 1;
209}
210
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100211int wilc_sdio_set_max_speed(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900212{
213 return linux_sdio_set_speed(MAX_SPEED);
214}
215
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100216int wilc_sdio_set_default_speed(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900217{
218 return linux_sdio_set_speed(sdio_default_speed);
219}
220
Arnd Bergmann857c7b02015-11-16 15:05:00 +0100221static int __init init_wilc_sdio_driver(void)
222{
223 return sdio_register_driver(&wilc_bus);
224}
225late_initcall(init_wilc_sdio_driver);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900226
Arnd Bergmann857c7b02015-11-16 15:05:00 +0100227static void __exit exit_wilc_sdio_driver(void)
228{
229 sdio_unregister_driver(&wilc_bus);
230}
231module_exit(exit_wilc_sdio_driver);
232
233MODULE_LICENSE("GPL");