linux/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010 Broadcom Corporation
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include <linux/types.h>
  18#include <linux/netdevice.h>
  19#include <linux/mmc/sdio.h>
  20#include <linux/mmc/core.h>
  21#include <linux/mmc/sdio_func.h>
  22#include <linux/mmc/sdio_ids.h>
  23#include <linux/mmc/card.h>
  24#include <linux/suspend.h>
  25#include <linux/errno.h>
  26#include <linux/sched.h>        /* request_irq() */
  27#include <linux/module.h>
  28#include <linux/platform_device.h>
  29#include <net/cfg80211.h>
  30
  31#include <defs.h>
  32#include <brcm_hw_ids.h>
  33#include <brcmu_utils.h>
  34#include <brcmu_wifi.h>
  35#include "sdio_host.h"
  36#include "dhd_dbg.h"
  37#include "dhd_bus.h"
  38
  39#define SDIO_VENDOR_ID_BROADCOM         0x02d0
  40
  41#define DMA_ALIGN_MASK  0x03
  42
  43#define SDIO_DEVICE_ID_BROADCOM_43241   0x4324
  44#define SDIO_DEVICE_ID_BROADCOM_4329    0x4329
  45#define SDIO_DEVICE_ID_BROADCOM_4330    0x4330
  46#define SDIO_DEVICE_ID_BROADCOM_4334    0x4334
  47
  48#define SDIO_FUNC1_BLOCKSIZE            64
  49#define SDIO_FUNC2_BLOCKSIZE            512
  50
  51/* devices we support, null terminated */
  52static const struct sdio_device_id brcmf_sdmmc_ids[] = {
  53        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)},
  54        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
  55        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
  56        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
  57        { /* end: all zeroes */ },
  58};
  59MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
  60
  61#ifdef CONFIG_BRCMFMAC_SDIO_OOB
  62static struct list_head oobirq_lh;
  63struct brcmf_sdio_oobirq {
  64        unsigned int irq;
  65        unsigned long flags;
  66        struct list_head list;
  67};
  68#endif          /* CONFIG_BRCMFMAC_SDIO_OOB */
  69
  70static bool
  71brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
  72{
  73        bool is_err = false;
  74#ifdef CONFIG_PM_SLEEP
  75        is_err = atomic_read(&sdiodev->suspend);
  76#endif
  77        return is_err;
  78}
  79
  80static void
  81brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, wait_queue_head_t *wq)
  82{
  83#ifdef CONFIG_PM_SLEEP
  84        int retry = 0;
  85        while (atomic_read(&sdiodev->suspend) && retry++ != 30)
  86                wait_event_timeout(*wq, false, HZ/100);
  87#endif
  88}
  89
  90static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
  91                                            uint regaddr, u8 *byte)
  92{
  93        struct sdio_func *sdfunc = sdiodev->func[0];
  94        int err_ret;
  95
  96        /*
  97         * Can only directly write to some F0 registers.
  98         * Handle F2 enable/disable and Abort command
  99         * as a special case.
 100         */
 101        if (regaddr == SDIO_CCCR_IOEx) {
 102                sdfunc = sdiodev->func[2];
 103                if (sdfunc) {
 104                        if (*byte & SDIO_FUNC_ENABLE_2) {
 105                                /* Enable Function 2 */
 106                                err_ret = sdio_enable_func(sdfunc);
 107                                if (err_ret)
 108                                        brcmf_err("enable F2 failed:%d\n",
 109                                                  err_ret);
 110                        } else {
 111                                /* Disable Function 2 */
 112                                err_ret = sdio_disable_func(sdfunc);
 113                                if (err_ret)
 114                                        brcmf_err("Disable F2 failed:%d\n",
 115                                                  err_ret);
 116                        }
 117                }
 118        } else if ((regaddr == SDIO_CCCR_ABORT) ||
 119                   (regaddr == SDIO_CCCR_IENx)) {
 120                sdfunc = kmemdup(sdiodev->func[0], sizeof(struct sdio_func),
 121                                 GFP_KERNEL);
 122                if (!sdfunc)
 123                        return -ENOMEM;
 124                sdfunc->num = 0;
 125                sdio_writeb(sdfunc, *byte, regaddr, &err_ret);
 126                kfree(sdfunc);
 127        } else if (regaddr < 0xF0) {
 128                brcmf_err("F0 Wr:0x%02x: write disallowed\n", regaddr);
 129                err_ret = -EPERM;
 130        } else {
 131                sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret);
 132        }
 133
 134        return err_ret;
 135}
 136
 137int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
 138                             uint regaddr, u8 *byte)
 139{
 140        int err_ret;
 141
 142        brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
 143
 144        brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
 145        if (brcmf_pm_resume_error(sdiodev))
 146                return -EIO;
 147
 148        if (rw && func == 0) {
 149                /* handle F0 separately */
 150                err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte);
 151        } else {
 152                if (rw) /* CMD52 Write */
 153                        sdio_writeb(sdiodev->func[func], *byte, regaddr,
 154                                    &err_ret);
 155                else if (func == 0) {
 156                        *byte = sdio_f0_readb(sdiodev->func[func], regaddr,
 157                                              &err_ret);
 158                } else {
 159                        *byte = sdio_readb(sdiodev->func[func], regaddr,
 160                                           &err_ret);
 161                }
 162        }
 163
 164        if (err_ret)
 165                brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
 166                          rw ? "write" : "read", func, regaddr, *byte, err_ret);
 167
 168        return err_ret;
 169}
 170
 171int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
 172                             uint rw, uint func, uint addr, u32 *word,
 173                             uint nbytes)
 174{
 175        int err_ret = -EIO;
 176
 177        if (func == 0) {
 178                brcmf_err("Only CMD52 allowed to F0\n");
 179                return -EINVAL;
 180        }
 181
 182        brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
 183                  rw, func, addr, nbytes);
 184
 185        brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
 186        if (brcmf_pm_resume_error(sdiodev))
 187                return -EIO;
 188
 189        if (rw) {               /* CMD52 Write */
 190                if (nbytes == 4)
 191                        sdio_writel(sdiodev->func[func], *word, addr,
 192                                    &err_ret);
 193                else if (nbytes == 2)
 194                        sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
 195                                    addr, &err_ret);
 196                else
 197                        brcmf_err("Invalid nbytes: %d\n", nbytes);
 198        } else {                /* CMD52 Read */
 199                if (nbytes == 4)
 200                        *word = sdio_readl(sdiodev->func[func], addr, &err_ret);
 201                else if (nbytes == 2)
 202                        *word = sdio_readw(sdiodev->func[func], addr,
 203                                           &err_ret) & 0xFFFF;
 204                else
 205                        brcmf_err("Invalid nbytes: %d\n", nbytes);
 206        }
 207
 208        if (err_ret)
 209                brcmf_err("Failed to %s word, Err: 0x%08x\n",
 210                          rw ? "write" : "read", err_ret);
 211
 212        return err_ret;
 213}
 214
 215/* precondition: host controller is claimed */
 216static int
 217brcmf_sdioh_request_data(struct brcmf_sdio_dev *sdiodev, uint write, bool fifo,
 218                         uint func, uint addr, struct sk_buff *pkt, uint pktlen)
 219{
 220        int err_ret = 0;
 221
 222        if ((write) && (!fifo)) {
 223                err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
 224                                           ((u8 *) (pkt->data)), pktlen);
 225        } else if (write) {
 226                err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
 227                                           ((u8 *) (pkt->data)), pktlen);
 228        } else if (fifo) {
 229                err_ret = sdio_readsb(sdiodev->func[func],
 230                                      ((u8 *) (pkt->data)), addr, pktlen);
 231        } else {
 232                err_ret = sdio_memcpy_fromio(sdiodev->func[func],
 233                                             ((u8 *) (pkt->data)),
 234                                             addr, pktlen);
 235        }
 236
 237        return err_ret;
 238}
 239
 240/*
 241 * This function takes a queue of packets. The packets on the queue
 242 * are assumed to be properly aligned by the caller.
 243 */
 244int
 245brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
 246                          uint write, uint func, uint addr,
 247                          struct sk_buff_head *pktq)
 248{
 249        bool fifo = (fix_inc == SDIOH_DATA_FIX);
 250        u32 SGCount = 0;
 251        int err_ret = 0;
 252
 253        struct sk_buff *pkt;
 254
 255        brcmf_dbg(TRACE, "Enter\n");
 256
 257        brcmf_pm_resume_wait(sdiodev, &sdiodev->request_chain_wait);
 258        if (brcmf_pm_resume_error(sdiodev))
 259                return -EIO;
 260
 261        skb_queue_walk(pktq, pkt) {
 262                uint pkt_len = pkt->len;
 263                pkt_len += 3;
 264                pkt_len &= 0xFFFFFFFC;
 265
 266                err_ret = brcmf_sdioh_request_data(sdiodev, write, fifo, func,
 267                                                   addr, pkt, pkt_len);
 268                if (err_ret) {
 269                        brcmf_err("%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
 270                                  write ? "TX" : "RX", pkt, SGCount, addr,
 271                                  pkt_len, err_ret);
 272                } else {
 273                        brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
 274                                  write ? "TX" : "RX", pkt, SGCount, addr,
 275                                  pkt_len);
 276                }
 277                if (!fifo)
 278                        addr += pkt_len;
 279
 280                SGCount++;
 281        }
 282
 283        brcmf_dbg(TRACE, "Exit\n");
 284        return err_ret;
 285}
 286
 287/*
 288 * This function takes a single DMA-able packet.
 289 */
 290int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
 291                               uint fix_inc, uint write, uint func, uint addr,
 292                               struct sk_buff *pkt)
 293{
 294        int status;
 295        uint pkt_len;
 296        bool fifo = (fix_inc == SDIOH_DATA_FIX);
 297
 298        brcmf_dbg(TRACE, "Enter\n");
 299
 300        if (pkt == NULL)
 301                return -EINVAL;
 302        pkt_len = pkt->len;
 303
 304        brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
 305        if (brcmf_pm_resume_error(sdiodev))
 306                return -EIO;
 307
 308        pkt_len += 3;
 309        pkt_len &= (uint)~3;
 310
 311        status = brcmf_sdioh_request_data(sdiodev, write, fifo, func,
 312                                           addr, pkt, pkt_len);
 313        if (status) {
 314                brcmf_err("%s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
 315                          write ? "TX" : "RX", pkt, addr, pkt_len, status);
 316        } else {
 317                brcmf_dbg(TRACE, "%s xfr'd %p, addr=0x%05x, len=%d\n",
 318                          write ? "TX" : "RX", pkt, addr, pkt_len);
 319        }
 320
 321        return status;
 322}
 323
 324static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr)
 325{
 326        /* read 24 bits and return valid 17 bit addr */
 327        int i, ret;
 328        u32 scratch, regdata;
 329        __le32 scratch_le;
 330        u8 *ptr = (u8 *)&scratch_le;
 331
 332        for (i = 0; i < 3; i++) {
 333                regdata = brcmf_sdio_regrl(sdiodev, regaddr, &ret);
 334                if (ret != 0)
 335                        brcmf_err("Can't read!\n");
 336
 337                *ptr++ = (u8) regdata;
 338                regaddr++;
 339        }
 340
 341        /* Only the lower 17-bits are valid */
 342        scratch = le32_to_cpu(scratch_le);
 343        scratch &= 0x0001FFFF;
 344        return scratch;
 345}
 346
 347static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
 348{
 349        int err_ret;
 350        u32 fbraddr;
 351        u8 func;
 352
 353        brcmf_dbg(TRACE, "\n");
 354
 355        /* Get the Card's common CIS address */
 356        sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev,
 357                                                           SDIO_CCCR_CIS);
 358        brcmf_dbg(INFO, "Card's Common CIS Ptr = 0x%x\n",
 359                  sdiodev->func_cis_ptr[0]);
 360
 361        /* Get the Card's function CIS (for each function) */
 362        for (fbraddr = SDIO_FBR_BASE(1), func = 1;
 363             func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
 364                sdiodev->func_cis_ptr[func] =
 365                    brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr);
 366                brcmf_dbg(INFO, "Function %d CIS Ptr = 0x%x\n",
 367                          func, sdiodev->func_cis_ptr[func]);
 368        }
 369
 370        /* Enable Function 1 */
 371        err_ret = sdio_enable_func(sdiodev->func[1]);
 372        if (err_ret)
 373                brcmf_err("Failed to enable F1 Err: 0x%08x\n", err_ret);
 374
 375        return false;
 376}
 377
 378/*
 379 *      Public entry points & extern's
 380 */
 381int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
 382{
 383        int err_ret = 0;
 384
 385        brcmf_dbg(TRACE, "\n");
 386
 387        sdiodev->num_funcs = 2;
 388
 389        sdio_claim_host(sdiodev->func[1]);
 390
 391        err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
 392        if (err_ret) {
 393                brcmf_err("Failed to set F1 blocksize\n");
 394                goto out;
 395        }
 396
 397        err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
 398        if (err_ret) {
 399                brcmf_err("Failed to set F2 blocksize\n");
 400                goto out;
 401        }
 402
 403        brcmf_sdioh_enablefuncs(sdiodev);
 404
 405out:
 406        sdio_release_host(sdiodev->func[1]);
 407        brcmf_dbg(TRACE, "Done\n");
 408        return err_ret;
 409}
 410
 411void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
 412{
 413        brcmf_dbg(TRACE, "\n");
 414
 415        /* Disable Function 2 */
 416        sdio_claim_host(sdiodev->func[2]);
 417        sdio_disable_func(sdiodev->func[2]);
 418        sdio_release_host(sdiodev->func[2]);
 419
 420        /* Disable Function 1 */
 421        sdio_claim_host(sdiodev->func[1]);
 422        sdio_disable_func(sdiodev->func[1]);
 423        sdio_release_host(sdiodev->func[1]);
 424
 425}
 426
 427#ifdef CONFIG_BRCMFMAC_SDIO_OOB
 428static int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev)
 429{
 430        struct brcmf_sdio_oobirq *oobirq_entry;
 431
 432        if (list_empty(&oobirq_lh)) {
 433                brcmf_err("no valid oob irq resource\n");
 434                return -ENXIO;
 435        }
 436
 437        oobirq_entry = list_first_entry(&oobirq_lh, struct brcmf_sdio_oobirq,
 438                                        list);
 439
 440        sdiodev->irq = oobirq_entry->irq;
 441        sdiodev->irq_flags = oobirq_entry->flags;
 442        list_del(&oobirq_entry->list);
 443        kfree(oobirq_entry);
 444
 445        return 0;
 446}
 447#else
 448static inline int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev)
 449{
 450        return 0;
 451}
 452#endif          /* CONFIG_BRCMFMAC_SDIO_OOB */
 453
 454static int brcmf_ops_sdio_probe(struct sdio_func *func,
 455                                const struct sdio_device_id *id)
 456{
 457        int err;
 458        struct brcmf_sdio_dev *sdiodev;
 459        struct brcmf_bus *bus_if;
 460
 461        brcmf_dbg(TRACE, "Enter\n");
 462        brcmf_dbg(TRACE, "Class=%x\n", func->class);
 463        brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor);
 464        brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device);
 465        brcmf_dbg(TRACE, "Function#: %d\n", func->num);
 466
 467        /* Consume func num 1 but dont do anything with it. */
 468        if (func->num == 1)
 469                return 0;
 470
 471        /* Ignore anything but func 2 */
 472        if (func->num != 2)
 473                return -ENODEV;
 474
 475        bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
 476        if (!bus_if)
 477                return -ENOMEM;
 478        sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
 479        if (!sdiodev) {
 480                kfree(bus_if);
 481                return -ENOMEM;
 482        }
 483
 484        sdiodev->func[0] = func->card->sdio_func[0];
 485        sdiodev->func[1] = func->card->sdio_func[0];
 486        sdiodev->func[2] = func;
 487
 488        sdiodev->bus_if = bus_if;
 489        bus_if->bus_priv.sdio = sdiodev;
 490        bus_if->align = BRCMF_SDALIGN;
 491        dev_set_drvdata(&func->dev, bus_if);
 492        dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
 493        sdiodev->dev = &sdiodev->func[1]->dev;
 494
 495        atomic_set(&sdiodev->suspend, false);
 496        init_waitqueue_head(&sdiodev->request_byte_wait);
 497        init_waitqueue_head(&sdiodev->request_word_wait);
 498        init_waitqueue_head(&sdiodev->request_chain_wait);
 499        init_waitqueue_head(&sdiodev->request_buffer_wait);
 500        err = brcmf_sdio_getintrcfg(sdiodev);
 501        if (err)
 502                goto fail;
 503
 504        brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
 505        err = brcmf_sdio_probe(sdiodev);
 506        if (err) {
 507                brcmf_err("F2 error, probe failed %d...\n", err);
 508                goto fail;
 509        }
 510        brcmf_dbg(TRACE, "F2 init completed...\n");
 511        return 0;
 512
 513fail:
 514        dev_set_drvdata(&func->dev, NULL);
 515        dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
 516        kfree(sdiodev);
 517        kfree(bus_if);
 518        return err;
 519}
 520
 521static void brcmf_ops_sdio_remove(struct sdio_func *func)
 522{
 523        struct brcmf_bus *bus_if;
 524        struct brcmf_sdio_dev *sdiodev;
 525
 526        brcmf_dbg(TRACE, "Enter\n");
 527        brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor);
 528        brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device);
 529        brcmf_dbg(TRACE, "Function: %d\n", func->num);
 530
 531        if (func->num != 1 && func->num != 2)
 532                return;
 533
 534        bus_if = dev_get_drvdata(&func->dev);
 535        if (bus_if) {
 536                sdiodev = bus_if->bus_priv.sdio;
 537                brcmf_sdio_remove(sdiodev);
 538
 539                dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
 540                dev_set_drvdata(&sdiodev->func[2]->dev, NULL);
 541
 542                kfree(bus_if);
 543                kfree(sdiodev);
 544        }
 545
 546        brcmf_dbg(TRACE, "Exit\n");
 547}
 548
 549#ifdef CONFIG_PM_SLEEP
 550static int brcmf_sdio_suspend(struct device *dev)
 551{
 552        mmc_pm_flag_t sdio_flags;
 553        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 554        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 555        int ret = 0;
 556
 557        brcmf_dbg(TRACE, "\n");
 558
 559        atomic_set(&sdiodev->suspend, true);
 560
 561        sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
 562        if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
 563                brcmf_err("Host can't keep power while suspended\n");
 564                return -EINVAL;
 565        }
 566
 567        ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
 568        if (ret) {
 569                brcmf_err("Failed to set pm_flags\n");
 570                return ret;
 571        }
 572
 573        brcmf_sdio_wdtmr_enable(sdiodev, false);
 574
 575        return ret;
 576}
 577
 578static int brcmf_sdio_resume(struct device *dev)
 579{
 580        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 581        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 582
 583        brcmf_sdio_wdtmr_enable(sdiodev, true);
 584        atomic_set(&sdiodev->suspend, false);
 585        return 0;
 586}
 587
 588static const struct dev_pm_ops brcmf_sdio_pm_ops = {
 589        .suspend        = brcmf_sdio_suspend,
 590        .resume         = brcmf_sdio_resume,
 591};
 592#endif  /* CONFIG_PM_SLEEP */
 593
 594static struct sdio_driver brcmf_sdmmc_driver = {
 595        .probe = brcmf_ops_sdio_probe,
 596        .remove = brcmf_ops_sdio_remove,
 597        .name = "brcmfmac",
 598        .id_table = brcmf_sdmmc_ids,
 599#ifdef CONFIG_PM_SLEEP
 600        .drv = {
 601                .pm = &brcmf_sdio_pm_ops,
 602        },
 603#endif  /* CONFIG_PM_SLEEP */
 604};
 605
 606#ifdef CONFIG_BRCMFMAC_SDIO_OOB
 607static int brcmf_sdio_pd_probe(struct platform_device *pdev)
 608{
 609        struct resource *res;
 610        struct brcmf_sdio_oobirq *oobirq_entry;
 611        int i, ret;
 612
 613        INIT_LIST_HEAD(&oobirq_lh);
 614
 615        for (i = 0; ; i++) {
 616                res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
 617                if (!res)
 618                        break;
 619
 620                oobirq_entry = kzalloc(sizeof(struct brcmf_sdio_oobirq),
 621                                       GFP_KERNEL);
 622                if (!oobirq_entry)
 623                        return -ENOMEM;
 624                oobirq_entry->irq = res->start;
 625                oobirq_entry->flags = res->flags & IRQF_TRIGGER_MASK;
 626                list_add_tail(&oobirq_entry->list, &oobirq_lh);
 627        }
 628        if (i == 0)
 629                return -ENXIO;
 630
 631        ret = sdio_register_driver(&brcmf_sdmmc_driver);
 632
 633        if (ret)
 634                brcmf_err("sdio_register_driver failed: %d\n", ret);
 635
 636        return ret;
 637}
 638
 639static struct platform_driver brcmf_sdio_pd = {
 640        .probe          = brcmf_sdio_pd_probe,
 641        .driver         = {
 642                .name   = "brcmf_sdio_pd"
 643        }
 644};
 645
 646void brcmf_sdio_exit(void)
 647{
 648        brcmf_dbg(TRACE, "Enter\n");
 649
 650        sdio_unregister_driver(&brcmf_sdmmc_driver);
 651
 652        platform_driver_unregister(&brcmf_sdio_pd);
 653}
 654
 655void brcmf_sdio_init(void)
 656{
 657        int ret;
 658
 659        brcmf_dbg(TRACE, "Enter\n");
 660
 661        ret = platform_driver_register(&brcmf_sdio_pd);
 662
 663        if (ret)
 664                brcmf_err("platform_driver_register failed: %d\n", ret);
 665}
 666#else
 667void brcmf_sdio_exit(void)
 668{
 669        brcmf_dbg(TRACE, "Enter\n");
 670
 671        sdio_unregister_driver(&brcmf_sdmmc_driver);
 672}
 673
 674void brcmf_sdio_init(void)
 675{
 676        int ret;
 677
 678        brcmf_dbg(TRACE, "Enter\n");
 679
 680        ret = sdio_register_driver(&brcmf_sdmmc_driver);
 681
 682        if (ret)
 683                brcmf_err("sdio_register_driver failed: %d\n", ret);
 684}
 685#endif          /* CONFIG_BRCMFMAC_SDIO_OOB */
 686
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.