1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * This file is part of wl1271 4 * 5 * Copyright (C) 2009-2010 Nokia Corporation 6 * 7 * Contact: Luciano Coelho <luciano.coelho@nokia.com> 8 */ 9 10 #include <linux/irq.h> 11 #include <linux/module.h> 12 #include <linux/vmalloc.h> 13 #include <linux/platform_device.h> 14 #include <linux/mmc/sdio.h> 15 #include <linux/mmc/sdio_func.h> 16 #include <linux/mmc/sdio_ids.h> 17 #include <linux/mmc/card.h> 18 #include <linux/mmc/host.h> 19 #include <linux/gpio.h> 20 #include <linux/pm_runtime.h> 21 #include <linux/printk.h> 22 #include <linux/of.h> 23 #include <linux/of_irq.h> 24 25 #include "wlcore.h" 26 #include "wl12xx_80211.h" 27 #include "io.h" 28 29 static bool dump; 30 31 struct wl12xx_sdio_glue { 32 struct device *dev; 33 struct platform_device *core; 34 }; 35 36 static const struct sdio_device_id wl1271_devices[] = { 37 { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) }, 38 {} 39 }; 40 MODULE_DEVICE_TABLE(sdio, wl1271_devices); 41 42 static void wl1271_sdio_set_block_size(struct device *child, 43 unsigned int blksz) 44 { 45 struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); 46 struct sdio_func *func = dev_to_sdio_func(glue->dev); 47 48 sdio_claim_host(func); 49 sdio_set_block_size(func, blksz); 50 sdio_release_host(func); 51 } 52 53 static int __must_check wl12xx_sdio_raw_read(struct device *child, int addr, 54 void *buf, size_t len, bool fixed) 55 { 56 int ret; 57 struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); 58 struct sdio_func *func = dev_to_sdio_func(glue->dev); 59 60 sdio_claim_host(func); 61 62 if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) { 63 ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); 64 dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n", 65 addr, ((u8 *)buf)[0]); 66 } else { 67 if (fixed) 68 ret = sdio_readsb(func, buf, addr, len); 69 else 70 ret = sdio_memcpy_fromio(func, buf, addr, len); 71 72 dev_dbg(child->parent, "sdio read 53 addr 0x%x, %zu bytes\n", 73 addr, len); 74 } 75 76 sdio_release_host(func); 77 78 if (WARN_ON(ret)) 79 dev_err(child->parent, "sdio read failed (%d)\n", ret); 80 81 if (unlikely(dump)) { 82 printk(KERN_DEBUG "wlcore_sdio: READ from 0x%04x\n", addr); 83 print_hex_dump(KERN_DEBUG, "wlcore_sdio: READ ", 84 DUMP_PREFIX_OFFSET, 16, 1, 85 buf, len, false); 86 } 87 88 return ret; 89 } 90 91 static int __must_check wl12xx_sdio_raw_write(struct device *child, int addr, 92 void *buf, size_t len, bool fixed) 93 { 94 int ret; 95 struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); 96 struct sdio_func *func = dev_to_sdio_func(glue->dev); 97 98 sdio_claim_host(func); 99 100 if (unlikely(dump)) { 101 printk(KERN_DEBUG "wlcore_sdio: WRITE to 0x%04x\n", addr); 102 print_hex_dump(KERN_DEBUG, "wlcore_sdio: WRITE ", 103 DUMP_PREFIX_OFFSET, 16, 1, 104 buf, len, false); 105 } 106 107 if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) { 108 sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); 109 dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n", 110 addr, ((u8 *)buf)[0]); 111 } else { 112 dev_dbg(child->parent, "sdio write 53 addr 0x%x, %zu bytes\n", 113 addr, len); 114 115 if (fixed) 116 ret = sdio_writesb(func, addr, buf, len); 117 else 118 ret = sdio_memcpy_toio(func, addr, buf, len); 119 } 120 121 sdio_release_host(func); 122 123 if (WARN_ON(ret)) 124 dev_err(child->parent, "sdio write failed (%d)\n", ret); 125 126 return ret; 127 } 128 129 static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) 130 { 131 int ret; 132 struct sdio_func *func = dev_to_sdio_func(glue->dev); 133 struct mmc_card *card = func->card; 134 135 ret = pm_runtime_resume_and_get(&card->dev); 136 if (ret < 0) { 137 dev_err(glue->dev, "%s: failed to get_sync(%d)\n", 138 __func__, ret); 139 140 return ret; 141 } 142 143 sdio_claim_host(func); 144 /* 145 * To guarantee that the SDIO card is power cycled, as required to make 146 * the FW programming to succeed, let's do a brute force HW reset. 147 */ 148 mmc_hw_reset(card); 149 150 sdio_enable_func(func); 151 sdio_release_host(func); 152 153 return 0; 154 } 155 156 static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue) 157 { 158 struct sdio_func *func = dev_to_sdio_func(glue->dev); 159 struct mmc_card *card = func->card; 160 161 sdio_claim_host(func); 162 sdio_disable_func(func); 163 sdio_release_host(func); 164 165 /* Let runtime PM know the card is powered off */ 166 pm_runtime_put(&card->dev); 167 return 0; 168 } 169 170 static int wl12xx_sdio_set_power(struct device *child, bool enable) 171 { 172 struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); 173 174 if (enable) 175 return wl12xx_sdio_power_on(glue); 176 else 177 return wl12xx_sdio_power_off(glue); 178 } 179 180 static struct wl1271_if_operations sdio_ops = { 181 .read = wl12xx_sdio_raw_read, 182 .write = wl12xx_sdio_raw_write, 183 .power = wl12xx_sdio_set_power, 184 .set_block_size = wl1271_sdio_set_block_size, 185 }; 186 187 #ifdef CONFIG_OF 188 189 static const struct wilink_family_data wl127x_data = { 190 .name = "wl127x", 191 .nvs_name = "ti-connectivity/wl127x-nvs.bin", 192 }; 193 194 static const struct wilink_family_data wl128x_data = { 195 .name = "wl128x", 196 .nvs_name = "ti-connectivity/wl128x-nvs.bin", 197 }; 198 199 static const struct wilink_family_data wl18xx_data = { 200 .name = "wl18xx", 201 .cfg_name = "ti-connectivity/wl18xx-conf.bin", 202 .nvs_name = "ti-connectivity/wl1271-nvs.bin", 203 }; 204 205 static const struct of_device_id wlcore_sdio_of_match_table[] = { 206 { .compatible = "ti,wl1271", .data = &wl127x_data }, 207 { .compatible = "ti,wl1273", .data = &wl127x_data }, 208 { .compatible = "ti,wl1281", .data = &wl128x_data }, 209 { .compatible = "ti,wl1283", .data = &wl128x_data }, 210 { .compatible = "ti,wl1285", .data = &wl128x_data }, 211 { .compatible = "ti,wl1801", .data = &wl18xx_data }, 212 { .compatible = "ti,wl1805", .data = &wl18xx_data }, 213 { .compatible = "ti,wl1807", .data = &wl18xx_data }, 214 { .compatible = "ti,wl1831", .data = &wl18xx_data }, 215 { .compatible = "ti,wl1835", .data = &wl18xx_data }, 216 { .compatible = "ti,wl1837", .data = &wl18xx_data }, 217 { } 218 }; 219 220 static int wlcore_probe_of(struct device *dev, int *irq, int *wakeirq, 221 struct wlcore_platdev_data *pdev_data) 222 { 223 struct device_node *np = dev->of_node; 224 const struct of_device_id *of_id; 225 226 of_id = of_match_node(wlcore_sdio_of_match_table, np); 227 if (!of_id) 228 return -ENODEV; 229 230 pdev_data->family = of_id->data; 231 232 *irq = irq_of_parse_and_map(np, 0); 233 if (!*irq) { 234 dev_err(dev, "No irq in platform data\n"); 235 return -EINVAL; 236 } 237 238 *wakeirq = irq_of_parse_and_map(np, 1); 239 240 /* optional clock frequency params */ 241 of_property_read_u32(np, "ref-clock-frequency", 242 &pdev_data->ref_clock_freq); 243 of_property_read_u32(np, "tcxo-clock-frequency", 244 &pdev_data->tcxo_clock_freq); 245 246 return 0; 247 } 248 #else 249 static int wlcore_probe_of(struct device *dev, int *irq, int *wakeirq, 250 struct wlcore_platdev_data *pdev_data) 251 { 252 return -ENODATA; 253 } 254 #endif 255 256 static int wl1271_probe(struct sdio_func *func, 257 const struct sdio_device_id *id) 258 { 259 struct wlcore_platdev_data *pdev_data; 260 struct wl12xx_sdio_glue *glue; 261 struct resource res[2]; 262 mmc_pm_flag_t mmcflags; 263 int ret = -ENOMEM; 264 int irq, wakeirq, num_irqs; 265 const char *chip_family; 266 267 /* We are only able to handle the wlan function */ 268 if (func->num != 0x02) 269 return -ENODEV; 270 271 pdev_data = devm_kzalloc(&func->dev, sizeof(*pdev_data), GFP_KERNEL); 272 if (!pdev_data) 273 return -ENOMEM; 274 275 pdev_data->if_ops = &sdio_ops; 276 277 glue = devm_kzalloc(&func->dev, sizeof(*glue), GFP_KERNEL); 278 if (!glue) 279 return -ENOMEM; 280 281 glue->dev = &func->dev; 282 283 /* Grab access to FN0 for ELP reg. */ 284 func->card->quirks |= MMC_QUIRK_LENIENT_FN0; 285 286 /* Use block mode for transferring over one block size of data */ 287 func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; 288 289 ret = wlcore_probe_of(&func->dev, &irq, &wakeirq, pdev_data); 290 if (ret) 291 goto out; 292 293 /* if sdio can keep power while host is suspended, enable wow */ 294 mmcflags = sdio_get_host_pm_caps(func); 295 dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); 296 297 if (mmcflags & MMC_PM_KEEP_POWER) 298 pdev_data->pwr_in_suspend = true; 299 300 sdio_set_drvdata(func, glue); 301 302 /* Tell PM core that we don't need the card to be powered now */ 303 pm_runtime_put_noidle(&func->dev); 304 305 /* 306 * Due to a hardware bug, we can't differentiate wl18xx from 307 * wl12xx, because both report the same device ID. The only 308 * way to differentiate is by checking the SDIO revision, 309 * which is 3.00 on the wl18xx chips. 310 */ 311 if (func->card->cccr.sdio_vsn == SDIO_SDIO_REV_3_00) 312 chip_family = "wl18xx"; 313 else 314 chip_family = "wl12xx"; 315 316 glue->core = platform_device_alloc(chip_family, PLATFORM_DEVID_AUTO); 317 if (!glue->core) { 318 dev_err(glue->dev, "can't allocate platform_device"); 319 ret = -ENOMEM; 320 goto out; 321 } 322 323 glue->core->dev.parent = &func->dev; 324 325 memset(res, 0x00, sizeof(res)); 326 327 res[0].start = irq; 328 res[0].flags = IORESOURCE_IRQ | 329 irqd_get_trigger_type(irq_get_irq_data(irq)); 330 res[0].name = "irq"; 331 332 333 if (wakeirq > 0) { 334 res[1].start = wakeirq; 335 res[1].flags = IORESOURCE_IRQ | 336 irqd_get_trigger_type(irq_get_irq_data(wakeirq)); 337 res[1].name = "wakeirq"; 338 num_irqs = 2; 339 } else { 340 num_irqs = 1; 341 } 342 ret = platform_device_add_resources(glue->core, res, num_irqs); 343 if (ret) { 344 dev_err(glue->dev, "can't add resources\n"); 345 goto out_dev_put; 346 } 347 348 ret = platform_device_add_data(glue->core, pdev_data, 349 sizeof(*pdev_data)); 350 if (ret) { 351 dev_err(glue->dev, "can't add platform data\n"); 352 goto out_dev_put; 353 } 354 355 ret = platform_device_add(glue->core); 356 if (ret) { 357 dev_err(glue->dev, "can't add platform device\n"); 358 goto out_dev_put; 359 } 360 return 0; 361 362 out_dev_put: 363 platform_device_put(glue->core); 364 365 out: 366 return ret; 367 } 368 369 static void wl1271_remove(struct sdio_func *func) 370 { 371 struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); 372 373 /* Undo decrement done above in wl1271_probe */ 374 pm_runtime_get_noresume(&func->dev); 375 376 platform_device_unregister(glue->core); 377 } 378 379 #ifdef CONFIG_PM 380 static int wl1271_suspend(struct device *dev) 381 { 382 /* Tell MMC/SDIO core it's OK to power down the card 383 * (if it isn't already), but not to remove it completely */ 384 struct sdio_func *func = dev_to_sdio_func(dev); 385 struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); 386 struct wl1271 *wl = platform_get_drvdata(glue->core); 387 mmc_pm_flag_t sdio_flags; 388 int ret = 0; 389 390 if (!wl) { 391 dev_err(dev, "no wilink module was probed\n"); 392 goto out; 393 } 394 395 dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", 396 wl->wow_enabled); 397 398 /* check whether sdio should keep power */ 399 if (wl->wow_enabled) { 400 sdio_flags = sdio_get_host_pm_caps(func); 401 402 if (!(sdio_flags & MMC_PM_KEEP_POWER)) { 403 dev_err(dev, "can't keep power while host " 404 "is suspended\n"); 405 ret = -EINVAL; 406 goto out; 407 } 408 409 /* keep power while host suspended */ 410 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 411 if (ret) { 412 dev_err(dev, "error while trying to keep power\n"); 413 goto out; 414 } 415 } 416 out: 417 return ret; 418 } 419 420 static int wl1271_resume(struct device *dev) 421 { 422 dev_dbg(dev, "wl1271 resume\n"); 423 424 return 0; 425 } 426 427 static const struct dev_pm_ops wl1271_sdio_pm_ops = { 428 .suspend = wl1271_suspend, 429 .resume = wl1271_resume, 430 }; 431 #endif 432 433 static struct sdio_driver wl1271_sdio_driver = { 434 .name = "wl1271_sdio", 435 .id_table = wl1271_devices, 436 .probe = wl1271_probe, 437 .remove = wl1271_remove, 438 #ifdef CONFIG_PM 439 .drv = { 440 .pm = &wl1271_sdio_pm_ops, 441 }, 442 #endif 443 }; 444 445 module_sdio_driver(wl1271_sdio_driver); 446 447 module_param(dump, bool, 0600); 448 MODULE_PARM_DESC(dump, "Enable sdio read/write dumps."); 449 450 MODULE_LICENSE("GPL"); 451 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); 452 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); 453