root/drivers/net/wireless/st/cw1200/cw1200_sdio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cw1200_sdio_set_platform_data
  2. cw1200_sdio_memcpy_fromio
  3. cw1200_sdio_memcpy_toio
  4. cw1200_sdio_lock
  5. cw1200_sdio_unlock
  6. cw1200_sdio_irq_handler
  7. cw1200_gpio_hardirq
  8. cw1200_gpio_irq
  9. cw1200_request_irq
  10. cw1200_sdio_irq_subscribe
  11. cw1200_sdio_irq_unsubscribe
  12. cw1200_sdio_off
  13. cw1200_sdio_on
  14. cw1200_sdio_align_size
  15. cw1200_sdio_pm
  16. cw1200_sdio_probe
  17. cw1200_sdio_disconnect
  18. cw1200_sdio_suspend
  19. cw1200_sdio_resume
  20. cw1200_sdio_init
  21. cw1200_sdio_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Mac80211 SDIO driver for ST-Ericsson CW1200 device
   4  *
   5  * Copyright (c) 2010, ST-Ericsson
   6  * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
   7  */
   8 
   9 #include <linux/module.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/gpio.h>
  12 #include <linux/delay.h>
  13 #include <linux/mmc/host.h>
  14 #include <linux/mmc/sdio_func.h>
  15 #include <linux/mmc/card.h>
  16 #include <linux/mmc/sdio.h>
  17 #include <net/mac80211.h>
  18 
  19 #include "cw1200.h"
  20 #include "hwbus.h"
  21 #include <linux/platform_data/net-cw1200.h>
  22 #include "hwio.h"
  23 
  24 MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
  25 MODULE_DESCRIPTION("mac80211 ST-Ericsson CW1200 SDIO driver");
  26 MODULE_LICENSE("GPL");
  27 
  28 #define SDIO_BLOCK_SIZE (512)
  29 
  30 /* Default platform data for Sagrad modules */
  31 static struct cw1200_platform_data_sdio sagrad_109x_evk_platform_data = {
  32         .ref_clk = 38400,
  33         .have_5ghz = false,
  34         .sdd_file = "sdd_sagrad_1091_1098.bin",
  35 };
  36 
  37 /* Allow platform data to be overridden */
  38 static struct cw1200_platform_data_sdio *global_plat_data = &sagrad_109x_evk_platform_data;
  39 
  40 void __init cw1200_sdio_set_platform_data(struct cw1200_platform_data_sdio *pdata)
  41 {
  42         global_plat_data = pdata;
  43 }
  44 
  45 struct hwbus_priv {
  46         struct sdio_func        *func;
  47         struct cw1200_common    *core;
  48         const struct cw1200_platform_data_sdio *pdata;
  49 };
  50 
  51 #ifndef SDIO_VENDOR_ID_STE
  52 #define SDIO_VENDOR_ID_STE              0x0020
  53 #endif
  54 
  55 #ifndef SDIO_DEVICE_ID_STE_CW1200
  56 #define SDIO_DEVICE_ID_STE_CW1200       0x2280
  57 #endif
  58 
  59 static const struct sdio_device_id cw1200_sdio_ids[] = {
  60         { SDIO_DEVICE(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200) },
  61         { /* end: all zeroes */                 },
  62 };
  63 
  64 /* hwbus_ops implemetation */
  65 
  66 static int cw1200_sdio_memcpy_fromio(struct hwbus_priv *self,
  67                                      unsigned int addr,
  68                                      void *dst, int count)
  69 {
  70         return sdio_memcpy_fromio(self->func, dst, addr, count);
  71 }
  72 
  73 static int cw1200_sdio_memcpy_toio(struct hwbus_priv *self,
  74                                    unsigned int addr,
  75                                    const void *src, int count)
  76 {
  77         return sdio_memcpy_toio(self->func, addr, (void *)src, count);
  78 }
  79 
  80 static void cw1200_sdio_lock(struct hwbus_priv *self)
  81 {
  82         sdio_claim_host(self->func);
  83 }
  84 
  85 static void cw1200_sdio_unlock(struct hwbus_priv *self)
  86 {
  87         sdio_release_host(self->func);
  88 }
  89 
  90 static void cw1200_sdio_irq_handler(struct sdio_func *func)
  91 {
  92         struct hwbus_priv *self = sdio_get_drvdata(func);
  93 
  94         /* note:  sdio_host already claimed here. */
  95         if (self->core)
  96                 cw1200_irq_handler(self->core);
  97 }
  98 
  99 static irqreturn_t cw1200_gpio_hardirq(int irq, void *dev_id)
 100 {
 101         return IRQ_WAKE_THREAD;
 102 }
 103 
 104 static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id)
 105 {
 106         struct hwbus_priv *self = dev_id;
 107 
 108         if (self->core) {
 109                 cw1200_sdio_lock(self);
 110                 cw1200_irq_handler(self->core);
 111                 cw1200_sdio_unlock(self);
 112                 return IRQ_HANDLED;
 113         } else {
 114                 return IRQ_NONE;
 115         }
 116 }
 117 
 118 static int cw1200_request_irq(struct hwbus_priv *self)
 119 {
 120         int ret;
 121         u8 cccr;
 122 
 123         cccr = sdio_f0_readb(self->func, SDIO_CCCR_IENx, &ret);
 124         if (WARN_ON(ret))
 125                 goto err;
 126 
 127         /* Master interrupt enable ... */
 128         cccr |= BIT(0);
 129 
 130         /* ... for our function */
 131         cccr |= BIT(self->func->num);
 132 
 133         sdio_f0_writeb(self->func, cccr, SDIO_CCCR_IENx, &ret);
 134         if (WARN_ON(ret))
 135                 goto err;
 136 
 137         ret = enable_irq_wake(self->pdata->irq);
 138         if (WARN_ON(ret))
 139                 goto err;
 140 
 141         /* Request the IRQ */
 142         ret =  request_threaded_irq(self->pdata->irq, cw1200_gpio_hardirq,
 143                                     cw1200_gpio_irq,
 144                                     IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
 145                                     "cw1200_wlan_irq", self);
 146         if (WARN_ON(ret))
 147                 goto err;
 148 
 149         return 0;
 150 
 151 err:
 152         return ret;
 153 }
 154 
 155 static int cw1200_sdio_irq_subscribe(struct hwbus_priv *self)
 156 {
 157         int ret = 0;
 158 
 159         pr_debug("SW IRQ subscribe\n");
 160         sdio_claim_host(self->func);
 161         if (self->pdata->irq)
 162                 ret = cw1200_request_irq(self);
 163         else
 164                 ret = sdio_claim_irq(self->func, cw1200_sdio_irq_handler);
 165 
 166         sdio_release_host(self->func);
 167         return ret;
 168 }
 169 
 170 static int cw1200_sdio_irq_unsubscribe(struct hwbus_priv *self)
 171 {
 172         int ret = 0;
 173 
 174         pr_debug("SW IRQ unsubscribe\n");
 175 
 176         if (self->pdata->irq) {
 177                 disable_irq_wake(self->pdata->irq);
 178                 free_irq(self->pdata->irq, self);
 179         } else {
 180                 sdio_claim_host(self->func);
 181                 ret = sdio_release_irq(self->func);
 182                 sdio_release_host(self->func);
 183         }
 184         return ret;
 185 }
 186 
 187 static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata)
 188 {
 189         if (pdata->reset) {
 190                 gpio_set_value(pdata->reset, 0);
 191                 msleep(30); /* Min is 2 * CLK32K cycles */
 192                 gpio_free(pdata->reset);
 193         }
 194 
 195         if (pdata->power_ctrl)
 196                 pdata->power_ctrl(pdata, false);
 197         if (pdata->clk_ctrl)
 198                 pdata->clk_ctrl(pdata, false);
 199 
 200         return 0;
 201 }
 202 
 203 static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
 204 {
 205         /* Ensure I/Os are pulled low */
 206         if (pdata->reset) {
 207                 gpio_request(pdata->reset, "cw1200_wlan_reset");
 208                 gpio_direction_output(pdata->reset, 0);
 209         }
 210         if (pdata->powerup) {
 211                 gpio_request(pdata->powerup, "cw1200_wlan_powerup");
 212                 gpio_direction_output(pdata->powerup, 0);
 213         }
 214         if (pdata->reset || pdata->powerup)
 215                 msleep(10); /* Settle time? */
 216 
 217         /* Enable 3v3 and 1v8 to hardware */
 218         if (pdata->power_ctrl) {
 219                 if (pdata->power_ctrl(pdata, true)) {
 220                         pr_err("power_ctrl() failed!\n");
 221                         return -1;
 222                 }
 223         }
 224 
 225         /* Enable CLK32K */
 226         if (pdata->clk_ctrl) {
 227                 if (pdata->clk_ctrl(pdata, true)) {
 228                         pr_err("clk_ctrl() failed!\n");
 229                         return -1;
 230                 }
 231                 msleep(10); /* Delay until clock is stable for 2 cycles */
 232         }
 233 
 234         /* Enable POWERUP signal */
 235         if (pdata->powerup) {
 236                 gpio_set_value(pdata->powerup, 1);
 237                 msleep(250); /* or more..? */
 238         }
 239         /* Enable RSTn signal */
 240         if (pdata->reset) {
 241                 gpio_set_value(pdata->reset, 1);
 242                 msleep(50); /* Or more..? */
 243         }
 244         return 0;
 245 }
 246 
 247 static size_t cw1200_sdio_align_size(struct hwbus_priv *self, size_t size)
 248 {
 249         if (self->pdata->no_nptb)
 250                 size = round_up(size, SDIO_BLOCK_SIZE);
 251         else
 252                 size = sdio_align_size(self->func, size);
 253 
 254         return size;
 255 }
 256 
 257 static int cw1200_sdio_pm(struct hwbus_priv *self, bool suspend)
 258 {
 259         int ret = 0;
 260 
 261         if (self->pdata->irq)
 262                 ret = irq_set_irq_wake(self->pdata->irq, suspend);
 263         return ret;
 264 }
 265 
 266 static const struct hwbus_ops cw1200_sdio_hwbus_ops = {
 267         .hwbus_memcpy_fromio    = cw1200_sdio_memcpy_fromio,
 268         .hwbus_memcpy_toio      = cw1200_sdio_memcpy_toio,
 269         .lock                   = cw1200_sdio_lock,
 270         .unlock                 = cw1200_sdio_unlock,
 271         .align_size             = cw1200_sdio_align_size,
 272         .power_mgmt             = cw1200_sdio_pm,
 273 };
 274 
 275 /* Probe Function to be called by SDIO stack when device is discovered */
 276 static int cw1200_sdio_probe(struct sdio_func *func,
 277                              const struct sdio_device_id *id)
 278 {
 279         struct hwbus_priv *self;
 280         int status;
 281 
 282         pr_info("cw1200_wlan_sdio: Probe called\n");
 283 
 284         /* We are only able to handle the wlan function */
 285         if (func->num != 0x01)
 286                 return -ENODEV;
 287 
 288         self = kzalloc(sizeof(*self), GFP_KERNEL);
 289         if (!self) {
 290                 pr_err("Can't allocate SDIO hwbus_priv.\n");
 291                 return -ENOMEM;
 292         }
 293 
 294         func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
 295 
 296         self->pdata = global_plat_data; /* FIXME */
 297         self->func = func;
 298         sdio_set_drvdata(func, self);
 299         sdio_claim_host(func);
 300         sdio_enable_func(func);
 301         sdio_release_host(func);
 302 
 303         status = cw1200_sdio_irq_subscribe(self);
 304 
 305         status = cw1200_core_probe(&cw1200_sdio_hwbus_ops,
 306                                    self, &func->dev, &self->core,
 307                                    self->pdata->ref_clk,
 308                                    self->pdata->macaddr,
 309                                    self->pdata->sdd_file,
 310                                    self->pdata->have_5ghz);
 311         if (status) {
 312                 cw1200_sdio_irq_unsubscribe(self);
 313                 sdio_claim_host(func);
 314                 sdio_disable_func(func);
 315                 sdio_release_host(func);
 316                 sdio_set_drvdata(func, NULL);
 317                 kfree(self);
 318         }
 319 
 320         return status;
 321 }
 322 
 323 /* Disconnect Function to be called by SDIO stack when
 324  * device is disconnected
 325  */
 326 static void cw1200_sdio_disconnect(struct sdio_func *func)
 327 {
 328         struct hwbus_priv *self = sdio_get_drvdata(func);
 329 
 330         if (self) {
 331                 cw1200_sdio_irq_unsubscribe(self);
 332                 if (self->core) {
 333                         cw1200_core_release(self->core);
 334                         self->core = NULL;
 335                 }
 336                 sdio_claim_host(func);
 337                 sdio_disable_func(func);
 338                 sdio_release_host(func);
 339                 sdio_set_drvdata(func, NULL);
 340                 kfree(self);
 341         }
 342 }
 343 
 344 #ifdef CONFIG_PM
 345 static int cw1200_sdio_suspend(struct device *dev)
 346 {
 347         int ret;
 348         struct sdio_func *func = dev_to_sdio_func(dev);
 349         struct hwbus_priv *self = sdio_get_drvdata(func);
 350 
 351         if (!cw1200_can_suspend(self->core))
 352                 return -EAGAIN;
 353 
 354         /* Notify SDIO that CW1200 will remain powered during suspend */
 355         ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
 356         if (ret)
 357                 pr_err("Error setting SDIO pm flags: %i\n", ret);
 358 
 359         return ret;
 360 }
 361 
 362 static int cw1200_sdio_resume(struct device *dev)
 363 {
 364         return 0;
 365 }
 366 
 367 static const struct dev_pm_ops cw1200_pm_ops = {
 368         .suspend = cw1200_sdio_suspend,
 369         .resume = cw1200_sdio_resume,
 370 };
 371 #endif
 372 
 373 static struct sdio_driver sdio_driver = {
 374         .name           = "cw1200_wlan_sdio",
 375         .id_table       = cw1200_sdio_ids,
 376         .probe          = cw1200_sdio_probe,
 377         .remove         = cw1200_sdio_disconnect,
 378 #ifdef CONFIG_PM
 379         .drv = {
 380                 .pm = &cw1200_pm_ops,
 381         }
 382 #endif
 383 };
 384 
 385 /* Init Module function -> Called by insmod */
 386 static int __init cw1200_sdio_init(void)
 387 {
 388         const struct cw1200_platform_data_sdio *pdata;
 389         int ret;
 390 
 391         /* FIXME -- this won't support multiple devices */
 392         pdata = global_plat_data;
 393 
 394         if (cw1200_sdio_on(pdata)) {
 395                 ret = -1;
 396                 goto err;
 397         }
 398 
 399         ret = sdio_register_driver(&sdio_driver);
 400         if (ret)
 401                 goto err;
 402 
 403         return 0;
 404 
 405 err:
 406         cw1200_sdio_off(pdata);
 407         return ret;
 408 }
 409 
 410 /* Called at Driver Unloading */
 411 static void __exit cw1200_sdio_exit(void)
 412 {
 413         const struct cw1200_platform_data_sdio *pdata;
 414 
 415         /* FIXME -- this won't support multiple devices */
 416         pdata = global_plat_data;
 417         sdio_unregister_driver(&sdio_driver);
 418         cw1200_sdio_off(pdata);
 419 }
 420 
 421 
 422 module_init(cw1200_sdio_init);
 423 module_exit(cw1200_sdio_exit);

/* [<][>][^][v][top][bottom][index][help] */