// SPDX-License-Identifier: GPL-2.0
/*
* Driver for KeyStream, KS7010 based SDIO cards.
*
* Copyright (C) 2006-2008 KeyStream Corp.
* Copyright (C) 2009 Renesas Technology Corp.
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
*/
#include <linux/atomic.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include "ks_wlan.h"
#include "ks_hostif.h"
#define ROM_FILE "ks7010sd.rom"
/* SDIO KeyStream vendor and device */
#define SDIO_VENDOR_ID_KS_CODE_A 0x005b
#define SDIO_VENDOR_ID_KS_CODE_B 0x0023
/* Older sources suggest earlier versions were named 7910 or 79xx */
#define SDIO_DEVICE_ID_KS_7010 0x7910
/* Read/Write Status Register */
#define READ_STATUS_REG 0x000000
#define WRITE_STATUS_REG 0x00000C
enum reg_status_type {
REG_STATUS_BUSY,
REG_STATUS_IDLE
};
/* Read Index Register */
#define READ_INDEX_REG 0x000004
/* Read Data Size Register */
#define READ_DATA_SIZE_REG 0x000008
/* Write Index Register */
#define WRITE_INDEX_REG 0x000010
/*
* Write Status/Read Data Size Register
* for network packet (less than 2048 bytes data)
*/
#define WSTATUS_RSIZE_REG 0x000014
/* Write Status Register value */
#define WSTATUS_MASK 0x80
/* Read Data Size Register value [10:4] */
#define RSIZE_MASK 0x7F
/* ARM to SD interrupt Enable */
#define INT_ENABLE_REG 0x000020
/* ARM to SD interrupt Pending */
#define INT_PENDING_REG 0x000024
#define INT_GCR_B BIT(7)
#define INT_GCR_A BIT(6)
#define INT_WRITE_STATUS BIT(5)
#define INT_WRITE_INDEX BIT(4)
#define INT_WRITE_SIZE BIT(3)
#define INT_READ_STATUS BIT(2)
#define INT_READ_INDEX BIT(1)
#define INT_READ_SIZE BIT(0)
/* General Communication Register A */
#define GCR_A_REG 0x000028
enum gen_com_reg_a {
GCR_A_INIT,
GCR_A_REMAP,
GCR_A_RUN
};
/* General Communication Register B */
#define GCR_B_REG 0x00002C
enum gen_com_reg_b {
GCR_B_ACTIVE,
GCR_B_DOZE
};
/* Wakeup Register */
#define WAKEUP_REG 0x008018
#define WAKEUP_REQ 0x5a
/* AHB Data Window 0x010000-0x01FFFF */
#define DATA_WINDOW 0x010000
#define WINDOW_SIZE (64 * 1024)
#define KS7010_IRAM_ADDRESS 0x06000000
#define KS7010_IO_BLOCK_SIZE 512
/**
* struct ks_sdio_card - SDIO device data.
*
* Structure is used as the &struct sdio_func private data.
*
* @func: Pointer to the SDIO function device.
* @priv: Pointer to the &struct net_device private data.
*/
struct ks_sdio_card {
struct sdio_func *func;
struct ks_wlan_private *priv;
};
static struct sdio_func *ks7010_to_func(struct ks_wlan_private *priv)
{
struct ks_sdio_card *ks_sdio = priv->if_hw;
return ks_sdio->func;
}
/* Read single byte from device address into byte (CMD52) */
static int ks7010_sdio_readb(struct ks_wlan_private *priv,
u32 address, u8 *byte)
{
struct sdio_func *func = ks7010_to_func(priv);
int ret;
*byte = sdio_readb(func, address, &ret);
return ret;
}
/* Read length bytes from device address into buffer (CMD53) */
static int ks7010_sdio_read(struct ks_wlan_private *priv, u32 address,
u8 *buffer, unsigned int length)
{
struct sdio_func *func = ks7010_to_func(priv);
return sdio_memcpy_fromio(func, buffer, address, length);
}
/* Write single byte to device address (CMD52) */
static int ks7010_sdio_writeb(struct ks_wlan_private *priv,
u32 address, u8 byte)
{
struct sdio_func *func = ks7010_to_func(priv);
int ret;
sdio_writeb(func, byte, address, &ret);
return ret;
}
/* Write length bytes to device address from buffer (CMD53) */
static int ks7010_sdio_write(struct ks_wlan_private *priv, u32 address,
u8 *buffer, unsigned int length)
{
struct sdio_func *func = ks7010_to_func(priv);
return sdio_memcpy_toio(func, address, buffer, length);
}
static void ks_wlan_hw_sleep_doze_request(struct ks_wlan_private *priv)
{
int ret;
/* clear request */
atomic_set(&priv->sleepstatus.doze_request, 0);
if (atomic_read(&priv->sleepstatus.status) == 0) {
ret = ks7010_sdio_writeb(priv, GCR_B_REG, GCR_B_DOZE);
if (ret) {
netdev_err(priv->net_dev, "write GCR_B_REG\n");
goto set_sleep_mode;
}
atomic_set(&priv->sleepstatus.status, 1);
priv->last_doze =