1/* 2 * This file is part of wl1271 3 * 4 * Copyright (C) 2009-2010 Nokia Corporation 5 * 6 * Contact: Luciano Coelho <luciano.coelho@nokia.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA 21 * 22 */ 23 24#include <linux/irq.h> 25#include <linux/module.h> 26#include <linux/vmalloc.h> 27#include <linux/platform_device.h> 28#include <linux/mmc/sdio_func.h> 29#include <linux/mmc/sdio_ids.h> 30#include <linux/mmc/card.h> 31#include <linux/mmc/host.h> 32#include <linux/gpio.h> 33#include <linux/wl12xx.h> 34#include <linux/pm_runtime.h> 35 36#include "wl12xx.h" 37#include "wl12xx_80211.h" 38#include "io.h" 39 40#ifndef SDIO_VENDOR_ID_TI 41#define SDIO_VENDOR_ID_TI 0x0097 42#endif 43 44#ifndef SDIO_DEVICE_ID_TI_WL1271 45#define SDIO_DEVICE_ID_TI_WL1271 0x4076 46#endif 47 48struct wl12xx_sdio_glue { 49 struct device *dev; 50 struct platform_device *core; 51}; 52 53static const struct sdio_device_id wl1271_devices[] __devinitconst = { 54 { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) }, 55 {} 56}; 57MODULE_DEVICE_TABLE(sdio, wl1271_devices); 58 59static void wl1271_sdio_set_block_size(struct device *child, 60 unsigned int blksz) 61{ 62 struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); 63 struct sdio_func *func = dev_to_sdio_func(glue->dev); 64 65 sdio_claim_host(func); 66 sdio_set_block_size(func, blksz); 67 sdio_release_host(func); 68} 69 70static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, 71 size_t len, bool fixed) 72{ 73 int ret; 74 struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); 75 struct sdio_func *func = dev_to_sdio_func(glue->dev); 76 77 sdio_claim_host(func); 78 79 if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { 80 ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); 81 dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n", 82 addr, ((u8 *)buf)[0]); 83 } else { 84 if (fixed) 85 ret = sdio_readsb(func, buf, addr, len); 86 else 87 ret = sdio_memcpy_fromio(func, buf, addr, len); 88 89 dev_dbg(child->parent, "sdio read 53 addr 0x%x, %zu bytes\n", 90 addr, len); 91 } 92 93 sdio_release_host(func); 94 95 if (ret) 96 dev_err(child->parent, "sdio read failed (%d)\n", ret); 97} 98 99static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, 100 size_t len, bool fixed) 101{ 102 int ret; 103 struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); 104 struct sdio_func *func = dev_to_sdio_func(glue->dev); 105 106 sdio_claim_host(func); 107 108 if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { 109 sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); 110 dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n", 111 addr, ((u8 *)buf)[0]); 112 } else { 113 dev_dbg(child->parent, "sdio write 53 addr 0x%x, %zu bytes\n", 114 addr, len); 115 116 if (fixed) 117 ret = sdio_writesb(func, addr, buf, len); 118 else 119 ret = sdio_memcpy_toio(func, addr, buf, len); 120 } 121 122 sdio_release_host(func); 123 124 if (ret) 125 dev_err(child->parent, "sdio write failed (%d)\n", ret); 126} 127 128static 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 133 /* If enabled, tell runtime PM not to power off the card */ 134 if (pm_runtime_enabled(&func->dev)) { 135 ret = pm_runtime_get_sync(&func->dev); 136 if (ret < 0) 137 goto out; 138 } else { 139 /* Runtime PM is disabled: power up the card manually */ 140 ret = mmc_power_restore_host(func->card->host); 141 if (ret < 0) 142 goto out; 143 } 144 145 sdio_claim_host(func); 146 sdio_enable_func(func); 147 sdio_release_host(func); 148 149out: 150 return ret; 151} 152 153static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue) 154{ 155 int ret; 156 struct sdio_func *func = dev_to_sdio_func(glue->dev); 157 158 sdio_claim_host(func); 159 sdio_disable_func(func); 160 sdio_release_host(func); 161 162 /* Power off the card manually, even if runtime PM is enabled. */ 163 ret = mmc_power_save_host(func->card->host); 164 if (ret < 0) 165 return ret; 166 167 /* If enabled, let runtime PM know the card is powered off */ 168 if (pm_runtime_enabled(&func->dev)) 169 ret = pm_runtime_put_sync(&func->dev); 170 171 return ret; 172} 173 174static int wl12xx_sdio_set_power(struct device *child, bool enable) 175{ 176 struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); 177 178 if (enable) 179 return wl12xx_sdio_power_on(glue); 180 else 181 return wl12xx_sdio_power_off(glue); 182} 183 184static struct wl1271_if_operations sdio_ops = { 185 .read = wl12xx_sdio_raw_read, 186 .write = wl12xx_sdio_raw_write, 187 .power = wl12xx_sdio_set_power, 188 .set_block_size = wl1271_sdio_set_block_size, 189}; 190 191static int __devinit wl1271_probe(struct sdio_func *func, 192 const struct sdio_device_id *id) 193{ 194 struct wl12xx_platform_data *wlan_data; 195 struct wl12xx_sdio_glue *glue; 196 struct resource res[1]; 197 mmc_pm_flag_t mmcflags; 198 int ret = -ENOMEM; 199 200 /* We are only able to handle the wlan function */ 201 if (func->num != 0x02) 202 return -ENODEV; 203 204 glue = kzalloc(sizeof(*glue), GFP_KERNEL); 205 if (!glue) { 206 dev_err(&func->dev, "can't allocate glue\n"); 207 goto out; 208 } 209 210 glue->dev = &func->dev; 211 212 /* Grab access to FN0 for ELP reg. */ 213 func->card->quirks |= MMC_QUIRK_LENIENT_FN0; 214 215 /* Use block mode for transferring over one block size of data */ 216 func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; 217 218 wlan_data = wl12xx_get_platform_data(); 219 if (IS_ERR(wlan_data)) { 220 ret = PTR_ERR(wlan_data); 221 dev_err(glue->dev, "missing wlan platform data: %d\n", ret); 222 goto out_free_glue; 223 } 224 225 /* if sdio can keep power while host is suspended, enable wow */ 226 mmcflags = sdio_get_host_pm_caps(func); 227 dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); 228 229 if (mmcflags & MMC_PM_KEEP_POWER) 230 wlan_data->pwr_in_suspend = true; 231 232 wlan_data->ops = &sdio_ops; 233 234 sdio_set_drvdata(func, glue); 235 236 /* Tell PM core that we don't need the card to be powered now */ 237 pm_runtime_put_noidle(&func->dev); 238 239 glue->core = platform_device_alloc("wl12xx", -1); 240 if (!glue->core) { 241 dev_err(glue->dev, "can't allocate platform_device"); 242 ret = -ENOMEM; 243 goto out_free_glue; 244 } 245 246 glue->core->dev.parent = &func->dev; 247 248 memset(res, 0x00, sizeof(res)); 249 250 res[0].start = wlan_data->irq; 251 res[0].flags = IORESOURCE_IRQ; 252 res[0].name = "irq"; 253 254 ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); 255 if (ret) { 256 dev_err(glue->dev, "can't add resources\n"); 257 goto out_dev_put; 258 } 259 260 ret = platform_device_add_data(glue->core, wlan_data, 261 sizeof(*wlan_data)); 262 if (ret) { 263 dev_err(glue->dev, "can't add platform data\n"); 264 goto out_dev_put; 265 } 266 267 ret = platform_device_add(glue->core); 268 if (ret) { 269 dev_err(glue->dev, "can't add platform device\n"); 270 goto out_dev_put; 271 } 272 return 0; 273 274out_dev_put: 275 platform_device_put(glue->core); 276 277out_free_glue: 278 kfree(glue); 279 280out: 281 return ret; 282} 283 284static void __devexit wl1271_remove(struct sdio_func *func) 285{ 286 struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); 287 288 /* Undo decrement done above in wl1271_probe */ 289 pm_runtime_get_noresume(&func->dev); 290 291 platform_device_del(glue->core); 292 platform_device_put(glue->core); 293 kfree(glue); 294} 295 296#ifdef CONFIG_PM 297static int wl1271_suspend(struct device *dev) 298{ 299 /* Tell MMC/SDIO core it's OK to power down the card 300 * (if it isn't already), but not to remove it completely */ 301 struct sdio_func *func = dev_to_sdio_func(dev); 302 struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); 303 struct wl1271 *wl = platform_get_drvdata(glue->core); 304 mmc_pm_flag_t sdio_flags; 305 int ret = 0; 306 307 dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", 308 wl->wow_enabled); 309 310 /* check whether sdio should keep power */ 311 if (wl->wow_enabled) { 312 sdio_flags = sdio_get_host_pm_caps(func); 313 314 if (!(sdio_flags & MMC_PM_KEEP_POWER)) { 315 dev_err(dev, "can't keep power while host " 316 "is suspended\n"); 317 ret = -EINVAL; 318 goto out; 319 } 320 321 /* keep power while host suspended */ 322 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 323 if (ret) { 324 dev_err(dev, "error while trying to keep power\n"); 325 goto out; 326 } 327 } 328out: 329 return ret; 330} 331 332static int wl1271_resume(struct device *dev) 333{ 334 dev_dbg(dev, "wl1271 resume\n"); 335 336 return 0; 337} 338 339static const struct dev_pm_ops wl1271_sdio_pm_ops = { 340 .suspend = wl1271_suspend, 341 .resume = wl1271_resume, 342}; 343#endif 344 345static struct sdio_driver wl1271_sdio_driver = { 346 .name = "wl1271_sdio", 347 .id_table = wl1271_devices, 348 .probe = wl1271_probe, 349 .remove = __devexit_p(wl1271_remove), 350#ifdef CONFIG_PM 351 .drv = { 352 .pm = &wl1271_sdio_pm_ops, 353 }, 354#endif 355}; 356 357static int __init wl1271_init(void) 358{ 359 return sdio_register_driver(&wl1271_sdio_driver); 360} 361 362static void __exit wl1271_exit(void) 363{ 364 sdio_unregister_driver(&wl1271_sdio_driver); 365} 366 367module_init(wl1271_init); 368module_exit(wl1271_exit); 369 370MODULE_LICENSE("GPL"); 371MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); 372MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); 373MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); 374MODULE_FIRMWARE(WL127X_FW_NAME_MULTI); 375MODULE_FIRMWARE(WL127X_PLT_FW_NAME); 376MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE); 377MODULE_FIRMWARE(WL128X_FW_NAME_MULTI); 378MODULE_FIRMWARE(WL128X_PLT_FW_NAME); 379