Here's v2 of the SDIO interface for wl12xx, still with a FIXME or two.
For my part, this is mainly a port of the Google/TI Android SDIO
interface logic to the existing SPI driver. I have confirmed that
the driver associates and sends some traffic.
Pierre, hoping to get your perspective on the SDIO bits in patch 7,
since I very likely don't know what I'm doing :) Especially regarding
the platform code setup, in which the correct GPIOs have to be written
to turn on the device before probe will work. For the SPI interface,
we use spi_register_board_info() for a similar purpose, but I'm not
sure if there is a standard way to do that for SDIO. This copies
Google's platform driver for now.
Conversion to readl/writel etc where appropriate is TODO.
Bob Copeland (7):
wl12xx: separate bus i/o code into io.c
wl12xx: use wiphy_dev instead of wl->spi->dev
wl12xx: introduce wl12xx_if_operations struct
wl12xx: make wl12xx_set_partition bus agnostic
wl12xx: move module probe methods into spi.c
wl12xx: split spi interface into separate module
wl12xx: add sdio support
drivers/net/wireless/wl12xx/Kconfig | 24 +++-
drivers/net/wireless/wl12xx/Makefile | 10 +-
drivers/net/wireless/wl12xx/acx.c | 3 +-
drivers/net/wireless/wl12xx/boot.c | 3 +-
drivers/net/wireless/wl12xx/cmd.c | 15 +-
drivers/net/wireless/wl12xx/event.c | 6 +-
drivers/net/wireless/wl12xx/io.c | 181 +++++++++++++++++++++
drivers/net/wireless/wl12xx/io.h | 62 +++++++
drivers/net/wireless/wl12xx/main.c | 152 ++++--------------
drivers/net/wireless/wl12xx/ps.c | 3 +-
drivers/net/wireless/wl12xx/rx.c | 10 +-
drivers/net/wireless/wl12xx/sdio.c | 250 +++++++++++++++++++++++++++++
drivers/net/wireless/wl12xx/spi.c | 289 ++++++++++++++-------------------
drivers/net/wireless/wl12xx/spi.h | 40 -----
drivers/net/wireless/wl12xx/tx.c | 64 ++++----
drivers/net/wireless/wl12xx/wl1251.c | 9 +-
drivers/net/wireless/wl12xx/wl12xx.h | 14 ++-
17 files changed, 752 insertions(+), 383 deletions(-)
create mode 100644 drivers/net/wireless/wl12xx/io.c
create mode 100644 drivers/net/wireless/wl12xx/io.h
create mode 100644 drivers/net/wireless/wl12xx/sdio.c
The same partition setting code can be used for both SPI and SDIO
modes, if we remove the spi-specific commands and use the more
generic buffer write routines. Do that and move it to io.c
since it deals with register/memory address offsets.
Signed-off-by: Bob Copeland <[email protected]>
---
drivers/net/wireless/wl12xx/io.c | 95 ++++++++++++++++++++++++++++++
drivers/net/wireless/wl12xx/io.h | 15 +++++-
drivers/net/wireless/wl12xx/spi.c | 117 -------------------------------------
drivers/net/wireless/wl12xx/spi.h | 11 ----
4 files changed, 109 insertions(+), 129 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c
index 611b644..b4178d8 100644
--- a/drivers/net/wireless/wl12xx/io.c
+++ b/drivers/net/wireless/wl12xx/io.c
@@ -84,3 +84,98 @@ void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val)
{
wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val);
}
+
+/* Set the partitions to access the chip addresses.
+ *
+ * There are two VIRTUAL partitions (the memory partition and the
+ * registers partition), which are mapped to two different areas of the
+ * PHYSICAL (hardware) memory. This function also makes other checks to
+ * ensure that the partitions are not overlapping. In the diagram below, the
+ * memory partition comes before the register partition, but the opposite is
+ * also supported.
+ *
+ * PHYSICAL address
+ * space
+ *
+ * | |
+ * ...+----+--> mem_start
+ * VIRTUAL address ... | |
+ * space ... | | [PART_0]
+ * ... | |
+ * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size
+ * | | ... | |
+ * |MEM | ... | |
+ * | | ... | |
+ * part_size <--+----+... | | {unused area)
+ * | | ... | |
+ * |REG | ... | |
+ * part_size | | ... | |
+ * + <--+----+... ...+----+--> reg_start
+ * reg_size ... | |
+ * ... | | [PART_1]
+ * ... | |
+ * ...+----+--> reg_start + reg_size
+ * | |
+ *
+ */
+void wl12xx_set_partition(struct wl12xx *wl,
+ u32 mem_start, u32 mem_size,
+ u32 reg_start, u32 reg_size)
+{
+ struct wl12xx_partition partition[2];
+
+ wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ mem_start, mem_size);
+ wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ reg_start, reg_size);
+
+ /* Make sure that the two partitions together don't exceed the
+ * address range */
+ if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) {
+ wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
+ " address range. Truncating partition[0].");
+ mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size;
+ wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ mem_start, mem_size);
+ wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ reg_start, reg_size);
+ }
+
+ if ((mem_start < reg_start) &&
+ ((mem_start + mem_size) > reg_start)) {
+ /* Guarantee that the memory partition doesn't overlap the
+ * registers partition */
+ wl12xx_debug(DEBUG_SPI, "End of partition[0] is "
+ "overlapping partition[1]. Adjusted.");
+ mem_size = reg_start - mem_start;
+ wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ mem_start, mem_size);
+ wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ reg_start, reg_size);
+ } else if ((reg_start < mem_start) &&
+ ((reg_start + reg_size) > mem_start)) {
+ /* Guarantee that the register partition doesn't overlap the
+ * memory partition */
+ wl12xx_debug(DEBUG_SPI, "End of partition[1] is"
+ " overlapping partition[0]. Adjusted.");
+ reg_size = mem_start - reg_start;
+ wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ mem_start, mem_size);
+ wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ reg_start, reg_size);
+ }
+
+ partition[0].start = mem_start;
+ partition[0].size = mem_size;
+ partition[1].start = reg_start;
+ partition[1].size = reg_size;
+
+ wl->physical_mem_addr = mem_start;
+ wl->physical_reg_addr = reg_start;
+
+ wl->virtual_mem_addr = 0;
+ wl->virtual_reg_addr = mem_size;
+
+ wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition,
+ sizeof(partition));
+}
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
index ecc18b6..b1ea67a 100644
--- a/drivers/net/wireless/wl12xx/io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -23,6 +23,17 @@
#include "wl12xx.h"
+#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
+
+#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0
+#define HW_ACCESS_PART0_START_ADDR 0x1FFC4
+#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8
+#define HW_ACCESS_PART1_START_ADDR 0x1FFCC
+
+#define HW_ACCESS_REGISTER_SIZE 4
+
+#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
+
static inline u32 wl12xx_read32(struct wl12xx *wl, int addr)
{
u32 response;
@@ -45,5 +56,7 @@ void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val);
/* Registers IO */
u32 wl12xx_reg_read32(struct wl12xx *wl, int addr);
void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val);
-
+void wl12xx_set_partition(struct wl12xx *wl,
+ u32 part_start, u32 part_size,
+ u32 reg_start, u32 reg_size);
#endif
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index 085755d..658464e 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -117,123 +117,6 @@ static void wl12xx_spi_reset_wake(struct wl12xx *wl)
wl12xx_spi_init(wl);
}
-/* Set the SPI partitions to access the chip addresses
- *
- * There are two VIRTUAL (SPI) partitions (the memory partition and the
- * registers partition), which are mapped to two different areas of the
- * PHYSICAL (hardware) memory. This function also makes other checks to
- * ensure that the partitions are not overlapping. In the diagram below, the
- * memory partition comes before the register partition, but the opposite is
- * also supported.
- *
- * PHYSICAL address
- * space
- *
- * | |
- * ...+----+--> mem_start
- * VIRTUAL address ... | |
- * space ... | | [PART_0]
- * ... | |
- * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size
- * | | ... | |
- * |MEM | ... | |
- * | | ... | |
- * part_size <--+----+... | | {unused area)
- * | | ... | |
- * |REG | ... | |
- * part_size | | ... | |
- * + <--+----+... ...+----+--> reg_start
- * reg_size ... | |
- * ... | | [PART_1]
- * ... | |
- * ...+----+--> reg_start + reg_size
- * | |
- *
- */
-void wl12xx_set_partition(struct wl12xx *wl,
- u32 mem_start, u32 mem_size,
- u32 reg_start, u32 reg_size)
-{
- u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)];
- struct wl12xx_partition *partition;
- struct spi_transfer t;
- struct spi_message m;
- u32 *cmd;
- size_t len;
- int addr;
-
- spi_message_init(&m);
- memset(&t, 0, sizeof(t));
- memset(tx_buf, 0, sizeof(tx_buf));
-
- cmd = (u32 *) tx_buf;
- partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32));
- addr = HW_ACCESS_PART0_SIZE_ADDR;
- len = 2 * sizeof(struct wl12xx_partition);
-
- *cmd |= WSPI_CMD_WRITE;
- *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- *cmd |= addr & WSPI_CMD_BYTE_ADDR;
-
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
-
- /* Make sure that the two partitions together don't exceed the
- * address range */
- if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) {
- wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
- " address range. Truncating partition[0].");
- mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
- }
-
- if ((mem_start < reg_start) &&
- ((mem_start + mem_size) > reg_start)) {
- /* Guarantee that the memory partition doesn't overlap the
- * registers partition */
- wl12xx_debug(DEBUG_SPI, "End of partition[0] is "
- "overlapping partition[1]. Adjusted.");
- mem_size = reg_start - mem_start;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
- } else if ((reg_start < mem_start) &&
- ((reg_start + reg_size) > mem_start)) {
- /* Guarantee that the register partition doesn't overlap the
- * memory partition */
- wl12xx_debug(DEBUG_SPI, "End of partition[1] is"
- " overlapping partition[0]. Adjusted.");
- reg_size = mem_start - reg_start;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
- }
-
- partition[0].start = mem_start;
- partition[0].size = mem_size;
- partition[1].start = reg_start;
- partition[1].size = reg_size;
-
- wl->physical_mem_addr = mem_start;
- wl->physical_reg_addr = reg_start;
-
- wl->virtual_mem_addr = 0;
- wl->virtual_reg_addr = mem_size;
-
- t.tx_buf = tx_buf;
- t.len = sizeof(tx_buf);
- spi_message_add_tail(&t, &m);
-
- spi_sync(wl->spi, &m);
-}
-
static void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
size_t len)
{
diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h
index 761401b..1cbedcf 100644
--- a/drivers/net/wireless/wl12xx/spi.h
+++ b/drivers/net/wireless/wl12xx/spi.h
@@ -29,17 +29,6 @@
#include "acx.h"
#include "reg.h"
-#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
-
-#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0
-#define HW_ACCESS_PART0_START_ADDR 0x1FFC4
-#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8
-#define HW_ACCESS_PART1_START_ADDR 0x1FFCC
-
-#define HW_ACCESS_REGISTER_SIZE 4
-
-#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
-
#define WSPI_CMD_READ 0x40000000
#define WSPI_CMD_WRITE 0x00000000
#define WSPI_CMD_FIXED 0x20000000
--
1.6.0.6
On Thu, Jun 11, 2009 at 4:59 PM, Florian Fainelli<[email protected]> wrote:
> Le Thursday 11 June 2009 16:55:20 Samuel Ortiz, vous avez ?crit?:
>> On Thu, 2009-06-11 at 16:38 +0200, G?bor Stefanik wrote:
>> > On Thu, Jun 11, 2009 at 4:02 AM, Bob Copeland<[email protected]> wrote:
>> > > Here's v2 of the SDIO interface for wl12xx, still with a FIXME or two.
>> > >
>> > > For my part, this is mainly a port of the Google/TI Android SDIO
>> > > interface logic to the existing SPI driver. ?I have confirmed that
>> > > the driver associates and sends some traffic.
>> > >
>> > > Pierre, hoping to get your perspective on the SDIO bits in patch 7,
>> > > since I very likely don't know what I'm doing :) ?Especially regarding
>> > > the platform code setup, in which the correct GPIOs have to be written
>> > > to turn on the device before probe will work. ?For the SPI interface,
>> > > we use spi_register_board_info() for a similar purpose, but I'm not
>> > > sure if there is a standard way to do that for SDIO. ?This copies
>> > > Google's platform driver for now.
>> > >
>> > > Conversion to readl/writel etc where appropriate is TODO.
>> > >
>> > > Bob Copeland (7):
>> > > ?wl12xx: separate bus i/o code into io.c
>> > > ?wl12xx: use wiphy_dev instead of wl->spi->dev
>> > > ?wl12xx: introduce wl12xx_if_operations struct
>> > > ?wl12xx: make wl12xx_set_partition bus agnostic
>> > > ?wl12xx: move module probe methods into spi.c
>> > > ?wl12xx: split spi interface into separate module
>> > > ?wl12xx: add sdio support
>> > >
>> > > ?drivers/net/wireless/wl12xx/Kconfig ?| ? 24 +++-
>> > > ?drivers/net/wireless/wl12xx/Makefile | ? 10 +-
>> > > ?drivers/net/wireless/wl12xx/acx.c ? ?| ? ?3 +-
>> > > ?drivers/net/wireless/wl12xx/boot.c ? | ? ?3 +-
>> > > ?drivers/net/wireless/wl12xx/cmd.c ? ?| ? 15 +-
>> > > ?drivers/net/wireless/wl12xx/event.c ?| ? ?6 +-
>> > > ?drivers/net/wireless/wl12xx/io.c ? ? | ?181 +++++++++++++++++++++
>> > > ?drivers/net/wireless/wl12xx/io.h ? ? | ? 62 +++++++
>> > > ?drivers/net/wireless/wl12xx/main.c ? | ?152 ++++--------------
>> > > ?drivers/net/wireless/wl12xx/ps.c ? ? | ? ?3 +-
>> > > ?drivers/net/wireless/wl12xx/rx.c ? ? | ? 10 +-
>> > > ?drivers/net/wireless/wl12xx/sdio.c ? | ?250
>> > > +++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/spi.c ? ?|
>> > > 289 ++++++++++++++------------------- drivers/net/wireless/wl12xx/spi.h
>> > > ? ?| ? 40 -----
>> > > ?drivers/net/wireless/wl12xx/tx.c ? ? | ? 64 ++++----
>> > > ?drivers/net/wireless/wl12xx/wl1251.c | ? ?9 +-
>> > > ?drivers/net/wireless/wl12xx/wl12xx.h | ? 14 ++-
>> > > ?17 files changed, 752 insertions(+), 383 deletions(-)
>> > > ?create mode 100644 drivers/net/wireless/wl12xx/io.c
>> > > ?create mode 100644 drivers/net/wireless/wl12xx/io.h
>> > > ?create mode 100644 drivers/net/wireless/wl12xx/sdio.c
>> >
>> > Can we expect vlynq any time soon?
>>
>> I guess we need:
>>
>> 1) A linux vlynq driver for that, and last thing I saw [1], it wasnt
>> really pretty/ready
>
> That driver is perfectly functionnal on a TI AR7 and we have used it in
> OpenWrt for months with the acx100/111 driver. What makes you think it is not
> yet ready ? There was a couple of suggestions from a TI employee, which are
> perfectly valid, but I have no hardware to implement what he is suggesting
> (no daisy chaining ...).
Better forget the acx1xx driver. There is legal controversy around it
- the devs never released any documentation during the reverse
engineering process, and development was quite slow until TI's
copyrighted ti_ap.o driver's source code leaked...
>
>> 2) A device that would have a wl12xx chip connected to the host through
>> vlynq.
>>
>> Cheers,
>> Samuel.
>>
>> [1] http://lkml.indiana.edu/hypermail/linux/kernel/0906.0/00155.html
>>
>>
>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-wireless"
>> in the body of a message to [email protected]
>> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
>
>
> --
> Best regards, Florian Fainelli
> Email : [email protected]
> http://openwrt.org
> -------------------------------
>
--
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
Introduce an ops struct with read, write, and reset functions to
abstract away the details of the wl12xx bus interface. Doing this
will allow SDIO to coexist with SPI by supplying its own I/O
routines.
Signed-off-by: Bob Copeland <[email protected]>
---
drivers/net/wireless/wl12xx/io.c | 4 ++--
drivers/net/wireless/wl12xx/io.h | 9 ++-------
drivers/net/wireless/wl12xx/main.c | 6 ++++--
drivers/net/wireless/wl12xx/spi.c | 24 ++++++++++++++++++------
drivers/net/wireless/wl12xx/spi.h | 2 --
drivers/net/wireless/wl12xx/wl12xx.h | 7 +++++++
6 files changed, 33 insertions(+), 19 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c
index 15af799..611b644 100644
--- a/drivers/net/wireless/wl12xx/io.c
+++ b/drivers/net/wireless/wl12xx/io.c
@@ -53,7 +53,7 @@ void wl12xx_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len)
physical = wl12xx_translate_mem_addr(wl, addr);
- wl12xx_spi_read(wl, physical, buf, len);
+ wl->if_ops->read(wl, physical, buf, len);
}
void wl12xx_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len)
@@ -62,7 +62,7 @@ void wl12xx_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len)
physical = wl12xx_translate_mem_addr(wl, addr);
- wl12xx_spi_write(wl, physical, buf, len);
+ wl->if_ops->write(wl, physical, buf, len);
}
u32 wl12xx_mem_read32(struct wl12xx *wl, int addr)
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
index 5f96871..ecc18b6 100644
--- a/drivers/net/wireless/wl12xx/io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -22,24 +22,19 @@
#define __WL12XX_IO_H__
#include "wl12xx.h"
-#include "spi.h"
-
-/* Raw target IO, address is not translated */
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len);
static inline u32 wl12xx_read32(struct wl12xx *wl, int addr)
{
u32 response;
- wl12xx_spi_read(wl, addr, &response, sizeof(u32));
+ wl->if_ops->read(wl, addr, &response, sizeof(u32));
return response;
}
static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val)
{
- wl12xx_spi_write(wl, addr, &val, sizeof(u32));
+ wl->if_ops->write(wl, addr, &val, sizeof(u32));
}
/* Memory target IO, address is translated to partition 0 */
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 5e975c8..eb4b5da 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -171,8 +171,7 @@ static int wl12xx_chip_wakeup(struct wl12xx *wl)
wl12xx_power_on(wl);
msleep(wl->chip.power_on_sleep);
- wl12xx_spi_reset(wl);
- wl12xx_spi_init(wl);
+ wl->if_ops->reset(wl);
/* We don't need a real memory partition here, because we only want
* to use the registers at this point. */
@@ -1173,6 +1172,8 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl)
return 0;
}
+extern struct wl12xx_if_operations wl12xx_spi_ops;
+
#define WL12XX_DEFAULT_CHANNEL 1
static int __devinit wl12xx_probe(struct spi_device *spi)
{
@@ -1200,6 +1201,7 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
wl->hw = hw;
dev_set_drvdata(&spi->dev, wl);
wl->spi = spi;
+ wl->if_ops = &wl12xx_spi_ops;
wl->data_in_count = 0;
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index aabc487..085755d 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -31,7 +31,7 @@
#include "spi.h"
#include "ps.h"
-void wl12xx_spi_reset(struct wl12xx *wl)
+static void wl12xx_spi_reset(struct wl12xx *wl)
{
u8 *cmd;
struct spi_transfer t;
@@ -57,7 +57,7 @@ void wl12xx_spi_reset(struct wl12xx *wl)
wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
}
-void wl12xx_spi_init(struct wl12xx *wl)
+static void wl12xx_spi_init(struct wl12xx *wl)
{
u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
struct spi_transfer t;
@@ -111,6 +111,12 @@ void wl12xx_spi_init(struct wl12xx *wl)
wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
}
+static void wl12xx_spi_reset_wake(struct wl12xx *wl)
+{
+ wl12xx_spi_reset(wl);
+ wl12xx_spi_init(wl);
+}
+
/* Set the SPI partitions to access the chip addresses
*
* There are two VIRTUAL (SPI) partitions (the memory partition and the
@@ -228,8 +234,8 @@ void wl12xx_set_partition(struct wl12xx *wl,
spi_sync(wl->spi, &m);
}
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
- size_t len)
+static void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
+ size_t len)
{
struct spi_transfer t[3];
struct spi_message m;
@@ -265,8 +271,8 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
}
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
- size_t len)
+static void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
+ size_t len)
{
struct spi_transfer t[2];
struct spi_message m;
@@ -293,3 +299,9 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd));
wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
+
+const struct wl12xx_if_operations wl12xx_spi_ops = {
+ .read = wl12xx_spi_read,
+ .write = wl12xx_spi_write,
+ .reset = wl12xx_spi_reset_wake,
+};
diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h
index 7c51475..761401b 100644
--- a/drivers/net/wireless/wl12xx/spi.h
+++ b/drivers/net/wireless/wl12xx/spi.h
@@ -73,8 +73,6 @@
/* INIT and RESET words */
-void wl12xx_spi_reset(struct wl12xx *wl);
-void wl12xx_spi_init(struct wl12xx *wl);
void wl12xx_set_partition(struct wl12xx *wl,
u32 part_start, u32 part_size,
u32 reg_start, u32 reg_size);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 4864143..bfabf8f 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -276,11 +276,18 @@ struct wl12xx_debugfs {
struct dentry *excessive_retries;
};
+struct wl12xx_if_operations {
+ void (*read)(struct wl12xx *wl, int addr, void *buf, size_t len);
+ void (*write)(struct wl12xx *wl, int addr, void *buf, size_t len);
+ void (*reset)(struct wl12xx *wl);
+};
+
struct wl12xx {
struct ieee80211_hw *hw;
bool mac80211_registered;
struct spi_device *spi;
+ struct wl12xx_if_operations *if_ops;
void (*set_power)(bool enable);
int irq;
--
1.6.0.6
In order to eventually support wl12xx spi and sdio interfaces, move
the register and memory transfer functions to a common file. Also
rename wl12xx_spi_mem_{read,write} to indicate its common usage.
We still use spi_read internally until SDIO interface is introduced
so nothing functional should change here.
Signed-off-by: Bob Copeland <[email protected]>
---
drivers/net/wireless/wl12xx/Makefile | 2 +-
drivers/net/wireless/wl12xx/acx.c | 2 +-
drivers/net/wireless/wl12xx/boot.c | 3 +-
drivers/net/wireless/wl12xx/cmd.c | 14 +++---
drivers/net/wireless/wl12xx/event.c | 6 +-
drivers/net/wireless/wl12xx/io.c | 86 ++++++++++++++++++++++++++++++++++
drivers/net/wireless/wl12xx/io.h | 54 +++++++++++++++++++++
drivers/net/wireless/wl12xx/main.c | 3 +-
drivers/net/wireless/wl12xx/ps.c | 3 +-
drivers/net/wireless/wl12xx/rx.c | 10 ++--
drivers/net/wireless/wl12xx/spi.c | 63 -------------------------
drivers/net/wireless/wl12xx/spi.h | 27 -----------
drivers/net/wireless/wl12xx/tx.c | 63 +++++++++++++------------
drivers/net/wireless/wl12xx/wl1251.c | 9 ++--
14 files changed, 201 insertions(+), 144 deletions(-)
create mode 100644 drivers/net/wireless/wl12xx/io.c
create mode 100644 drivers/net/wireless/wl12xx/io.h
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index d43de27..c1281fc 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -1,4 +1,4 @@
wl12xx-objs = main.o spi.o event.o tx.o rx.o \
ps.o cmd.o acx.o boot.o init.o wl1251.o \
- debugfs.o
+ debugfs.o io.o
obj-$(CONFIG_WL12XX) += wl12xx.o
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 1cfd458..9e48de2 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -7,7 +7,7 @@
#include "wl12xx.h"
#include "wl12xx_80211.h"
#include "reg.h"
-#include "spi.h"
+#include "cmd.h"
#include "ps.h"
int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index 48ac08c..1878dc5 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -25,7 +25,8 @@
#include "reg.h"
#include "boot.h"
-#include "spi.h"
+#include "io.h"
+#include "wl12xx.h"
#include "event.h"
static void wl12xx_boot_enable_interrupts(struct wl12xx *wl)
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index f73ab60..56bf6a6 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -7,7 +7,7 @@
#include "wl12xx.h"
#include "wl12xx_80211.h"
#include "reg.h"
-#include "spi.h"
+#include "io.h"
#include "ps.h"
int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len)
@@ -26,7 +26,7 @@ int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len)
wl12xx_ps_elp_wakeup(wl);
- wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len);
+ wl12xx_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len);
wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
@@ -77,7 +77,7 @@ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer)
wl12xx_ps_elp_wakeup(wl);
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
+ wl12xx_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
wl12xx_ps_elp_sleep(wl);
@@ -112,8 +112,8 @@ int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
wl12xx_ps_elp_wakeup(wl);
/* the interrogate command got in, we can read the answer */
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer,
- CMDMBOX_HEADER_LEN + ie_len);
+ wl12xx_mem_read(wl, wl->cmd_box_addr, answer,
+ CMDMBOX_HEADER_LEN + ie_len);
wl12xx_ps_elp_sleep(wl);
@@ -313,8 +313,8 @@ int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer)
}
/* the read command got in, we can now read the answer */
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd,
- CMDMBOX_HEADER_LEN + sizeof(mem_cmd));
+ wl12xx_mem_read(wl, wl->cmd_box_addr, &cmd,
+ CMDMBOX_HEADER_LEN + sizeof(mem_cmd));
if (cmd.status != CMD_STATUS_SUCCESS)
wl12xx_error("error in read command result: %d", cmd.status);
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index 99529ca..0a86a1a 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -24,7 +24,7 @@
#include "wl12xx.h"
#include "reg.h"
-#include "spi.h"
+#include "io.h"
#include "event.h"
#include "ps.h"
@@ -112,8 +112,8 @@ int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num)
return -EINVAL;
/* first we read the mbox descriptor */
- wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
- sizeof(struct event_mailbox));
+ wl12xx_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+ sizeof(struct event_mailbox));
/* process the descriptor */
ret = wl12xx_event_process(wl, &mbox);
diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c
new file mode 100644
index 0000000..15af799
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/io.c
@@ -0,0 +1,86 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "wl12xx.h"
+#include "reg.h"
+#include "io.h"
+
+static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
+{
+ /* If the address is lower than REGISTERS_BASE, it means that this is
+ * a chip-specific register address, so look it up in the registers
+ * table */
+ if (addr < REGISTERS_BASE) {
+ /* Make sure we don't go over the table */
+ if (addr >= ACX_REG_TABLE_LEN) {
+ wl12xx_error("address out of range (%d)", addr);
+ return -EINVAL;
+ }
+ addr = wl->chip.acx_reg_table[addr];
+ }
+
+ return addr - wl->physical_reg_addr + wl->virtual_reg_addr;
+}
+
+static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr)
+{
+ return addr - wl->physical_mem_addr + wl->virtual_mem_addr;
+}
+
+void wl12xx_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len)
+{
+ int physical;
+
+ physical = wl12xx_translate_mem_addr(wl, addr);
+
+ wl12xx_spi_read(wl, physical, buf, len);
+}
+
+void wl12xx_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len)
+{
+ int physical;
+
+ physical = wl12xx_translate_mem_addr(wl, addr);
+
+ wl12xx_spi_write(wl, physical, buf, len);
+}
+
+u32 wl12xx_mem_read32(struct wl12xx *wl, int addr)
+{
+ return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr));
+}
+
+void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val)
+{
+ wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val);
+}
+
+u32 wl12xx_reg_read32(struct wl12xx *wl, int addr)
+{
+ return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr));
+}
+
+void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val)
+{
+ wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val);
+}
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
new file mode 100644
index 0000000..5f96871
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef __WL12XX_IO_H__
+#define __WL12XX_IO_H__
+
+#include "wl12xx.h"
+#include "spi.h"
+
+/* Raw target IO, address is not translated */
+void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len);
+void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len);
+
+static inline u32 wl12xx_read32(struct wl12xx *wl, int addr)
+{
+ u32 response;
+
+ wl12xx_spi_read(wl, addr, &response, sizeof(u32));
+
+ return response;
+}
+
+static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val)
+{
+ wl12xx_spi_write(wl, addr, &val, sizeof(u32));
+}
+
+/* Memory target IO, address is translated to partition 0 */
+void wl12xx_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len);
+void wl12xx_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len);
+u32 wl12xx_mem_read32(struct wl12xx *wl, int addr);
+void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val);
+/* Registers IO */
+u32 wl12xx_reg_read32(struct wl12xx *wl, int addr);
+void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val);
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 603d611..9ecfb9e 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -35,6 +35,7 @@
#include "wl12xx_80211.h"
#include "reg.h"
#include "wl1251.h"
+#include "io.h"
#include "spi.h"
#include "event.h"
#include "tx.h"
@@ -885,7 +886,7 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
if (ret < 0)
wl12xx_error("SCAN failed");
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+ wl12xx_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
cmd_answer = (struct wl12xx_command *) params;
if (cmd_answer->status != CMD_STATUS_SUCCESS) {
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index 83a1011..f2de45b 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -23,7 +23,8 @@
#include "reg.h"
#include "ps.h"
-#include "spi.h"
+#include "cmd.h"
+#include "io.h"
#define WL12XX_WAKEUP_TIMEOUT 2000
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 981ea25..f3a2ede 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -27,8 +27,10 @@
#include "wl12xx.h"
#include "reg.h"
-#include "spi.h"
+#include "io.h"
#include "rx.h"
+#include "cmd.h"
+#include "acx.h"
static void wl12xx_rx_header(struct wl12xx *wl,
struct wl12xx_rx_descriptor *desc)
@@ -39,8 +41,8 @@ static void wl12xx_rx_header(struct wl12xx *wl,
if (wl->rx_current_buffer)
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
- wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc,
- sizeof(struct wl12xx_rx_descriptor));
+ wl12xx_mem_read(wl, rx_packet_ring_addr, desc,
+ sizeof(struct wl12xx_rx_descriptor));
}
static void wl12xx_rx_status(struct wl12xx *wl,
@@ -151,7 +153,7 @@ static void wl12xx_rx_body(struct wl12xx *wl,
}
rx_buffer = skb_put(skb, length);
- wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
+ wl12xx_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
/* The actual lenght doesn't include the target's alignment */
skb->len = desc->length - PLCP_HEADER_LENGTH;
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index abdf171..aabc487 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -31,29 +31,6 @@
#include "spi.h"
#include "ps.h"
-static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
-{
- /* If the address is lower than REGISTERS_BASE, it means that this is
- * a chip-specific register address, so look it up in the registers
- * table */
- if (addr < REGISTERS_BASE) {
- /* Make sure we don't go over the table */
- if (addr >= ACX_REG_TABLE_LEN) {
- wl12xx_error("address out of range (%d)", addr);
- return -EINVAL;
- }
- addr = wl->chip.acx_reg_table[addr];
- }
-
- return addr - wl->physical_reg_addr + wl->virtual_reg_addr;
-}
-
-static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr)
-{
- return addr - wl->physical_mem_addr + wl->virtual_mem_addr;
-}
-
-
void wl12xx_spi_reset(struct wl12xx *wl)
{
u8 *cmd;
@@ -316,43 +293,3 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd));
wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
-
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf,
- size_t len)
-{
- int physical;
-
- physical = wl12xx_translate_mem_addr(wl, addr);
-
- wl12xx_spi_read(wl, physical, buf, len);
-}
-
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf,
- size_t len)
-{
- int physical;
-
- physical = wl12xx_translate_mem_addr(wl, addr);
-
- wl12xx_spi_write(wl, physical, buf, len);
-}
-
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr)
-{
- return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr));
-}
-
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val)
-{
- wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val);
-}
-
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr)
-{
- return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr));
-}
-
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val)
-{
- wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val);
-}
diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h
index fd3227e..7c51475 100644
--- a/drivers/net/wireless/wl12xx/spi.h
+++ b/drivers/net/wireless/wl12xx/spi.h
@@ -71,19 +71,6 @@
#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
-/* Raw target IO, address is not translated */
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len);
-
-/* Memory target IO, address is tranlated to partition 0 */
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len);
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr);
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val);
-
-/* Registers IO */
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr);
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val);
/* INIT and RESET words */
void wl12xx_spi_reset(struct wl12xx *wl);
@@ -92,18 +79,4 @@ void wl12xx_set_partition(struct wl12xx *wl,
u32 part_start, u32 part_size,
u32 reg_start, u32 reg_size);
-static inline u32 wl12xx_read32(struct wl12xx *wl, int addr)
-{
- u32 response;
-
- wl12xx_spi_read(wl, addr, &response, sizeof(u32));
-
- return response;
-}
-
-static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val)
-{
- wl12xx_spi_write(wl, addr, &val, sizeof(u32));
-}
-
#endif /* __WL12XX_SPI_H__ */
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 62145e2..2079aba 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -30,6 +30,7 @@
#include "spi.h"
#include "tx.h"
#include "ps.h"
+#include "io.h"
static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
{
@@ -235,7 +236,7 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
else
addr = wl->data_path->tx_packet_ring_addr;
- wl12xx_spi_mem_write(wl, addr, skb->data, len);
+ wl12xx_mem_write(wl, addr, skb->data, len);
wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate);
@@ -449,8 +450,8 @@ void wl12xx_tx_complete(struct wl12xx *wl)
return;
/* First we read the result */
- wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr,
- result, sizeof(result));
+ wl12xx_mem_read(wl, wl->data_path->tx_complete_addr,
+ result, sizeof(result));
result_index = wl->next_tx_complete;
@@ -480,41 +481,41 @@ void wl12xx_tx_complete(struct wl12xx *wl)
*/
if (result_index > wl->next_tx_complete) {
/* Only 1 write is needed */
- wl12xx_spi_mem_write(wl,
- wl->data_path->tx_complete_addr +
- (wl->next_tx_complete *
- sizeof(struct tx_result)),
- &result[wl->next_tx_complete],
- num_complete *
- sizeof(struct tx_result));
+ wl12xx_mem_write(wl,
+ wl->data_path->tx_complete_addr +
+ (wl->next_tx_complete *
+ sizeof(struct tx_result)),
+ &result[wl->next_tx_complete],
+ num_complete *
+ sizeof(struct tx_result));
} else if (result_index < wl->next_tx_complete) {
/* 2 writes are needed */
- wl12xx_spi_mem_write(wl,
- wl->data_path->tx_complete_addr +
- (wl->next_tx_complete *
- sizeof(struct tx_result)),
- &result[wl->next_tx_complete],
- (FW_TX_CMPLT_BLOCK_SIZE -
- wl->next_tx_complete) *
- sizeof(struct tx_result));
-
- wl12xx_spi_mem_write(wl,
- wl->data_path->tx_complete_addr,
- result,
- (num_complete -
- FW_TX_CMPLT_BLOCK_SIZE +
- wl->next_tx_complete) *
- sizeof(struct tx_result));
+ wl12xx_mem_write(wl,
+ wl->data_path->tx_complete_addr +
+ (wl->next_tx_complete *
+ sizeof(struct tx_result)),
+ &result[wl->next_tx_complete],
+ (FW_TX_CMPLT_BLOCK_SIZE -
+ wl->next_tx_complete) *
+ sizeof(struct tx_result));
+
+ wl12xx_mem_write(wl,
+ wl->data_path->tx_complete_addr,
+ result,
+ (num_complete -
+ FW_TX_CMPLT_BLOCK_SIZE +
+ wl->next_tx_complete) *
+ sizeof(struct tx_result));
} else {
/* We have to write the whole array */
- wl12xx_spi_mem_write(wl,
- wl->data_path->tx_complete_addr,
- result,
- FW_TX_CMPLT_BLOCK_SIZE *
- sizeof(struct tx_result));
+ wl12xx_mem_write(wl,
+ wl->data_path->tx_complete_addr,
+ result,
+ FW_TX_CMPLT_BLOCK_SIZE *
+ sizeof(struct tx_result));
}
}
diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c
index ce1561a..543a5b8 100644
--- a/drivers/net/wireless/wl12xx/wl1251.c
+++ b/drivers/net/wireless/wl12xx/wl1251.c
@@ -34,6 +34,7 @@
#include "rx.h"
#include "ps.h"
#include "init.h"
+#include "io.h"
static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = {
[PART_DOWN] = {
@@ -130,7 +131,7 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
p, addr);
- wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE);
+ wl12xx_mem_write(wl, addr, p, CHUNK_SIZE);
chunk_num++;
}
@@ -140,7 +141,7 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
fw_data_len % CHUNK_SIZE, p, addr);
- wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
+ wl12xx_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
return 0;
}
@@ -412,8 +413,8 @@ static void wl1251_irq_work(struct work_struct *work)
wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr);
if (wl->data_path) {
- wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr,
- &wl->rx_counter, sizeof(u32));
+ wl12xx_mem_read(wl, wl->data_path->rx_control_addr,
+ &wl->rx_counter, sizeof(u32));
/* We handle a frmware bug here */
switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
--
1.6.0.6
Hi Kalle,
> >> wl1251 has these lines to the host:
> >>
> >> o four lines for SDIO or SPI, configured to SDIO by default
> >> o power line
> >> o interrupt line
> >>
> >> When the power line is pulled up, the chip will power on itself.
> >> Whenever the power line goes down, the chip will power off. For example,
> >> the power line can be controlled with a GPIO pin from the host. But how
> >> the power line is really controlled, is board specific and should be
> >> handled in the board file. And here comes the set_power() function to
> >> the picture. The wl1251 driver will call set_power() function every time
> >> user space calls wlan interface up or down.
> >>
> >> Pierre, how do you propose we should do this? I understood based on
> >> discussions from linux-omap that this is a common way.
> >
> > actually this looks like a RFKILL hard switch to me.
>
> I have my doubts. For example, when you turn off and on the power from
> the wl1251 chip you have to reupload the firmware and boot it again,
> which is slow. I have been thinking more like turning off the radios
> when rfkill is enabled, which is significantly faster. But I haven't
> looked at rfkill yet, and I'm not planning to do it until the dust has
> settled within the next few months :)
>
> > Why don't we just integrate it with RFKILL and this way have a common
> > interface to handle all of these.
>
> But rfkill won't solve the problem under discussion. rfkill is the
> interface between wl12xx driver and higher levels, but the problem here
> is the lower level interface, that is how does wl12xx driver shall
> control the actual hw line. We need to have a generic way to control the
> hw line so that driver works in TI's OMAP architecture, whatever Google
> is using and all the other possible (embedded) combination where Linux
> can run.
>
> Because I know that my english sucks, I'll draw an architecture diagram
> to show what I'm trying to say here:
>
> ---------- ------------
> | rfkill | | mac80211 |
> ---------- ------------
>
> -----------------------
> | wl12xx |
> -----------------------
>
> -----------------------
> | hw power line |
> -----------------------
>
> So rfkill is on the opposite side of wl12xx compared to the actual hw
> power line.
we do have the RFKILL (aka soft killswitch) that is now integrated with
mac80211 and we do have separate RFKILL hardware killswitches.
For example the Bluetooth pieces inside a laptop now have a Bluetooth
hardware killswitch (behind a platform device) and the soft killswitch
from the Bluetooth subsystem. They are two independent pieces.
RFKILL is a confusing beast ;)
Regards
Marcel
On Thu, 2009-06-11 at 16:55 +0200, Samuel Ortiz wrote:
> On Thu, 2009-06-11 at 16:38 +0200, Gábor Stefanik wrote:
> > On Thu, Jun 11, 2009 at 4:02 AM, Bob Copeland<[email protected]> wrote:
> > > Here's v2 of the SDIO interface for wl12xx, still with a FIXME or two.
> > >
> > > For my part, this is mainly a port of the Google/TI Android SDIO
> > > interface logic to the existing SPI driver. I have confirmed that
> > > the driver associates and sends some traffic.
> > >
> > > Pierre, hoping to get your perspective on the SDIO bits in patch 7,
> > > since I very likely don't know what I'm doing :) Especially regarding
> > > the platform code setup, in which the correct GPIOs have to be written
> > > to turn on the device before probe will work. For the SPI interface,
> > > we use spi_register_board_info() for a similar purpose, but I'm not
> > > sure if there is a standard way to do that for SDIO. This copies
> > > Google's platform driver for now.
> > >
> > > Conversion to readl/writel etc where appropriate is TODO.
> > >
> > > Bob Copeland (7):
> > > wl12xx: separate bus i/o code into io.c
> > > wl12xx: use wiphy_dev instead of wl->spi->dev
> > > wl12xx: introduce wl12xx_if_operations struct
> > > wl12xx: make wl12xx_set_partition bus agnostic
> > > wl12xx: move module probe methods into spi.c
> > > wl12xx: split spi interface into separate module
> > > wl12xx: add sdio support
> > >
> > > drivers/net/wireless/wl12xx/Kconfig | 24 +++-
> > > drivers/net/wireless/wl12xx/Makefile | 10 +-
> > > drivers/net/wireless/wl12xx/acx.c | 3 +-
> > > drivers/net/wireless/wl12xx/boot.c | 3 +-
> > > drivers/net/wireless/wl12xx/cmd.c | 15 +-
> > > drivers/net/wireless/wl12xx/event.c | 6 +-
> > > drivers/net/wireless/wl12xx/io.c | 181 +++++++++++++++++++++
> > > drivers/net/wireless/wl12xx/io.h | 62 +++++++
> > > drivers/net/wireless/wl12xx/main.c | 152 ++++--------------
> > > drivers/net/wireless/wl12xx/ps.c | 3 +-
> > > drivers/net/wireless/wl12xx/rx.c | 10 +-
> > > drivers/net/wireless/wl12xx/sdio.c | 250 +++++++++++++++++++++++++++++
> > > drivers/net/wireless/wl12xx/spi.c | 289 ++++++++++++++-------------------
> > > drivers/net/wireless/wl12xx/spi.h | 40 -----
> > > drivers/net/wireless/wl12xx/tx.c | 64 ++++----
> > > drivers/net/wireless/wl12xx/wl1251.c | 9 +-
> > > drivers/net/wireless/wl12xx/wl12xx.h | 14 ++-
> > > 17 files changed, 752 insertions(+), 383 deletions(-)
> > > create mode 100644 drivers/net/wireless/wl12xx/io.c
> > > create mode 100644 drivers/net/wireless/wl12xx/io.h
> > > create mode 100644 drivers/net/wireless/wl12xx/sdio.c
> >
> > Can we expect vlynq any time soon?
> I guess we need:
>
> 1) A linux vlynq driver for that, and last thing I saw [1], it wasnt
> really pretty/ready
This: http://lkml.org/lkml/2009/6/4/259 seems to be a bit better...
> 2) A device that would have a wl12xx chip connected to the host through
> vlynq.
>
> Cheers,
> Samuel.
>
> [1] http://lkml.indiana.edu/hypermail/linux/kernel/0906.0/00155.html
>
>
> >
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, 19 Jun 2009 16:31:41 -0400
Bob Copeland <[email protected]> wrote:
> On Fri, Jun 19, 2009 at 3:24 PM, Pierre Ossman<[email protected]> wrote:
> > I'm afraid I don't understand the problem. If you power up the card
> > before the MMC system has started, it should still properly find the
> > card and activate the wl12xx driver once things are in sync.
>
> Okay a little more background:
>
> This is with the out-of-tree Android msm_sdcc host driver. There are
> various implicit assumptions in module ordering. For example, one of
> the platform callbacks sets a "virtual card select" flag, and then
> tries to notify the MMC host via another callback to do
> mmc_detect_change(). But that code runs before the MMC driver is
> loaded so the callback isn't yet registered and no one gets the
> notification.
>
This does not sound very Linux:y. Module loading order should not foul
up things. If it does, then there is some missing dependency somewhere.
> > Do you want me to merge it?
>
> It can go via the wireless tree if that's ok with you, since the
> SPI driver already lives there and this all needs to be rebased
> on Kalle Valo's latest changes anyway.
>
> It'd be nice to get msm_sdcc upstream though.
>
Yeah, sorry. Of course it should go through wireless. I was just in
merge-mode from all the MMC patches thrown my way. :)
I noticed one more thing though. You call wl12xx_irq() on interrupts,
and that's all you do. So I have to assume that calls back to
wl12xx_sdio_read(). That in turn calls sdio_claim_host(), which will
cause the system to deadlock as that lock is not recursive (yeah I
know, patches welcome).
Has this code actually been tested? It doesn't seem like it can work to
me.
Rgds
--
-- Pierre Ossman
WARNING: This correspondence is being monitored by the
Swedish government. Make sure your server uses encryption
for SMTP traffic and consider using PGP for end-to-end
encryption.
Marcel Holtmann <[email protected]> writes:
>> wl1251 has these lines to the host:
>>
>> o four lines for SDIO or SPI, configured to SDIO by default
>> o power line
>> o interrupt line
>>
>> When the power line is pulled up, the chip will power on itself.
>> Whenever the power line goes down, the chip will power off. For example,
>> the power line can be controlled with a GPIO pin from the host. But how
>> the power line is really controlled, is board specific and should be
>> handled in the board file. And here comes the set_power() function to
>> the picture. The wl1251 driver will call set_power() function every time
>> user space calls wlan interface up or down.
>>
>> Pierre, how do you propose we should do this? I understood based on
>> discussions from linux-omap that this is a common way.
>
> actually this looks like a RFKILL hard switch to me.
I have my doubts. For example, when you turn off and on the power from
the wl1251 chip you have to reupload the firmware and boot it again,
which is slow. I have been thinking more like turning off the radios
when rfkill is enabled, which is significantly faster. But I haven't
looked at rfkill yet, and I'm not planning to do it until the dust has
settled within the next few months :)
> Why don't we just integrate it with RFKILL and this way have a common
> interface to handle all of these.
But rfkill won't solve the problem under discussion. rfkill is the
interface between wl12xx driver and higher levels, but the problem here
is the lower level interface, that is how does wl12xx driver shall
control the actual hw line. We need to have a generic way to control the
hw line so that driver works in TI's OMAP architecture, whatever Google
is using and all the other possible (embedded) combination where Linux
can run.
Because I know that my english sucks, I'll draw an architecture diagram
to show what I'm trying to say here:
---------- ------------
| rfkill | | mac80211 |
---------- ------------
-----------------------
| wl12xx |
-----------------------
-----------------------
| hw power line |
-----------------------
So rfkill is on the opposite side of wl12xx compared to the actual hw
power line.
--
Kalle Valo
Bob Copeland <[email protected]> writes:
> Here's v2 of the SDIO interface for wl12xx, still with a FIXME or two.
>
> For my part, this is mainly a port of the Google/TI Android SDIO
> interface logic to the existing SPI driver. I have confirmed that
> the driver associates and sends some traffic.
I quickly read the patches and they look really good. Thanks a lot for
your work on this, you have done a great job.
About the plan how to merge these. I have quite a big pile of patches
pending for submission and I hope to send them either tomorrow or latest
on Monday. Unfortunately the patches will conflict your patches, but I
can rebase your sdio patches on top of my patches. It shouldn't take
that long. Only problem is that I don't have a device to test the SDIO,
so I might need your help with that.
Sorry about the mess, I have been sitting on top of the wl1251 patches
way too long.
--
Kalle Valo
On Thu, Jun 11, 2009 at 11:54 AM, Kalle Valo<[email protected]> wrote:
> Sorry about the mess, I have been sitting on top of the wl1251 patches
> way too long.
No worries, yeah if you rebase them I'll test the result... patch 7 won't
compile in a vanilla tree until the platform stuff is straightened out,
but the rest should be OK for inclusion I think.
--
Bob Copeland %% http://www.bobcopeland.com
Le Thursday 11 June 2009 16:55:20 Samuel Ortiz, vous avez écrit :
> On Thu, 2009-06-11 at 16:38 +0200, Gábor Stefanik wrote:
> > On Thu, Jun 11, 2009 at 4:02 AM, Bob Copeland<[email protected]> wrote:
> > > Here's v2 of the SDIO interface for wl12xx, still with a FIXME or two.
> > >
> > > For my part, this is mainly a port of the Google/TI Android SDIO
> > > interface logic to the existing SPI driver. I have confirmed that
> > > the driver associates and sends some traffic.
> > >
> > > Pierre, hoping to get your perspective on the SDIO bits in patch 7,
> > > since I very likely don't know what I'm doing :) Especially regarding
> > > the platform code setup, in which the correct GPIOs have to be written
> > > to turn on the device before probe will work. For the SPI interface,
> > > we use spi_register_board_info() for a similar purpose, but I'm not
> > > sure if there is a standard way to do that for SDIO. This copies
> > > Google's platform driver for now.
> > >
> > > Conversion to readl/writel etc where appropriate is TODO.
> > >
> > > Bob Copeland (7):
> > > wl12xx: separate bus i/o code into io.c
> > > wl12xx: use wiphy_dev instead of wl->spi->dev
> > > wl12xx: introduce wl12xx_if_operations struct
> > > wl12xx: make wl12xx_set_partition bus agnostic
> > > wl12xx: move module probe methods into spi.c
> > > wl12xx: split spi interface into separate module
> > > wl12xx: add sdio support
> > >
> > > drivers/net/wireless/wl12xx/Kconfig | 24 +++-
> > > drivers/net/wireless/wl12xx/Makefile | 10 +-
> > > drivers/net/wireless/wl12xx/acx.c | 3 +-
> > > drivers/net/wireless/wl12xx/boot.c | 3 +-
> > > drivers/net/wireless/wl12xx/cmd.c | 15 +-
> > > drivers/net/wireless/wl12xx/event.c | 6 +-
> > > drivers/net/wireless/wl12xx/io.c | 181 +++++++++++++++++++++
> > > drivers/net/wireless/wl12xx/io.h | 62 +++++++
> > > drivers/net/wireless/wl12xx/main.c | 152 ++++--------------
> > > drivers/net/wireless/wl12xx/ps.c | 3 +-
> > > drivers/net/wireless/wl12xx/rx.c | 10 +-
> > > drivers/net/wireless/wl12xx/sdio.c | 250
> > > +++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/spi.c |
> > > 289 ++++++++++++++------------------- drivers/net/wireless/wl12xx/spi.h
> > > | 40 -----
> > > drivers/net/wireless/wl12xx/tx.c | 64 ++++----
> > > drivers/net/wireless/wl12xx/wl1251.c | 9 +-
> > > drivers/net/wireless/wl12xx/wl12xx.h | 14 ++-
> > > 17 files changed, 752 insertions(+), 383 deletions(-)
> > > create mode 100644 drivers/net/wireless/wl12xx/io.c
> > > create mode 100644 drivers/net/wireless/wl12xx/io.h
> > > create mode 100644 drivers/net/wireless/wl12xx/sdio.c
> >
> > Can we expect vlynq any time soon?
>
> I guess we need:
>
> 1) A linux vlynq driver for that, and last thing I saw [1], it wasnt
> really pretty/ready
That driver is perfectly functionnal on a TI AR7 and we have used it in
OpenWrt for months with the acx100/111 driver. What makes you think it is not
yet ready ? There was a couple of suggestions from a TI employee, which are
perfectly valid, but I have no hardware to implement what he is suggesting
(no daisy chaining ...).
> 2) A device that would have a wl12xx chip connected to the host through
> vlynq.
>
> Cheers,
> Samuel.
>
> [1] http://lkml.indiana.edu/hypermail/linux/kernel/0906.0/00155.html
>
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless"
> in the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Best regards, Florian Fainelli
Email : [email protected]
http://openwrt.org
-------------------------------
On Sat, Jun 13, 2009 at 10:09:08PM +0200, Pierre Ossman wrote:
> On Sat, 13 Jun 2009 19:00:41 +0300
> Kalle Valo <[email protected]> wrote:
>
> That doesn't make sense. If the card doesn't have power then there will
> be no device and no interface to bring up.
For SPI, you would register the platform driver with the SPI subsystem,
which gives you the ability to call the set_power callback at any time.
There's not a problem starting the driver if there is no device (as I
understand it, SPI is so simple there's no way to probe the bus anyway).
It would be nice to allow the SDIO driver to similarly invoke the
platform->set_power() callback at interface up/down time (that's why
there's wl12xx_sdio_set_power() which does nothing right now). However,
then the device will disappear from the bus...
> + wifi_ctrl->set_power(1); /* Power On */
Except for the problems outlined above, this would be invoked from
wl12xx_sdio_set_power(). But without it being up at start, probe()
won't work anyway. So it sounds like wl12xx_sdio_set_power() will
have to be a no-op for sdio devices unless there's some register
we can poke on the chip to put it to sleep.
> I think this should be somewhere under arch/ in the board setup code,
> where currently you have some code adding the "msm_wifi" platform
> device.
Yeah, in fact I tried that a while ago but something didn't work right,
some ordering issue perhaps. I'll try again.
--
Bob Copeland %% http://www.bobcopeland.com
Marcel Holtmann <[email protected]> writes:
>> So rfkill is on the opposite side of wl12xx compared to the actual hw
>> power line.
>
> we do have the RFKILL (aka soft killswitch) that is now integrated with
> mac80211 and we do have separate RFKILL hardware killswitches.
>
> For example the Bluetooth pieces inside a laptop now have a Bluetooth
> hardware killswitch (behind a platform device) and the soft killswitch
> from the Bluetooth subsystem. They are two independent pieces.
Oh, I didn't know that. I need to some studying now. Thanks.
> RFKILL is a confusing beast ;)
That's what everyone seem to say :)
--
Kalle Valo
On Fri, Jun 19, 2009 at 3:24 PM, Pierre Ossman<[email protected]> wrote:
> I'm afraid I don't understand the problem. If you power up the card
> before the MMC system has started, it should still properly find the
> card and activate the wl12xx driver once things are in sync.
Okay a little more background:
This is with the out-of-tree Android msm_sdcc host driver. There are
various implicit assumptions in module ordering. For example, one of
the platform callbacks sets a "virtual card select" flag, and then
tries to notify the MMC host via another callback to do
mmc_detect_change(). But that code runs before the MMC driver is
loaded so the callback isn't yet registered and no one gets the
notification.
The Android loads the TI wifi module whenever someone uses it and
then unloads it afterwards, so the current use of the msm_wifi platform
driver is always after MMC is running. And that's why the set_power()
callbacks exist in the first place: they enable the phone to turn off
the module via gpios, disconnect external oscillators, etc. when the
person isn't actively using the wifi (i.e. module is unloaded). A
separate platform driver could still manage all of that.
(The above is just from my reading the source, San can correct any
errors.)
IOW, this particular issue isn't related to the core in-tree code, I
was just describing why my first try failed. I believe you that it will
work fine once the Android specifics are worked out.
> Do you want me to merge it?
It can go via the wireless tree if that's ok with you, since the
SPI driver already lives there and this all needs to be rebased
on Kalle Valo's latest changes anyway.
It'd be nice to get msm_sdcc upstream though.
--
Bob Copeland %% http://www.bobcopeland.com
On Mon, Jun 22, 2009 at 08:14:36AM +0200, Pierre Ossman wrote:
> SDIO interrupts are level interrupts, not edge. That means that the
> interrupt source needs to be handled before the interrupt routine
> returns or the system will get stuck in a fairly tight loop, rehandling
> the same interrupt over and over again.
Hmm good point, let me look into that.
--
Bob Copeland %% http://www.bobcopeland.com
This creates a module called wl12xx_spi.ko which contains just the
SPI-specific code. The core remains in the module wl12xx.ko.
Signed-off-by: Bob Copeland <[email protected]>
---
drivers/net/wireless/wl12xx/Kconfig | 13 ++++++++++++-
drivers/net/wireless/wl12xx/Makefile | 6 +++++-
drivers/net/wireless/wl12xx/main.c | 9 +++++++++
drivers/net/wireless/wl12xx/spi.c | 15 ++++++++++-----
drivers/net/wireless/wl12xx/wl12xx.h | 2 +-
5 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index a82c4cd..9575d16 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -1,6 +1,6 @@
config WL12XX
tristate "TI wl1251/wl1271 support"
- depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL
+ depends on MAC80211 && WLAN_80211 && GENERIC_HARDIRQS && EXPERIMENTAL
select FW_LOADER
select CRC7
---help---
@@ -9,3 +9,14 @@ config WL12XX
If you choose to build a module, it'll be called wl12xx. Say N if
unsure.
+
+config WL12XX_SPI
+ tristate "TI wl1251/wl1271 SPI support"
+ depends on WL12XX && SPI_MASTER
+ ---help---
+ This module adds support for the SPI interface of adapters using
+ TI wl1251/wl1271 chipsets. Select this if your platform is using
+ the SPI bus.
+
+ If you choose to build a module, it'll be called wl12xx_spi. Say N if
+ unsure.
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index c1281fc..ffd5664 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -1,4 +1,8 @@
-wl12xx-objs = main.o spi.o event.o tx.o rx.o \
+wl12xx-objs = main.o event.o tx.o rx.o \
ps.o cmd.o acx.o boot.o init.o wl1251.o \
debugfs.o io.o
+
+wl12xx_spi-objs += spi.o
+
obj-$(CONFIG_WL12XX) += wl12xx.o
+obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 06c1973..d5faaa1 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -69,6 +69,7 @@ irqreturn_t wl12xx_irq(int irq, void *cookie)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_GPL(wl12xx_irq);
static int wl12xx_fetch_firmware(struct wl12xx *wl)
{
@@ -1179,6 +1180,7 @@ int wl12xx_init_ieee80211(struct wl12xx *wl)
out:
return ret;
}
+EXPORT_SYMBOL_GPL(wl12xx_init_ieee80211);
#define WL12XX_DEFAULT_CHANNEL 1
struct ieee80211_hw *wl12xx_alloc_hw(void)
@@ -1245,6 +1247,7 @@ struct ieee80211_hw *wl12xx_alloc_hw(void)
return hw;
}
+EXPORT_SYMBOL_GPL(wl12xx_alloc_hw);
int wl12xx_free_hw(struct wl12xx *wl)
{
@@ -1263,3 +1266,9 @@ int wl12xx_free_hw(struct wl12xx *wl)
return 0;
}
+EXPORT_SYMBOL_GPL(wl12xx_free_hw);
+
+MODULE_DESCRIPTION("TI 12xx Wireles LAN Driver Core");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kalle Valo <[email protected]>");
+MODULE_AUTHOR("Luciano Coelho <[email protected]>");
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index 852c990..6b453e2 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -32,6 +32,11 @@
#include "spi.h"
#include "ps.h"
+static struct spi_device *wl_to_spi(struct wl12xx *wl)
+{
+ return wl->if_priv;
+}
+
static void wl12xx_spi_reset(struct wl12xx *wl)
{
u8 *cmd;
@@ -53,7 +58,7 @@ static void wl12xx_spi_reset(struct wl12xx *wl)
t.len = WSPI_INIT_CMD_LEN;
spi_message_add_tail(&t, &m);
- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);
wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
}
@@ -107,7 +112,7 @@ static void wl12xx_spi_wake(struct wl12xx *wl)
t.len = WSPI_INIT_CMD_LEN;
spi_message_add_tail(&t, &m);
- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);
wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
}
@@ -147,7 +152,7 @@ static void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
t[2].len = len;
spi_message_add_tail(&t[2], &m);
- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);
/* FIXME: check busy words */
@@ -178,7 +183,7 @@ static void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
t[1].len = len;
spi_message_add_tail(&t[1], &m);
- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);
wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd));
wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
@@ -211,7 +216,7 @@ static int __devinit wl12xx_spi_probe(struct spi_device *spi)
SET_IEEE80211_DEV(hw, &spi->dev);
dev_set_drvdata(&spi->dev, wl);
- wl->spi = spi;
+ wl->if_priv = spi;
wl->if_ops = &wl12xx_spi_ops;
/* This is the only SPI value that we need to set here, the rest
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 46d3bc1..d8bc4c6 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -286,7 +286,7 @@ struct wl12xx {
struct ieee80211_hw *hw;
bool mac80211_registered;
- struct spi_device *spi;
+ void *if_priv;
const struct wl12xx_if_operations *if_ops;
void (*set_power)(bool enable);
--
1.6.0.6
Bob Copeland <[email protected]> writes:
>> Do you want me to merge it?
>
> It can go via the wireless tree if that's ok with you, since the
> SPI driver already lives there and this all needs to be rebased
> on Kalle Valo's latest changes anyway.
I agree, better to merge all wl12xx patches through John. Otherwise we
start to get conflicts, and that's pain.
--
Kalle Valo
Hi Kalle,
> >> This adds the wl12xx_sdio module, enabling the SDIO interface for
> >> wl12xx, as used by the Google G1 phone and others.
> >>
> >> Signed-off-by: Bob Copeland <[email protected]>
> >> ---
> >
> > I think the drivers looks quite ok. There are really just a few things
> > I'm concerned about:
> >
>
> [...]
>
> > - Why do you have a platform device with the sole purpose of enabling
> > power to the SDIO card? Shouldn't this be handled in the arch code?
>
> wl1251 has these lines to the host:
>
> o four lines for SDIO or SPI, configured to SDIO by default
> o power line
> o interrupt line
>
> When the power line is pulled up, the chip will power on itself.
> Whenever the power line goes down, the chip will power off. For example,
> the power line can be controlled with a GPIO pin from the host. But how
> the power line is really controlled, is board specific and should be
> handled in the board file. And here comes the set_power() function to
> the picture. The wl1251 driver will call set_power() function every time
> user space calls wlan interface up or down.
>
> Pierre, how do you propose we should do this? I understood based on
> discussions from linux-omap that this is a common way.
actually this looks like a RFKILL hard switch to me. Why don't we just
integrate it with RFKILL and this way have a common interface to handle
all of these.
Regards
Marcel
This adds the wl12xx_sdio module, enabling the SDIO interface for
wl12xx, as used by the Google G1 phone and others.
Signed-off-by: Bob Copeland <[email protected]>
---
drivers/net/wireless/wl12xx/Kconfig | 11 ++
drivers/net/wireless/wl12xx/Makefile | 2 +
drivers/net/wireless/wl12xx/sdio.c | 250 ++++++++++++++++++++++++++++++++++
3 files changed, 263 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/wireless/wl12xx/sdio.c
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 9575d16..c4af50a 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -20,3 +20,14 @@ config WL12XX_SPI
If you choose to build a module, it'll be called wl12xx_spi. Say N if
unsure.
+
+config WL12XX_SDIO
+ tristate "TI wl1251/wl1271 SDIO support"
+ depends on WL12XX && MMC
+ ---help---
+ This module adds support for the SDIO interface of adapters using
+ TI wl1251/wl1271 chipsets. Select this if your platform is using
+ the SDIO bus.
+
+ If you choose to build a module, it'll be called wl12xx_sdio. Say N if
+ unsure.
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index ffd5664..25df712 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -3,6 +3,8 @@ wl12xx-objs = main.o event.o tx.o rx.o \
debugfs.o io.o
wl12xx_spi-objs += spi.o
+wl12xx_sdio-objs += sdio.o
obj-$(CONFIG_WL12XX) += wl12xx.o
obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o
+obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
new file mode 100644
index 0000000..9aae632
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -0,0 +1,250 @@
+/*
+ * wl12xx SDIO routines
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Copyright (C) 2005 Texas Instruments Incorporated
+ * Copyright (C) 2008 Google Inc
+ * Copyright (C) 2009 Bob Copeland ([email protected])
+ */
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/mod_devicetable.h>
+#include <linux/irq.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/platform_device.h>
+
+#include "wl12xx.h"
+#include "wl12xx_80211.h"
+#include "reg.h"
+#include "ps.h"
+#include "io.h"
+#include "tx.h"
+#include "debugfs.h"
+
+#define SDIO_VENDOR_ID_TI 0x104c
+#define SDIO_DEVICE_ID_WL1251 0x9066
+
+static struct sdio_func *wl_to_func(struct wl12xx *wl)
+{
+ return wl->if_priv;
+}
+
+static void wl12xx_sdio_interrupt(struct sdio_func *func)
+{
+ wl12xx_irq(0, sdio_get_drvdata(func));
+}
+
+/* FIXME use wl12xx_platform_data instead of msm-specific wifi_XXX */
+#if 1
+#include <linux/wifi_tiwlan.h>
+static int wifi_probe(struct platform_device *pdev)
+{
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *)(pdev->dev.platform_data);
+
+ if (!wifi_ctrl)
+ return -ENODEV;
+
+ wifi_ctrl->set_power(1); /* Power On */
+ wifi_ctrl->set_reset(0); /* Reset clear */
+ wifi_ctrl->set_carddetect(1); /* CardDetect (0->1) */
+
+ return 0;
+}
+
+static int wifi_remove(struct platform_device *pdev)
+{
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *)(pdev->dev.platform_data);
+
+ if (!wifi_ctrl)
+ return -ENODEV;
+
+ wifi_ctrl->set_carddetect(0); /* CardDetect (1->0) */
+ wifi_ctrl->set_reset(1); /* Reset active */
+ wifi_ctrl->set_power(0); /* Power Off */
+
+ return 0;
+}
+
+static struct platform_driver wifi_device = {
+ .probe = wifi_probe,
+ .remove = wifi_remove,
+ .driver = {
+ .name = "msm_wifi",
+ },
+};
+
+static int wifi_add_dev(void)
+{
+ return platform_driver_register(&wifi_device);
+}
+
+static void wifi_del_dev(void)
+{
+ platform_driver_unregister(&wifi_device);
+}
+#else
+static int wifi_add_dev(void)
+{
+ return 0;
+}
+
+static void wifi_del_dev(void)
+{
+}
+#endif
+
+static const struct sdio_device_id wl12xx_devices[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_WL1251) },
+ {}
+};
+MODULE_DEVICE_TABLE(sdio, wl12xx_devices);
+
+
+void wl12xx_sdio_read(struct wl12xx *wl, int addr, void *buf, size_t len)
+{
+ int ret;
+ struct sdio_func *func = wl_to_func(wl);
+
+ sdio_claim_host(func);
+ ret = sdio_memcpy_fromio(func, buf, addr, len);
+ if (ret)
+ wl12xx_error("sdio read failed (%d)", ret);
+ sdio_release_host(func);
+}
+
+void wl12xx_sdio_write(struct wl12xx *wl, int addr, void *buf, size_t len)
+{
+ int ret;
+ struct sdio_func *func = wl_to_func(wl);
+
+ sdio_claim_host(func);
+ ret = sdio_memcpy_toio(func, addr, buf, len);
+ if (ret)
+ wl12xx_error("sdio write failed (%d)", ret);
+ sdio_release_host(func);
+}
+
+void wl12xx_sdio_reset(struct wl12xx *wl)
+{
+}
+
+void wl12xx_sdio_set_power(bool enable)
+{
+}
+
+struct wl12xx_if_operations wl12xx_sdio_ops = {
+ .read = wl12xx_sdio_read,
+ .write = wl12xx_sdio_write,
+ .reset = wl12xx_sdio_reset,
+};
+
+int wl12xx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int ret;
+ struct wl12xx *wl;
+ struct ieee80211_hw *hw;
+
+ hw = wl12xx_alloc_hw();
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ wl = hw->priv;
+
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ if (ret)
+ goto release;
+
+ sdio_set_block_size(func, 512);
+
+ SET_IEEE80211_DEV(hw, &func->dev);
+ wl->if_priv = func;
+ wl->if_ops = &wl12xx_sdio_ops;
+ wl->set_power = wl12xx_sdio_set_power;
+
+ sdio_release_host(func);
+ ret = wl12xx_init_ieee80211(wl);
+ sdio_claim_host(func);
+ if (ret)
+ goto disable;
+
+ ret = sdio_claim_irq(func, wl12xx_sdio_interrupt);
+ if (ret)
+ goto no_irq;
+
+ sdio_release_host(func);
+ sdio_set_drvdata(func, wl);
+ return ret;
+
+no_irq:
+ wl12xx_free_hw(wl);
+disable:
+ sdio_disable_func(func);
+release:
+ sdio_release_host(func);
+ return ret;
+}
+
+static void __devexit wl12xx_sdio_remove(struct sdio_func *func)
+{
+ struct wl12xx *wl = sdio_get_drvdata(func);
+
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+
+ wl12xx_free_hw(wl);
+}
+
+static struct sdio_driver wl12xx_sdio_driver = {
+ .name = "wl12xx_sdio",
+ .id_table = wl12xx_devices,
+ .probe = wl12xx_sdio_probe,
+ .remove = __devexit_p(wl12xx_sdio_remove),
+};
+
+static int __init wl12xx_sdio_init(void)
+{
+ int err;
+
+ err = wifi_add_dev();
+ if (err)
+ goto out;
+
+ err = sdio_register_driver(&wl12xx_sdio_driver);
+out:
+ if (err)
+ wl12xx_error("failed to register sdio driver: %d", ret);
+ return err;
+}
+
+static void __exit wl12xx_sdio_exit(void)
+{
+ wifi_del_dev();
+ sdio_unregister_driver(&wl12xx_sdio_driver);
+ wl12xx_notice("unloaded");
+}
+
+module_init(wl12xx_sdio_init);
+module_exit(wl12xx_sdio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kalle Valo <[email protected]>");
+MODULE_AUTHOR("Luciano Coelho <[email protected]>");
--
1.6.0.6
On Sun, 21 Jun 2009 20:05:12 -0400
Bob Copeland <[email protected]> wrote:
> On Sun, Jun 21, 2009 at 08:38:00PM +0200, Pierre Ossman wrote:
> > I noticed one more thing though. You call wl12xx_irq() on interrupts,
> > and that's all you do. So I have to assume that calls back to
> > wl12xx_sdio_read().
>
> It schedules a workqueue, so it shouldn't be a problem.
>
Ah, I see. In that case you can add:
Acked-by: Pierre Ossman <[email protected]>
Rgds
--
-- Pierre Ossman
WARNING: This correspondence is being monitored by the
Swedish government. Make sure your server uses encryption
for SMTP traffic and consider using PGP for end-to-end
encryption.
On Sun, Jun 21, 2009 at 08:38:00PM +0200, Pierre Ossman wrote:
> This does not sound very Linux:y. Module loading order should not foul
> up things. If it does, then there is some missing dependency somewhere.
Agreed.
> I noticed one more thing though. You call wl12xx_irq() on interrupts,
> and that's all you do. So I have to assume that calls back to
> wl12xx_sdio_read().
It schedules a workqueue, so it shouldn't be a problem.
> Has this code actually been tested? It doesn't seem like it can work to
> me.
Only very basic testing but yeah, it works.
--
Bob Copeland %% http://www.bobcopeland.com
On Thu, 2009-06-11 at 16:38 +0200, Gábor Stefanik wrote:
> On Thu, Jun 11, 2009 at 4:02 AM, Bob Copeland<[email protected]> wrote:
> > Here's v2 of the SDIO interface for wl12xx, still with a FIXME or two.
> >
> > For my part, this is mainly a port of the Google/TI Android SDIO
> > interface logic to the existing SPI driver. I have confirmed that
> > the driver associates and sends some traffic.
> >
> > Pierre, hoping to get your perspective on the SDIO bits in patch 7,
> > since I very likely don't know what I'm doing :) Especially regarding
> > the platform code setup, in which the correct GPIOs have to be written
> > to turn on the device before probe will work. For the SPI interface,
> > we use spi_register_board_info() for a similar purpose, but I'm not
> > sure if there is a standard way to do that for SDIO. This copies
> > Google's platform driver for now.
> >
> > Conversion to readl/writel etc where appropriate is TODO.
> >
> > Bob Copeland (7):
> > wl12xx: separate bus i/o code into io.c
> > wl12xx: use wiphy_dev instead of wl->spi->dev
> > wl12xx: introduce wl12xx_if_operations struct
> > wl12xx: make wl12xx_set_partition bus agnostic
> > wl12xx: move module probe methods into spi.c
> > wl12xx: split spi interface into separate module
> > wl12xx: add sdio support
> >
> > drivers/net/wireless/wl12xx/Kconfig | 24 +++-
> > drivers/net/wireless/wl12xx/Makefile | 10 +-
> > drivers/net/wireless/wl12xx/acx.c | 3 +-
> > drivers/net/wireless/wl12xx/boot.c | 3 +-
> > drivers/net/wireless/wl12xx/cmd.c | 15 +-
> > drivers/net/wireless/wl12xx/event.c | 6 +-
> > drivers/net/wireless/wl12xx/io.c | 181 +++++++++++++++++++++
> > drivers/net/wireless/wl12xx/io.h | 62 +++++++
> > drivers/net/wireless/wl12xx/main.c | 152 ++++--------------
> > drivers/net/wireless/wl12xx/ps.c | 3 +-
> > drivers/net/wireless/wl12xx/rx.c | 10 +-
> > drivers/net/wireless/wl12xx/sdio.c | 250 +++++++++++++++++++++++++++++
> > drivers/net/wireless/wl12xx/spi.c | 289 ++++++++++++++-------------------
> > drivers/net/wireless/wl12xx/spi.h | 40 -----
> > drivers/net/wireless/wl12xx/tx.c | 64 ++++----
> > drivers/net/wireless/wl12xx/wl1251.c | 9 +-
> > drivers/net/wireless/wl12xx/wl12xx.h | 14 ++-
> > 17 files changed, 752 insertions(+), 383 deletions(-)
> > create mode 100644 drivers/net/wireless/wl12xx/io.c
> > create mode 100644 drivers/net/wireless/wl12xx/io.h
> > create mode 100644 drivers/net/wireless/wl12xx/sdio.c
>
> Can we expect vlynq any time soon?
I guess we need:
1) A linux vlynq driver for that, and last thing I saw [1], it wasnt
really pretty/ready
2) A device that would have a wl12xx chip connected to the host through
vlynq.
Cheers,
Samuel.
[1] http://lkml.indiana.edu/hypermail/linux/kernel/0906.0/00155.html
>
On Sat, Jun 13, 2009 at 04:57:37PM -0400, Bob Copeland wrote:
> > I think this should be somewhere under arch/ in the board setup code,
> > where currently you have some code adding the "msm_wifi" platform
> > device.
>
> Yeah, in fact I tried that a while ago but something didn't work right,
> some ordering issue perhaps. I'll try again.
Just to follow up now that I've tested that again: the issue is msm_wifi
setup loads before the mmc host driver, which interferes with mounting the
sdcard in the other slot. There's also some platform code in the host
driver that registers callbacks when the wifi driver is loaded, presumably
to avoid using a timer for card detect.
Anyway, this is only compile tested but should work when we get all that
sorted...
v3:
* remove platform junk
* fix ordering of remove()
* move IDs to sdio_ids.h
* remove sdio_set_block_size() call
From: Bob Copeland <[email protected]>
Date: Sat, 30 May 2009 13:50:29 -0400
Subject: [PATCH] wl12xx: add sdio support
This adds the wl12xx_sdio module, enabling the SDIO interface for
wl12xx, as used by the Google G1 phone and others.
Signed-off-by: Bob Copeland <[email protected]>
---
drivers/net/wireless/wl12xx/Kconfig | 11 ++
drivers/net/wireless/wl12xx/Makefile | 2 +
drivers/net/wireless/wl12xx/sdio.c | 180 ++++++++++++++++++++++++++++++++++
include/linux/mmc/sdio_ids.h | 3 +
4 files changed, 196 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/wireless/wl12xx/sdio.c
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 9575d16..c4af50a 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -20,3 +20,14 @@ config WL12XX_SPI
If you choose to build a module, it'll be called wl12xx_spi. Say N if
unsure.
+
+config WL12XX_SDIO
+ tristate "TI wl1251/wl1271 SDIO support"
+ depends on WL12XX && MMC
+ ---help---
+ This module adds support for the SDIO interface of adapters using
+ TI wl1251/wl1271 chipsets. Select this if your platform is using
+ the SDIO bus.
+
+ If you choose to build a module, it'll be called wl12xx_sdio. Say N if
+ unsure.
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index ffd5664..25df712 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -3,6 +3,8 @@ wl12xx-objs = main.o event.o tx.o rx.o \
debugfs.o io.o
wl12xx_spi-objs += spi.o
+wl12xx_sdio-objs += sdio.o
obj-$(CONFIG_WL12XX) += wl12xx.o
obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o
+obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
new file mode 100644
index 0000000..afe6bd4
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -0,0 +1,180 @@
+/*
+ * wl12xx SDIO routines
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Copyright (C) 2005 Texas Instruments Incorporated
+ * Copyright (C) 2008 Google Inc
+ * Copyright (C) 2009 Bob Copeland ([email protected])
+ */
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/mod_devicetable.h>
+#include <linux/irq.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/platform_device.h>
+
+#include "wl12xx.h"
+#include "wl12xx_80211.h"
+#include "reg.h"
+#include "ps.h"
+#include "io.h"
+#include "tx.h"
+#include "debugfs.h"
+
+static struct sdio_func *wl_to_func(struct wl12xx *wl)
+{
+ return wl->if_priv;
+}
+
+static void wl12xx_sdio_interrupt(struct sdio_func *func)
+{
+ wl12xx_irq(0, sdio_get_drvdata(func));
+}
+
+static const struct sdio_device_id wl12xx_devices[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) },
+ {}
+};
+MODULE_DEVICE_TABLE(sdio, wl12xx_devices);
+
+
+void wl12xx_sdio_read(struct wl12xx *wl, int addr, void *buf, size_t len)
+{
+ int ret;
+ struct sdio_func *func = wl_to_func(wl);
+
+ sdio_claim_host(func);
+ ret = sdio_memcpy_fromio(func, buf, addr, len);
+ if (ret)
+ wl12xx_error("sdio read failed (%d)", ret);
+ sdio_release_host(func);
+}
+
+void wl12xx_sdio_write(struct wl12xx *wl, int addr, void *buf, size_t len)
+{
+ int ret;
+ struct sdio_func *func = wl_to_func(wl);
+
+ sdio_claim_host(func);
+ ret = sdio_memcpy_toio(func, addr, buf, len);
+ if (ret)
+ wl12xx_error("sdio write failed (%d)", ret);
+ sdio_release_host(func);
+}
+
+void wl12xx_sdio_reset(struct wl12xx *wl)
+{
+}
+
+void wl12xx_sdio_set_power(bool enable)
+{
+}
+
+struct wl12xx_if_operations wl12xx_sdio_ops = {
+ .read = wl12xx_sdio_read,
+ .write = wl12xx_sdio_write,
+ .reset = wl12xx_sdio_reset,
+};
+
+int wl12xx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int ret;
+ struct wl12xx *wl;
+ struct ieee80211_hw *hw;
+
+ printk(KERN_DEBUG "wl12xx: in probe\n");
+
+ hw = wl12xx_alloc_hw();
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ wl = hw->priv;
+
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ if (ret)
+ goto release;
+
+ SET_IEEE80211_DEV(hw, &func->dev);
+ wl->if_priv = func;
+ wl->if_ops = &wl12xx_sdio_ops;
+ wl->set_power = wl12xx_sdio_set_power;
+
+ sdio_release_host(func);
+ ret = wl12xx_init_ieee80211(wl);
+ sdio_claim_host(func);
+ if (ret)
+ goto disable;
+
+ ret = sdio_claim_irq(func, wl12xx_sdio_interrupt);
+ if (ret)
+ goto no_irq;
+
+ sdio_release_host(func);
+ sdio_set_drvdata(func, wl);
+ return ret;
+
+no_irq:
+ wl12xx_free_hw(wl);
+disable:
+ sdio_disable_func(func);
+release:
+ sdio_release_host(func);
+ return ret;
+}
+
+static void __devexit wl12xx_sdio_remove(struct sdio_func *func)
+{
+ struct wl12xx *wl = sdio_get_drvdata(func);
+
+ wl12xx_free_hw(wl);
+
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+}
+
+static struct sdio_driver wl12xx_sdio_driver = {
+ .name = "wl12xx_sdio",
+ .id_table = wl12xx_devices,
+ .probe = wl12xx_sdio_probe,
+ .remove = __devexit_p(wl12xx_sdio_remove),
+};
+
+static int __init wl12xx_sdio_init(void)
+{
+ int err;
+
+ err = sdio_register_driver(&wl12xx_sdio_driver);
+ if (err)
+ wl12xx_error("failed to register sdio driver: %d", err);
+ return err;
+}
+
+static void __exit wl12xx_sdio_exit(void)
+{
+ sdio_unregister_driver(&wl12xx_sdio_driver);
+ wl12xx_notice("unloaded");
+}
+
+module_init(wl12xx_sdio_init);
+module_exit(wl12xx_sdio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kalle Valo <[email protected]>");
+MODULE_AUTHOR("Luciano Coelho <[email protected]>");
diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h
index c7211ab..403840f 100644
--- a/include/linux/mmc/sdio_ids.h
+++ b/include/linux/mmc/sdio_ids.h
@@ -28,4 +28,7 @@
#define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104
#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105
+#define SDIO_VENDOR_ID_TI 0x104c
+#define SDIO_DEVICE_ID_TI_WL1251 0x9066
+
#endif
--
1.6.2.2
--
Bob Copeland %% http://www.bobcopeland.com
Le Thursday 11 June 2009 17:04:01 G?bor Stefanik, vous avez ?crit?:
> On Thu, Jun 11, 2009 at 4:59 PM, Florian Fainelli<[email protected]>
wrote:
> > Le Thursday 11 June 2009 16:55:20 Samuel Ortiz, vous avez ?crit?:
> >> On Thu, 2009-06-11 at 16:38 +0200, G?bor Stefanik wrote:
> >> > On Thu, Jun 11, 2009 at 4:02 AM, Bob Copeland<[email protected]>
wrote:
> >> > > Here's v2 of the SDIO interface for wl12xx, still with a FIXME or
> >> > > two.
> >> > >
> >> > > For my part, this is mainly a port of the Google/TI Android SDIO
> >> > > interface logic to the existing SPI driver. ?I have confirmed that
> >> > > the driver associates and sends some traffic.
> >> > >
> >> > > Pierre, hoping to get your perspective on the SDIO bits in patch 7,
> >> > > since I very likely don't know what I'm doing :) ?Especially
> >> > > regarding the platform code setup, in which the correct GPIOs have
> >> > > to be written to turn on the device before probe will work. ?For the
> >> > > SPI interface, we use spi_register_board_info() for a similar
> >> > > purpose, but I'm not sure if there is a standard way to do that for
> >> > > SDIO. ?This copies Google's platform driver for now.
> >> > >
> >> > > Conversion to readl/writel etc where appropriate is TODO.
> >> > >
> >> > > Bob Copeland (7):
> >> > > ?wl12xx: separate bus i/o code into io.c
> >> > > ?wl12xx: use wiphy_dev instead of wl->spi->dev
> >> > > ?wl12xx: introduce wl12xx_if_operations struct
> >> > > ?wl12xx: make wl12xx_set_partition bus agnostic
> >> > > ?wl12xx: move module probe methods into spi.c
> >> > > ?wl12xx: split spi interface into separate module
> >> > > ?wl12xx: add sdio support
> >> > >
> >> > > ?drivers/net/wireless/wl12xx/Kconfig ?| ? 24 +++-
> >> > > ?drivers/net/wireless/wl12xx/Makefile | ? 10 +-
> >> > > ?drivers/net/wireless/wl12xx/acx.c ? ?| ? ?3 +-
> >> > > ?drivers/net/wireless/wl12xx/boot.c ? | ? ?3 +-
> >> > > ?drivers/net/wireless/wl12xx/cmd.c ? ?| ? 15 +-
> >> > > ?drivers/net/wireless/wl12xx/event.c ?| ? ?6 +-
> >> > > ?drivers/net/wireless/wl12xx/io.c ? ? | ?181 +++++++++++++++++++++
> >> > > ?drivers/net/wireless/wl12xx/io.h ? ? | ? 62 +++++++
> >> > > ?drivers/net/wireless/wl12xx/main.c ? | ?152 ++++--------------
> >> > > ?drivers/net/wireless/wl12xx/ps.c ? ? | ? ?3 +-
> >> > > ?drivers/net/wireless/wl12xx/rx.c ? ? | ? 10 +-
> >> > > ?drivers/net/wireless/wl12xx/sdio.c ? | ?250
> >> > > +++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/spi.c ? ?|
> >> > > 289 ++++++++++++++-------------------
> >> > > drivers/net/wireless/wl12xx/spi.h | ? 40 -----
> >> > > ?drivers/net/wireless/wl12xx/tx.c ? ? | ? 64 ++++----
> >> > > ?drivers/net/wireless/wl12xx/wl1251.c | ? ?9 +-
> >> > > ?drivers/net/wireless/wl12xx/wl12xx.h | ? 14 ++-
> >> > > ?17 files changed, 752 insertions(+), 383 deletions(-)
> >> > > ?create mode 100644 drivers/net/wireless/wl12xx/io.c
> >> > > ?create mode 100644 drivers/net/wireless/wl12xx/io.h
> >> > > ?create mode 100644 drivers/net/wireless/wl12xx/sdio.c
> >> >
> >> > Can we expect vlynq any time soon?
> >>
> >> I guess we need:
> >>
> >> 1) A linux vlynq driver for that, and last thing I saw [1], it wasnt
> >> really pretty/ready
> >
> > That driver is perfectly functionnal on a TI AR7 and we have used it in
> > OpenWrt for months with the acx100/111 driver. What makes you think it is
> > not yet ready ? There was a couple of suggestions from a TI employee,
> > which are perfectly valid, but I have no hardware to implement what he is
> > suggesting (no daisy chaining ...).
>
> Better forget the acx1xx driver. There is legal controversy around it
> - the devs never released any documentation during the reverse
> engineering process, and development was quite slow until TI's
> copyrighted ti_ap.o driver's source code leaked...
This is why I ask if wl12xx can actually drive an acx111 chipset or the HW is
completely different.
--
Best regards, Florian Fainelli
Email : [email protected]
http://openwrt.org
-------------------------------
This change moves all of the spi specific code from main.c into
spi.c. The module initialization code also moves, but common
code for initializing mac80211 etc. stays in main.c, as this will
eventually form a common library module also used by wl12xx_sdio.
Signed-off-by: Bob Copeland <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 1 -
drivers/net/wireless/wl12xx/cmd.c | 1 -
drivers/net/wireless/wl12xx/main.c | 138 +++++-----------------------------
drivers/net/wireless/wl12xx/spi.c | 124 ++++++++++++++++++++++++++++++-
drivers/net/wireless/wl12xx/tx.c | 1 -
drivers/net/wireless/wl12xx/wl12xx.h | 7 ++-
6 files changed, 148 insertions(+), 124 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 9e48de2..c55d6a6 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -2,7 +2,6 @@
#include <linux/module.h>
#include <linux/crc7.h>
-#include <linux/spi/spi.h>
#include "wl12xx.h"
#include "wl12xx_80211.h"
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 56bf6a6..0fe296d 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -2,7 +2,6 @@
#include <linux/module.h>
#include <linux/crc7.h>
-#include <linux/spi/spi.h>
#include "wl12xx.h"
#include "wl12xx_80211.h"
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index eb4b5da..06c1973 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -26,17 +26,15 @@
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/irq.h>
-#include <linux/spi/spi.h>
#include <linux/crc32.h>
#include <linux/etherdevice.h>
-#include <linux/spi/wl12xx.h>
#include "wl12xx.h"
#include "wl12xx_80211.h"
#include "reg.h"
#include "wl1251.h"
#include "io.h"
-#include "spi.h"
+#include "cmd.h"
#include "event.h"
#include "tx.h"
#include "rx.h"
@@ -59,7 +57,7 @@ static void wl12xx_power_on(struct wl12xx *wl)
wl->set_power(true);
}
-static irqreturn_t wl12xx_irq(int irq, void *cookie)
+irqreturn_t wl12xx_irq(int irq, void *cookie)
{
struct wl12xx *wl;
@@ -1150,8 +1148,10 @@ static int wl12xx_register_hw(struct wl12xx *wl)
return 0;
}
-static int wl12xx_init_ieee80211(struct wl12xx *wl)
+int wl12xx_init_ieee80211(struct wl12xx *wl)
{
+ int ret;
+
/* The tx descriptor buffer and the TKIP space */
wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc)
+ WL12XX_TKIP_IV_SPACE;
@@ -1167,41 +1167,37 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl)
wl->hw->wiphy->max_scan_ssids = 1;
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz;
- SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
+ ret = wl12xx_register_hw(wl);
+ if (ret)
+ goto out;
- return 0;
-}
+ wl12xx_debugfs_init(wl);
-extern struct wl12xx_if_operations wl12xx_spi_ops;
+ wl12xx_notice("initialized");
+
+ ret = 0;
+out:
+ return ret;
+}
#define WL12XX_DEFAULT_CHANNEL 1
-static int __devinit wl12xx_probe(struct spi_device *spi)
+struct ieee80211_hw *wl12xx_alloc_hw(void)
{
- struct wl12xx_platform_data *pdata;
struct ieee80211_hw *hw;
struct wl12xx *wl;
- int ret, i;
+ int i;
static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
- pdata = spi->dev.platform_data;
- if (!pdata) {
- wl12xx_error("no platform data");
- return -ENODEV;
- }
-
hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops);
if (!hw) {
wl12xx_error("could not alloc ieee80211_hw");
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
wl = hw->priv;
memset(wl, 0, sizeof(*wl));
wl->hw = hw;
- dev_set_drvdata(&spi->dev, wl);
- wl->spi = spi;
- wl->if_ops = &wl12xx_spi_ops;
wl->data_in_count = 0;
@@ -1247,65 +1243,11 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
- /* This is the only SPI value that we need to set here, the rest
- * comes from the board-peripherals file */
- spi->bits_per_word = 32;
-
- ret = spi_setup(spi);
- if (ret < 0) {
- wl12xx_error("spi_setup failed");
- goto out_free;
- }
-
- wl->set_power = pdata->set_power;
- if (!wl->set_power) {
- wl12xx_error("set power function missing in platform data");
- return -ENODEV;
- }
-
- wl->irq = spi->irq;
- if (wl->irq < 0) {
- wl12xx_error("irq missing in platform data");
- return -ENODEV;
- }
-
- ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl);
- if (ret < 0) {
- wl12xx_error("request_irq() failed: %d", ret);
- goto out_free;
- }
-
- set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
-
- disable_irq(wl->irq);
-
- ret = wl12xx_init_ieee80211(wl);
- if (ret)
- goto out_irq;
-
- ret = wl12xx_register_hw(wl);
- if (ret)
- goto out_irq;
-
- wl12xx_debugfs_init(wl);
-
- wl12xx_notice("initialized");
-
- return 0;
-
- out_irq:
- free_irq(wl->irq, wl);
-
- out_free:
- ieee80211_free_hw(hw);
-
- return ret;
+ return hw;
}
-static int __devexit wl12xx_remove(struct spi_device *spi)
+int wl12xx_free_hw(struct wl12xx *wl)
{
- struct wl12xx *wl = dev_get_drvdata(&spi->dev);
-
ieee80211_unregister_hw(wl->hw);
wl12xx_debugfs_exit(wl);
@@ -1321,43 +1263,3 @@ static int __devexit wl12xx_remove(struct spi_device *spi)
return 0;
}
-
-
-static struct spi_driver wl12xx_spi_driver = {
- .driver = {
- .name = "wl12xx",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
-
- .probe = wl12xx_probe,
- .remove = __devexit_p(wl12xx_remove),
-};
-
-static int __init wl12xx_init(void)
-{
- int ret;
-
- ret = spi_register_driver(&wl12xx_spi_driver);
- if (ret < 0) {
- wl12xx_error("failed to register spi driver: %d", ret);
- goto out;
- }
-
-out:
- return ret;
-}
-
-static void __exit wl12xx_exit(void)
-{
- spi_unregister_driver(&wl12xx_spi_driver);
-
- wl12xx_notice("unloaded");
-}
-
-module_init(wl12xx_init);
-module_exit(wl12xx_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <[email protected]>, "
- "Luciano Coelho <[email protected]>");
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index 658464e..852c990 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
+#include <linux/spi/wl12xx.h>
#include "wl12xx.h"
#include "wl12xx_80211.h"
@@ -57,7 +58,7 @@ static void wl12xx_spi_reset(struct wl12xx *wl)
wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
}
-static void wl12xx_spi_init(struct wl12xx *wl)
+static void wl12xx_spi_wake(struct wl12xx *wl)
{
u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
struct spi_transfer t;
@@ -114,7 +115,7 @@ static void wl12xx_spi_init(struct wl12xx *wl)
static void wl12xx_spi_reset_wake(struct wl12xx *wl)
{
wl12xx_spi_reset(wl);
- wl12xx_spi_init(wl);
+ wl12xx_spi_wake(wl);
}
static void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
@@ -188,3 +189,122 @@ const struct wl12xx_if_operations wl12xx_spi_ops = {
.write = wl12xx_spi_write,
.reset = wl12xx_spi_reset_wake,
};
+
+static int __devinit wl12xx_spi_probe(struct spi_device *spi)
+{
+ struct wl12xx_platform_data *pdata;
+ struct ieee80211_hw *hw;
+ struct wl12xx *wl;
+ int ret;
+
+ pdata = spi->dev.platform_data;
+ if (!pdata) {
+ wl12xx_error("no platform data");
+ return -ENODEV;
+ }
+
+ hw = wl12xx_alloc_hw();
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ wl = hw->priv;
+
+ SET_IEEE80211_DEV(hw, &spi->dev);
+ dev_set_drvdata(&spi->dev, wl);
+ wl->spi = spi;
+ wl->if_ops = &wl12xx_spi_ops;
+
+ /* This is the only SPI value that we need to set here, the rest
+ * comes from the board-peripherals file */
+ spi->bits_per_word = 32;
+
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ wl12xx_error("spi_setup failed");
+ goto out_free;
+ }
+
+ wl->set_power = pdata->set_power;
+ if (!wl->set_power) {
+ wl12xx_error("set power function missing in platform data");
+ return -ENODEV;
+ }
+
+ wl->irq = spi->irq;
+ if (wl->irq < 0) {
+ wl12xx_error("irq missing in platform data");
+ return -ENODEV;
+ }
+
+ ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl);
+ if (ret < 0) {
+ wl12xx_error("request_irq() failed: %d", ret);
+ goto out_free;
+ }
+
+ set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
+
+ disable_irq(wl->irq);
+
+ ret = wl12xx_init_ieee80211(wl);
+ if (ret)
+ goto out_irq;
+
+ return 0;
+
+ out_irq:
+ free_irq(wl->irq, wl);
+
+ out_free:
+ ieee80211_free_hw(hw);
+
+ return ret;
+}
+
+static int __devexit wl12xx_spi_remove(struct spi_device *spi)
+{
+ struct wl12xx *wl = dev_get_drvdata(&spi->dev);
+
+ wl12xx_free_hw(wl);
+
+ return 0;
+}
+
+static struct spi_driver wl12xx_spi_driver = {
+ .driver = {
+ .name = "wl12xx",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wl12xx_spi_probe,
+ .remove = __devexit_p(wl12xx_spi_remove),
+};
+
+static int __init wl12xx_spi_init(void)
+{
+ int ret;
+
+ ret = spi_register_driver(&wl12xx_spi_driver);
+ if (ret < 0) {
+ wl12xx_error("failed to register spi driver: %d", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void __exit wl12xx_spi_exit(void)
+{
+ spi_unregister_driver(&wl12xx_spi_driver);
+
+ wl12xx_notice("unloaded");
+}
+
+module_init(wl12xx_spi_init);
+module_exit(wl12xx_spi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kalle Valo <[email protected]>");
+MODULE_AUTHOR("Luciano Coelho <[email protected]>");
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 2079aba..b327a93 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -27,7 +27,6 @@
#include "wl12xx.h"
#include "reg.h"
-#include "spi.h"
#include "tx.h"
#include "ps.h"
#include "io.h"
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index bfabf8f..46d3bc1 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -287,7 +287,7 @@ struct wl12xx {
bool mac80211_registered;
struct spi_device *spi;
- struct wl12xx_if_operations *if_ops;
+ const struct wl12xx_if_operations *if_ops;
void (*set_power)(bool enable);
int irq;
@@ -394,6 +394,11 @@ struct wl12xx {
int wl12xx_plt_start(struct wl12xx *wl);
int wl12xx_plt_stop(struct wl12xx *wl);
+irqreturn_t wl12xx_irq(int irq, void *cookie);
+struct ieee80211_hw *wl12xx_alloc_hw(void);
+int wl12xx_free_hw(struct wl12xx *wl);
+int wl12xx_init_ieee80211(struct wl12xx *wl);
+
#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */
#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS
#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
--
1.6.0.6
Pierre Ossman <[email protected]> writes:
> On Wed, 10 Jun 2009 22:03:00 -0400
> Bob Copeland <[email protected]> wrote:
>
>> This adds the wl12xx_sdio module, enabling the SDIO interface for
>> wl12xx, as used by the Google G1 phone and others.
>>
>> Signed-off-by: Bob Copeland <[email protected]>
>> ---
>
> I think the drivers looks quite ok. There are really just a few things
> I'm concerned about:
>
[...]
> - Why do you have a platform device with the sole purpose of enabling
> power to the SDIO card? Shouldn't this be handled in the arch code?
wl1251 has these lines to the host:
o four lines for SDIO or SPI, configured to SDIO by default
o power line
o interrupt line
When the power line is pulled up, the chip will power on itself.
Whenever the power line goes down, the chip will power off. For example,
the power line can be controlled with a GPIO pin from the host. But how
the power line is really controlled, is board specific and should be
handled in the board file. And here comes the set_power() function to
the picture. The wl1251 driver will call set_power() function every time
user space calls wlan interface up or down.
Pierre, how do you propose we should do this? I understood based on
discussions from linux-omap that this is a common way.
--
Kalle Valo
2009/6/11 Florian Fainelli <[email protected]>:
> That would be really great. FYI, vlynq bus support was added to -mm tree few
> days ago. Do you guys know how much wl12xx differs from acx111 ?
I don't know offhand how different they are, but http://gitorious.org/wl12xx/
seems to be a small step in that direction...
--
Bob Copeland %% http://www.bobcopeland.com
On Sat, 13 Jun 2009 19:00:41 +0300
Kalle Valo <[email protected]> wrote:
>
> When the power line is pulled up, the chip will power on itself.
> Whenever the power line goes down, the chip will power off. For example,
> the power line can be controlled with a GPIO pin from the host. But how
> the power line is really controlled, is board specific and should be
> handled in the board file. And here comes the set_power() function to
> the picture. The wl1251 driver will call set_power() function every time
> user space calls wlan interface up or down.
>
That doesn't make sense. If the card doesn't have power then there will
be no device and no interface to bring up.
I suspect we're not talking about the same thing. I'm referring to this:
+static int wifi_probe(struct platform_device *pdev)
+{
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *)(pdev->dev.platform_data);
+
+ if (!wifi_ctrl)
+ return -ENODEV;
+
+ wifi_ctrl->set_power(1); /* Power On */
+ wifi_ctrl->set_reset(0); /* Reset clear */
+ wifi_ctrl->set_carddetect(1); /* CardDetect (0->1) */
+
+ return 0;
+}
This seems very board specific and not something that should be in the
chip driver.
> Pierre, how do you propose we should do this? I understood based on
> discussions from linux-omap that this is a common way.
I haven't seen anything like this before, but it might just be that
I've looked in the wrong places.
I think this should be somewhere under arch/ in the board setup code,
where currently you have some code adding the "msm_wifi" platform
device.
(I also agree with Marcel that this looks like RFKILL material)
Rgds
--
-- Pierre Ossman
WARNING: This correspondence is being monitored by the
Swedish government. Make sure your server uses encryption
for SMTP traffic and consider using PGP for end-to-end
encryption.
Remove a dependency on the bus-specific struct device by using wiphy_dev
when requesting firmware.
Signed-off-by: Bob Copeland <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 9ecfb9e..5e975c8 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -75,9 +75,10 @@ static irqreturn_t wl12xx_irq(int irq, void *cookie)
static int wl12xx_fetch_firmware(struct wl12xx *wl)
{
const struct firmware *fw;
+ struct device *dev = wiphy_dev(wl->hw->wiphy);
int ret;
- ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev);
+ ret = request_firmware(&fw, wl->chip.fw_filename, dev);
if (ret < 0) {
wl12xx_error("could not get firmware: %d", ret);
@@ -113,9 +114,10 @@ out:
static int wl12xx_fetch_nvs(struct wl12xx *wl)
{
const struct firmware *fw;
+ struct device *dev = wiphy_dev(wl->hw->wiphy);
int ret;
- ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev);
+ ret = request_firmware(&fw, wl->chip.nvs_filename, dev);
if (ret < 0) {
wl12xx_error("could not get nvs file: %d", ret);
--
1.6.0.6
On Wed, 10 Jun 2009 22:03:00 -0400
Bob Copeland <[email protected]> wrote:
> This adds the wl12xx_sdio module, enabling the SDIO interface for
> wl12xx, as used by the Google G1 phone and others.
>
> Signed-off-by: Bob Copeland <[email protected]>
> ---
I think the drivers looks quite ok. There are really just a few things
I'm concerned about:
- Please put the device id:s in sdio_ids.h. There is no pci-ids
equivalent for SDIO so I'd like to fill up the kernel header with
device ids as much as possible.
- Why do you have a platform device with the sole purpose of enabling
power to the SDIO card? Shouldn't this be handled in the arch code?
> + sdio_set_block_size(func, 512);
Since you do not actually rely on this, why not leave it at the default
value?
> +static void __devexit wl12xx_sdio_remove(struct sdio_func *func)
> +{
> + struct wl12xx *wl = sdio_get_drvdata(func);
> +
> + sdio_claim_host(func);
> + sdio_release_irq(func);
> + sdio_disable_func(func);
> + sdio_release_host(func);
> +
> + wl12xx_free_hw(wl);
> +}
This seems wrong. Shouldn't you unregister the device with the upper
layers first?
Rgds
--
-- Pierre Ossman
WARNING: This correspondence is being monitored by the
Swedish government. Make sure your server uses encryption
for SMTP traffic and consider using PGP for end-to-end
encryption.
On Mon, 22 Jun 2009 08:09:31 +0200
Pierre Ossman <[email protected]> wrote:
> On Sun, 21 Jun 2009 20:05:12 -0400
> Bob Copeland <[email protected]> wrote:
>
> > On Sun, Jun 21, 2009 at 08:38:00PM +0200, Pierre Ossman wrote:
> > > I noticed one more thing though. You call wl12xx_irq() on interrupts,
> > > and that's all you do. So I have to assume that calls back to
> > > wl12xx_sdio_read().
> >
> > It schedules a workqueue, so it shouldn't be a problem.
> >
>
> Ah, I see. In that case you can add:
>
> Acked-by: Pierre Ossman <[email protected]>
>
And just as I hit send I realised another problem...
SDIO interrupts are level interrupts, not edge. That means that the
interrupt source needs to be handled before the interrupt routine
returns or the system will get stuck in a fairly tight loop, rehandling
the same interrupt over and over again.
Has the testing been performed on a host that has proper SDIO interrupt
support, or one that polls? If it's the latter, then you probably have
latent issues that just haven't been noticed yet.
Rgds
--
-- Pierre Ossman
WARNING: This correspondence is being monitored by the
Swedish government. Make sure your server uses encryption
for SMTP traffic and consider using PGP for end-to-end
encryption.
On Wed, 17 Jun 2009 22:25:24 -0400
Bob Copeland <[email protected]> wrote:
>
> Just to follow up now that I've tested that again: the issue is msm_wifi
> setup loads before the mmc host driver, which interferes with mounting the
> sdcard in the other slot. There's also some platform code in the host
> driver that registers callbacks when the wifi driver is loaded, presumably
> to avoid using a timer for card detect.
>
I'm afraid I don't understand the problem. If you power up the card
before the MMC system has started, it should still properly find the
card and activate the wl12xx driver once things are in sync.
> Anyway, this is only compile tested but should work when we get all that
> sorted...
>
Do you want me to merge it?
Rgds
--
-- Pierre Ossman
WARNING: This correspondence is being monitored by the
Swedish government. Make sure your server uses encryption
for SMTP traffic and consider using PGP for end-to-end
encryption.
Le Thursday 11 June 2009 16:38:46 G?bor Stefanik, vous avez ?crit?:
> On Thu, Jun 11, 2009 at 4:02 AM, Bob Copeland<[email protected]> wrote:
> > Here's v2 of the SDIO interface for wl12xx, still with a FIXME or two.
> >
> > For my part, this is mainly a port of the Google/TI Android SDIO
> > interface logic to the existing SPI driver. ?I have confirmed that
> > the driver associates and sends some traffic.
> >
> > Pierre, hoping to get your perspective on the SDIO bits in patch 7,
> > since I very likely don't know what I'm doing :) ?Especially regarding
> > the platform code setup, in which the correct GPIOs have to be written
> > to turn on the device before probe will work. ?For the SPI interface,
> > we use spi_register_board_info() for a similar purpose, but I'm not
> > sure if there is a standard way to do that for SDIO. ?This copies
> > Google's platform driver for now.
> >
> > Conversion to readl/writel etc where appropriate is TODO.
> >
> > Bob Copeland (7):
> > ?wl12xx: separate bus i/o code into io.c
> > ?wl12xx: use wiphy_dev instead of wl->spi->dev
> > ?wl12xx: introduce wl12xx_if_operations struct
> > ?wl12xx: make wl12xx_set_partition bus agnostic
> > ?wl12xx: move module probe methods into spi.c
> > ?wl12xx: split spi interface into separate module
> > ?wl12xx: add sdio support
> >
> > ?drivers/net/wireless/wl12xx/Kconfig ?| ? 24 +++-
> > ?drivers/net/wireless/wl12xx/Makefile | ? 10 +-
> > ?drivers/net/wireless/wl12xx/acx.c ? ?| ? ?3 +-
> > ?drivers/net/wireless/wl12xx/boot.c ? | ? ?3 +-
> > ?drivers/net/wireless/wl12xx/cmd.c ? ?| ? 15 +-
> > ?drivers/net/wireless/wl12xx/event.c ?| ? ?6 +-
> > ?drivers/net/wireless/wl12xx/io.c ? ? | ?181 +++++++++++++++++++++
> > ?drivers/net/wireless/wl12xx/io.h ? ? | ? 62 +++++++
> > ?drivers/net/wireless/wl12xx/main.c ? | ?152 ++++--------------
> > ?drivers/net/wireless/wl12xx/ps.c ? ? | ? ?3 +-
> > ?drivers/net/wireless/wl12xx/rx.c ? ? | ? 10 +-
> > ?drivers/net/wireless/wl12xx/sdio.c ? | ?250
> > +++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/spi.c ? ?| ?289
> > ++++++++++++++------------------- drivers/net/wireless/wl12xx/spi.h ? ?|
> > ? 40 -----
> > ?drivers/net/wireless/wl12xx/tx.c ? ? | ? 64 ++++----
> > ?drivers/net/wireless/wl12xx/wl1251.c | ? ?9 +-
> > ?drivers/net/wireless/wl12xx/wl12xx.h | ? 14 ++-
> > ?17 files changed, 752 insertions(+), 383 deletions(-)
> > ?create mode 100644 drivers/net/wireless/wl12xx/io.c
> > ?create mode 100644 drivers/net/wireless/wl12xx/io.h
> > ?create mode 100644 drivers/net/wireless/wl12xx/sdio.c
>
> Can we expect vlynq any time soon?
That would be really great. FYI, vlynq bus support was added to -mm tree few
days ago. Do you guys know how much wl12xx differs from acx111 ?
--
Best regards, Florian Fainelli
Email : [email protected]
http://openwrt.org
-------------------------------
Bob Copeland <[email protected]> writes:
> On Thu, Jun 11, 2009 at 11:54 AM, Kalle Valo<[email protected]> wrote:
>> Sorry about the mess, I have been sitting on top of the wl1251 patches
>> way too long.
>
> No worries, yeah if you rebase them I'll test the result...
Excellent. Thanks for understanding :)
> patch 7 won't compile in a vanilla tree until the platform stuff is
> straightened out, but the rest should be OK for inclusion I think.
Ok, good to know. Let's try to find a generic solution for sdio
configuration so that wl12xx would work in different platforms. For
example also OpenPandora has wl1251 with sdio, it would be cool to
support that as well.
--
Kalle Valo
On Thu, Jun 11, 2009 at 4:02 AM, Bob Copeland<[email protected]> wrote:
> Here's v2 of the SDIO interface for wl12xx, still with a FIXME or two.
>
> For my part, this is mainly a port of the Google/TI Android SDIO
> interface logic to the existing SPI driver. ?I have confirmed that
> the driver associates and sends some traffic.
>
> Pierre, hoping to get your perspective on the SDIO bits in patch 7,
> since I very likely don't know what I'm doing :) ?Especially regarding
> the platform code setup, in which the correct GPIOs have to be written
> to turn on the device before probe will work. ?For the SPI interface,
> we use spi_register_board_info() for a similar purpose, but I'm not
> sure if there is a standard way to do that for SDIO. ?This copies
> Google's platform driver for now.
>
> Conversion to readl/writel etc where appropriate is TODO.
>
> Bob Copeland (7):
> ?wl12xx: separate bus i/o code into io.c
> ?wl12xx: use wiphy_dev instead of wl->spi->dev
> ?wl12xx: introduce wl12xx_if_operations struct
> ?wl12xx: make wl12xx_set_partition bus agnostic
> ?wl12xx: move module probe methods into spi.c
> ?wl12xx: split spi interface into separate module
> ?wl12xx: add sdio support
>
> ?drivers/net/wireless/wl12xx/Kconfig ?| ? 24 +++-
> ?drivers/net/wireless/wl12xx/Makefile | ? 10 +-
> ?drivers/net/wireless/wl12xx/acx.c ? ?| ? ?3 +-
> ?drivers/net/wireless/wl12xx/boot.c ? | ? ?3 +-
> ?drivers/net/wireless/wl12xx/cmd.c ? ?| ? 15 +-
> ?drivers/net/wireless/wl12xx/event.c ?| ? ?6 +-
> ?drivers/net/wireless/wl12xx/io.c ? ? | ?181 +++++++++++++++++++++
> ?drivers/net/wireless/wl12xx/io.h ? ? | ? 62 +++++++
> ?drivers/net/wireless/wl12xx/main.c ? | ?152 ++++--------------
> ?drivers/net/wireless/wl12xx/ps.c ? ? | ? ?3 +-
> ?drivers/net/wireless/wl12xx/rx.c ? ? | ? 10 +-
> ?drivers/net/wireless/wl12xx/sdio.c ? | ?250 +++++++++++++++++++++++++++++
> ?drivers/net/wireless/wl12xx/spi.c ? ?| ?289 ++++++++++++++-------------------
> ?drivers/net/wireless/wl12xx/spi.h ? ?| ? 40 -----
> ?drivers/net/wireless/wl12xx/tx.c ? ? | ? 64 ++++----
> ?drivers/net/wireless/wl12xx/wl1251.c | ? ?9 +-
> ?drivers/net/wireless/wl12xx/wl12xx.h | ? 14 ++-
> ?17 files changed, 752 insertions(+), 383 deletions(-)
> ?create mode 100644 drivers/net/wireless/wl12xx/io.c
> ?create mode 100644 drivers/net/wireless/wl12xx/io.h
> ?create mode 100644 drivers/net/wireless/wl12xx/sdio.c
Can we expect vlynq any time soon?
--
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
Hi Bob, Pierre,
On Thu, Jun 18, 2009 at 5:25 AM, Bob Copeland <[email protected]> wrote:
> +#define SDIO_VENDOR_ID_TI ? ? ? ? ? ? ? ? ? ? ?0x104c
> +#define SDIO_DEVICE_ID_TI_WL1251 ? ? ? ? ? ? ? 0x9066
I wonder how those values are derived ?
Are they officially registered anywhere ?
Thanks,
Ohad.
On Wed, Jul 15, 2009 at 10:12:59AM +0300, Ohad Ben-Cohen wrote:
> Hi Bob, Pierre,
>
> On Thu, Jun 18, 2009 at 5:25 AM, Bob Copeland <[email protected]> wrote:
> > +#define SDIO_VENDOR_ID_TI ? ? ? ? ? ? ? ? ? ? ?0x104c
> > +#define SDIO_DEVICE_ID_TI_WL1251 ? ? ? ? ? ? ? 0x9066
>
> I wonder how those values are derived ?
>
> Are they officially registered anywhere ?
This is what the card reports, also you can find it in the TI
vendor drivers. I don't know who the registrar is, but as I
understand, the vendor ID is the same as the PCMCIA vendor ID,
so it's whoever assigns those. I'm sure 0x9066 is defined by
TI.
--
Bob Copeland %% http://www.bobcopeland.com