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 = ®addr, 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 = ®addr, 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