| 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> | 
|  | 27 |  | 
| Shahar Levi | 00d2010 | 2010-11-08 11:20:10 +0000 | [diff] [blame] | 28 | #include "wl12xx.h" | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 29 | #include "wl12xx_80211.h" | 
| Shahar Levi | 00d2010 | 2010-11-08 11:20:10 +0000 | [diff] [blame] | 30 | #include "io.h" | 
| Ido Yariv | 0da13da | 2011-03-31 10:06:58 +0200 | [diff] [blame] | 31 | #include "tx.h" | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 32 |  | 
| Teemu Paasikivi | 760d969 | 2010-02-22 08:38:25 +0200 | [diff] [blame] | 33 | #define OCP_CMD_LOOP  32 | 
|  | 34 |  | 
|  | 35 | #define OCP_CMD_WRITE 0x1 | 
|  | 36 | #define OCP_CMD_READ  0x2 | 
|  | 37 |  | 
|  | 38 | #define OCP_READY_MASK  BIT(18) | 
|  | 39 | #define OCP_STATUS_MASK (BIT(16) | BIT(17)) | 
|  | 40 |  | 
|  | 41 | #define OCP_STATUS_NO_RESP    0x00000 | 
|  | 42 | #define OCP_STATUS_OK         0x10000 | 
|  | 43 | #define OCP_STATUS_REQ_FAILED 0x20000 | 
|  | 44 | #define OCP_STATUS_RESP_ERROR 0x30000 | 
|  | 45 |  | 
| Shahar Levi | 48a6147 | 2011-03-06 16:32:08 +0200 | [diff] [blame] | 46 | bool wl1271_set_block_size(struct wl1271 *wl) | 
|  | 47 | { | 
|  | 48 | if (wl->if_ops->set_block_size) { | 
| Ido Yariv | 0da13da | 2011-03-31 10:06:58 +0200 | [diff] [blame] | 49 | wl->if_ops->set_block_size(wl, WL12XX_BUS_BLOCK_SIZE); | 
| Shahar Levi | 48a6147 | 2011-03-06 16:32:08 +0200 | [diff] [blame] | 50 | return true; | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | return false; | 
|  | 54 | } | 
|  | 55 |  | 
| Teemu Paasikivi | 54f7e50 | 2010-02-22 08:38:22 +0200 | [diff] [blame] | 56 | void wl1271_disable_interrupts(struct wl1271 *wl) | 
|  | 57 | { | 
| Teemu Paasikivi | 8197b71 | 2010-02-22 08:38:23 +0200 | [diff] [blame] | 58 | wl->if_ops->disable_irq(wl); | 
| Teemu Paasikivi | 54f7e50 | 2010-02-22 08:38:22 +0200 | [diff] [blame] | 59 | } | 
|  | 60 |  | 
|  | 61 | void wl1271_enable_interrupts(struct wl1271 *wl) | 
|  | 62 | { | 
| Teemu Paasikivi | 8197b71 | 2010-02-22 08:38:23 +0200 | [diff] [blame] | 63 | wl->if_ops->enable_irq(wl); | 
| Teemu Paasikivi | 54f7e50 | 2010-02-22 08:38:22 +0200 | [diff] [blame] | 64 | } | 
|  | 65 |  | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 66 | /* Set the SPI partitions to access the chip addresses | 
|  | 67 | * | 
|  | 68 | * To simplify driver code, a fixed (virtual) memory map is defined for | 
|  | 69 | * register and memory addresses. Because in the chipset, in different stages | 
|  | 70 | * of operation, those addresses will move around, an address translation | 
|  | 71 | * mechanism is required. | 
|  | 72 | * | 
|  | 73 | * There are four partitions (three memory and one register partition), | 
|  | 74 | * which are mapped to two different areas of the hardware memory. | 
|  | 75 | * | 
|  | 76 | *                                Virtual address | 
|  | 77 | *                                     space | 
|  | 78 | * | 
|  | 79 | *                                    |    | | 
|  | 80 | *                                 ...+----+--> mem.start | 
|  | 81 | *          Physical address    ...   |    | | 
|  | 82 | *               space       ...      |    | [PART_0] | 
|  | 83 | *                        ...         |    | | 
|  | 84 | *  00000000  <--+----+...         ...+----+--> mem.start + mem.size | 
|  | 85 | *               |    |         ...   |    | | 
|  | 86 | *               |MEM |      ...      |    | | 
|  | 87 | *               |    |   ...         |    | | 
|  | 88 | *  mem.size  <--+----+...            |    | {unused area) | 
|  | 89 | *               |    |   ...         |    | | 
|  | 90 | *               |REG |      ...      |    | | 
|  | 91 | *  mem.size     |    |         ...   |    | | 
|  | 92 | *      +     <--+----+...         ...+----+--> reg.start | 
|  | 93 | *  reg.size     |    |   ...         |    | | 
|  | 94 | *               |MEM2|      ...      |    | [PART_1] | 
|  | 95 | *               |    |         ...   |    | | 
|  | 96 | *                                 ...+----+--> reg.start + reg.size | 
|  | 97 | *                                    |    | | 
|  | 98 | * | 
|  | 99 | */ | 
|  | 100 | int wl1271_set_partition(struct wl1271 *wl, | 
|  | 101 | struct wl1271_partition_set *p) | 
|  | 102 | { | 
|  | 103 | /* copy partition info */ | 
|  | 104 | memcpy(&wl->part, p, sizeof(*p)); | 
|  | 105 |  | 
|  | 106 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | 
|  | 107 | p->mem.start, p->mem.size); | 
|  | 108 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | 
|  | 109 | p->reg.start, p->reg.size); | 
|  | 110 | wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X", | 
|  | 111 | p->mem2.start, p->mem2.size); | 
|  | 112 | wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X", | 
|  | 113 | p->mem3.start, p->mem3.size); | 
|  | 114 |  | 
|  | 115 | /* write partition info to the chipset */ | 
|  | 116 | wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); | 
|  | 117 | wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); | 
|  | 118 | wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); | 
|  | 119 | wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); | 
|  | 120 | wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); | 
|  | 121 | wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); | 
|  | 122 | wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); | 
|  | 123 |  | 
|  | 124 | return 0; | 
|  | 125 | } | 
| Roger Quadros | 870c367 | 2010-11-29 16:24:57 +0200 | [diff] [blame] | 126 | EXPORT_SYMBOL_GPL(wl1271_set_partition); | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 127 |  | 
| Teemu Paasikivi | 9b28072 | 2010-02-18 13:25:56 +0200 | [diff] [blame] | 128 | void wl1271_io_reset(struct wl1271 *wl) | 
|  | 129 | { | 
| Felipe Balbi | 77d7d7a | 2011-05-14 00:26:21 +0300 | [diff] [blame] | 130 | if (wl->if_ops->reset) | 
|  | 131 | wl->if_ops->reset(wl); | 
| Teemu Paasikivi | 9b28072 | 2010-02-18 13:25:56 +0200 | [diff] [blame] | 132 | } | 
|  | 133 |  | 
|  | 134 | void wl1271_io_init(struct wl1271 *wl) | 
|  | 135 | { | 
| Felipe Balbi | 77d7d7a | 2011-05-14 00:26:21 +0300 | [diff] [blame] | 136 | if (wl->if_ops->init) | 
|  | 137 | wl->if_ops->init(wl); | 
| Teemu Paasikivi | 9b28072 | 2010-02-18 13:25:56 +0200 | [diff] [blame] | 138 | } | 
|  | 139 |  | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 140 | void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) | 
|  | 141 | { | 
|  | 142 | /* write address >> 1 + 0x30000 to OCP_POR_CTR */ | 
|  | 143 | addr = (addr >> 1) + 0x30000; | 
| Teemu Paasikivi | 7b048c5 | 2010-02-18 13:25:55 +0200 | [diff] [blame] | 144 | wl1271_write32(wl, OCP_POR_CTR, addr); | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 145 |  | 
|  | 146 | /* write value to OCP_POR_WDATA */ | 
| Teemu Paasikivi | 7b048c5 | 2010-02-18 13:25:55 +0200 | [diff] [blame] | 147 | wl1271_write32(wl, OCP_DATA_WRITE, val); | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 148 |  | 
|  | 149 | /* write 1 to OCP_CMD */ | 
| Teemu Paasikivi | 7b048c5 | 2010-02-18 13:25:55 +0200 | [diff] [blame] | 150 | wl1271_write32(wl, OCP_CMD, OCP_CMD_WRITE); | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 151 | } | 
|  | 152 |  | 
|  | 153 | u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) | 
|  | 154 | { | 
|  | 155 | u32 val; | 
|  | 156 | int timeout = OCP_CMD_LOOP; | 
|  | 157 |  | 
|  | 158 | /* write address >> 1 + 0x30000 to OCP_POR_CTR */ | 
|  | 159 | addr = (addr >> 1) + 0x30000; | 
| Teemu Paasikivi | 7b048c5 | 2010-02-18 13:25:55 +0200 | [diff] [blame] | 160 | wl1271_write32(wl, OCP_POR_CTR, addr); | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 161 |  | 
|  | 162 | /* write 2 to OCP_CMD */ | 
| Teemu Paasikivi | 7b048c5 | 2010-02-18 13:25:55 +0200 | [diff] [blame] | 163 | wl1271_write32(wl, OCP_CMD, OCP_CMD_READ); | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 164 |  | 
|  | 165 | /* poll for data ready */ | 
|  | 166 | do { | 
| Teemu Paasikivi | 7b048c5 | 2010-02-18 13:25:55 +0200 | [diff] [blame] | 167 | val = wl1271_read32(wl, OCP_DATA_READ); | 
| Teemu Paasikivi | 521a5b2 | 2010-02-18 13:25:54 +0200 | [diff] [blame] | 168 | } while (!(val & OCP_READY_MASK) && --timeout); | 
|  | 169 |  | 
|  | 170 | if (!timeout) { | 
|  | 171 | wl1271_warning("Top register access timed out."); | 
|  | 172 | return 0xffff; | 
|  | 173 | } | 
|  | 174 |  | 
|  | 175 | /* check data status and return if OK */ | 
|  | 176 | if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) | 
|  | 177 | return val & 0xffff; | 
|  | 178 | else { | 
|  | 179 | wl1271_warning("Top register access returned error."); | 
|  | 180 | return 0xffff; | 
|  | 181 | } | 
|  | 182 | } | 
|  | 183 |  |