Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 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> |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 26 | #include <linux/spi/spi.h> |
Felipe Balbi | a390e85 | 2011-10-06 10:07:44 +0300 | [diff] [blame] | 27 | #include <linux/interrupt.h> |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 28 | |
Luciano Coelho | c31be25a7 | 2011-11-21 19:25:24 +0200 | [diff] [blame] | 29 | #include "wlcore.h" |
Luciano Coelho | 0f4e312 | 2011-10-07 11:02:42 +0300 | [diff] [blame] | 30 | #include "debug.h" |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 31 | #include "wl12xx_80211.h" |
Shahar Levi | 00d2010 | 2010-11-08 11:20:10 +0000 | [diff] [blame] | 32 | #include "io.h" |
Ido Yariv | 0da13da7 | 2011-03-31 10:06:58 +0200 | [diff] [blame] | 33 | #include "tx.h" |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 34 | |
Shahar Levi | 48a6147 | 2011-03-06 16:32:08 +0200 | [diff] [blame] | 35 | bool wl1271_set_block_size(struct wl1271 *wl) |
| 36 | { |
| 37 | if (wl->if_ops->set_block_size) { |
Felipe Balbi | a390e85 | 2011-10-06 10:07:44 +0300 | [diff] [blame] | 38 | wl->if_ops->set_block_size(wl->dev, WL12XX_BUS_BLOCK_SIZE); |
Shahar Levi | 48a6147 | 2011-03-06 16:32:08 +0200 | [diff] [blame] | 39 | return true; |
| 40 | } |
| 41 | |
| 42 | return false; |
| 43 | } |
| 44 | |
Luciano Coelho | dd5512eb | 2012-04-11 11:03:14 +0300 | [diff] [blame] | 45 | void wlcore_disable_interrupts(struct wl1271 *wl) |
Teemu Paasikivi | 54f7e50 | 2010-02-22 08:38:22 +0200 | [diff] [blame] | 46 | { |
Felipe Balbi | a390e85 | 2011-10-06 10:07:44 +0300 | [diff] [blame] | 47 | disable_irq(wl->irq); |
Teemu Paasikivi | 54f7e50 | 2010-02-22 08:38:22 +0200 | [diff] [blame] | 48 | } |
Luciano Coelho | dd5512eb | 2012-04-11 11:03:14 +0300 | [diff] [blame] | 49 | EXPORT_SYMBOL_GPL(wlcore_disable_interrupts); |
Teemu Paasikivi | 54f7e50 | 2010-02-22 08:38:22 +0200 | [diff] [blame] | 50 | |
Ido Yariv | b666bb7 | 2012-05-21 01:10:11 +0300 | [diff] [blame] | 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 | |
Luciano Coelho | dd5512eb | 2012-04-11 11:03:14 +0300 | [diff] [blame] | 57 | void wlcore_enable_interrupts(struct wl1271 *wl) |
Teemu Paasikivi | 54f7e50 | 2010-02-22 08:38:22 +0200 | [diff] [blame] | 58 | { |
Felipe Balbi | a390e85 | 2011-10-06 10:07:44 +0300 | [diff] [blame] | 59 | enable_irq(wl->irq); |
Teemu Paasikivi | 54f7e50 | 2010-02-22 08:38:22 +0200 | [diff] [blame] | 60 | } |
Luciano Coelho | dd5512eb | 2012-04-11 11:03:14 +0300 | [diff] [blame] | 61 | EXPORT_SYMBOL_GPL(wlcore_enable_interrupts); |
Teemu Paasikivi | 54f7e50 | 2010-02-22 08:38:22 +0200 | [diff] [blame] | 62 | |
Ido Yariv | c24ec83 | 2012-06-26 21:08:58 +0300 | [diff] [blame] | 63 | void wlcore_synchronize_interrupts(struct wl1271 *wl) |
| 64 | { |
| 65 | synchronize_irq(wl->irq); |
| 66 | } |
| 67 | EXPORT_SYMBOL_GPL(wlcore_synchronize_interrupts); |
| 68 | |
Luciano Coelho | 25a43d7 | 2011-11-21 20:37:14 +0200 | [diff] [blame] | 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 |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 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 | */ |
Ido Yariv | b0f0ad39 | 2012-06-20 00:48:23 +0300 | [diff] [blame] | 137 | int wlcore_set_partition(struct wl1271 *wl, |
| 138 | const struct wlcore_partition_set *p) |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 139 | { |
Ido Yariv | b0f0ad39 | 2012-06-20 00:48:23 +0300 | [diff] [blame] | 140 | int ret; |
| 141 | |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 142 | /* copy partition info */ |
Luciano Coelho | 25a43d7 | 2011-11-21 20:37:14 +0200 | [diff] [blame] | 143 | memcpy(&wl->curr_part, p, sizeof(*p)); |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 144 | |
Luciano Coelho | 25a43d7 | 2011-11-21 20:37:14 +0200 | [diff] [blame] | 145 | wl1271_debug(DEBUG_IO, "mem_start %08X mem_size %08X", |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 146 | p->mem.start, p->mem.size); |
Luciano Coelho | 25a43d7 | 2011-11-21 20:37:14 +0200 | [diff] [blame] | 147 | wl1271_debug(DEBUG_IO, "reg_start %08X reg_size %08X", |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 148 | p->reg.start, p->reg.size); |
Luciano Coelho | 25a43d7 | 2011-11-21 20:37:14 +0200 | [diff] [blame] | 149 | wl1271_debug(DEBUG_IO, "mem2_start %08X mem2_size %08X", |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 150 | p->mem2.start, p->mem2.size); |
Luciano Coelho | 25a43d7 | 2011-11-21 20:37:14 +0200 | [diff] [blame] | 151 | wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X", |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 152 | p->mem3.start, p->mem3.size); |
| 153 | |
Ido Yariv | b0f0ad39 | 2012-06-20 00:48:23 +0300 | [diff] [blame] | 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 | |
Emil Goode | fb724ed | 2016-02-10 02:22:16 +0100 | [diff] [blame] | 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 | */ |
Ido Yariv | b0f0ad39 | 2012-06-20 00:48:23 +0300 | [diff] [blame] | 182 | ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); |
Shahar Patury | 3719c17 | 2015-12-22 14:30:06 +0200 | [diff] [blame] | 183 | if (ret < 0) |
| 184 | goto out; |
| 185 | |
Ido Yariv | b0f0ad39 | 2012-06-20 00:48:23 +0300 | [diff] [blame] | 186 | out: |
| 187 | return ret; |
Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 188 | } |
Luciano Coelho | 25a43d7 | 2011-11-21 20:37:14 +0200 | [diff] [blame] | 189 | EXPORT_SYMBOL_GPL(wlcore_set_partition); |
| 190 | |
Teemu Paasikivi | 9b28072 | 2010-02-18 13:25:56 +0200 | [diff] [blame] | 191 | void wl1271_io_reset(struct wl1271 *wl) |
| 192 | { |
Felipe Balbi | 77d7d7a | 2011-05-14 00:26:21 +0300 | [diff] [blame] | 193 | if (wl->if_ops->reset) |
Felipe Balbi | a390e85 | 2011-10-06 10:07:44 +0300 | [diff] [blame] | 194 | wl->if_ops->reset(wl->dev); |
Teemu Paasikivi | 9b28072 | 2010-02-18 13:25:56 +0200 | [diff] [blame] | 195 | } |
| 196 | |
| 197 | void wl1271_io_init(struct wl1271 *wl) |
| 198 | { |
Felipe Balbi | 77d7d7a | 2011-05-14 00:26:21 +0300 | [diff] [blame] | 199 | if (wl->if_ops->init) |
Felipe Balbi | a390e85 | 2011-10-06 10:07:44 +0300 | [diff] [blame] | 200 | wl->if_ops->init(wl->dev); |
Teemu Paasikivi | 9b28072 | 2010-02-18 13:25:56 +0200 | [diff] [blame] | 201 | } |