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_disable_interrupts_nosync(struct wl1271 *wl) 52 { 53 disable_irq_nosync(wl->irq); 54 } 55 EXPORT_SYMBOL_GPL(wlcore_disable_interrupts_nosync); 56 57 void wlcore_enable_interrupts(struct wl1271 *wl) 58 { 59 enable_irq(wl->irq); 60 } 61 EXPORT_SYMBOL_GPL(wlcore_enable_interrupts); 62 63 void wlcore_synchronize_interrupts(struct wl1271 *wl) 64 { 65 synchronize_irq(wl->irq); 66 } 67 EXPORT_SYMBOL_GPL(wlcore_synchronize_interrupts); 68 69 int 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 } 101 EXPORT_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 */ 137 int 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 186 out: 187 return ret; 188 } 189 EXPORT_SYMBOL_GPL(wlcore_set_partition); 190 191 void wl1271_io_reset(struct wl1271 *wl) 192 { 193 if (wl->if_ops->reset) 194 wl->if_ops->reset(wl->dev); 195 } 196 197 void wl1271_io_init(struct wl1271 *wl) 198 { 199 if (wl->if_ops->init) 200 wl->if_ops->init(wl->dev); 201 } 202