Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 1 | #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 Bergmann | c4d139c | 2015-11-16 15:05:04 +0100 | [diff] [blame] | 8 | #include <linux/of_gpio.h> |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 9 | |
Arnd Bergmann | 5547c1f | 2015-11-16 15:05:06 +0100 | [diff] [blame^] | 10 | #include "linux_wlan_sdio.h" |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 11 | |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 12 | #define SDIO_MODALIAS "wilc1000_sdio" |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 13 | |
Kim, Leo | e89419b | 2015-09-08 17:08:02 +0900 | [diff] [blame] | 14 | #if defined(CUSTOMER_PLATFORM) |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 15 | /* 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 Bergmann | 2e7d537 | 2015-11-16 15:05:03 +0100 | [diff] [blame] | 25 | static struct sdio_func *wilc_sdio_func; |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 26 | static unsigned int sdio_default_speed; |
| 27 | |
| 28 | #define SDIO_VENDOR_ID_WILC 0x0296 |
| 29 | #define SDIO_DEVICE_ID_WILC 0x5347 |
| 30 | |
| 31 | static const struct sdio_device_id wilc_sdio_ids[] = { |
| 32 | { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) }, |
Axel Lin | f9db385 | 2015-09-12 22:02:12 +0800 | [diff] [blame] | 33 | { }, |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 34 | }; |
| 35 | |
| 36 | |
| 37 | static void wilc_sdio_interrupt(struct sdio_func *func) |
| 38 | { |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 39 | sdio_release_host(func); |
Arnd Bergmann | b03314e | 2015-11-16 15:05:01 +0100 | [diff] [blame] | 40 | wilc_handle_isr(sdio_get_drvdata(func)); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 41 | sdio_claim_host(func); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 42 | } |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 43 | |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 44 | int wilc_sdio_cmd52(sdio_cmd52_t *cmd) |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 45 | { |
Arnd Bergmann | b03314e | 2015-11-16 15:05:01 +0100 | [diff] [blame] | 46 | struct sdio_func *func = container_of(wilc_dev->dev, struct sdio_func, dev); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 47 | 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 Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 76 | int wilc_sdio_cmd53(sdio_cmd53_t *cmd) |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 77 | { |
Arnd Bergmann | b03314e | 2015-11-16 15:05:01 +0100 | [diff] [blame] | 78 | struct sdio_func *func = container_of(wilc_dev->dev, struct sdio_func, dev); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 79 | 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 Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 107 | static int linux_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) |
| 108 | { |
Tony Cho | 12ba541 | 2015-10-20 14:26:56 +0900 | [diff] [blame] | 109 | struct wilc *wilc; |
Arnd Bergmann | c4d139c | 2015-11-16 15:05:04 +0100 | [diff] [blame] | 110 | int gpio; |
Tony Cho | 75ce07d | 2015-10-20 14:26:55 +0900 | [diff] [blame] | 111 | |
Arnd Bergmann | c4d139c | 2015-11-16 15:05:04 +0100 | [diff] [blame] | 112 | 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 Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 118 | |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 119 | PRINT_D(INIT_DBG, "Initializing netdev\n"); |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 120 | wilc_sdio_func = func; |
Arnd Bergmann | 7d37a4a | 2015-11-16 15:05:05 +0100 | [diff] [blame] | 121 | if (wilc_netdev_init(&wilc, &func->dev, HIF_SDIO, gpio, |
| 122 | &wilc_hif_sdio)) { |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 123 | PRINT_ER("Couldn't initialize netdev\n"); |
| 124 | return -1; |
| 125 | } |
Arnd Bergmann | b03314e | 2015-11-16 15:05:01 +0100 | [diff] [blame] | 126 | sdio_set_drvdata(func, wilc); |
| 127 | wilc->dev = &func->dev; |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 128 | |
| 129 | printk("Driver Initializing success\n"); |
| 130 | return 0; |
| 131 | } |
| 132 | |
| 133 | static void linux_sdio_remove(struct sdio_func *func) |
| 134 | { |
Arnd Bergmann | b03314e | 2015-11-16 15:05:01 +0100 | [diff] [blame] | 135 | wilc_netdev_cleanup(sdio_get_drvdata(func)); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 136 | } |
| 137 | |
Arnd Bergmann | 857c7b0 | 2015-11-16 15:05:00 +0100 | [diff] [blame] | 138 | static struct sdio_driver wilc_bus = { |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 139 | .name = SDIO_MODALIAS, |
| 140 | .id_table = wilc_sdio_ids, |
| 141 | .probe = linux_sdio_probe, |
| 142 | .remove = linux_sdio_remove, |
| 143 | }; |
| 144 | |
Arnd Bergmann | 5547c1f | 2015-11-16 15:05:06 +0100 | [diff] [blame^] | 145 | int wilc_sdio_enable_interrupt(struct wilc *dev) |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 146 | { |
Arnd Bergmann | 5547c1f | 2015-11-16 15:05:06 +0100 | [diff] [blame^] | 147 | struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 148 | int ret = 0; |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 149 | |
Arnd Bergmann | 5547c1f | 2015-11-16 15:05:06 +0100 | [diff] [blame^] | 150 | sdio_claim_host(func); |
| 151 | ret = sdio_claim_irq(func, wilc_sdio_interrupt); |
| 152 | sdio_release_host(func); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 153 | |
| 154 | if (ret < 0) { |
| 155 | PRINT_ER("can't claim sdio_irq, err(%d)\n", ret); |
| 156 | ret = -EIO; |
| 157 | } |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 158 | return ret; |
| 159 | } |
| 160 | |
Arnd Bergmann | 5547c1f | 2015-11-16 15:05:06 +0100 | [diff] [blame^] | 161 | void wilc_sdio_disable_interrupt(struct wilc *dev) |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 162 | { |
Arnd Bergmann | 5547c1f | 2015-11-16 15:05:06 +0100 | [diff] [blame^] | 163 | struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 164 | int ret; |
| 165 | |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 166 | PRINT_D(INIT_DBG, "wilc_sdio_disable_interrupt IN\n"); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 167 | |
Arnd Bergmann | 5547c1f | 2015-11-16 15:05:06 +0100 | [diff] [blame^] | 168 | sdio_claim_host(func); |
| 169 | ret = sdio_release_irq(func); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 170 | if (ret < 0) { |
| 171 | PRINT_ER("can't release sdio_irq, err(%d)\n", ret); |
| 172 | } |
Arnd Bergmann | 5547c1f | 2015-11-16 15:05:06 +0100 | [diff] [blame^] | 173 | sdio_release_host(func); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 174 | |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 175 | PRINT_D(INIT_DBG, "wilc_sdio_disable_interrupt OUT\n"); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | static int linux_sdio_set_speed(int speed) |
| 179 | { |
| 180 | struct mmc_ios ios; |
Chaehyun Lim | 8dfaafd | 2015-08-18 23:18:11 +0900 | [diff] [blame] | 181 | |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 182 | sdio_claim_host(wilc_sdio_func); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 183 | |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 184 | memcpy((void *)&ios, (void *)&wilc_sdio_func->card->host->ios, sizeof(struct mmc_ios)); |
| 185 | wilc_sdio_func->card->host->ios.clock = speed; |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 186 | ios.clock = speed; |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 187 | wilc_sdio_func->card->host->ops->set_ios(wilc_sdio_func->card->host, &ios); |
| 188 | sdio_release_host(wilc_sdio_func); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 189 | PRINT_INFO(INIT_DBG, "@@@@@@@@@@@@ change SDIO speed to %d @@@@@@@@@\n", speed); |
| 190 | |
| 191 | return 1; |
| 192 | } |
| 193 | |
| 194 | static int linux_sdio_get_speed(void) |
| 195 | { |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 196 | return wilc_sdio_func->card->host->ios.clock; |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 197 | } |
| 198 | |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 199 | int wilc_sdio_init(void) |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 200 | { |
| 201 | |
| 202 | /** |
| 203 | * TODO : |
| 204 | **/ |
| 205 | |
| 206 | |
| 207 | sdio_default_speed = linux_sdio_get_speed(); |
| 208 | return 1; |
| 209 | } |
| 210 | |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 211 | int wilc_sdio_set_max_speed(void) |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 212 | { |
| 213 | return linux_sdio_set_speed(MAX_SPEED); |
| 214 | } |
| 215 | |
Arnd Bergmann | 0e1af73 | 2015-11-16 15:04:54 +0100 | [diff] [blame] | 216 | int wilc_sdio_set_default_speed(void) |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 217 | { |
| 218 | return linux_sdio_set_speed(sdio_default_speed); |
| 219 | } |
| 220 | |
Arnd Bergmann | 857c7b0 | 2015-11-16 15:05:00 +0100 | [diff] [blame] | 221 | static int __init init_wilc_sdio_driver(void) |
| 222 | { |
| 223 | return sdio_register_driver(&wilc_bus); |
| 224 | } |
| 225 | late_initcall(init_wilc_sdio_driver); |
Johnny Kim | c5c77ba | 2015-05-11 14:30:56 +0900 | [diff] [blame] | 226 | |
Arnd Bergmann | 857c7b0 | 2015-11-16 15:05:00 +0100 | [diff] [blame] | 227 | static void __exit exit_wilc_sdio_driver(void) |
| 228 | { |
| 229 | sdio_unregister_driver(&wilc_bus); |
| 230 | } |
| 231 | module_exit(exit_wilc_sdio_driver); |
| 232 | |
| 233 | MODULE_LICENSE("GPL"); |