18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Mac80211 SPI driver for ST-Ericsson CW1200 device
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2011, Sagrad Inc.
68c2ecf20Sopenharmony_ci * Author:  Solomon Peachy <speachy@sagrad.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Based on cw1200_sdio.c
98c2ecf20Sopenharmony_ci * Copyright (c) 2010, ST-Ericsson
108c2ecf20Sopenharmony_ci * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/gpio.h>
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
178c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
188c2ecf20Sopenharmony_ci#include <net/mac80211.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
218c2ecf20Sopenharmony_ci#include <linux/device.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "cw1200.h"
248c2ecf20Sopenharmony_ci#include "hwbus.h"
258c2ecf20Sopenharmony_ci#include <linux/platform_data/net-cw1200.h>
268c2ecf20Sopenharmony_ci#include "hwio.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>");
298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("mac80211 ST-Ericsson CW1200 SPI driver");
308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
318c2ecf20Sopenharmony_ciMODULE_ALIAS("spi:cw1200_wlan_spi");
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/* #define SPI_DEBUG */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct hwbus_priv {
368c2ecf20Sopenharmony_ci	struct spi_device	*func;
378c2ecf20Sopenharmony_ci	struct cw1200_common	*core;
388c2ecf20Sopenharmony_ci	const struct cw1200_platform_data_spi *pdata;
398c2ecf20Sopenharmony_ci	spinlock_t		lock; /* Serialize all bus operations */
408c2ecf20Sopenharmony_ci	wait_queue_head_t       wq;
418c2ecf20Sopenharmony_ci	int claimed;
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2)
458c2ecf20Sopenharmony_ci#define SET_WRITE 0x7FFF /* usage: and operation */
468c2ecf20Sopenharmony_ci#define SET_READ 0x8000  /* usage: or operation */
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* Notes on byte ordering:
498c2ecf20Sopenharmony_ci   LE:  B0 B1 B2 B3
508c2ecf20Sopenharmony_ci   BE:  B3 B2 B1 B0
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci   Hardware expects 32-bit data to be written as 16-bit BE words:
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci   B1 B0 B3 B2
558c2ecf20Sopenharmony_ci*/
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic int cw1200_spi_memcpy_fromio(struct hwbus_priv *self,
588c2ecf20Sopenharmony_ci				     unsigned int addr,
598c2ecf20Sopenharmony_ci				     void *dst, int count)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	int ret, i;
628c2ecf20Sopenharmony_ci	u16 regaddr;
638c2ecf20Sopenharmony_ci	struct spi_message      m;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	struct spi_transfer     t_addr = {
668c2ecf20Sopenharmony_ci		.tx_buf         = &regaddr,
678c2ecf20Sopenharmony_ci		.len            = sizeof(regaddr),
688c2ecf20Sopenharmony_ci	};
698c2ecf20Sopenharmony_ci	struct spi_transfer     t_msg = {
708c2ecf20Sopenharmony_ci		.rx_buf         = dst,
718c2ecf20Sopenharmony_ci		.len            = count,
728c2ecf20Sopenharmony_ci	};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	regaddr = (SDIO_TO_SPI_ADDR(addr))<<12;
758c2ecf20Sopenharmony_ci	regaddr |= SET_READ;
768c2ecf20Sopenharmony_ci	regaddr |= (count>>1);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#ifdef SPI_DEBUG
798c2ecf20Sopenharmony_ci	pr_info("READ : %04d from 0x%02x (%04x)\n", count, addr, regaddr);
808c2ecf20Sopenharmony_ci#endif
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* Header is LE16 */
838c2ecf20Sopenharmony_ci	regaddr = cpu_to_le16(regaddr);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* We have to byteswap if the SPI bus is limited to 8b operation
868c2ecf20Sopenharmony_ci	   or we are running on a Big Endian system
878c2ecf20Sopenharmony_ci	*/
888c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
898c2ecf20Sopenharmony_ci	if (self->func->bits_per_word == 8)
908c2ecf20Sopenharmony_ci#endif
918c2ecf20Sopenharmony_ci		regaddr = swab16(regaddr);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	spi_message_init(&m);
948c2ecf20Sopenharmony_ci	spi_message_add_tail(&t_addr, &m);
958c2ecf20Sopenharmony_ci	spi_message_add_tail(&t_msg, &m);
968c2ecf20Sopenharmony_ci	ret = spi_sync(self->func, &m);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#ifdef SPI_DEBUG
998c2ecf20Sopenharmony_ci	pr_info("READ : ");
1008c2ecf20Sopenharmony_ci	for (i = 0; i < t_addr.len; i++)
1018c2ecf20Sopenharmony_ci		printk("%02x ", ((u8 *)t_addr.tx_buf)[i]);
1028c2ecf20Sopenharmony_ci	printk(" : ");
1038c2ecf20Sopenharmony_ci	for (i = 0; i < t_msg.len; i++)
1048c2ecf20Sopenharmony_ci		printk("%02x ", ((u8 *)t_msg.rx_buf)[i]);
1058c2ecf20Sopenharmony_ci	printk("\n");
1068c2ecf20Sopenharmony_ci#endif
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/* We have to byteswap if the SPI bus is limited to 8b operation
1098c2ecf20Sopenharmony_ci	   or we are running on a Big Endian system
1108c2ecf20Sopenharmony_ci	*/
1118c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
1128c2ecf20Sopenharmony_ci	if (self->func->bits_per_word == 8)
1138c2ecf20Sopenharmony_ci#endif
1148c2ecf20Sopenharmony_ci	{
1158c2ecf20Sopenharmony_ci		uint16_t *buf = (uint16_t *)dst;
1168c2ecf20Sopenharmony_ci		for (i = 0; i < ((count + 1) >> 1); i++)
1178c2ecf20Sopenharmony_ci			buf[i] = swab16(buf[i]);
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return ret;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic int cw1200_spi_memcpy_toio(struct hwbus_priv *self,
1248c2ecf20Sopenharmony_ci				   unsigned int addr,
1258c2ecf20Sopenharmony_ci				   const void *src, int count)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	int rval, i;
1288c2ecf20Sopenharmony_ci	u16 regaddr;
1298c2ecf20Sopenharmony_ci	struct spi_transfer     t_addr = {
1308c2ecf20Sopenharmony_ci		.tx_buf         = &regaddr,
1318c2ecf20Sopenharmony_ci		.len            = sizeof(regaddr),
1328c2ecf20Sopenharmony_ci	};
1338c2ecf20Sopenharmony_ci	struct spi_transfer     t_msg = {
1348c2ecf20Sopenharmony_ci		.tx_buf         = src,
1358c2ecf20Sopenharmony_ci		.len            = count,
1368c2ecf20Sopenharmony_ci	};
1378c2ecf20Sopenharmony_ci	struct spi_message      m;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	regaddr = (SDIO_TO_SPI_ADDR(addr))<<12;
1408c2ecf20Sopenharmony_ci	regaddr &= SET_WRITE;
1418c2ecf20Sopenharmony_ci	regaddr |= (count>>1);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci#ifdef SPI_DEBUG
1448c2ecf20Sopenharmony_ci	pr_info("WRITE: %04d  to  0x%02x (%04x)\n", count, addr, regaddr);
1458c2ecf20Sopenharmony_ci#endif
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* Header is LE16 */
1488c2ecf20Sopenharmony_ci	regaddr = cpu_to_le16(regaddr);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* We have to byteswap if the SPI bus is limited to 8b operation
1518c2ecf20Sopenharmony_ci	   or we are running on a Big Endian system
1528c2ecf20Sopenharmony_ci	*/
1538c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
1548c2ecf20Sopenharmony_ci	if (self->func->bits_per_word == 8)
1558c2ecf20Sopenharmony_ci#endif
1568c2ecf20Sopenharmony_ci	{
1578c2ecf20Sopenharmony_ci		uint16_t *buf = (uint16_t *)src;
1588c2ecf20Sopenharmony_ci	        regaddr = swab16(regaddr);
1598c2ecf20Sopenharmony_ci		for (i = 0; i < ((count + 1) >> 1); i++)
1608c2ecf20Sopenharmony_ci			buf[i] = swab16(buf[i]);
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci#ifdef SPI_DEBUG
1648c2ecf20Sopenharmony_ci	pr_info("WRITE: ");
1658c2ecf20Sopenharmony_ci	for (i = 0; i < t_addr.len; i++)
1668c2ecf20Sopenharmony_ci		printk("%02x ", ((u8 *)t_addr.tx_buf)[i]);
1678c2ecf20Sopenharmony_ci	printk(" : ");
1688c2ecf20Sopenharmony_ci	for (i = 0; i < t_msg.len; i++)
1698c2ecf20Sopenharmony_ci		printk("%02x ", ((u8 *)t_msg.tx_buf)[i]);
1708c2ecf20Sopenharmony_ci	printk("\n");
1718c2ecf20Sopenharmony_ci#endif
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	spi_message_init(&m);
1748c2ecf20Sopenharmony_ci	spi_message_add_tail(&t_addr, &m);
1758c2ecf20Sopenharmony_ci	spi_message_add_tail(&t_msg, &m);
1768c2ecf20Sopenharmony_ci	rval = spi_sync(self->func, &m);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci#ifdef SPI_DEBUG
1798c2ecf20Sopenharmony_ci	pr_info("WROTE: %d\n", m.actual_length);
1808c2ecf20Sopenharmony_ci#endif
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
1838c2ecf20Sopenharmony_ci	/* We have to byteswap if the SPI bus is limited to 8b operation */
1848c2ecf20Sopenharmony_ci	if (self->func->bits_per_word == 8)
1858c2ecf20Sopenharmony_ci#endif
1868c2ecf20Sopenharmony_ci	{
1878c2ecf20Sopenharmony_ci		uint16_t *buf = (uint16_t *)src;
1888c2ecf20Sopenharmony_ci		for (i = 0; i < ((count + 1) >> 1); i++)
1898c2ecf20Sopenharmony_ci			buf[i] = swab16(buf[i]);
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci	return rval;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic void cw1200_spi_lock(struct hwbus_priv *self)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	unsigned long flags;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	DECLARE_WAITQUEUE(wait, current);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	might_sleep();
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	add_wait_queue(&self->wq, &wait);
2038c2ecf20Sopenharmony_ci	spin_lock_irqsave(&self->lock, flags);
2048c2ecf20Sopenharmony_ci	while (1) {
2058c2ecf20Sopenharmony_ci		set_current_state(TASK_UNINTERRUPTIBLE);
2068c2ecf20Sopenharmony_ci		if (!self->claimed)
2078c2ecf20Sopenharmony_ci			break;
2088c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&self->lock, flags);
2098c2ecf20Sopenharmony_ci		schedule();
2108c2ecf20Sopenharmony_ci		spin_lock_irqsave(&self->lock, flags);
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci	set_current_state(TASK_RUNNING);
2138c2ecf20Sopenharmony_ci	self->claimed = 1;
2148c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&self->lock, flags);
2158c2ecf20Sopenharmony_ci	remove_wait_queue(&self->wq, &wait);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic void cw1200_spi_unlock(struct hwbus_priv *self)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	unsigned long flags;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	spin_lock_irqsave(&self->lock, flags);
2258c2ecf20Sopenharmony_ci	self->claimed = 0;
2268c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&self->lock, flags);
2278c2ecf20Sopenharmony_ci	wake_up(&self->wq);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	return;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct hwbus_priv *self = dev_id;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (self->core) {
2378c2ecf20Sopenharmony_ci		cw1200_spi_lock(self);
2388c2ecf20Sopenharmony_ci		cw1200_irq_handler(self->core);
2398c2ecf20Sopenharmony_ci		cw1200_spi_unlock(self);
2408c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
2418c2ecf20Sopenharmony_ci	} else {
2428c2ecf20Sopenharmony_ci		return IRQ_NONE;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic int cw1200_spi_irq_subscribe(struct hwbus_priv *self)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	int ret;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	pr_debug("SW IRQ subscribe\n");
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	ret = request_threaded_irq(self->func->irq, NULL,
2538c2ecf20Sopenharmony_ci				   cw1200_spi_irq_handler,
2548c2ecf20Sopenharmony_ci				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
2558c2ecf20Sopenharmony_ci				   "cw1200_wlan_irq", self);
2568c2ecf20Sopenharmony_ci	if (WARN_ON(ret < 0))
2578c2ecf20Sopenharmony_ci		goto exit;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	ret = enable_irq_wake(self->func->irq);
2608c2ecf20Sopenharmony_ci	if (WARN_ON(ret))
2618c2ecf20Sopenharmony_ci		goto free_irq;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return 0;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cifree_irq:
2668c2ecf20Sopenharmony_ci	free_irq(self->func->irq, self);
2678c2ecf20Sopenharmony_ciexit:
2688c2ecf20Sopenharmony_ci	return ret;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic void cw1200_spi_irq_unsubscribe(struct hwbus_priv *self)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	pr_debug("SW IRQ unsubscribe\n");
2748c2ecf20Sopenharmony_ci	disable_irq_wake(self->func->irq);
2758c2ecf20Sopenharmony_ci	free_irq(self->func->irq, self);
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	if (pdata->reset) {
2818c2ecf20Sopenharmony_ci		gpio_set_value(pdata->reset, 0);
2828c2ecf20Sopenharmony_ci		msleep(30); /* Min is 2 * CLK32K cycles */
2838c2ecf20Sopenharmony_ci		gpio_free(pdata->reset);
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (pdata->power_ctrl)
2878c2ecf20Sopenharmony_ci		pdata->power_ctrl(pdata, false);
2888c2ecf20Sopenharmony_ci	if (pdata->clk_ctrl)
2898c2ecf20Sopenharmony_ci		pdata->clk_ctrl(pdata, false);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return 0;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	/* Ensure I/Os are pulled low */
2978c2ecf20Sopenharmony_ci	if (pdata->reset) {
2988c2ecf20Sopenharmony_ci		gpio_request(pdata->reset, "cw1200_wlan_reset");
2998c2ecf20Sopenharmony_ci		gpio_direction_output(pdata->reset, 0);
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci	if (pdata->powerup) {
3028c2ecf20Sopenharmony_ci		gpio_request(pdata->powerup, "cw1200_wlan_powerup");
3038c2ecf20Sopenharmony_ci		gpio_direction_output(pdata->powerup, 0);
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci	if (pdata->reset || pdata->powerup)
3068c2ecf20Sopenharmony_ci		msleep(10); /* Settle time? */
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	/* Enable 3v3 and 1v8 to hardware */
3098c2ecf20Sopenharmony_ci	if (pdata->power_ctrl) {
3108c2ecf20Sopenharmony_ci		if (pdata->power_ctrl(pdata, true)) {
3118c2ecf20Sopenharmony_ci			pr_err("power_ctrl() failed!\n");
3128c2ecf20Sopenharmony_ci			return -1;
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/* Enable CLK32K */
3178c2ecf20Sopenharmony_ci	if (pdata->clk_ctrl) {
3188c2ecf20Sopenharmony_ci		if (pdata->clk_ctrl(pdata, true)) {
3198c2ecf20Sopenharmony_ci			pr_err("clk_ctrl() failed!\n");
3208c2ecf20Sopenharmony_ci			return -1;
3218c2ecf20Sopenharmony_ci		}
3228c2ecf20Sopenharmony_ci		msleep(10); /* Delay until clock is stable for 2 cycles */
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	/* Enable POWERUP signal */
3268c2ecf20Sopenharmony_ci	if (pdata->powerup) {
3278c2ecf20Sopenharmony_ci		gpio_set_value(pdata->powerup, 1);
3288c2ecf20Sopenharmony_ci		msleep(250); /* or more..? */
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci	/* Enable RSTn signal */
3318c2ecf20Sopenharmony_ci	if (pdata->reset) {
3328c2ecf20Sopenharmony_ci		gpio_set_value(pdata->reset, 1);
3338c2ecf20Sopenharmony_ci		msleep(50); /* Or more..? */
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci	return 0;
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic size_t cw1200_spi_align_size(struct hwbus_priv *self, size_t size)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	return size & 1 ? size + 1 : size;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int cw1200_spi_pm(struct hwbus_priv *self, bool suspend)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	return irq_set_irq_wake(self->func->irq, suspend);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic const struct hwbus_ops cw1200_spi_hwbus_ops = {
3498c2ecf20Sopenharmony_ci	.hwbus_memcpy_fromio	= cw1200_spi_memcpy_fromio,
3508c2ecf20Sopenharmony_ci	.hwbus_memcpy_toio	= cw1200_spi_memcpy_toio,
3518c2ecf20Sopenharmony_ci	.lock			= cw1200_spi_lock,
3528c2ecf20Sopenharmony_ci	.unlock			= cw1200_spi_unlock,
3538c2ecf20Sopenharmony_ci	.align_size		= cw1200_spi_align_size,
3548c2ecf20Sopenharmony_ci	.power_mgmt		= cw1200_spi_pm,
3558c2ecf20Sopenharmony_ci};
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci/* Probe Function to be called by SPI stack when device is discovered */
3588c2ecf20Sopenharmony_cistatic int cw1200_spi_probe(struct spi_device *func)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	const struct cw1200_platform_data_spi *plat_data =
3618c2ecf20Sopenharmony_ci		dev_get_platdata(&func->dev);
3628c2ecf20Sopenharmony_ci	struct hwbus_priv *self;
3638c2ecf20Sopenharmony_ci	int status;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/* Sanity check speed */
3668c2ecf20Sopenharmony_ci	if (func->max_speed_hz > 52000000)
3678c2ecf20Sopenharmony_ci		func->max_speed_hz = 52000000;
3688c2ecf20Sopenharmony_ci	if (func->max_speed_hz < 1000000)
3698c2ecf20Sopenharmony_ci		func->max_speed_hz = 1000000;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	/* Fix up transfer size */
3728c2ecf20Sopenharmony_ci	if (plat_data->spi_bits_per_word)
3738c2ecf20Sopenharmony_ci		func->bits_per_word = plat_data->spi_bits_per_word;
3748c2ecf20Sopenharmony_ci	if (!func->bits_per_word)
3758c2ecf20Sopenharmony_ci		func->bits_per_word = 16;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/* And finally.. */
3788c2ecf20Sopenharmony_ci	func->mode = SPI_MODE_0;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	pr_info("cw1200_wlan_spi: Probe called (CS %d M %d BPW %d CLK %d)\n",
3818c2ecf20Sopenharmony_ci		func->chip_select, func->mode, func->bits_per_word,
3828c2ecf20Sopenharmony_ci		func->max_speed_hz);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (cw1200_spi_on(plat_data)) {
3858c2ecf20Sopenharmony_ci		pr_err("spi_on() failed!\n");
3868c2ecf20Sopenharmony_ci		return -1;
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (spi_setup(func)) {
3908c2ecf20Sopenharmony_ci		pr_err("spi_setup() failed!\n");
3918c2ecf20Sopenharmony_ci		return -1;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL);
3958c2ecf20Sopenharmony_ci	if (!self) {
3968c2ecf20Sopenharmony_ci		pr_err("Can't allocate SPI hwbus_priv.");
3978c2ecf20Sopenharmony_ci		return -ENOMEM;
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	self->pdata = plat_data;
4018c2ecf20Sopenharmony_ci	self->func = func;
4028c2ecf20Sopenharmony_ci	spin_lock_init(&self->lock);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	spi_set_drvdata(func, self);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	init_waitqueue_head(&self->wq);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	status = cw1200_spi_irq_subscribe(self);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	status = cw1200_core_probe(&cw1200_spi_hwbus_ops,
4118c2ecf20Sopenharmony_ci				   self, &func->dev, &self->core,
4128c2ecf20Sopenharmony_ci				   self->pdata->ref_clk,
4138c2ecf20Sopenharmony_ci				   self->pdata->macaddr,
4148c2ecf20Sopenharmony_ci				   self->pdata->sdd_file,
4158c2ecf20Sopenharmony_ci				   self->pdata->have_5ghz);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	if (status) {
4188c2ecf20Sopenharmony_ci		cw1200_spi_irq_unsubscribe(self);
4198c2ecf20Sopenharmony_ci		cw1200_spi_off(plat_data);
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return status;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci/* Disconnect Function to be called by SPI stack when device is disconnected */
4268c2ecf20Sopenharmony_cistatic int cw1200_spi_disconnect(struct spi_device *func)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	struct hwbus_priv *self = spi_get_drvdata(func);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (self) {
4318c2ecf20Sopenharmony_ci		cw1200_spi_irq_unsubscribe(self);
4328c2ecf20Sopenharmony_ci		if (self->core) {
4338c2ecf20Sopenharmony_ci			cw1200_core_release(self->core);
4348c2ecf20Sopenharmony_ci			self->core = NULL;
4358c2ecf20Sopenharmony_ci		}
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci	cw1200_spi_off(dev_get_platdata(&func->dev));
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	return 0;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic int __maybe_unused cw1200_spi_suspend(struct device *dev)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev));
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (!cw1200_can_suspend(self->core))
4478c2ecf20Sopenharmony_ci		return -EAGAIN;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* XXX notify host that we have to keep CW1200 powered on? */
4508c2ecf20Sopenharmony_ci	return 0;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(cw1200_pm_ops, cw1200_spi_suspend, NULL);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic struct spi_driver spi_driver = {
4568c2ecf20Sopenharmony_ci	.probe		= cw1200_spi_probe,
4578c2ecf20Sopenharmony_ci	.remove		= cw1200_spi_disconnect,
4588c2ecf20Sopenharmony_ci	.driver = {
4598c2ecf20Sopenharmony_ci		.name		= "cw1200_wlan_spi",
4608c2ecf20Sopenharmony_ci		.pm		= IS_ENABLED(CONFIG_PM) ? &cw1200_pm_ops : NULL,
4618c2ecf20Sopenharmony_ci	},
4628c2ecf20Sopenharmony_ci};
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cimodule_spi_driver(spi_driver);
465