linux/drivers/net/wireless/ti/wlcore/io.c
<<
>>
Prefs
   1/*
   2 * This file is part of wl1271
   3 *
   4 * Copyright (C) 2008-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/module.h>
  25#include <linux/platform_device.h>
  26#include <linux/spi/spi.h>
  27#include <linux/interrupt.h>
  28
  29#include "wlcore.h"
  30#include "debug.h"
  31#include "wl12xx_80211.h"
  32#include "io.h"
  33#include "tx.h"
  34
  35bool wl1271_set_block_size(struct wl1271 *wl)
  36{
  37        if (wl->if_ops->set_block_size) {
  38                wl->if_ops->set_block_size(wl->dev, WL12XX_BUS_BLOCK_SIZE);
  39                return true;
  40        }
  41
  42        return false;
  43}
  44
  45void wlcore_disable_interrupts(struct wl1271 *wl)
  46{
  47        disable_irq(wl->irq);
  48}
  49EXPORT_SYMBOL_GPL(wlcore_disable_interrupts);
  50
  51void wlcore_disable_interrupts_nosync(struct wl1271 *wl)
  52{
  53        disable_irq_nosync(wl->irq);
  54}
  55EXPORT_SYMBOL_GPL(wlcore_disable_interrupts_nosync);
  56
  57void wlcore_enable_interrupts(struct wl1271 *wl)
  58{
  59        enable_irq(wl->irq);
  60}
  61EXPORT_SYMBOL_GPL(wlcore_enable_interrupts);
  62
  63void wlcore_synchronize_interrupts(struct wl1271 *wl)
  64{
  65        synchronize_irq(wl->irq);
  66}
  67EXPORT_SYMBOL_GPL(wlcore_synchronize_interrupts);
  68
  69int wlcore_translate_addr(struct wl1271 *wl, int addr)
  70{
  71        struct wlcore_partition_set *part = &wl->curr_part;
  72
  73        /*
  74         * To translate, first check to which window of addresses the
  75         * particular address belongs. Then subtract the starting address
  76         * of that window from the address. Then, add offset of the
  77         * translated region.
  78         *
  79         * The translated regions occur next to each other in physical device
  80         * memory, so just add the sizes of the preceding address regions to
  81         * get the offset to the new region.
  82         */
  83        if ((addr >= part->mem.start) &&
  84            (addr < part->mem.start + part->mem.size))
  85                return addr - part->mem.start;
  86        else if ((addr >= part->reg.start) &&
  87                 (addr < part->reg.start + part->reg.size))
  88                return addr - part->reg.start + part->mem.size;
  89        else if ((addr >= part->mem2.start) &&
  90                 (addr < part->mem2.start + part->mem2.size))
  91                return addr - part->mem2.start + part->mem.size +
  92                        part->reg.size;
  93        else if ((addr >= part->mem3.start) &&
  94                 (addr < part->mem3.start + part->mem3.size))
  95                return addr - part->mem3.start + part->mem.size +
  96                        part->reg.size + part->mem2.size;
  97
  98        WARN(1, "HW address 0x%x out of range", addr);
  99        return 0;
 100}
 101EXPORT_SYMBOL_GPL(wlcore_translate_addr);
 102
 103/* Set the partitions to access the chip addresses
 104 *
 105 * To simplify driver code, a fixed (virtual) memory map is defined for
 106 * register and memory addresses. Because in the chipset, in different stages
 107 * of operation, those addresses will move around, an address translation
 108 * mechanism is required.
 109 *
 110 * There are four partitions (three memory and one register partition),
 111 * which are mapped to two different areas of the hardware memory.
 112 *
 113 *                                Virtual address
 114 *                                     space
 115 *
 116 *                                    |    |
 117 *                                 ...+----+--> mem.start
 118 *          Physical address    ...   |    |
 119 *               space       ...      |    | [PART_0]
 120 *                        ...         |    |
 121 *  00000000  <--+----+...         ...+----+--> mem.start + mem.size
 122 *               |    |         ...   |    |
 123 *               |MEM |      ...      |    |
 124 *               |    |   ...         |    |
 125 *  mem.size  <--+----+...            |    | {unused area)
 126 *               |    |   ...         |    |
 127 *               |REG |      ...      |    |
 128 *  mem.size     |    |         ...   |    |
 129 *      +     <--+----+...         ...+----+--> reg.start
 130 *  reg.size     |    |   ...         |    |
 131 *               |MEM2|      ...      |    | [PART_1]
 132 *               |    |         ...   |    |
 133 *                                 ...+----+--> reg.start + reg.size
 134 *                                    |    |
 135 *
 136 */
 137int wlcore_set_partition(struct wl1271 *wl,
 138                         const struct wlcore_partition_set *p)
 139{
 140        int ret;
 141
 142        /* copy partition info */
 143        memcpy(&wl->curr_part, p, sizeof(*p));
 144
 145        wl1271_debug(DEBUG_IO, "mem_start %08X mem_size %08X",
 146                     p->mem.start, p->mem.size);
 147        wl1271_debug(DEBUG_IO, "reg_start %08X reg_size %08X",
 148                     p->reg.start, p->reg.size);
 149        wl1271_debug(DEBUG_IO, "mem2_start %08X mem2_size %08X",
 150                     p->mem2.start, p->mem2.size);
 151        wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X",
 152                     p->mem3.start, p->mem3.size);
 153
 154        ret = wlcore_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
 155        if (ret < 0)
 156                goto out;
 157
 158        ret = wlcore_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
 159        if (ret < 0)
 160                goto out;
 161
 162        ret = wlcore_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
 163        if (ret < 0)
 164                goto out;
 165
 166        ret = wlcore_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
 167        if (ret < 0)
 168                goto out;
 169
 170        ret = wlcore_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
 171        if (ret < 0)
 172                goto out;
 173
 174        ret = wlcore_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
 175        if (ret < 0)
 176                goto out;
 177
 178        /* We don't need the size of the last partition, as it is
 179         * automatically calculated based on the total memory size and
 180         * the sizes of the previous partitions.
 181         */
 182        ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
 183        if (ret < 0)
 184                goto out;
 185
 186out:
 187        return ret;
 188}
 189EXPORT_SYMBOL_GPL(wlcore_set_partition);
 190
 191void wl1271_io_reset(struct wl1271 *wl)
 192{
 193        if (wl->if_ops->reset)
 194                wl->if_ops->reset(wl->dev);
 195}
 196
 197void wl1271_io_init(struct wl1271 *wl)
 198{
 199        if (wl->if_ops->init)
 200                wl->if_ops->init(wl->dev);
 201}
 202