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