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 35 bool 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 45 void wlcore_disable_interrupts(struct wl1271 *wl) 46 { 47 disable_irq(wl->irq); 48 } 49 EXPORT_SYMBOL_GPL(wlcore_disable_interrupts); 50 51 void wlcore_enable_interrupts(struct wl1271 *wl) 52 { 53 enable_irq(wl->irq); 54 } 55 EXPORT_SYMBOL_GPL(wlcore_enable_interrupts); 56 57 int wlcore_translate_addr(struct wl1271 *wl, int addr) 58 { 59 struct wlcore_partition_set *part = &wl->curr_part; 60 61 /* 62 * To translate, first check to which window of addresses the 63 * particular address belongs. Then subtract the starting address 64 * of that window from the address. Then, add offset of the 65 * translated region. 66 * 67 * The translated regions occur next to each other in physical device 68 * memory, so just add the sizes of the preceding address regions to 69 * get the offset to the new region. 70 */ 71 if ((addr >= part->mem.start) && 72 (addr < part->mem.start + part->mem.size)) 73 return addr - part->mem.start; 74 else if ((addr >= part->reg.start) && 75 (addr < part->reg.start + part->reg.size)) 76 return addr - part->reg.start + part->mem.size; 77 else if ((addr >= part->mem2.start) && 78 (addr < part->mem2.start + part->mem2.size)) 79 return addr - part->mem2.start + part->mem.size + 80 part->reg.size; 81 else if ((addr >= part->mem3.start) && 82 (addr < part->mem3.start + part->mem3.size)) 83 return addr - part->mem3.start + part->mem.size + 84 part->reg.size + part->mem2.size; 85 86 WARN(1, "HW address 0x%x out of range", addr); 87 return 0; 88 } 89 EXPORT_SYMBOL_GPL(wlcore_translate_addr); 90 91 /* Set the partitions to access the chip addresses 92 * 93 * To simplify driver code, a fixed (virtual) memory map is defined for 94 * register and memory addresses. Because in the chipset, in different stages 95 * of operation, those addresses will move around, an address translation 96 * mechanism is required. 97 * 98 * There are four partitions (three memory and one register partition), 99 * which are mapped to two different areas of the hardware memory. 100 * 101 * Virtual address 102 * space 103 * 104 * | | 105 * ...+----+--> mem.start 106 * Physical address ... | | 107 * space ... | | [PART_0] 108 * ... | | 109 * 00000000 <--+----+... ...+----+--> mem.start + mem.size 110 * | | ... | | 111 * |MEM | ... | | 112 * | | ... | | 113 * mem.size <--+----+... | | {unused area) 114 * | | ... | | 115 * |REG | ... | | 116 * mem.size | | ... | | 117 * + <--+----+... ...+----+--> reg.start 118 * reg.size | | ... | | 119 * |MEM2| ... | | [PART_1] 120 * | | ... | | 121 * ...+----+--> reg.start + reg.size 122 * | | 123 * 124 */ 125 void wlcore_set_partition(struct wl1271 *wl, 126 const struct wlcore_partition_set *p) 127 { 128 /* copy partition info */ 129 memcpy(&wl->curr_part, p, sizeof(*p)); 130 131 wl1271_debug(DEBUG_IO, "mem_start %08X mem_size %08X", 132 p->mem.start, p->mem.size); 133 wl1271_debug(DEBUG_IO, "reg_start %08X reg_size %08X", 134 p->reg.start, p->reg.size); 135 wl1271_debug(DEBUG_IO, "mem2_start %08X mem2_size %08X", 136 p->mem2.start, p->mem2.size); 137 wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X", 138 p->mem3.start, p->mem3.size); 139 140 wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); 141 wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); 142 wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); 143 wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); 144 wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); 145 wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); 146 /* 147 * We don't need the size of the last partition, as it is 148 * automatically calculated based on the total memory size and 149 * the sizes of the previous partitions. 150 */ 151 wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); 152 } 153 EXPORT_SYMBOL_GPL(wlcore_set_partition); 154 155 void wlcore_select_partition(struct wl1271 *wl, u8 part) 156 { 157 wl1271_debug(DEBUG_IO, "setting partition %d", part); 158 159 wlcore_set_partition(wl, &wl->ptable[part]); 160 } 161 EXPORT_SYMBOL_GPL(wlcore_select_partition); 162 163 void wl1271_io_reset(struct wl1271 *wl) 164 { 165 if (wl->if_ops->reset) 166 wl->if_ops->reset(wl->dev); 167 } 168 169 void wl1271_io_init(struct wl1271 *wl) 170 { 171 if (wl->if_ops->init) 172 wl->if_ops->init(wl->dev); 173 } 174