15625f965SAjay Singh // SPDX-License-Identifier: GPL-2.0 25625f965SAjay Singh /* 35625f965SAjay Singh * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. 45625f965SAjay Singh * All rights reserved. 55625f965SAjay Singh */ 65625f965SAjay Singh 75625f965SAjay Singh #include <linux/clk.h> 85625f965SAjay Singh #include <linux/spi/spi.h> 95625f965SAjay Singh #include <linux/crc7.h> 10c872e7aeSDavid Mosberger-Tang #include <linux/crc-itu-t.h> 11*ec031ac4SDavid Mosberger-Tang #include <linux/gpio/consumer.h> 125625f965SAjay Singh 135625f965SAjay Singh #include "netdev.h" 145625f965SAjay Singh #include "cfg80211.h" 155625f965SAjay Singh 164347d34eSDavid Mosberger-Tang #define SPI_MODALIAS "wilc1000_spi" 174347d34eSDavid Mosberger-Tang 18c872e7aeSDavid Mosberger-Tang static bool enable_crc7; /* protect SPI commands with CRC7 */ 19c872e7aeSDavid Mosberger-Tang module_param(enable_crc7, bool, 0644); 20c872e7aeSDavid Mosberger-Tang MODULE_PARM_DESC(enable_crc7, 21c872e7aeSDavid Mosberger-Tang "Enable CRC7 checksum to protect command transfers\n" 22c872e7aeSDavid Mosberger-Tang "\t\t\tagainst corruption during the SPI transfer.\n" 23c872e7aeSDavid Mosberger-Tang "\t\t\tCommand transfers are short and the CPU-cycle cost\n" 24c872e7aeSDavid Mosberger-Tang "\t\t\tof enabling this is small."); 25c872e7aeSDavid Mosberger-Tang 26c872e7aeSDavid Mosberger-Tang static bool enable_crc16; /* protect SPI data with CRC16 */ 27c872e7aeSDavid Mosberger-Tang module_param(enable_crc16, bool, 0644); 28c872e7aeSDavid Mosberger-Tang MODULE_PARM_DESC(enable_crc16, 29c872e7aeSDavid Mosberger-Tang "Enable CRC16 checksum to protect data transfers\n" 30c872e7aeSDavid Mosberger-Tang "\t\t\tagainst corruption during the SPI transfer.\n" 31c872e7aeSDavid Mosberger-Tang "\t\t\tData transfers can be large and the CPU-cycle cost\n" 32c872e7aeSDavid Mosberger-Tang "\t\t\tof enabling this may be substantial."); 33c872e7aeSDavid Mosberger-Tang 34f2131fa5SDavid Mosberger-Tang /* 35f2131fa5SDavid Mosberger-Tang * For CMD_SINGLE_READ and CMD_INTERNAL_READ, WILC may insert one or 36f2131fa5SDavid Mosberger-Tang * more zero bytes between the command response and the DATA Start tag 37f2131fa5SDavid Mosberger-Tang * (0xf3). This behavior appears to be undocumented in "ATWILC1000 38f2131fa5SDavid Mosberger-Tang * USER GUIDE" (https://tinyurl.com/4hhshdts) but we have observed 1-4 39f2131fa5SDavid Mosberger-Tang * zero bytes when the SPI bus operates at 48MHz and none when it 40f2131fa5SDavid Mosberger-Tang * operates at 1MHz. 41f2131fa5SDavid Mosberger-Tang */ 42f2131fa5SDavid Mosberger-Tang #define WILC_SPI_RSP_HDR_EXTRA_DATA 8 43f2131fa5SDavid Mosberger-Tang 445625f965SAjay Singh struct wilc_spi { 4550cbbfd4SDavid Mosberger-Tang bool isinit; /* true if SPI protocol has been configured */ 46c872e7aeSDavid Mosberger-Tang bool probing_crc; /* true if we're probing chip's CRC config */ 47c872e7aeSDavid Mosberger-Tang bool crc7_enabled; /* true if crc7 is currently enabled */ 48c872e7aeSDavid Mosberger-Tang bool crc16_enabled; /* true if crc16 is currently enabled */ 49*ec031ac4SDavid Mosberger-Tang struct wilc_gpios { 50*ec031ac4SDavid Mosberger-Tang struct gpio_desc *enable; /* ENABLE GPIO or NULL */ 51*ec031ac4SDavid Mosberger-Tang struct gpio_desc *reset; /* RESET GPIO or NULL */ 52*ec031ac4SDavid Mosberger-Tang } gpios; 535625f965SAjay Singh }; 545625f965SAjay Singh 555625f965SAjay Singh static const struct wilc_hif_func wilc_hif_spi; 565625f965SAjay Singh 57c2dcb476SAjay Singh static int wilc_spi_reset(struct wilc *wilc); 58c2dcb476SAjay Singh 595625f965SAjay Singh /******************************************** 605625f965SAjay Singh * 615625f965SAjay Singh * Spi protocol Function 625625f965SAjay Singh * 635625f965SAjay Singh ********************************************/ 645625f965SAjay Singh 655625f965SAjay Singh #define CMD_DMA_WRITE 0xc1 665625f965SAjay Singh #define CMD_DMA_READ 0xc2 675625f965SAjay Singh #define CMD_INTERNAL_WRITE 0xc3 685625f965SAjay Singh #define CMD_INTERNAL_READ 0xc4 695625f965SAjay Singh #define CMD_TERMINATE 0xc5 705625f965SAjay Singh #define CMD_REPEAT 0xc6 715625f965SAjay Singh #define CMD_DMA_EXT_WRITE 0xc7 725625f965SAjay Singh #define CMD_DMA_EXT_READ 0xc8 735625f965SAjay Singh #define CMD_SINGLE_WRITE 0xc9 745625f965SAjay Singh #define CMD_SINGLE_READ 0xca 755625f965SAjay Singh #define CMD_RESET 0xcf 765625f965SAjay Singh 77382726d1SAjay Singh #define SPI_ENABLE_VMM_RETRY_LIMIT 2 785ee2d9ddSDavid Mosberger-Tang 79ce3b9338SDavid Mosberger-Tang /* SPI response fields (section 11.1.2 in ATWILC1000 User Guide): */ 80ce3b9338SDavid Mosberger-Tang #define RSP_START_FIELD GENMASK(7, 4) 81ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_FIELD GENMASK(3, 0) 82ce3b9338SDavid Mosberger-Tang 83ce3b9338SDavid Mosberger-Tang /* SPI response values for the response fields: */ 84ce3b9338SDavid Mosberger-Tang #define RSP_START_TAG 0xc 85ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_FIRST_PACKET 0x1 86ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_INNER_PACKET 0x2 87ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_LAST_PACKET 0x3 88ce3b9338SDavid Mosberger-Tang #define RSP_STATE_NO_ERROR 0x00 89ce3b9338SDavid Mosberger-Tang 905ee2d9ddSDavid Mosberger-Tang #define PROTOCOL_REG_PKT_SZ_MASK GENMASK(6, 4) 915ee2d9ddSDavid Mosberger-Tang #define PROTOCOL_REG_CRC16_MASK GENMASK(3, 3) 925ee2d9ddSDavid Mosberger-Tang #define PROTOCOL_REG_CRC7_MASK GENMASK(2, 2) 935ee2d9ddSDavid Mosberger-Tang 945ee2d9ddSDavid Mosberger-Tang /* 955ee2d9ddSDavid Mosberger-Tang * The SPI data packet size may be any integer power of two in the 965ee2d9ddSDavid Mosberger-Tang * range from 256 to 8192 bytes. 975ee2d9ddSDavid Mosberger-Tang */ 985ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_LOG_SZ_MIN 8 /* 256 B */ 995ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_LOG_SZ_MAX 13 /* 8 KiB */ 1005ee2d9ddSDavid Mosberger-Tang 1015ee2d9ddSDavid Mosberger-Tang /* 1025ee2d9ddSDavid Mosberger-Tang * Select the data packet size (log2 of number of bytes): Use the 1035ee2d9ddSDavid Mosberger-Tang * maximum data packet size. We only retransmit complete packets, so 1045ee2d9ddSDavid Mosberger-Tang * there is no benefit from using smaller data packets. 1055ee2d9ddSDavid Mosberger-Tang */ 1065ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_LOG_SZ DATA_PKT_LOG_SZ_MAX 1075ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_SZ (1 << DATA_PKT_LOG_SZ) 1085625f965SAjay Singh 1095625f965SAjay Singh #define WILC_SPI_COMMAND_STAT_SUCCESS 0 1105625f965SAjay Singh #define WILC_GET_RESP_HDR_START(h) (((h) >> 4) & 0xf) 1115625f965SAjay Singh 1125625f965SAjay Singh struct wilc_spi_cmd { 1135625f965SAjay Singh u8 cmd_type; 1145625f965SAjay Singh union { 1155625f965SAjay Singh struct { 1165625f965SAjay Singh u8 addr[3]; 1175625f965SAjay Singh u8 crc[]; 1185625f965SAjay Singh } __packed simple_cmd; 1195625f965SAjay Singh struct { 1205625f965SAjay Singh u8 addr[3]; 1215625f965SAjay Singh u8 size[2]; 1225625f965SAjay Singh u8 crc[]; 1235625f965SAjay Singh } __packed dma_cmd; 1245625f965SAjay Singh struct { 1255625f965SAjay Singh u8 addr[3]; 1265625f965SAjay Singh u8 size[3]; 1275625f965SAjay Singh u8 crc[]; 1285625f965SAjay Singh } __packed dma_cmd_ext; 1295625f965SAjay Singh struct { 1305625f965SAjay Singh u8 addr[2]; 1315625f965SAjay Singh __be32 data; 1325625f965SAjay Singh u8 crc[]; 1335625f965SAjay Singh } __packed internal_w_cmd; 1345625f965SAjay Singh struct { 1355625f965SAjay Singh u8 addr[3]; 1365625f965SAjay Singh __be32 data; 1375625f965SAjay Singh u8 crc[]; 1385625f965SAjay Singh } __packed w_cmd; 1395625f965SAjay Singh } u; 1405625f965SAjay Singh } __packed; 1415625f965SAjay Singh 1425625f965SAjay Singh struct wilc_spi_read_rsp_data { 143f2131fa5SDavid Mosberger-Tang u8 header; 144f2131fa5SDavid Mosberger-Tang u8 data[4]; 1455625f965SAjay Singh u8 crc[]; 1465625f965SAjay Singh } __packed; 1475625f965SAjay Singh 1485625f965SAjay Singh struct wilc_spi_rsp_data { 1495625f965SAjay Singh u8 rsp_cmd_type; 1505625f965SAjay Singh u8 status; 151f2131fa5SDavid Mosberger-Tang u8 data[]; 1525625f965SAjay Singh } __packed; 1535625f965SAjay Singh 1541bcc0879SAjay Singh struct wilc_spi_special_cmd_rsp { 1551bcc0879SAjay Singh u8 skip_byte; 1561bcc0879SAjay Singh u8 rsp_cmd_type; 1571bcc0879SAjay Singh u8 status; 1581bcc0879SAjay Singh } __packed; 1591bcc0879SAjay Singh 160*ec031ac4SDavid Mosberger-Tang static int wilc_parse_gpios(struct wilc *wilc) 161*ec031ac4SDavid Mosberger-Tang { 162*ec031ac4SDavid Mosberger-Tang struct spi_device *spi = to_spi_device(wilc->dev); 163*ec031ac4SDavid Mosberger-Tang struct wilc_spi *spi_priv = wilc->bus_data; 164*ec031ac4SDavid Mosberger-Tang struct wilc_gpios *gpios = &spi_priv->gpios; 165*ec031ac4SDavid Mosberger-Tang 166*ec031ac4SDavid Mosberger-Tang /* get ENABLE pin and deassert it (if it is defined): */ 167*ec031ac4SDavid Mosberger-Tang gpios->enable = devm_gpiod_get_optional(&spi->dev, 168*ec031ac4SDavid Mosberger-Tang "enable", GPIOD_OUT_LOW); 169*ec031ac4SDavid Mosberger-Tang /* get RESET pin and assert it (if it is defined): */ 170*ec031ac4SDavid Mosberger-Tang if (gpios->enable) { 171*ec031ac4SDavid Mosberger-Tang /* if enable pin exists, reset must exist as well */ 172*ec031ac4SDavid Mosberger-Tang gpios->reset = devm_gpiod_get(&spi->dev, 173*ec031ac4SDavid Mosberger-Tang "reset", GPIOD_OUT_HIGH); 174*ec031ac4SDavid Mosberger-Tang if (IS_ERR(gpios->reset)) { 175*ec031ac4SDavid Mosberger-Tang dev_err(&spi->dev, "missing reset gpio.\n"); 176*ec031ac4SDavid Mosberger-Tang return PTR_ERR(gpios->reset); 177*ec031ac4SDavid Mosberger-Tang } 178*ec031ac4SDavid Mosberger-Tang } else { 179*ec031ac4SDavid Mosberger-Tang gpios->reset = devm_gpiod_get_optional(&spi->dev, 180*ec031ac4SDavid Mosberger-Tang "reset", GPIOD_OUT_HIGH); 181*ec031ac4SDavid Mosberger-Tang } 182*ec031ac4SDavid Mosberger-Tang return 0; 183*ec031ac4SDavid Mosberger-Tang } 184*ec031ac4SDavid Mosberger-Tang 185*ec031ac4SDavid Mosberger-Tang static void wilc_wlan_power(struct wilc *wilc, bool on) 186*ec031ac4SDavid Mosberger-Tang { 187*ec031ac4SDavid Mosberger-Tang struct wilc_spi *spi_priv = wilc->bus_data; 188*ec031ac4SDavid Mosberger-Tang struct wilc_gpios *gpios = &spi_priv->gpios; 189*ec031ac4SDavid Mosberger-Tang 190*ec031ac4SDavid Mosberger-Tang if (on) { 191*ec031ac4SDavid Mosberger-Tang /* assert ENABLE: */ 192*ec031ac4SDavid Mosberger-Tang gpiod_set_value(gpios->enable, 1); 193*ec031ac4SDavid Mosberger-Tang mdelay(5); 194*ec031ac4SDavid Mosberger-Tang /* deassert RESET: */ 195*ec031ac4SDavid Mosberger-Tang gpiod_set_value(gpios->reset, 0); 196*ec031ac4SDavid Mosberger-Tang } else { 197*ec031ac4SDavid Mosberger-Tang /* assert RESET: */ 198*ec031ac4SDavid Mosberger-Tang gpiod_set_value(gpios->reset, 1); 199*ec031ac4SDavid Mosberger-Tang /* deassert ENABLE: */ 200*ec031ac4SDavid Mosberger-Tang gpiod_set_value(gpios->enable, 0); 201*ec031ac4SDavid Mosberger-Tang } 202*ec031ac4SDavid Mosberger-Tang } 203*ec031ac4SDavid Mosberger-Tang 2045625f965SAjay Singh static int wilc_bus_probe(struct spi_device *spi) 2055625f965SAjay Singh { 2065625f965SAjay Singh int ret; 2075625f965SAjay Singh struct wilc *wilc; 2085625f965SAjay Singh struct wilc_spi *spi_priv; 2095625f965SAjay Singh 2105625f965SAjay Singh spi_priv = kzalloc(sizeof(*spi_priv), GFP_KERNEL); 2115625f965SAjay Singh if (!spi_priv) 2125625f965SAjay Singh return -ENOMEM; 2135625f965SAjay Singh 2145625f965SAjay Singh ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi); 215dc8b338fSClaudiu Beznea if (ret) 216dc8b338fSClaudiu Beznea goto free; 2175625f965SAjay Singh 2185625f965SAjay Singh spi_set_drvdata(spi, wilc); 2195625f965SAjay Singh wilc->dev = &spi->dev; 2205625f965SAjay Singh wilc->bus_data = spi_priv; 2215625f965SAjay Singh wilc->dev_irq_num = spi->irq; 2225625f965SAjay Singh 223*ec031ac4SDavid Mosberger-Tang ret = wilc_parse_gpios(wilc); 224*ec031ac4SDavid Mosberger-Tang if (ret < 0) 225*ec031ac4SDavid Mosberger-Tang goto netdev_cleanup; 226*ec031ac4SDavid Mosberger-Tang 2271d89fd1aSClaudiu Beznea wilc->rtc_clk = devm_clk_get_optional(&spi->dev, "rtc"); 2281d89fd1aSClaudiu Beznea if (IS_ERR(wilc->rtc_clk)) { 2291d89fd1aSClaudiu Beznea ret = PTR_ERR(wilc->rtc_clk); 230dc8b338fSClaudiu Beznea goto netdev_cleanup; 2311d89fd1aSClaudiu Beznea } 2325625f965SAjay Singh clk_prepare_enable(wilc->rtc_clk); 2335625f965SAjay Singh 2345625f965SAjay Singh return 0; 235dc8b338fSClaudiu Beznea 236dc8b338fSClaudiu Beznea netdev_cleanup: 237dc8b338fSClaudiu Beznea wilc_netdev_cleanup(wilc); 238dc8b338fSClaudiu Beznea free: 239dc8b338fSClaudiu Beznea kfree(spi_priv); 240dc8b338fSClaudiu Beznea return ret; 2415625f965SAjay Singh } 2425625f965SAjay Singh 2435625f965SAjay Singh static int wilc_bus_remove(struct spi_device *spi) 2445625f965SAjay Singh { 2455625f965SAjay Singh struct wilc *wilc = spi_get_drvdata(spi); 2464894edacSDan Carpenter struct wilc_spi *spi_priv = wilc->bus_data; 2475625f965SAjay Singh 2485625f965SAjay Singh clk_disable_unprepare(wilc->rtc_clk); 2495625f965SAjay Singh wilc_netdev_cleanup(wilc); 2504894edacSDan Carpenter kfree(spi_priv); 2511d89fd1aSClaudiu Beznea 2525625f965SAjay Singh return 0; 2535625f965SAjay Singh } 2545625f965SAjay Singh 2555625f965SAjay Singh static const struct of_device_id wilc_of_match[] = { 2565625f965SAjay Singh { .compatible = "microchip,wilc1000", }, 2575625f965SAjay Singh { /* sentinel */ } 2585625f965SAjay Singh }; 2595625f965SAjay Singh MODULE_DEVICE_TABLE(of, wilc_of_match); 2605625f965SAjay Singh 261f2f16ae9SDavid Mosberger-Tang static const struct spi_device_id wilc_spi_id[] = { 262f2f16ae9SDavid Mosberger-Tang { "wilc1000", 0 }, 263f2f16ae9SDavid Mosberger-Tang { /* sentinel */ } 264f2f16ae9SDavid Mosberger-Tang }; 265f2f16ae9SDavid Mosberger-Tang MODULE_DEVICE_TABLE(spi, wilc_spi_id); 266f2f16ae9SDavid Mosberger-Tang 2675625f965SAjay Singh static struct spi_driver wilc_spi_driver = { 2685625f965SAjay Singh .driver = { 2694347d34eSDavid Mosberger-Tang .name = SPI_MODALIAS, 2705625f965SAjay Singh .of_match_table = wilc_of_match, 2715625f965SAjay Singh }, 272f2f16ae9SDavid Mosberger-Tang .id_table = wilc_spi_id, 2735625f965SAjay Singh .probe = wilc_bus_probe, 2745625f965SAjay Singh .remove = wilc_bus_remove, 2755625f965SAjay Singh }; 2765625f965SAjay Singh module_spi_driver(wilc_spi_driver); 2775625f965SAjay Singh MODULE_LICENSE("GPL"); 2785625f965SAjay Singh 2795625f965SAjay Singh static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len) 2805625f965SAjay Singh { 2815625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 2825625f965SAjay Singh int ret; 2835625f965SAjay Singh struct spi_message msg; 2845625f965SAjay Singh 2855625f965SAjay Singh if (len > 0 && b) { 2865625f965SAjay Singh struct spi_transfer tr = { 2875625f965SAjay Singh .tx_buf = b, 2885625f965SAjay Singh .len = len, 2895625f965SAjay Singh .delay = { 2905625f965SAjay Singh .value = 0, 2915625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 2925625f965SAjay Singh }, 2935625f965SAjay Singh }; 2945625f965SAjay Singh char *r_buffer = kzalloc(len, GFP_KERNEL); 2955625f965SAjay Singh 2965625f965SAjay Singh if (!r_buffer) 2975625f965SAjay Singh return -ENOMEM; 2985625f965SAjay Singh 2995625f965SAjay Singh tr.rx_buf = r_buffer; 3005625f965SAjay Singh dev_dbg(&spi->dev, "Request writing %d bytes\n", len); 3015625f965SAjay Singh 3025625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 3035625f965SAjay Singh spi_message_init(&msg); 3045625f965SAjay Singh msg.spi = spi; 3055625f965SAjay Singh spi_message_add_tail(&tr, &msg); 3065625f965SAjay Singh 3075625f965SAjay Singh ret = spi_sync(spi, &msg); 3085625f965SAjay Singh if (ret < 0) 3095625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 3105625f965SAjay Singh 3115625f965SAjay Singh kfree(r_buffer); 3125625f965SAjay Singh } else { 3135625f965SAjay Singh dev_err(&spi->dev, 3145625f965SAjay Singh "can't write data with the following length: %d\n", 3155625f965SAjay Singh len); 3165625f965SAjay Singh ret = -EINVAL; 3175625f965SAjay Singh } 3185625f965SAjay Singh 3195625f965SAjay Singh return ret; 3205625f965SAjay Singh } 3215625f965SAjay Singh 3225625f965SAjay Singh static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen) 3235625f965SAjay Singh { 3245625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 3255625f965SAjay Singh int ret; 3265625f965SAjay Singh 3275625f965SAjay Singh if (rlen > 0) { 3285625f965SAjay Singh struct spi_message msg; 3295625f965SAjay Singh struct spi_transfer tr = { 3305625f965SAjay Singh .rx_buf = rb, 3315625f965SAjay Singh .len = rlen, 3325625f965SAjay Singh .delay = { 3335625f965SAjay Singh .value = 0, 3345625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 3355625f965SAjay Singh }, 3365625f965SAjay Singh 3375625f965SAjay Singh }; 3385625f965SAjay Singh char *t_buffer = kzalloc(rlen, GFP_KERNEL); 3395625f965SAjay Singh 3405625f965SAjay Singh if (!t_buffer) 3415625f965SAjay Singh return -ENOMEM; 3425625f965SAjay Singh 3435625f965SAjay Singh tr.tx_buf = t_buffer; 3445625f965SAjay Singh 3455625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 3465625f965SAjay Singh spi_message_init(&msg); 3475625f965SAjay Singh msg.spi = spi; 3485625f965SAjay Singh spi_message_add_tail(&tr, &msg); 3495625f965SAjay Singh 3505625f965SAjay Singh ret = spi_sync(spi, &msg); 3515625f965SAjay Singh if (ret < 0) 3525625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 3535625f965SAjay Singh kfree(t_buffer); 3545625f965SAjay Singh } else { 3555625f965SAjay Singh dev_err(&spi->dev, 3565625f965SAjay Singh "can't read data with the following length: %u\n", 3575625f965SAjay Singh rlen); 3585625f965SAjay Singh ret = -EINVAL; 3595625f965SAjay Singh } 3605625f965SAjay Singh 3615625f965SAjay Singh return ret; 3625625f965SAjay Singh } 3635625f965SAjay Singh 3645625f965SAjay Singh static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen) 3655625f965SAjay Singh { 3665625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 3675625f965SAjay Singh int ret; 3685625f965SAjay Singh 3695625f965SAjay Singh if (rlen > 0) { 3705625f965SAjay Singh struct spi_message msg; 3715625f965SAjay Singh struct spi_transfer tr = { 3725625f965SAjay Singh .rx_buf = rb, 3735625f965SAjay Singh .tx_buf = wb, 3745625f965SAjay Singh .len = rlen, 3755625f965SAjay Singh .bits_per_word = 8, 3765625f965SAjay Singh .delay = { 3775625f965SAjay Singh .value = 0, 3785625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 3795625f965SAjay Singh }, 3805625f965SAjay Singh 3815625f965SAjay Singh }; 3825625f965SAjay Singh 3835625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 3845625f965SAjay Singh spi_message_init(&msg); 3855625f965SAjay Singh msg.spi = spi; 3865625f965SAjay Singh 3875625f965SAjay Singh spi_message_add_tail(&tr, &msg); 3885625f965SAjay Singh ret = spi_sync(spi, &msg); 3895625f965SAjay Singh if (ret < 0) 3905625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 3915625f965SAjay Singh } else { 3925625f965SAjay Singh dev_err(&spi->dev, 3935625f965SAjay Singh "can't read data with the following length: %u\n", 3945625f965SAjay Singh rlen); 3955625f965SAjay Singh ret = -EINVAL; 3965625f965SAjay Singh } 3975625f965SAjay Singh 3985625f965SAjay Singh return ret; 3995625f965SAjay Singh } 4005625f965SAjay Singh 4015625f965SAjay Singh static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) 4025625f965SAjay Singh { 4035625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 4045625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 4055625f965SAjay Singh int ix, nbytes; 4065625f965SAjay Singh int result = 0; 407c872e7aeSDavid Mosberger-Tang u8 cmd, order, crc[2]; 408c872e7aeSDavid Mosberger-Tang u16 crc_calc; 4095625f965SAjay Singh 4105625f965SAjay Singh /* 4115625f965SAjay Singh * Data 4125625f965SAjay Singh */ 4135625f965SAjay Singh ix = 0; 4145625f965SAjay Singh do { 4155625f965SAjay Singh if (sz <= DATA_PKT_SZ) { 4165625f965SAjay Singh nbytes = sz; 4175625f965SAjay Singh order = 0x3; 4185625f965SAjay Singh } else { 4195625f965SAjay Singh nbytes = DATA_PKT_SZ; 4205625f965SAjay Singh if (ix == 0) 4215625f965SAjay Singh order = 0x1; 4225625f965SAjay Singh else 4235625f965SAjay Singh order = 0x02; 4245625f965SAjay Singh } 4255625f965SAjay Singh 4265625f965SAjay Singh /* 4275625f965SAjay Singh * Write command 4285625f965SAjay Singh */ 4295625f965SAjay Singh cmd = 0xf0; 4305625f965SAjay Singh cmd |= order; 4315625f965SAjay Singh 4325625f965SAjay Singh if (wilc_spi_tx(wilc, &cmd, 1)) { 4335625f965SAjay Singh dev_err(&spi->dev, 4345625f965SAjay Singh "Failed data block cmd write, bus error...\n"); 4355625f965SAjay Singh result = -EINVAL; 4365625f965SAjay Singh break; 4375625f965SAjay Singh } 4385625f965SAjay Singh 4395625f965SAjay Singh /* 4405625f965SAjay Singh * Write data 4415625f965SAjay Singh */ 4425625f965SAjay Singh if (wilc_spi_tx(wilc, &b[ix], nbytes)) { 4435625f965SAjay Singh dev_err(&spi->dev, 4445625f965SAjay Singh "Failed data block write, bus error...\n"); 4455625f965SAjay Singh result = -EINVAL; 4465625f965SAjay Singh break; 4475625f965SAjay Singh } 4485625f965SAjay Singh 4495625f965SAjay Singh /* 450c872e7aeSDavid Mosberger-Tang * Write CRC 4515625f965SAjay Singh */ 452c872e7aeSDavid Mosberger-Tang if (spi_priv->crc16_enabled) { 453c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, &b[ix], nbytes); 454c872e7aeSDavid Mosberger-Tang crc[0] = crc_calc >> 8; 455c872e7aeSDavid Mosberger-Tang crc[1] = crc_calc; 4565625f965SAjay Singh if (wilc_spi_tx(wilc, crc, 2)) { 4575625f965SAjay Singh dev_err(&spi->dev, "Failed data block crc write, bus error...\n"); 4585625f965SAjay Singh result = -EINVAL; 4595625f965SAjay Singh break; 4605625f965SAjay Singh } 4615625f965SAjay Singh } 4625625f965SAjay Singh 4635625f965SAjay Singh /* 4645625f965SAjay Singh * No need to wait for response 4655625f965SAjay Singh */ 4665625f965SAjay Singh ix += nbytes; 4675625f965SAjay Singh sz -= nbytes; 4685625f965SAjay Singh } while (sz); 4695625f965SAjay Singh 4705625f965SAjay Singh return result; 4715625f965SAjay Singh } 4725625f965SAjay Singh 4735625f965SAjay Singh /******************************************** 4745625f965SAjay Singh * 4755625f965SAjay Singh * Spi Internal Read/Write Function 4765625f965SAjay Singh * 4775625f965SAjay Singh ********************************************/ 4785625f965SAjay Singh static u8 wilc_get_crc7(u8 *buffer, u32 len) 4795625f965SAjay Singh { 4805625f965SAjay Singh return crc7_be(0xfe, buffer, len); 4815625f965SAjay Singh } 4825625f965SAjay Singh 4835625f965SAjay Singh static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, 4845625f965SAjay Singh u8 clockless) 4855625f965SAjay Singh { 4865625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 4875625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 4885625f965SAjay Singh u8 wb[32], rb[32]; 489f2131fa5SDavid Mosberger-Tang int cmd_len, resp_len, i; 490c872e7aeSDavid Mosberger-Tang u16 crc_calc, crc_recv; 4915625f965SAjay Singh struct wilc_spi_cmd *c; 492f2131fa5SDavid Mosberger-Tang struct wilc_spi_rsp_data *r; 493c872e7aeSDavid Mosberger-Tang struct wilc_spi_read_rsp_data *r_data; 4945625f965SAjay Singh 4955625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 4965625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 4975625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 4985625f965SAjay Singh c->cmd_type = cmd; 4995625f965SAjay Singh if (cmd == CMD_SINGLE_READ) { 5005625f965SAjay Singh c->u.simple_cmd.addr[0] = adr >> 16; 5015625f965SAjay Singh c->u.simple_cmd.addr[1] = adr >> 8; 5025625f965SAjay Singh c->u.simple_cmd.addr[2] = adr; 5035625f965SAjay Singh } else if (cmd == CMD_INTERNAL_READ) { 5045625f965SAjay Singh c->u.simple_cmd.addr[0] = adr >> 8; 5055625f965SAjay Singh if (clockless == 1) 5065625f965SAjay Singh c->u.simple_cmd.addr[0] |= BIT(7); 5075625f965SAjay Singh c->u.simple_cmd.addr[1] = adr; 5085625f965SAjay Singh c->u.simple_cmd.addr[2] = 0x0; 5095625f965SAjay Singh } else { 5105625f965SAjay Singh dev_err(&spi->dev, "cmd [%x] not supported\n", cmd); 5115625f965SAjay Singh return -EINVAL; 5125625f965SAjay Singh } 5135625f965SAjay Singh 5145625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc); 515f2131fa5SDavid Mosberger-Tang resp_len = sizeof(*r) + sizeof(*r_data) + WILC_SPI_RSP_HDR_EXTRA_DATA; 516f2131fa5SDavid Mosberger-Tang 517c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) { 5185625f965SAjay Singh c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 5195625f965SAjay Singh cmd_len += 1; 5205625f965SAjay Singh resp_len += 2; 5215625f965SAjay Singh } 5225625f965SAjay Singh 5235625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 5245625f965SAjay Singh dev_err(&spi->dev, 5255625f965SAjay Singh "spi buffer size too small (%d) (%d) (%zu)\n", 5265625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 5275625f965SAjay Singh return -EINVAL; 5285625f965SAjay Singh } 5295625f965SAjay Singh 5305625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 5315625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 5325625f965SAjay Singh return -EINVAL; 5335625f965SAjay Singh } 5345625f965SAjay Singh 535f2131fa5SDavid Mosberger-Tang r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 536aa3fda4fSAjay Singh if (r->rsp_cmd_type != cmd && !clockless) { 537c872e7aeSDavid Mosberger-Tang if (!spi_priv->probing_crc) 5385625f965SAjay Singh dev_err(&spi->dev, 539c872e7aeSDavid Mosberger-Tang "Failed cmd, cmd (%02x), resp (%02x)\n", 5405625f965SAjay Singh cmd, r->rsp_cmd_type); 5415625f965SAjay Singh return -EINVAL; 5425625f965SAjay Singh } 5435625f965SAjay Singh 544aa3fda4fSAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS && !clockless) { 5455625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 5465625f965SAjay Singh r->status); 5475625f965SAjay Singh return -EINVAL; 5485625f965SAjay Singh } 5495625f965SAjay Singh 550f2131fa5SDavid Mosberger-Tang for (i = 0; i < WILC_SPI_RSP_HDR_EXTRA_DATA; ++i) 551f2131fa5SDavid Mosberger-Tang if (WILC_GET_RESP_HDR_START(r->data[i]) == 0xf) 552f2131fa5SDavid Mosberger-Tang break; 553f2131fa5SDavid Mosberger-Tang 554f2131fa5SDavid Mosberger-Tang if (i >= WILC_SPI_RSP_HDR_EXTRA_DATA) { 555f2131fa5SDavid Mosberger-Tang dev_err(&spi->dev, "Error, data start missing\n"); 5565625f965SAjay Singh return -EINVAL; 5575625f965SAjay Singh } 5585625f965SAjay Singh 559f2131fa5SDavid Mosberger-Tang r_data = (struct wilc_spi_read_rsp_data *)&r->data[i]; 560f2131fa5SDavid Mosberger-Tang 5615625f965SAjay Singh if (b) 562f2131fa5SDavid Mosberger-Tang memcpy(b, r_data->data, 4); 5635625f965SAjay Singh 564c872e7aeSDavid Mosberger-Tang if (!clockless && spi_priv->crc16_enabled) { 565c872e7aeSDavid Mosberger-Tang crc_recv = (r_data->crc[0] << 8) | r_data->crc[1]; 566c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, r_data->data, 4); 567c872e7aeSDavid Mosberger-Tang if (crc_recv != crc_calc) { 568c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "%s: bad CRC 0x%04x " 569c872e7aeSDavid Mosberger-Tang "(calculated 0x%04x)\n", __func__, 570c872e7aeSDavid Mosberger-Tang crc_recv, crc_calc); 571c872e7aeSDavid Mosberger-Tang return -EINVAL; 572c872e7aeSDavid Mosberger-Tang } 573c872e7aeSDavid Mosberger-Tang } 5745625f965SAjay Singh 5755625f965SAjay Singh return 0; 5765625f965SAjay Singh } 5775625f965SAjay Singh 5785625f965SAjay Singh static int wilc_spi_write_cmd(struct wilc *wilc, u8 cmd, u32 adr, u32 data, 5795625f965SAjay Singh u8 clockless) 5805625f965SAjay Singh { 5815625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 5825625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 5835625f965SAjay Singh u8 wb[32], rb[32]; 5845625f965SAjay Singh int cmd_len, resp_len; 5855625f965SAjay Singh struct wilc_spi_cmd *c; 5865625f965SAjay Singh struct wilc_spi_rsp_data *r; 5875625f965SAjay Singh 5885625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 5895625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 5905625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 5915625f965SAjay Singh c->cmd_type = cmd; 5925625f965SAjay Singh if (cmd == CMD_INTERNAL_WRITE) { 5935625f965SAjay Singh c->u.internal_w_cmd.addr[0] = adr >> 8; 5945625f965SAjay Singh if (clockless == 1) 5955625f965SAjay Singh c->u.internal_w_cmd.addr[0] |= BIT(7); 5965625f965SAjay Singh 5975625f965SAjay Singh c->u.internal_w_cmd.addr[1] = adr; 5985625f965SAjay Singh c->u.internal_w_cmd.data = cpu_to_be32(data); 5995625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.internal_w_cmd.crc); 600c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6015625f965SAjay Singh c->u.internal_w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 6025625f965SAjay Singh } else if (cmd == CMD_SINGLE_WRITE) { 6035625f965SAjay Singh c->u.w_cmd.addr[0] = adr >> 16; 6045625f965SAjay Singh c->u.w_cmd.addr[1] = adr >> 8; 6055625f965SAjay Singh c->u.w_cmd.addr[2] = adr; 6065625f965SAjay Singh c->u.w_cmd.data = cpu_to_be32(data); 6075625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.w_cmd.crc); 608c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6095625f965SAjay Singh c->u.w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 6105625f965SAjay Singh } else { 6115625f965SAjay Singh dev_err(&spi->dev, "write cmd [%x] not supported\n", cmd); 6125625f965SAjay Singh return -EINVAL; 6135625f965SAjay Singh } 6145625f965SAjay Singh 615c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6165625f965SAjay Singh cmd_len += 1; 6175625f965SAjay Singh 6185625f965SAjay Singh resp_len = sizeof(*r); 6195625f965SAjay Singh 6205625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 6215625f965SAjay Singh dev_err(&spi->dev, 6225625f965SAjay Singh "spi buffer size too small (%d) (%d) (%zu)\n", 6235625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 6245625f965SAjay Singh return -EINVAL; 6255625f965SAjay Singh } 6265625f965SAjay Singh 6275625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 6285625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 6295625f965SAjay Singh return -EINVAL; 6305625f965SAjay Singh } 6315625f965SAjay Singh 6325625f965SAjay Singh r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 633aa3fda4fSAjay Singh /* 634aa3fda4fSAjay Singh * Clockless registers operations might return unexptected responses, 635aa3fda4fSAjay Singh * even if successful. 636aa3fda4fSAjay Singh */ 637aa3fda4fSAjay Singh if (r->rsp_cmd_type != cmd && !clockless) { 6385625f965SAjay Singh dev_err(&spi->dev, 6395625f965SAjay Singh "Failed cmd response, cmd (%02x), resp (%02x)\n", 6405625f965SAjay Singh cmd, r->rsp_cmd_type); 6415625f965SAjay Singh return -EINVAL; 6425625f965SAjay Singh } 6435625f965SAjay Singh 644aa3fda4fSAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS && !clockless) { 6455625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 6465625f965SAjay Singh r->status); 6475625f965SAjay Singh return -EINVAL; 6485625f965SAjay Singh } 6495625f965SAjay Singh 6505625f965SAjay Singh return 0; 6515625f965SAjay Singh } 6525625f965SAjay Singh 6535625f965SAjay Singh static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz) 6545625f965SAjay Singh { 6555625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 6565625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 657c872e7aeSDavid Mosberger-Tang u16 crc_recv, crc_calc; 6585625f965SAjay Singh u8 wb[32], rb[32]; 6595625f965SAjay Singh int cmd_len, resp_len; 6605625f965SAjay Singh int retry, ix = 0; 6615625f965SAjay Singh u8 crc[2]; 6625625f965SAjay Singh struct wilc_spi_cmd *c; 6635625f965SAjay Singh struct wilc_spi_rsp_data *r; 6645625f965SAjay Singh 6655625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 6665625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 6675625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 6685625f965SAjay Singh c->cmd_type = cmd; 6695625f965SAjay Singh if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_READ) { 6705625f965SAjay Singh c->u.dma_cmd.addr[0] = adr >> 16; 6715625f965SAjay Singh c->u.dma_cmd.addr[1] = adr >> 8; 6725625f965SAjay Singh c->u.dma_cmd.addr[2] = adr; 6735625f965SAjay Singh c->u.dma_cmd.size[0] = sz >> 8; 6745625f965SAjay Singh c->u.dma_cmd.size[1] = sz; 6755625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd.crc); 676c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6775625f965SAjay Singh c->u.dma_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 6785625f965SAjay Singh } else if (cmd == CMD_DMA_EXT_WRITE || cmd == CMD_DMA_EXT_READ) { 6795625f965SAjay Singh c->u.dma_cmd_ext.addr[0] = adr >> 16; 6805625f965SAjay Singh c->u.dma_cmd_ext.addr[1] = adr >> 8; 6815625f965SAjay Singh c->u.dma_cmd_ext.addr[2] = adr; 6825625f965SAjay Singh c->u.dma_cmd_ext.size[0] = sz >> 16; 6835625f965SAjay Singh c->u.dma_cmd_ext.size[1] = sz >> 8; 6845625f965SAjay Singh c->u.dma_cmd_ext.size[2] = sz; 6855625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd_ext.crc); 686c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6875625f965SAjay Singh c->u.dma_cmd_ext.crc[0] = wilc_get_crc7(wb, cmd_len); 6885625f965SAjay Singh } else { 6895625f965SAjay Singh dev_err(&spi->dev, "dma read write cmd [%x] not supported\n", 6905625f965SAjay Singh cmd); 6915625f965SAjay Singh return -EINVAL; 6925625f965SAjay Singh } 693c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6945625f965SAjay Singh cmd_len += 1; 6955625f965SAjay Singh 6965625f965SAjay Singh resp_len = sizeof(*r); 6975625f965SAjay Singh 6985625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 6995625f965SAjay Singh dev_err(&spi->dev, "spi buffer size too small (%d)(%d) (%zu)\n", 7005625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 7015625f965SAjay Singh return -EINVAL; 7025625f965SAjay Singh } 7035625f965SAjay Singh 7045625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 7055625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 7065625f965SAjay Singh return -EINVAL; 7075625f965SAjay Singh } 7085625f965SAjay Singh 7095625f965SAjay Singh r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 7105625f965SAjay Singh if (r->rsp_cmd_type != cmd) { 7115625f965SAjay Singh dev_err(&spi->dev, 7125625f965SAjay Singh "Failed cmd response, cmd (%02x), resp (%02x)\n", 7135625f965SAjay Singh cmd, r->rsp_cmd_type); 7145625f965SAjay Singh return -EINVAL; 7155625f965SAjay Singh } 7165625f965SAjay Singh 7175625f965SAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { 7185625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 7195625f965SAjay Singh r->status); 7205625f965SAjay Singh return -EINVAL; 7215625f965SAjay Singh } 7225625f965SAjay Singh 7235625f965SAjay Singh if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_EXT_WRITE) 7245625f965SAjay Singh return 0; 7255625f965SAjay Singh 7265625f965SAjay Singh while (sz > 0) { 7275625f965SAjay Singh int nbytes; 7285625f965SAjay Singh u8 rsp; 7295625f965SAjay Singh 7305625f965SAjay Singh if (sz <= DATA_PKT_SZ) 7315625f965SAjay Singh nbytes = sz; 7325625f965SAjay Singh else 7335625f965SAjay Singh nbytes = DATA_PKT_SZ; 7345625f965SAjay Singh 7355625f965SAjay Singh /* 7365625f965SAjay Singh * Data Response header 7375625f965SAjay Singh */ 7385625f965SAjay Singh retry = 100; 7395625f965SAjay Singh do { 7405625f965SAjay Singh if (wilc_spi_rx(wilc, &rsp, 1)) { 7415625f965SAjay Singh dev_err(&spi->dev, 7425625f965SAjay Singh "Failed resp read, bus err\n"); 7435625f965SAjay Singh return -EINVAL; 7445625f965SAjay Singh } 7455625f965SAjay Singh if (WILC_GET_RESP_HDR_START(rsp) == 0xf) 7465625f965SAjay Singh break; 7475625f965SAjay Singh } while (retry--); 7485625f965SAjay Singh 7495625f965SAjay Singh /* 7505625f965SAjay Singh * Read bytes 7515625f965SAjay Singh */ 7525625f965SAjay Singh if (wilc_spi_rx(wilc, &b[ix], nbytes)) { 7535625f965SAjay Singh dev_err(&spi->dev, 7545625f965SAjay Singh "Failed block read, bus err\n"); 7555625f965SAjay Singh return -EINVAL; 7565625f965SAjay Singh } 7575625f965SAjay Singh 7585625f965SAjay Singh /* 759c872e7aeSDavid Mosberger-Tang * Read CRC 7605625f965SAjay Singh */ 761c872e7aeSDavid Mosberger-Tang if (spi_priv->crc16_enabled) { 762c872e7aeSDavid Mosberger-Tang if (wilc_spi_rx(wilc, crc, 2)) { 7635625f965SAjay Singh dev_err(&spi->dev, 764c872e7aeSDavid Mosberger-Tang "Failed block CRC read, bus err\n"); 7655625f965SAjay Singh return -EINVAL; 7665625f965SAjay Singh } 767c872e7aeSDavid Mosberger-Tang crc_recv = (crc[0] << 8) | crc[1]; 768c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, &b[ix], nbytes); 769c872e7aeSDavid Mosberger-Tang if (crc_recv != crc_calc) { 770c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "%s: bad CRC 0x%04x " 771c872e7aeSDavid Mosberger-Tang "(calculated 0x%04x)\n", __func__, 772c872e7aeSDavid Mosberger-Tang crc_recv, crc_calc); 773c872e7aeSDavid Mosberger-Tang return -EINVAL; 774c872e7aeSDavid Mosberger-Tang } 775c872e7aeSDavid Mosberger-Tang } 7765625f965SAjay Singh 7775625f965SAjay Singh ix += nbytes; 7785625f965SAjay Singh sz -= nbytes; 7795625f965SAjay Singh } 7805625f965SAjay Singh return 0; 7815625f965SAjay Singh } 7825625f965SAjay Singh 7831bcc0879SAjay Singh static int wilc_spi_special_cmd(struct wilc *wilc, u8 cmd) 7841bcc0879SAjay Singh { 7851bcc0879SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 7861bcc0879SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 7871bcc0879SAjay Singh u8 wb[32], rb[32]; 7881bcc0879SAjay Singh int cmd_len, resp_len = 0; 7891bcc0879SAjay Singh struct wilc_spi_cmd *c; 7901bcc0879SAjay Singh struct wilc_spi_special_cmd_rsp *r; 7911bcc0879SAjay Singh 7921bcc0879SAjay Singh if (cmd != CMD_TERMINATE && cmd != CMD_REPEAT && cmd != CMD_RESET) 7931bcc0879SAjay Singh return -EINVAL; 7941bcc0879SAjay Singh 7951bcc0879SAjay Singh memset(wb, 0x0, sizeof(wb)); 7961bcc0879SAjay Singh memset(rb, 0x0, sizeof(rb)); 7971bcc0879SAjay Singh c = (struct wilc_spi_cmd *)wb; 7981bcc0879SAjay Singh c->cmd_type = cmd; 7991bcc0879SAjay Singh 8001bcc0879SAjay Singh if (cmd == CMD_RESET) 8011bcc0879SAjay Singh memset(c->u.simple_cmd.addr, 0xFF, 3); 8021bcc0879SAjay Singh 8031bcc0879SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc); 8041bcc0879SAjay Singh resp_len = sizeof(*r); 8051bcc0879SAjay Singh 8061bcc0879SAjay Singh if (spi_priv->crc7_enabled) { 8071bcc0879SAjay Singh c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 8081bcc0879SAjay Singh cmd_len += 1; 8091bcc0879SAjay Singh } 8101bcc0879SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 8111bcc0879SAjay Singh dev_err(&spi->dev, "spi buffer size too small (%d) (%d) (%zu)\n", 8121bcc0879SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 8131bcc0879SAjay Singh return -EINVAL; 8141bcc0879SAjay Singh } 8151bcc0879SAjay Singh 8161bcc0879SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 8171bcc0879SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 8181bcc0879SAjay Singh return -EINVAL; 8191bcc0879SAjay Singh } 8201bcc0879SAjay Singh 8211bcc0879SAjay Singh r = (struct wilc_spi_special_cmd_rsp *)&rb[cmd_len]; 8221bcc0879SAjay Singh if (r->rsp_cmd_type != cmd) { 8231bcc0879SAjay Singh if (!spi_priv->probing_crc) 8241bcc0879SAjay Singh dev_err(&spi->dev, 8251bcc0879SAjay Singh "Failed cmd response, cmd (%02x), resp (%02x)\n", 8261bcc0879SAjay Singh cmd, r->rsp_cmd_type); 8271bcc0879SAjay Singh return -EINVAL; 8281bcc0879SAjay Singh } 8291bcc0879SAjay Singh 8301bcc0879SAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { 8311bcc0879SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 8321bcc0879SAjay Singh r->status); 8331bcc0879SAjay Singh return -EINVAL; 8341bcc0879SAjay Singh } 8351bcc0879SAjay Singh return 0; 8361bcc0879SAjay Singh } 8371bcc0879SAjay Singh 8385625f965SAjay Singh static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data) 8395625f965SAjay Singh { 8405625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 8415625f965SAjay Singh int result; 8425625f965SAjay Singh u8 cmd = CMD_SINGLE_READ; 8435625f965SAjay Singh u8 clockless = 0; 8445625f965SAjay Singh 8455625f965SAjay Singh if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) { 8465625f965SAjay Singh /* Clockless register */ 8475625f965SAjay Singh cmd = CMD_INTERNAL_READ; 8485625f965SAjay Singh clockless = 1; 8495625f965SAjay Singh } 8505625f965SAjay Singh 8515625f965SAjay Singh result = wilc_spi_single_read(wilc, cmd, addr, data, clockless); 8525625f965SAjay Singh if (result) { 8535625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr); 8545625f965SAjay Singh return result; 8555625f965SAjay Singh } 8565625f965SAjay Singh 8575625f965SAjay Singh le32_to_cpus(data); 8585625f965SAjay Singh 8595625f965SAjay Singh return 0; 8605625f965SAjay Singh } 8615625f965SAjay Singh 8625625f965SAjay Singh static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) 8635625f965SAjay Singh { 8645625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 8655625f965SAjay Singh int result; 8665625f965SAjay Singh 8675625f965SAjay Singh if (size <= 4) 8685625f965SAjay Singh return -EINVAL; 8695625f965SAjay Singh 8705625f965SAjay Singh result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_READ, addr, buf, size); 8715625f965SAjay Singh if (result) { 8725625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr); 8735625f965SAjay Singh return result; 8745625f965SAjay Singh } 8755625f965SAjay Singh 8765625f965SAjay Singh return 0; 8775625f965SAjay Singh } 8785625f965SAjay Singh 8795625f965SAjay Singh static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat) 8805625f965SAjay Singh { 8815625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 8825625f965SAjay Singh int result; 8835625f965SAjay Singh 8845625f965SAjay Singh result = wilc_spi_write_cmd(wilc, CMD_INTERNAL_WRITE, adr, dat, 0); 8855625f965SAjay Singh if (result) { 8865625f965SAjay Singh dev_err(&spi->dev, "Failed internal write cmd...\n"); 8875625f965SAjay Singh return result; 8885625f965SAjay Singh } 8895625f965SAjay Singh 8905625f965SAjay Singh return 0; 8915625f965SAjay Singh } 8925625f965SAjay Singh 8935625f965SAjay Singh static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data) 8945625f965SAjay Singh { 8955625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 896c872e7aeSDavid Mosberger-Tang struct wilc_spi *spi_priv = wilc->bus_data; 8975625f965SAjay Singh int result; 8985625f965SAjay Singh 8995625f965SAjay Singh result = wilc_spi_single_read(wilc, CMD_INTERNAL_READ, adr, data, 0); 9005625f965SAjay Singh if (result) { 901c872e7aeSDavid Mosberger-Tang if (!spi_priv->probing_crc) 9025625f965SAjay Singh dev_err(&spi->dev, "Failed internal read cmd...\n"); 9035625f965SAjay Singh return result; 9045625f965SAjay Singh } 9055625f965SAjay Singh 9065625f965SAjay Singh le32_to_cpus(data); 9075625f965SAjay Singh 9085625f965SAjay Singh return 0; 9095625f965SAjay Singh } 9105625f965SAjay Singh 9115625f965SAjay Singh /******************************************** 9125625f965SAjay Singh * 9135625f965SAjay Singh * Spi interfaces 9145625f965SAjay Singh * 9155625f965SAjay Singh ********************************************/ 9165625f965SAjay Singh 9175625f965SAjay Singh static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data) 9185625f965SAjay Singh { 9195625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 9205625f965SAjay Singh int result; 9215625f965SAjay Singh u8 cmd = CMD_SINGLE_WRITE; 9225625f965SAjay Singh u8 clockless = 0; 9235625f965SAjay Singh 9245625f965SAjay Singh if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) { 9255625f965SAjay Singh /* Clockless register */ 9265625f965SAjay Singh cmd = CMD_INTERNAL_WRITE; 9275625f965SAjay Singh clockless = 1; 9285625f965SAjay Singh } 9295625f965SAjay Singh 9305625f965SAjay Singh result = wilc_spi_write_cmd(wilc, cmd, addr, data, clockless); 9315625f965SAjay Singh if (result) { 9325625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr); 9335625f965SAjay Singh return result; 9345625f965SAjay Singh } 9355625f965SAjay Singh 9365625f965SAjay Singh return 0; 9375625f965SAjay Singh } 9385625f965SAjay Singh 939ce3b9338SDavid Mosberger-Tang static int spi_data_rsp(struct wilc *wilc, u8 cmd) 940ce3b9338SDavid Mosberger-Tang { 941ce3b9338SDavid Mosberger-Tang struct spi_device *spi = to_spi_device(wilc->dev); 942ce3b9338SDavid Mosberger-Tang int result, i; 943ce3b9338SDavid Mosberger-Tang u8 rsp[4]; 944ce3b9338SDavid Mosberger-Tang 945ce3b9338SDavid Mosberger-Tang /* 946ce3b9338SDavid Mosberger-Tang * The response to data packets is two bytes long. For 947ce3b9338SDavid Mosberger-Tang * efficiency's sake, wilc_spi_write() wisely ignores the 948ce3b9338SDavid Mosberger-Tang * responses for all packets but the final one. The downside 949ce3b9338SDavid Mosberger-Tang * of that optimization is that when the final data packet is 950ce3b9338SDavid Mosberger-Tang * short, we may receive (part of) the response to the 951ce3b9338SDavid Mosberger-Tang * second-to-last packet before the one for the final packet. 952ce3b9338SDavid Mosberger-Tang * To handle this, we always read 4 bytes and then search for 953ce3b9338SDavid Mosberger-Tang * the last byte that contains the "Response Start" code (0xc 954ce3b9338SDavid Mosberger-Tang * in the top 4 bits). We then know that this byte is the 955ce3b9338SDavid Mosberger-Tang * first response byte of the final data packet. 956ce3b9338SDavid Mosberger-Tang */ 957ce3b9338SDavid Mosberger-Tang result = wilc_spi_rx(wilc, rsp, sizeof(rsp)); 958ce3b9338SDavid Mosberger-Tang if (result) { 959ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, "Failed bus error...\n"); 960ce3b9338SDavid Mosberger-Tang return result; 961ce3b9338SDavid Mosberger-Tang } 962ce3b9338SDavid Mosberger-Tang 963ce3b9338SDavid Mosberger-Tang for (i = sizeof(rsp) - 2; i >= 0; --i) 964ce3b9338SDavid Mosberger-Tang if (FIELD_GET(RSP_START_FIELD, rsp[i]) == RSP_START_TAG) 965ce3b9338SDavid Mosberger-Tang break; 966ce3b9338SDavid Mosberger-Tang 967ce3b9338SDavid Mosberger-Tang if (i < 0) { 968ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, 969ce3b9338SDavid Mosberger-Tang "Data packet response missing (%02x %02x %02x %02x)\n", 970ce3b9338SDavid Mosberger-Tang rsp[0], rsp[1], rsp[2], rsp[3]); 971ce3b9338SDavid Mosberger-Tang return -1; 972ce3b9338SDavid Mosberger-Tang } 973ce3b9338SDavid Mosberger-Tang 974ce3b9338SDavid Mosberger-Tang /* rsp[i] is the last response start byte */ 975ce3b9338SDavid Mosberger-Tang 976ce3b9338SDavid Mosberger-Tang if (FIELD_GET(RSP_TYPE_FIELD, rsp[i]) != RSP_TYPE_LAST_PACKET 977ce3b9338SDavid Mosberger-Tang || rsp[i + 1] != RSP_STATE_NO_ERROR) { 978ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, "Data response error (%02x %02x)\n", 979ce3b9338SDavid Mosberger-Tang rsp[i], rsp[i + 1]); 980ce3b9338SDavid Mosberger-Tang return -1; 981ce3b9338SDavid Mosberger-Tang } 982ce3b9338SDavid Mosberger-Tang return 0; 983ce3b9338SDavid Mosberger-Tang } 984ce3b9338SDavid Mosberger-Tang 9855625f965SAjay Singh static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) 9865625f965SAjay Singh { 9875625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 9885625f965SAjay Singh int result; 9895625f965SAjay Singh 9905625f965SAjay Singh /* 9915625f965SAjay Singh * has to be greated than 4 9925625f965SAjay Singh */ 9935625f965SAjay Singh if (size <= 4) 9945625f965SAjay Singh return -EINVAL; 9955625f965SAjay Singh 9965625f965SAjay Singh result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size); 9975625f965SAjay Singh if (result) { 9985625f965SAjay Singh dev_err(&spi->dev, 9995625f965SAjay Singh "Failed cmd, write block (%08x)...\n", addr); 10005625f965SAjay Singh return result; 10015625f965SAjay Singh } 10025625f965SAjay Singh 10035625f965SAjay Singh /* 10045625f965SAjay Singh * Data 10055625f965SAjay Singh */ 10065625f965SAjay Singh result = spi_data_write(wilc, buf, size); 10075625f965SAjay Singh if (result) { 10085625f965SAjay Singh dev_err(&spi->dev, "Failed block data write...\n"); 10095625f965SAjay Singh return result; 10105625f965SAjay Singh } 10115625f965SAjay Singh 1012ce3b9338SDavid Mosberger-Tang /* 1013ce3b9338SDavid Mosberger-Tang * Data response 1014ce3b9338SDavid Mosberger-Tang */ 1015ce3b9338SDavid Mosberger-Tang return spi_data_rsp(wilc, CMD_DMA_EXT_WRITE); 10165625f965SAjay Singh } 10175625f965SAjay Singh 10185625f965SAjay Singh /******************************************** 10195625f965SAjay Singh * 10205625f965SAjay Singh * Bus interfaces 10215625f965SAjay Singh * 10225625f965SAjay Singh ********************************************/ 10235625f965SAjay Singh 1024c2dcb476SAjay Singh static int wilc_spi_reset(struct wilc *wilc) 1025c2dcb476SAjay Singh { 1026c2dcb476SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 1027c2dcb476SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 1028c2dcb476SAjay Singh int result; 1029c2dcb476SAjay Singh 1030c2dcb476SAjay Singh result = wilc_spi_special_cmd(wilc, CMD_RESET); 1031c2dcb476SAjay Singh if (result && !spi_priv->probing_crc) 1032c2dcb476SAjay Singh dev_err(&spi->dev, "Failed cmd reset\n"); 1033c2dcb476SAjay Singh 1034c2dcb476SAjay Singh return result; 1035c2dcb476SAjay Singh } 1036c2dcb476SAjay Singh 10375625f965SAjay Singh static int wilc_spi_deinit(struct wilc *wilc) 10385625f965SAjay Singh { 1039*ec031ac4SDavid Mosberger-Tang struct wilc_spi *spi_priv = wilc->bus_data; 1040*ec031ac4SDavid Mosberger-Tang 1041*ec031ac4SDavid Mosberger-Tang spi_priv->isinit = false; 1042*ec031ac4SDavid Mosberger-Tang wilc_wlan_power(wilc, false); 10435625f965SAjay Singh return 0; 10445625f965SAjay Singh } 10455625f965SAjay Singh 10465625f965SAjay Singh static int wilc_spi_init(struct wilc *wilc, bool resume) 10475625f965SAjay Singh { 10485625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 10495625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 10505625f965SAjay Singh u32 reg; 10515625f965SAjay Singh u32 chipid; 1052c872e7aeSDavid Mosberger-Tang int ret, i; 10535625f965SAjay Singh 105450cbbfd4SDavid Mosberger-Tang if (spi_priv->isinit) { 105550cbbfd4SDavid Mosberger-Tang /* Confirm we can read chipid register without error: */ 10565625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); 105750cbbfd4SDavid Mosberger-Tang if (ret == 0) 105850cbbfd4SDavid Mosberger-Tang return 0; 10595625f965SAjay Singh 106050cbbfd4SDavid Mosberger-Tang dev_err(&spi->dev, "Fail cmd read chip id...\n"); 10615625f965SAjay Singh } 10625625f965SAjay Singh 1063*ec031ac4SDavid Mosberger-Tang wilc_wlan_power(wilc, true); 1064*ec031ac4SDavid Mosberger-Tang 10655625f965SAjay Singh /* 10665625f965SAjay Singh * configure protocol 10675625f965SAjay Singh */ 10685625f965SAjay Singh 10695625f965SAjay Singh /* 1070c872e7aeSDavid Mosberger-Tang * Infer the CRC settings that are currently in effect. This 1071c872e7aeSDavid Mosberger-Tang * is necessary because we can't be sure that the chip has 1072c872e7aeSDavid Mosberger-Tang * been RESET (e.g, after module unload and reload). 10735625f965SAjay Singh */ 1074c872e7aeSDavid Mosberger-Tang spi_priv->probing_crc = true; 1075c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = enable_crc7; 1076c872e7aeSDavid Mosberger-Tang spi_priv->crc16_enabled = false; /* don't check CRC16 during probing */ 1077c872e7aeSDavid Mosberger-Tang for (i = 0; i < 2; ++i) { 10785625f965SAjay Singh ret = spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); 1079c872e7aeSDavid Mosberger-Tang if (ret == 0) 1080c872e7aeSDavid Mosberger-Tang break; 1081c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = !enable_crc7; 1082c872e7aeSDavid Mosberger-Tang } 10835625f965SAjay Singh if (ret) { 1084c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "Failed with CRC7 on and off.\n"); 10855625f965SAjay Singh return ret; 10865625f965SAjay Singh } 10875ee2d9ddSDavid Mosberger-Tang 1088c872e7aeSDavid Mosberger-Tang /* set up the desired CRC configuration: */ 1089c872e7aeSDavid Mosberger-Tang reg &= ~(PROTOCOL_REG_CRC7_MASK | PROTOCOL_REG_CRC16_MASK); 1090c872e7aeSDavid Mosberger-Tang if (enable_crc7) 1091c872e7aeSDavid Mosberger-Tang reg |= PROTOCOL_REG_CRC7_MASK; 1092c872e7aeSDavid Mosberger-Tang if (enable_crc16) 1093c872e7aeSDavid Mosberger-Tang reg |= PROTOCOL_REG_CRC16_MASK; 1094c872e7aeSDavid Mosberger-Tang 1095c872e7aeSDavid Mosberger-Tang /* set up the data packet size: */ 10965ee2d9ddSDavid Mosberger-Tang BUILD_BUG_ON(DATA_PKT_LOG_SZ < DATA_PKT_LOG_SZ_MIN 10975ee2d9ddSDavid Mosberger-Tang || DATA_PKT_LOG_SZ > DATA_PKT_LOG_SZ_MAX); 10985ee2d9ddSDavid Mosberger-Tang reg &= ~PROTOCOL_REG_PKT_SZ_MASK; 10995ee2d9ddSDavid Mosberger-Tang reg |= FIELD_PREP(PROTOCOL_REG_PKT_SZ_MASK, 11005ee2d9ddSDavid Mosberger-Tang DATA_PKT_LOG_SZ - DATA_PKT_LOG_SZ_MIN); 11015ee2d9ddSDavid Mosberger-Tang 1102c872e7aeSDavid Mosberger-Tang /* establish the new setup: */ 11035625f965SAjay Singh ret = spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg); 11045625f965SAjay Singh if (ret) { 11055625f965SAjay Singh dev_err(&spi->dev, 11065625f965SAjay Singh "[wilc spi %d]: Failed internal write reg\n", 11075625f965SAjay Singh __LINE__); 11085625f965SAjay Singh return ret; 11095625f965SAjay Singh } 1110c872e7aeSDavid Mosberger-Tang /* update our state to match new protocol settings: */ 1111c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = enable_crc7; 1112c872e7aeSDavid Mosberger-Tang spi_priv->crc16_enabled = enable_crc16; 1113c872e7aeSDavid Mosberger-Tang 1114c872e7aeSDavid Mosberger-Tang /* re-read to make sure new settings are in effect: */ 1115c872e7aeSDavid Mosberger-Tang spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); 1116c872e7aeSDavid Mosberger-Tang 1117c872e7aeSDavid Mosberger-Tang spi_priv->probing_crc = false; 11185625f965SAjay Singh 11195625f965SAjay Singh /* 112050cbbfd4SDavid Mosberger-Tang * make sure can read chip id without protocol error 11215625f965SAjay Singh */ 11225625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); 11235625f965SAjay Singh if (ret) { 11245625f965SAjay Singh dev_err(&spi->dev, "Fail cmd read chip id...\n"); 11255625f965SAjay Singh return ret; 11265625f965SAjay Singh } 11275625f965SAjay Singh 112850cbbfd4SDavid Mosberger-Tang spi_priv->isinit = true; 11295625f965SAjay Singh 11305625f965SAjay Singh return 0; 11315625f965SAjay Singh } 11325625f965SAjay Singh 11335625f965SAjay Singh static int wilc_spi_read_size(struct wilc *wilc, u32 *size) 11345625f965SAjay Singh { 11355625f965SAjay Singh int ret; 11365625f965SAjay Singh 11375625f965SAjay Singh ret = spi_internal_read(wilc, 11385625f965SAjay Singh WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, size); 11395625f965SAjay Singh *size = FIELD_GET(IRQ_DMA_WD_CNT_MASK, *size); 11405625f965SAjay Singh 11415625f965SAjay Singh return ret; 11425625f965SAjay Singh } 11435625f965SAjay Singh 11445625f965SAjay Singh static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status) 11455625f965SAjay Singh { 11465625f965SAjay Singh return spi_internal_read(wilc, WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, 11475625f965SAjay Singh int_status); 11485625f965SAjay Singh } 11495625f965SAjay Singh 11505625f965SAjay Singh static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val) 11515625f965SAjay Singh { 1152382726d1SAjay Singh int ret; 1153382726d1SAjay Singh int retry = SPI_ENABLE_VMM_RETRY_LIMIT; 1154382726d1SAjay Singh u32 check; 1155382726d1SAjay Singh 1156382726d1SAjay Singh while (retry) { 1157382726d1SAjay Singh ret = spi_internal_write(wilc, 1158382726d1SAjay Singh WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE, 11595625f965SAjay Singh val); 1160382726d1SAjay Singh if (ret) 1161382726d1SAjay Singh break; 1162382726d1SAjay Singh 1163382726d1SAjay Singh ret = spi_internal_read(wilc, 1164382726d1SAjay Singh WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE, 1165382726d1SAjay Singh &check); 1166382726d1SAjay Singh if (ret || ((check & EN_VMM) == (val & EN_VMM))) 1167382726d1SAjay Singh break; 1168382726d1SAjay Singh 1169382726d1SAjay Singh retry--; 1170382726d1SAjay Singh } 1171382726d1SAjay Singh return ret; 11725625f965SAjay Singh } 11735625f965SAjay Singh 11745625f965SAjay Singh static int wilc_spi_sync_ext(struct wilc *wilc, int nint) 11755625f965SAjay Singh { 11765625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 11775625f965SAjay Singh u32 reg; 11785625f965SAjay Singh int ret, i; 11795625f965SAjay Singh 11805625f965SAjay Singh if (nint > MAX_NUM_INT) { 11815625f965SAjay Singh dev_err(&spi->dev, "Too many interrupts (%d)...\n", nint); 11825625f965SAjay Singh return -EINVAL; 11835625f965SAjay Singh } 11845625f965SAjay Singh 11855625f965SAjay Singh /* 11865625f965SAjay Singh * interrupt pin mux select 11875625f965SAjay Singh */ 11885625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, ®); 11895625f965SAjay Singh if (ret) { 11905625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 11915625f965SAjay Singh WILC_PIN_MUX_0); 11925625f965SAjay Singh return ret; 11935625f965SAjay Singh } 11945625f965SAjay Singh reg |= BIT(8); 11955625f965SAjay Singh ret = wilc_spi_write_reg(wilc, WILC_PIN_MUX_0, reg); 11965625f965SAjay Singh if (ret) { 11975625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 11985625f965SAjay Singh WILC_PIN_MUX_0); 11995625f965SAjay Singh return ret; 12005625f965SAjay Singh } 12015625f965SAjay Singh 12025625f965SAjay Singh /* 12035625f965SAjay Singh * interrupt enable 12045625f965SAjay Singh */ 12055625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, ®); 12065625f965SAjay Singh if (ret) { 12075625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 12085625f965SAjay Singh WILC_INTR_ENABLE); 12095625f965SAjay Singh return ret; 12105625f965SAjay Singh } 12115625f965SAjay Singh 12125625f965SAjay Singh for (i = 0; (i < 5) && (nint > 0); i++, nint--) 12135625f965SAjay Singh reg |= (BIT((27 + i))); 12145625f965SAjay Singh 12155625f965SAjay Singh ret = wilc_spi_write_reg(wilc, WILC_INTR_ENABLE, reg); 12165625f965SAjay Singh if (ret) { 12175625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 12185625f965SAjay Singh WILC_INTR_ENABLE); 12195625f965SAjay Singh return ret; 12205625f965SAjay Singh } 12215625f965SAjay Singh if (nint) { 12225625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, ®); 12235625f965SAjay Singh if (ret) { 12245625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 12255625f965SAjay Singh WILC_INTR2_ENABLE); 12265625f965SAjay Singh return ret; 12275625f965SAjay Singh } 12285625f965SAjay Singh 12295625f965SAjay Singh for (i = 0; (i < 3) && (nint > 0); i++, nint--) 12305625f965SAjay Singh reg |= BIT(i); 12315625f965SAjay Singh 1232301cfbabSAjay Singh ret = wilc_spi_write_reg(wilc, WILC_INTR2_ENABLE, reg); 12335625f965SAjay Singh if (ret) { 12345625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 12355625f965SAjay Singh WILC_INTR2_ENABLE); 12365625f965SAjay Singh return ret; 12375625f965SAjay Singh } 12385625f965SAjay Singh } 12395625f965SAjay Singh 12405625f965SAjay Singh return 0; 12415625f965SAjay Singh } 12425625f965SAjay Singh 12435625f965SAjay Singh /* Global spi HIF function table */ 12445625f965SAjay Singh static const struct wilc_hif_func wilc_hif_spi = { 12455625f965SAjay Singh .hif_init = wilc_spi_init, 12465625f965SAjay Singh .hif_deinit = wilc_spi_deinit, 12475625f965SAjay Singh .hif_read_reg = wilc_spi_read_reg, 12485625f965SAjay Singh .hif_write_reg = wilc_spi_write_reg, 12495625f965SAjay Singh .hif_block_rx = wilc_spi_read, 12505625f965SAjay Singh .hif_block_tx = wilc_spi_write, 12515625f965SAjay Singh .hif_read_int = wilc_spi_read_int, 12525625f965SAjay Singh .hif_clear_int_ext = wilc_spi_clear_int_ext, 12535625f965SAjay Singh .hif_read_size = wilc_spi_read_size, 12545625f965SAjay Singh .hif_block_tx_ext = wilc_spi_write, 12555625f965SAjay Singh .hif_block_rx_ext = wilc_spi_read, 12565625f965SAjay Singh .hif_sync_ext = wilc_spi_sync_ext, 1257c2dcb476SAjay Singh .hif_reset = wilc_spi_reset, 12585625f965SAjay Singh }; 1259