Commit 9e49a9d3 authored by John W. Linville's avatar John W. Linville
parents 0b21eb9a 789e90e5
......@@ -93,8 +93,7 @@ static void wl1251_spi_wake(struct wl1251 *wl)
memset(&t, 0, sizeof(t));
spi_message_init(&m);
/*
* Set WSPI_INIT_COMMAND
/* Set WSPI_INIT_COMMAND
* the data is being send from the MSB to LSB
*/
cmd[2] = 0xff;
......@@ -262,7 +261,8 @@ static int wl1251_spi_probe(struct spi_device *spi)
wl->if_ops = &wl1251_spi_ops;
/* This is the only SPI value that we need to set here, the rest
* comes from the board-peripherals file */
* comes from the board-peripherals file
*/
spi->bits_per_word = 32;
ret = spi_setup(spi);
......@@ -329,29 +329,7 @@ static struct spi_driver wl1251_spi_driver = {
.remove = wl1251_spi_remove,
};
static int __init wl1251_spi_init(void)
{
int ret;
ret = spi_register_driver(&wl1251_spi_driver);
if (ret < 0) {
wl1251_error("failed to register spi driver: %d", ret);
goto out;
}
out:
return ret;
}
static void __exit wl1251_spi_exit(void)
{
spi_unregister_driver(&wl1251_spi_driver);
wl1251_notice("unloaded");
}
module_init(wl1251_spi_init);
module_exit(wl1251_spi_exit);
module_spi_driver(wl1251_spi_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
......
......@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/ip.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
#include "../wlcore/wlcore.h"
#include "../wlcore/debug.h"
......@@ -594,8 +595,8 @@ static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
.mem3 = { .start = 0x00000000, .size = 0x00000000 },
},
[PART_PHY_INIT] = {
.mem = { .start = 0x80926000,
.size = sizeof(struct wl18xx_mac_and_phy_params) },
.mem = { .start = WL18XX_PHY_INIT_MEM_ADDR,
.size = WL18XX_PHY_INIT_MEM_SIZE },
.reg = { .start = 0x00000000, .size = 0x00000000 },
.mem2 = { .start = 0x00000000, .size = 0x00000000 },
.mem3 = { .start = 0x00000000, .size = 0x00000000 },
......@@ -799,6 +800,9 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
u32 tmp;
int ret;
BUILD_BUG_ON(sizeof(struct wl18xx_mac_and_phy_params) >
WL18XX_PHY_INIT_MEM_SIZE);
ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
if (ret < 0)
goto out;
......@@ -815,6 +819,35 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
ret = wlcore_read32(wl, WL18XX_SCR_PAD2, &tmp);
if (ret < 0)
goto out;
/*
* Workaround for FDSP code RAM corruption (needed for PG2.1
* and newer; for older chips it's a NOP). Change FDSP clock
* settings so that it's muxed to the ATGP clock instead of
* its own clock.
*/
ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
if (ret < 0)
goto out;
/* disable FDSP clock */
ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
MEM_FDSP_CLK_120_DISABLE);
if (ret < 0)
goto out;
/* set ATPG clock toward FDSP Code RAM rather than its own clock */
ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
MEM_FDSP_CODERAM_FUNC_CLK_SEL);
if (ret < 0)
goto out;
/* re-enable FDSP clock */
ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
MEM_FDSP_CLK_120_ENABLE);
out:
return ret;
......@@ -1286,6 +1319,16 @@ static int wl18xx_get_mac(struct wl1271 *wl)
((mac1 & 0xff000000) >> 24);
wl->fuse_nic_addr = (mac1 & 0xffffff);
if (!wl->fuse_oui_addr && !wl->fuse_nic_addr) {
u8 mac[ETH_ALEN];
eth_random_addr(mac);
wl->fuse_oui_addr = (mac[0] << 16) + (mac[1] << 8) + mac[2];
wl->fuse_nic_addr = (mac[3] << 16) + (mac[4] << 8) + mac[5];
wl1271_warning("MAC address from fuse not available, using random locally administered addresses.");
}
ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
out:
......
......@@ -38,6 +38,9 @@
#define WL18XX_REG_BOOT_PART_SIZE 0x00014578
#define WL18XX_PHY_INIT_MEM_ADDR 0x80926000
#define WL18XX_PHY_END_MEM_ADDR 0x8093CA44
#define WL18XX_PHY_INIT_MEM_SIZE \
(WL18XX_PHY_END_MEM_ADDR - WL18XX_PHY_INIT_MEM_ADDR)
#define WL18XX_SDIO_WSPI_BASE (WL18XX_REGISTERS_BASE)
#define WL18XX_REG_CONFIG_BASE (WL18XX_REGISTERS_BASE + 0x02000)
......@@ -217,4 +220,16 @@ static const char * const rdl_names[] = {
[RDL_4_SP] = "1897 MIMO",
};
/* FPGA_SPARE_1 register - used to change the PHY ATPG clock at boot time */
#define WL18XX_PHY_FPGA_SPARE_1 0x8093CA40
/* command to disable FDSP clock */
#define MEM_FDSP_CLK_120_DISABLE 0x80000000
/* command to set ATPG clock toward FDSP Code RAM rather than its own clock */
#define MEM_FDSP_CODERAM_FUNC_CLK_SEL 0xC0000000
/* command to re-enable FDSP clock */
#define MEM_FDSP_CLK_120_ENABLE 0x40000000
#endif /* __REG_H__ */
wlcore-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \
boot.o init.o debugfs.o scan.o
boot.o init.o debugfs.o scan.o sysfs.o
wlcore_spi-objs = spi.o
wlcore_sdio-objs = sdio.o
......
This diff is collapsed.
......@@ -110,7 +110,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
DECLARE_COMPLETION_ONSTACK(compl);
unsigned long flags;
int ret;
u32 start_time = jiffies;
unsigned long start_time = jiffies;
bool pending = false;
/*
......
......@@ -434,19 +434,7 @@ static struct spi_driver wl1271_spi_driver = {
.remove = wl1271_remove,
};
static int __init wl1271_init(void)
{
return spi_register_driver(&wl1271_spi_driver);
}
static void __exit wl1271_exit(void)
{
spi_unregister_driver(&wl1271_spi_driver);
}
module_init(wl1271_init);
module_exit(wl1271_exit);
module_spi_driver(wl1271_spi_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
......
/*
* This file is part of wlcore
*
* Copyright (C) 2013 Texas Instruments Inc.
*
* 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 "wlcore.h"
#include "debug.h"
#include "ps.h"
#include "sysfs.h"
static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
len = PAGE_SIZE;
mutex_lock(&wl->mutex);
len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
wl->sg_enabled);
mutex_unlock(&wl->mutex);
return len;
}
static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct wl1271 *wl = dev_get_drvdata(dev);
unsigned long res;
int ret;
ret = kstrtoul(buf, 10, &res);
if (ret < 0) {
wl1271_warning("incorrect value written to bt_coex_mode");
return count;
}
mutex_lock(&wl->mutex);
res = !!res;
if (res == wl->sg_enabled)
goto out;
wl->sg_enabled = res;
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
wl1271_acx_sg_enable(wl, wl->sg_enabled);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return count;
}
static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
wl1271_sysfs_show_bt_coex_state,
wl1271_sysfs_store_bt_coex_state);
static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
len = PAGE_SIZE;
mutex_lock(&wl->mutex);
if (wl->hw_pg_ver >= 0)
len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
else
len = snprintf(buf, len, "n/a\n");
mutex_unlock(&wl->mutex);
return len;
}
static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
wl1271_sysfs_show_hw_pg_ver, NULL);
static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buffer, loff_t pos, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
int ret;
ret = mutex_lock_interruptible(&wl->mutex);
if (ret < 0)
return -ERESTARTSYS;
/* Let only one thread read the log at a time, blocking others */
while (wl->fwlog_size == 0) {
DEFINE_WAIT(wait);
prepare_to_wait_exclusive(&wl->fwlog_waitq,
&wait,
TASK_INTERRUPTIBLE);
if (wl->fwlog_size != 0) {
finish_wait(&wl->fwlog_waitq, &wait);
break;
}
mutex_unlock(&wl->mutex);
schedule();
finish_wait(&wl->fwlog_waitq, &wait);
if (signal_pending(current))
return -ERESTARTSYS;
ret = mutex_lock_interruptible(&wl->mutex);
if (ret < 0)
return -ERESTARTSYS;
}
/* Check if the fwlog is still valid */
if (wl->fwlog_size < 0) {
mutex_unlock(&wl->mutex);
return 0;
}
/* Seeking is not supported - old logs are not kept. Disregard pos. */
len = min(count, (size_t)wl->fwlog_size);
wl->fwlog_size -= len;
memcpy(buffer, wl->fwlog, len);
/* Make room for new messages */
memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
mutex_unlock(&wl->mutex);
return len;
}
static struct bin_attribute fwlog_attr = {
.attr = {.name = "fwlog", .mode = S_IRUSR},
.read = wl1271_sysfs_read_fwlog,
};
int wlcore_sysfs_init(struct wl1271 *wl)
{
int ret;
/* Create sysfs file to control bt coex state */
ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
if (ret < 0) {
wl1271_error("failed to create sysfs file bt_coex_state");
goto out;
}
/* Create sysfs file to get HW PG version */
ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
if (ret < 0) {
wl1271_error("failed to create sysfs file hw_pg_ver");
goto out_bt_coex_state;
}
/* Create sysfs file for the FW log */
ret = device_create_bin_file(wl->dev, &fwlog_attr);
if (ret < 0) {
wl1271_error("failed to create sysfs file fwlog");
goto out_hw_pg_ver;
}
goto out;
out_hw_pg_ver:
device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
out_bt_coex_state:
device_remove_file(wl->dev, &dev_attr_bt_coex_state);
out:
return ret;
}
void wlcore_sysfs_free(struct wl1271 *wl)
{
device_remove_bin_file(wl->dev, &fwlog_attr);
device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
device_remove_file(wl->dev, &dev_attr_bt_coex_state);
}
/*
* This file is part of wlcore
*
* Copyright (C) 2013 Texas Instruments Inc.
*
* 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 __SYSFS_H__
#define __SYSFS_H__
int wlcore_sysfs_init(struct wl1271 *wl);
void wlcore_sysfs_free(struct wl1271 *wl);
#endif
......@@ -386,7 +386,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
(cipher == WLAN_CIPHER_SUITE_WEP104);
if (unlikely(is_wep && wlvif->default_key != idx)) {
if (WARN_ON(is_wep && wlvif->default_key != idx)) {
ret = wl1271_set_default_wep_key(wl, wlvif, idx);
if (ret < 0)
return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment