// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/net/wireless/libertas/if_spi.c
*
* Driver for Marvell SPI WLAN cards.
*
* Copyright 2008 Analog Devices Inc.
*
* Authors:
* Andrey Yurovsky <andrey@cozybit.com>
* Colin McCabe <colin@cozybit.com>
*
* Inspired by if_sdio.c, Copyright 2007-2008 Pierre Ossman
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/hardirq.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <linux/spi/libertas_spi.h>
#include <linux/spi/spi.h>
#include "host.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
#include "if_spi.h"
struct if_spi_packet {
struct list_head list;
u16 blen;
u8 buffer[] __aligned(4);
};
struct if_spi_card {
struct spi_device *spi;
struct lbs_private *priv;
struct libertas_spi_platform_data *pdata;
/* The card ID and card revision, as reported by the hardware. */
u16 card_id;
u8 card_rev;
/* The last time that we initiated an SPU operation */
unsigned long prev_xfer_time;
int use_dummy_writes;
unsigned long spu_port_delay;
unsigned long spu_reg_delay;
/* Handles all SPI communication (except for FW load) */
struct workqueue_struct *workqueue;
struct work_struct packet_work;
struct work_struct resume_work;
u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE];
/* A buffer of incoming packets from libertas core.
* Since we can't sleep in hw_host_to_card, we have to buffer
* them. */
struct list_head cmd_packet_list;
struct list_head data_packet_list;
/* Protects cmd_packet_list and data_packet_list */
spinlock_t buffer_lock;
/* True is card suspended */
u8 suspended;
};
static void free_if_spi_card(struct if_spi_card *card)
{
struct if_spi_packet *packet, *tmp;
list_for_each_entry_safe(packet, tmp, &card->cmd_packet_list, list) {
list_del(&packet->list);
kfree(packet);
}
list_for_each_entry_safe(packet, tmp, &card->data_packet_list, list) {
list_del(&packet->list);
kfree(packet);
}
kfree(card);
}
#define MODEL_8385 0x04
#define MODEL_8686 0x0b
#define MODEL_8688 0x10
static const struct lbs_fw_table fw_table[] = {
{ MODEL_8385, "libertas/gspi8385_helper.bin", "libertas/gspi8385.bin" },
{ MODEL_8385, "libertas/gspi8385_hlp.bin", "libertas/gspi8385.bin" },
{ MODEL_8686, "libertas/gspi8686_v9_helper.bin", "libertas/gspi8686_v9.bin" },
{ MODEL_8686, "libertas/gspi8686_hlp.bin", "libertas/gspi8686.bin" },
{ MODEL_8688, "libertas/gspi8688_helper.bin", "libertas/gspi8688.bin" },
{ 0, NULL, NULL }
};
MODULE_FIRMWARE("libertas/gspi8385_helper.bin");
MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
MODULE_FIRMWARE("libertas/gspi8385.bin");
MODULE_FIRMWARE("libertas/gspi8686_v9_helper.bin");
MODULE_FIRMWARE("libertas/gspi8686_v9.bin");
MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
MODULE_FIRMWARE("libertas/gspi8686.bin");
MODULE_FIRMWARE("libertas/gspi8688_helper.bin");
MODULE_FIRMWARE("libertas/gspi8688.bin");
/*
* SPI Interface Unit Routines
*
* The SPU sits between the host and the WLAN module.
* All communication with the firmware is through SPU transactions.
*
* First we have to put a SPU register name on the bus. Then we can
* eith