linux/drivers/usb/host/whci/init.c
<<
>>
Prefs
   1/*
   2 * Wireless Host Controller (WHC) initialization.
   3 *
   4 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License version
   8 * 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 */
  18#include <linux/kernel.h>
  19#include <linux/gfp.h>
  20#include <linux/dma-mapping.h>
  21#include <linux/uwb/umc.h>
  22
  23#include "../../wusbcore/wusbhc.h"
  24
  25#include "whcd.h"
  26
  27/*
  28 * Reset the host controller.
  29 */
  30static void whc_hw_reset(struct whc *whc)
  31{
  32        le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD);
  33        whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0,
  34                      100, "reset");
  35}
  36
  37static void whc_hw_init_di_buf(struct whc *whc)
  38{
  39        int d;
  40
  41        /* Disable all entries in the Device Information buffer. */
  42        for (d = 0; d < whc->n_devices; d++)
  43                whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE;
  44
  45        le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR);
  46}
  47
  48static void whc_hw_init_dn_buf(struct whc *whc)
  49{
  50        /* Clear the Device Notification buffer to ensure the V (valid)
  51         * bits are clear.  */
  52        memset(whc->dn_buf, 0, 4096);
  53
  54        le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR);
  55}
  56
  57int whc_init(struct whc *whc)
  58{
  59        u32 whcsparams;
  60        int ret, i;
  61        resource_size_t start, len;
  62
  63        spin_lock_init(&whc->lock);
  64        mutex_init(&whc->mutex);
  65        init_waitqueue_head(&whc->cmd_wq);
  66        init_waitqueue_head(&whc->async_list_wq);
  67        init_waitqueue_head(&whc->periodic_list_wq);
  68        whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0);
  69        if (whc->workqueue == NULL) {
  70                ret = -ENOMEM;
  71                goto error;
  72        }
  73        INIT_WORK(&whc->dn_work, whc_dn_work);
  74
  75        INIT_WORK(&whc->async_work, scan_async_work);
  76        INIT_LIST_HEAD(&whc->async_list);
  77        INIT_LIST_HEAD(&whc->async_removed_list);
  78
  79        INIT_WORK(&whc->periodic_work, scan_periodic_work);
  80        for (i = 0; i < 5; i++)
  81                INIT_LIST_HEAD(&whc->periodic_list[i]);
  82        INIT_LIST_HEAD(&whc->periodic_removed_list);
  83
  84        /* Map HC registers. */
  85        start = whc->umc->resource.start;
  86        len   = whc->umc->resource.end - start + 1;
  87        if (!request_mem_region(start, len, "whci-hc")) {
  88                dev_err(&whc->umc->dev, "can't request HC region\n");
  89                ret = -EBUSY;
  90                goto error;
  91        }
  92        whc->base_phys = start;
  93        whc->base = ioremap(start, len);
  94        if (!whc->base) {
  95                dev_err(&whc->umc->dev, "ioremap\n");
  96                ret = -ENOMEM;
  97                goto error;
  98        }
  99
 100        whc_hw_reset(whc);
 101
 102        /* Read maximum number of devices, keys and MMC IEs. */
 103        whcsparams = le_readl(whc->base + WHCSPARAMS);
 104        whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams);
 105        whc->n_keys    = WHCSPARAMS_TO_N_KEYS(whcsparams);
 106        whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams);
 107
 108        dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
 109                whc->n_devices, whc->n_keys, whc->n_mmc_ies);
 110
 111        whc->qset_pool = dma_pool_create("qset", &whc->umc->dev,
 112                                         sizeof(struct whc_qset), 64, 0);
 113        if (whc->qset_pool == NULL) {
 114                ret = -ENOMEM;
 115                goto error;
 116        }
 117
 118        ret = asl_init(whc);
 119        if (ret < 0)
 120                goto error;
 121        ret = pzl_init(whc);
 122        if (ret < 0)
 123                goto error;
 124
 125        /* Allocate and initialize a buffer for generic commands, the
 126           Device Information buffer, and the Device Notification
 127           buffer. */
 128
 129        whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
 130                                              &whc->gen_cmd_buf_dma, GFP_KERNEL);
 131        if (whc->gen_cmd_buf == NULL) {
 132                ret = -ENOMEM;
 133                goto error;
 134        }
 135
 136        whc->dn_buf = dma_alloc_coherent(&whc->umc->dev,
 137                                         sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
 138                                         &whc->dn_buf_dma, GFP_KERNEL);
 139        if (!whc->dn_buf) {
 140                ret = -ENOMEM;
 141                goto error;
 142        }
 143        whc_hw_init_dn_buf(whc);
 144
 145        whc->di_buf = dma_alloc_coherent(&whc->umc->dev,
 146                                         sizeof(struct di_buf_entry) * whc->n_devices,
 147                                         &whc->di_buf_dma, GFP_KERNEL);
 148        if (!whc->di_buf) {
 149                ret = -ENOMEM;
 150                goto error;
 151        }
 152        whc_hw_init_di_buf(whc);
 153
 154        return 0;
 155
 156error:
 157        whc_clean_up(whc);
 158        return ret;
 159}
 160
 161void whc_clean_up(struct whc *whc)
 162{
 163        resource_size_t len;
 164
 165        if (whc->di_buf)
 166                dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices,
 167                                  whc->di_buf, whc->di_buf_dma);
 168        if (whc->dn_buf)
 169                dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
 170                                  whc->dn_buf, whc->dn_buf_dma);
 171        if (whc->gen_cmd_buf)
 172                dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
 173                                  whc->gen_cmd_buf, whc->gen_cmd_buf_dma);
 174
 175        pzl_clean_up(whc);
 176        asl_clean_up(whc);
 177
 178        dma_pool_destroy(whc->qset_pool);
 179
 180        len   = resource_size(&whc->umc->resource);
 181        if (whc->base)
 182                iounmap(whc->base);
 183        if (whc->base_phys)
 184                release_mem_region(whc->base_phys, len);
 185
 186        if (whc->workqueue)
 187                destroy_workqueue(whc->workqueue);
 188}
 189