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> 11ec031ac4SDavid 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 */ 49ec031ac4SDavid Mosberger-Tang struct wilc_gpios { 50ec031ac4SDavid Mosberger-Tang struct gpio_desc *enable; /* ENABLE GPIO or NULL */ 51ec031ac4SDavid Mosberger-Tang struct gpio_desc *reset; /* RESET GPIO or NULL */ 52ec031ac4SDavid 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 160ec031ac4SDavid Mosberger-Tang static int wilc_parse_gpios(struct wilc *wilc) 161ec031ac4SDavid Mosberger-Tang { 162ec031ac4SDavid Mosberger-Tang struct spi_device *spi = to_spi_device(wilc->dev); 163ec031ac4SDavid Mosberger-Tang struct wilc_spi *spi_priv = wilc->bus_data; 164ec031ac4SDavid Mosberger-Tang struct wilc_gpios *gpios = &spi_priv->gpios; 165ec031ac4SDavid Mosberger-Tang 166ec031ac4SDavid Mosberger-Tang /* get ENABLE pin and deassert it (if it is defined): */ 167ec031ac4SDavid Mosberger-Tang gpios->enable = devm_gpiod_get_optional(&spi->dev, 168ec031ac4SDavid Mosberger-Tang "enable", GPIOD_OUT_LOW); 169ec031ac4SDavid Mosberger-Tang /* get RESET pin and assert it (if it is defined): */ 170ec031ac4SDavid Mosberger-Tang if (gpios->enable) { 171ec031ac4SDavid Mosberger-Tang /* if enable pin exists, reset must exist as well */ 172ec031ac4SDavid Mosberger-Tang gpios->reset = devm_gpiod_get(&spi->dev, 173ec031ac4SDavid Mosberger-Tang "reset", GPIOD_OUT_HIGH); 174ec031ac4SDavid Mosberger-Tang if (IS_ERR(gpios->reset)) { 175ec031ac4SDavid Mosberger-Tang dev_err(&spi->dev, "missing reset gpio.\n"); 176ec031ac4SDavid Mosberger-Tang return PTR_ERR(gpios->reset); 177ec031ac4SDavid Mosberger-Tang } 178ec031ac4SDavid Mosberger-Tang } else { 179ec031ac4SDavid Mosberger-Tang gpios->reset = devm_gpiod_get_optional(&spi->dev, 180ec031ac4SDavid Mosberger-Tang "reset", GPIOD_OUT_HIGH); 181ec031ac4SDavid Mosberger-Tang } 182ec031ac4SDavid Mosberger-Tang return 0; 183ec031ac4SDavid Mosberger-Tang } 184ec031ac4SDavid Mosberger-Tang 185ec031ac4SDavid Mosberger-Tang static void wilc_wlan_power(struct wilc *wilc, bool on) 186ec031ac4SDavid Mosberger-Tang { 187ec031ac4SDavid Mosberger-Tang struct wilc_spi *spi_priv = wilc->bus_data; 188ec031ac4SDavid Mosberger-Tang struct wilc_gpios *gpios = &spi_priv->gpios; 189ec031ac4SDavid Mosberger-Tang 190ec031ac4SDavid Mosberger-Tang if (on) { 191ec031ac4SDavid Mosberger-Tang /* assert ENABLE: */ 192ec031ac4SDavid Mosberger-Tang gpiod_set_value(gpios->enable, 1); 193ec031ac4SDavid Mosberger-Tang mdelay(5); 194ec031ac4SDavid Mosberger-Tang /* assert RESET: */ 195ec031ac4SDavid Mosberger-Tang gpiod_set_value(gpios->reset, 1); 196fcf690b0SAjay Singh } else { 197fcf690b0SAjay Singh /* deassert RESET: */ 198fcf690b0SAjay Singh gpiod_set_value(gpios->reset, 0); 199ec031ac4SDavid Mosberger-Tang /* deassert ENABLE: */ 200ec031ac4SDavid Mosberger-Tang gpiod_set_value(gpios->enable, 0); 201ec031ac4SDavid Mosberger-Tang } 202ec031ac4SDavid Mosberger-Tang } 203ec031ac4SDavid 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 223ec031ac4SDavid Mosberger-Tang ret = wilc_parse_gpios(wilc); 224ec031ac4SDavid Mosberger-Tang if (ret < 0) 225ec031ac4SDavid Mosberger-Tang goto netdev_cleanup; 226ec031ac4SDavid 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 243a0386bbaSUwe Kleine-König static void 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); 2515625f965SAjay Singh } 2525625f965SAjay Singh 2535625f965SAjay Singh static const struct of_device_id wilc_of_match[] = { 2545625f965SAjay Singh { .compatible = "microchip,wilc1000", }, 2555625f965SAjay Singh { /* sentinel */ } 2565625f965SAjay Singh }; 2575625f965SAjay Singh MODULE_DEVICE_TABLE(of, wilc_of_match); 2585625f965SAjay Singh 259f2f16ae9SDavid Mosberger-Tang static const struct spi_device_id wilc_spi_id[] = { 260f2f16ae9SDavid Mosberger-Tang { "wilc1000", 0 }, 261f2f16ae9SDavid Mosberger-Tang { /* sentinel */ } 262f2f16ae9SDavid Mosberger-Tang }; 263f2f16ae9SDavid Mosberger-Tang MODULE_DEVICE_TABLE(spi, wilc_spi_id); 264f2f16ae9SDavid Mosberger-Tang 2655625f965SAjay Singh static struct spi_driver wilc_spi_driver = { 2665625f965SAjay Singh .driver = { 2674347d34eSDavid Mosberger-Tang .name = SPI_MODALIAS, 2685625f965SAjay Singh .of_match_table = wilc_of_match, 2695625f965SAjay Singh }, 270f2f16ae9SDavid Mosberger-Tang .id_table = wilc_spi_id, 2715625f965SAjay Singh .probe = wilc_bus_probe, 2725625f965SAjay Singh .remove = wilc_bus_remove, 2735625f965SAjay Singh }; 2745625f965SAjay Singh module_spi_driver(wilc_spi_driver); 2755625f965SAjay Singh MODULE_LICENSE("GPL"); 2765625f965SAjay Singh 2775625f965SAjay Singh static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len) 2785625f965SAjay Singh { 2795625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 2805625f965SAjay Singh int ret; 2815625f965SAjay Singh struct spi_message msg; 2825625f965SAjay Singh 2835625f965SAjay Singh if (len > 0 && b) { 2845625f965SAjay Singh struct spi_transfer tr = { 2855625f965SAjay Singh .tx_buf = b, 2865625f965SAjay Singh .len = len, 2875625f965SAjay Singh .delay = { 2885625f965SAjay Singh .value = 0, 2895625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 2905625f965SAjay Singh }, 2915625f965SAjay Singh }; 2925625f965SAjay Singh char *r_buffer = kzalloc(len, GFP_KERNEL); 2935625f965SAjay Singh 2945625f965SAjay Singh if (!r_buffer) 2955625f965SAjay Singh return -ENOMEM; 2965625f965SAjay Singh 2975625f965SAjay Singh tr.rx_buf = r_buffer; 2985625f965SAjay Singh dev_dbg(&spi->dev, "Request writing %d bytes\n", len); 2995625f965SAjay Singh 3005625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 3015625f965SAjay Singh spi_message_init(&msg); 3025625f965SAjay Singh msg.spi = spi; 3035625f965SAjay Singh spi_message_add_tail(&tr, &msg); 3045625f965SAjay Singh 3055625f965SAjay Singh ret = spi_sync(spi, &msg); 3065625f965SAjay Singh if (ret < 0) 3075625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 3085625f965SAjay Singh 3095625f965SAjay Singh kfree(r_buffer); 3105625f965SAjay Singh } else { 3115625f965SAjay Singh dev_err(&spi->dev, 3125625f965SAjay Singh "can't write data with the following length: %d\n", 3135625f965SAjay Singh len); 3145625f965SAjay Singh ret = -EINVAL; 3155625f965SAjay Singh } 3165625f965SAjay Singh 3175625f965SAjay Singh return ret; 3185625f965SAjay Singh } 3195625f965SAjay Singh 3205625f965SAjay Singh static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen) 3215625f965SAjay Singh { 3225625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 3235625f965SAjay Singh int ret; 3245625f965SAjay Singh 3255625f965SAjay Singh if (rlen > 0) { 3265625f965SAjay Singh struct spi_message msg; 3275625f965SAjay Singh struct spi_transfer tr = { 3285625f965SAjay Singh .rx_buf = rb, 3295625f965SAjay Singh .len = rlen, 3305625f965SAjay Singh .delay = { 3315625f965SAjay Singh .value = 0, 3325625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 3335625f965SAjay Singh }, 3345625f965SAjay Singh 3355625f965SAjay Singh }; 3365625f965SAjay Singh char *t_buffer = kzalloc(rlen, GFP_KERNEL); 3375625f965SAjay Singh 3385625f965SAjay Singh if (!t_buffer) 3395625f965SAjay Singh return -ENOMEM; 3405625f965SAjay Singh 3415625f965SAjay Singh tr.tx_buf = t_buffer; 3425625f965SAjay Singh 3435625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 3445625f965SAjay Singh spi_message_init(&msg); 3455625f965SAjay Singh msg.spi = spi; 3465625f965SAjay Singh spi_message_add_tail(&tr, &msg); 3475625f965SAjay Singh 3485625f965SAjay Singh ret = spi_sync(spi, &msg); 3495625f965SAjay Singh if (ret < 0) 3505625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 3515625f965SAjay Singh kfree(t_buffer); 3525625f965SAjay Singh } else { 3535625f965SAjay Singh dev_err(&spi->dev, 3545625f965SAjay Singh "can't read data with the following length: %u\n", 3555625f965SAjay Singh rlen); 3565625f965SAjay Singh ret = -EINVAL; 3575625f965SAjay Singh } 3585625f965SAjay Singh 3595625f965SAjay Singh return ret; 3605625f965SAjay Singh } 3615625f965SAjay Singh 3625625f965SAjay Singh static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen) 3635625f965SAjay Singh { 3645625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 3655625f965SAjay Singh int ret; 3665625f965SAjay Singh 3675625f965SAjay Singh if (rlen > 0) { 3685625f965SAjay Singh struct spi_message msg; 3695625f965SAjay Singh struct spi_transfer tr = { 3705625f965SAjay Singh .rx_buf = rb, 3715625f965SAjay Singh .tx_buf = wb, 3725625f965SAjay Singh .len = rlen, 3735625f965SAjay Singh .bits_per_word = 8, 3745625f965SAjay Singh .delay = { 3755625f965SAjay Singh .value = 0, 3765625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 3775625f965SAjay Singh }, 3785625f965SAjay Singh 3795625f965SAjay Singh }; 3805625f965SAjay Singh 3815625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 3825625f965SAjay Singh spi_message_init(&msg); 3835625f965SAjay Singh msg.spi = spi; 3845625f965SAjay Singh 3855625f965SAjay Singh spi_message_add_tail(&tr, &msg); 3865625f965SAjay Singh ret = spi_sync(spi, &msg); 3875625f965SAjay Singh if (ret < 0) 3885625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 3895625f965SAjay Singh } else { 3905625f965SAjay Singh dev_err(&spi->dev, 3915625f965SAjay Singh "can't read data with the following length: %u\n", 3925625f965SAjay Singh rlen); 3935625f965SAjay Singh ret = -EINVAL; 3945625f965SAjay Singh } 3955625f965SAjay Singh 3965625f965SAjay Singh return ret; 3975625f965SAjay Singh } 3985625f965SAjay Singh 3995625f965SAjay Singh static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) 4005625f965SAjay Singh { 4015625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 4025625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 4035625f965SAjay Singh int ix, nbytes; 4045625f965SAjay Singh int result = 0; 405c872e7aeSDavid Mosberger-Tang u8 cmd, order, crc[2]; 406c872e7aeSDavid Mosberger-Tang u16 crc_calc; 4075625f965SAjay Singh 4085625f965SAjay Singh /* 4095625f965SAjay Singh * Data 4105625f965SAjay Singh */ 4115625f965SAjay Singh ix = 0; 4125625f965SAjay Singh do { 4135625f965SAjay Singh if (sz <= DATA_PKT_SZ) { 4145625f965SAjay Singh nbytes = sz; 4155625f965SAjay Singh order = 0x3; 4165625f965SAjay Singh } else { 4175625f965SAjay Singh nbytes = DATA_PKT_SZ; 4185625f965SAjay Singh if (ix == 0) 4195625f965SAjay Singh order = 0x1; 4205625f965SAjay Singh else 4215625f965SAjay Singh order = 0x02; 4225625f965SAjay Singh } 4235625f965SAjay Singh 4245625f965SAjay Singh /* 4255625f965SAjay Singh * Write command 4265625f965SAjay Singh */ 4275625f965SAjay Singh cmd = 0xf0; 4285625f965SAjay Singh cmd |= order; 4295625f965SAjay Singh 4305625f965SAjay Singh if (wilc_spi_tx(wilc, &cmd, 1)) { 4315625f965SAjay Singh dev_err(&spi->dev, 4325625f965SAjay Singh "Failed data block cmd write, bus error...\n"); 4335625f965SAjay Singh result = -EINVAL; 4345625f965SAjay Singh break; 4355625f965SAjay Singh } 4365625f965SAjay Singh 4375625f965SAjay Singh /* 4385625f965SAjay Singh * Write data 4395625f965SAjay Singh */ 4405625f965SAjay Singh if (wilc_spi_tx(wilc, &b[ix], nbytes)) { 4415625f965SAjay Singh dev_err(&spi->dev, 4425625f965SAjay Singh "Failed data block write, bus error...\n"); 4435625f965SAjay Singh result = -EINVAL; 4445625f965SAjay Singh break; 4455625f965SAjay Singh } 4465625f965SAjay Singh 4475625f965SAjay Singh /* 448c872e7aeSDavid Mosberger-Tang * Write CRC 4495625f965SAjay Singh */ 450c872e7aeSDavid Mosberger-Tang if (spi_priv->crc16_enabled) { 451c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, &b[ix], nbytes); 452c872e7aeSDavid Mosberger-Tang crc[0] = crc_calc >> 8; 453c872e7aeSDavid Mosberger-Tang crc[1] = crc_calc; 4545625f965SAjay Singh if (wilc_spi_tx(wilc, crc, 2)) { 4555625f965SAjay Singh dev_err(&spi->dev, "Failed data block crc write, bus error...\n"); 4565625f965SAjay Singh result = -EINVAL; 4575625f965SAjay Singh break; 4585625f965SAjay Singh } 4595625f965SAjay Singh } 4605625f965SAjay Singh 4615625f965SAjay Singh /* 4625625f965SAjay Singh * No need to wait for response 4635625f965SAjay Singh */ 4645625f965SAjay Singh ix += nbytes; 4655625f965SAjay Singh sz -= nbytes; 4665625f965SAjay Singh } while (sz); 4675625f965SAjay Singh 4685625f965SAjay Singh return result; 4695625f965SAjay Singh } 4705625f965SAjay Singh 4715625f965SAjay Singh /******************************************** 4725625f965SAjay Singh * 4735625f965SAjay Singh * Spi Internal Read/Write Function 4745625f965SAjay Singh * 4755625f965SAjay Singh ********************************************/ 4765625f965SAjay Singh static u8 wilc_get_crc7(u8 *buffer, u32 len) 4775625f965SAjay Singh { 4785625f965SAjay Singh return crc7_be(0xfe, buffer, len); 4795625f965SAjay Singh } 4805625f965SAjay Singh 4815625f965SAjay Singh static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, 4825625f965SAjay Singh u8 clockless) 4835625f965SAjay Singh { 4845625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 4855625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 4865625f965SAjay Singh u8 wb[32], rb[32]; 487f2131fa5SDavid Mosberger-Tang int cmd_len, resp_len, i; 488c872e7aeSDavid Mosberger-Tang u16 crc_calc, crc_recv; 4895625f965SAjay Singh struct wilc_spi_cmd *c; 490f2131fa5SDavid Mosberger-Tang struct wilc_spi_rsp_data *r; 491c872e7aeSDavid Mosberger-Tang struct wilc_spi_read_rsp_data *r_data; 4925625f965SAjay Singh 4935625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 4945625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 4955625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 4965625f965SAjay Singh c->cmd_type = cmd; 4975625f965SAjay Singh if (cmd == CMD_SINGLE_READ) { 4985625f965SAjay Singh c->u.simple_cmd.addr[0] = adr >> 16; 4995625f965SAjay Singh c->u.simple_cmd.addr[1] = adr >> 8; 5005625f965SAjay Singh c->u.simple_cmd.addr[2] = adr; 5015625f965SAjay Singh } else if (cmd == CMD_INTERNAL_READ) { 5025625f965SAjay Singh c->u.simple_cmd.addr[0] = adr >> 8; 5035625f965SAjay Singh if (clockless == 1) 5045625f965SAjay Singh c->u.simple_cmd.addr[0] |= BIT(7); 5055625f965SAjay Singh c->u.simple_cmd.addr[1] = adr; 5065625f965SAjay Singh c->u.simple_cmd.addr[2] = 0x0; 5075625f965SAjay Singh } else { 5085625f965SAjay Singh dev_err(&spi->dev, "cmd [%x] not supported\n", cmd); 5095625f965SAjay Singh return -EINVAL; 5105625f965SAjay Singh } 5115625f965SAjay Singh 5125625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc); 513f2131fa5SDavid Mosberger-Tang resp_len = sizeof(*r) + sizeof(*r_data) + WILC_SPI_RSP_HDR_EXTRA_DATA; 514f2131fa5SDavid Mosberger-Tang 515c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) { 5165625f965SAjay Singh c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 5175625f965SAjay Singh cmd_len += 1; 5185625f965SAjay Singh resp_len += 2; 5195625f965SAjay Singh } 5205625f965SAjay Singh 5215625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 5225625f965SAjay Singh dev_err(&spi->dev, 5235625f965SAjay Singh "spi buffer size too small (%d) (%d) (%zu)\n", 5245625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 5255625f965SAjay Singh return -EINVAL; 5265625f965SAjay Singh } 5275625f965SAjay Singh 5285625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 5295625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 5305625f965SAjay Singh return -EINVAL; 5315625f965SAjay Singh } 5325625f965SAjay Singh 533f2131fa5SDavid Mosberger-Tang r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 534aa3fda4fSAjay Singh if (r->rsp_cmd_type != cmd && !clockless) { 535c872e7aeSDavid Mosberger-Tang if (!spi_priv->probing_crc) 5365625f965SAjay Singh dev_err(&spi->dev, 537c872e7aeSDavid Mosberger-Tang "Failed cmd, cmd (%02x), resp (%02x)\n", 5385625f965SAjay Singh cmd, r->rsp_cmd_type); 5395625f965SAjay Singh return -EINVAL; 5405625f965SAjay Singh } 5415625f965SAjay Singh 542aa3fda4fSAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS && !clockless) { 5435625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 5445625f965SAjay Singh r->status); 5455625f965SAjay Singh return -EINVAL; 5465625f965SAjay Singh } 5475625f965SAjay Singh 548f2131fa5SDavid Mosberger-Tang for (i = 0; i < WILC_SPI_RSP_HDR_EXTRA_DATA; ++i) 549f2131fa5SDavid Mosberger-Tang if (WILC_GET_RESP_HDR_START(r->data[i]) == 0xf) 550f2131fa5SDavid Mosberger-Tang break; 551f2131fa5SDavid Mosberger-Tang 552f2131fa5SDavid Mosberger-Tang if (i >= WILC_SPI_RSP_HDR_EXTRA_DATA) { 553f2131fa5SDavid Mosberger-Tang dev_err(&spi->dev, "Error, data start missing\n"); 5545625f965SAjay Singh return -EINVAL; 5555625f965SAjay Singh } 5565625f965SAjay Singh 557f2131fa5SDavid Mosberger-Tang r_data = (struct wilc_spi_read_rsp_data *)&r->data[i]; 558f2131fa5SDavid Mosberger-Tang 5595625f965SAjay Singh if (b) 560f2131fa5SDavid Mosberger-Tang memcpy(b, r_data->data, 4); 5615625f965SAjay Singh 562c872e7aeSDavid Mosberger-Tang if (!clockless && spi_priv->crc16_enabled) { 563c872e7aeSDavid Mosberger-Tang crc_recv = (r_data->crc[0] << 8) | r_data->crc[1]; 564c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, r_data->data, 4); 565c872e7aeSDavid Mosberger-Tang if (crc_recv != crc_calc) { 566c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "%s: bad CRC 0x%04x " 567c872e7aeSDavid Mosberger-Tang "(calculated 0x%04x)\n", __func__, 568c872e7aeSDavid Mosberger-Tang crc_recv, crc_calc); 569c872e7aeSDavid Mosberger-Tang return -EINVAL; 570c872e7aeSDavid Mosberger-Tang } 571c872e7aeSDavid Mosberger-Tang } 5725625f965SAjay Singh 5735625f965SAjay Singh return 0; 5745625f965SAjay Singh } 5755625f965SAjay Singh 5765625f965SAjay Singh static int wilc_spi_write_cmd(struct wilc *wilc, u8 cmd, u32 adr, u32 data, 5775625f965SAjay Singh u8 clockless) 5785625f965SAjay Singh { 5795625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 5805625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 5815625f965SAjay Singh u8 wb[32], rb[32]; 5825625f965SAjay Singh int cmd_len, resp_len; 5835625f965SAjay Singh struct wilc_spi_cmd *c; 5845625f965SAjay Singh struct wilc_spi_rsp_data *r; 5855625f965SAjay Singh 5865625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 5875625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 5885625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 5895625f965SAjay Singh c->cmd_type = cmd; 5905625f965SAjay Singh if (cmd == CMD_INTERNAL_WRITE) { 5915625f965SAjay Singh c->u.internal_w_cmd.addr[0] = adr >> 8; 5925625f965SAjay Singh if (clockless == 1) 5935625f965SAjay Singh c->u.internal_w_cmd.addr[0] |= BIT(7); 5945625f965SAjay Singh 5955625f965SAjay Singh c->u.internal_w_cmd.addr[1] = adr; 5965625f965SAjay Singh c->u.internal_w_cmd.data = cpu_to_be32(data); 5975625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.internal_w_cmd.crc); 598c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 5995625f965SAjay Singh c->u.internal_w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 6005625f965SAjay Singh } else if (cmd == CMD_SINGLE_WRITE) { 6015625f965SAjay Singh c->u.w_cmd.addr[0] = adr >> 16; 6025625f965SAjay Singh c->u.w_cmd.addr[1] = adr >> 8; 6035625f965SAjay Singh c->u.w_cmd.addr[2] = adr; 6045625f965SAjay Singh c->u.w_cmd.data = cpu_to_be32(data); 6055625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.w_cmd.crc); 606c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6075625f965SAjay Singh c->u.w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 6085625f965SAjay Singh } else { 6095625f965SAjay Singh dev_err(&spi->dev, "write cmd [%x] not supported\n", cmd); 6105625f965SAjay Singh return -EINVAL; 6115625f965SAjay Singh } 6125625f965SAjay Singh 613c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6145625f965SAjay Singh cmd_len += 1; 6155625f965SAjay Singh 6165625f965SAjay Singh resp_len = sizeof(*r); 6175625f965SAjay Singh 6185625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 6195625f965SAjay Singh dev_err(&spi->dev, 6205625f965SAjay Singh "spi buffer size too small (%d) (%d) (%zu)\n", 6215625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 6225625f965SAjay Singh return -EINVAL; 6235625f965SAjay Singh } 6245625f965SAjay Singh 6255625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 6265625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 6275625f965SAjay Singh return -EINVAL; 6285625f965SAjay Singh } 6295625f965SAjay Singh 6305625f965SAjay Singh r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 631aa3fda4fSAjay Singh /* 632aa3fda4fSAjay Singh * Clockless registers operations might return unexptected responses, 633aa3fda4fSAjay Singh * even if successful. 634aa3fda4fSAjay Singh */ 635aa3fda4fSAjay Singh if (r->rsp_cmd_type != cmd && !clockless) { 6365625f965SAjay Singh dev_err(&spi->dev, 6375625f965SAjay Singh "Failed cmd response, cmd (%02x), resp (%02x)\n", 6385625f965SAjay Singh cmd, r->rsp_cmd_type); 6395625f965SAjay Singh return -EINVAL; 6405625f965SAjay Singh } 6415625f965SAjay Singh 642aa3fda4fSAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS && !clockless) { 6435625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 6445625f965SAjay Singh r->status); 6455625f965SAjay Singh return -EINVAL; 6465625f965SAjay Singh } 6475625f965SAjay Singh 6485625f965SAjay Singh return 0; 6495625f965SAjay Singh } 6505625f965SAjay Singh 6515625f965SAjay Singh static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz) 6525625f965SAjay Singh { 6535625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 6545625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 655c872e7aeSDavid Mosberger-Tang u16 crc_recv, crc_calc; 6565625f965SAjay Singh u8 wb[32], rb[32]; 6575625f965SAjay Singh int cmd_len, resp_len; 6585625f965SAjay Singh int retry, ix = 0; 6595625f965SAjay Singh u8 crc[2]; 6605625f965SAjay Singh struct wilc_spi_cmd *c; 6615625f965SAjay Singh struct wilc_spi_rsp_data *r; 6625625f965SAjay Singh 6635625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 6645625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 6655625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 6665625f965SAjay Singh c->cmd_type = cmd; 6675625f965SAjay Singh if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_READ) { 6685625f965SAjay Singh c->u.dma_cmd.addr[0] = adr >> 16; 6695625f965SAjay Singh c->u.dma_cmd.addr[1] = adr >> 8; 6705625f965SAjay Singh c->u.dma_cmd.addr[2] = adr; 6715625f965SAjay Singh c->u.dma_cmd.size[0] = sz >> 8; 6725625f965SAjay Singh c->u.dma_cmd.size[1] = sz; 6735625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd.crc); 674c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6755625f965SAjay Singh c->u.dma_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 6765625f965SAjay Singh } else if (cmd == CMD_DMA_EXT_WRITE || cmd == CMD_DMA_EXT_READ) { 6775625f965SAjay Singh c->u.dma_cmd_ext.addr[0] = adr >> 16; 6785625f965SAjay Singh c->u.dma_cmd_ext.addr[1] = adr >> 8; 6795625f965SAjay Singh c->u.dma_cmd_ext.addr[2] = adr; 6805625f965SAjay Singh c->u.dma_cmd_ext.size[0] = sz >> 16; 6815625f965SAjay Singh c->u.dma_cmd_ext.size[1] = sz >> 8; 6825625f965SAjay Singh c->u.dma_cmd_ext.size[2] = sz; 6835625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd_ext.crc); 684c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6855625f965SAjay Singh c->u.dma_cmd_ext.crc[0] = wilc_get_crc7(wb, cmd_len); 6865625f965SAjay Singh } else { 6875625f965SAjay Singh dev_err(&spi->dev, "dma read write cmd [%x] not supported\n", 6885625f965SAjay Singh cmd); 6895625f965SAjay Singh return -EINVAL; 6905625f965SAjay Singh } 691c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6925625f965SAjay Singh cmd_len += 1; 6935625f965SAjay Singh 6945625f965SAjay Singh resp_len = sizeof(*r); 6955625f965SAjay Singh 6965625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 6975625f965SAjay Singh dev_err(&spi->dev, "spi buffer size too small (%d)(%d) (%zu)\n", 6985625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 6995625f965SAjay Singh return -EINVAL; 7005625f965SAjay Singh } 7015625f965SAjay Singh 7025625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 7035625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 7045625f965SAjay Singh return -EINVAL; 7055625f965SAjay Singh } 7065625f965SAjay Singh 7075625f965SAjay Singh r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 7085625f965SAjay Singh if (r->rsp_cmd_type != cmd) { 7095625f965SAjay Singh dev_err(&spi->dev, 7105625f965SAjay Singh "Failed cmd response, cmd (%02x), resp (%02x)\n", 7115625f965SAjay Singh cmd, r->rsp_cmd_type); 7125625f965SAjay Singh return -EINVAL; 7135625f965SAjay Singh } 7145625f965SAjay Singh 7155625f965SAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { 7165625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 7175625f965SAjay Singh r->status); 7185625f965SAjay Singh return -EINVAL; 7195625f965SAjay Singh } 7205625f965SAjay Singh 7215625f965SAjay Singh if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_EXT_WRITE) 7225625f965SAjay Singh return 0; 7235625f965SAjay Singh 7245625f965SAjay Singh while (sz > 0) { 7255625f965SAjay Singh int nbytes; 7265625f965SAjay Singh u8 rsp; 7275625f965SAjay Singh 728708db268SChangcheng Deng nbytes = min_t(u32, sz, DATA_PKT_SZ); 7295625f965SAjay Singh 7305625f965SAjay Singh /* 7315625f965SAjay Singh * Data Response header 7325625f965SAjay Singh */ 7335625f965SAjay Singh retry = 100; 7345625f965SAjay Singh do { 7355625f965SAjay Singh if (wilc_spi_rx(wilc, &rsp, 1)) { 7365625f965SAjay Singh dev_err(&spi->dev, 7375625f965SAjay Singh "Failed resp read, bus err\n"); 7385625f965SAjay Singh return -EINVAL; 7395625f965SAjay Singh } 7405625f965SAjay Singh if (WILC_GET_RESP_HDR_START(rsp) == 0xf) 7415625f965SAjay Singh break; 7425625f965SAjay Singh } while (retry--); 7435625f965SAjay Singh 7445625f965SAjay Singh /* 7455625f965SAjay Singh * Read bytes 7465625f965SAjay Singh */ 7475625f965SAjay Singh if (wilc_spi_rx(wilc, &b[ix], nbytes)) { 7485625f965SAjay Singh dev_err(&spi->dev, 7495625f965SAjay Singh "Failed block read, bus err\n"); 7505625f965SAjay Singh return -EINVAL; 7515625f965SAjay Singh } 7525625f965SAjay Singh 7535625f965SAjay Singh /* 754c872e7aeSDavid Mosberger-Tang * Read CRC 7555625f965SAjay Singh */ 756c872e7aeSDavid Mosberger-Tang if (spi_priv->crc16_enabled) { 757c872e7aeSDavid Mosberger-Tang if (wilc_spi_rx(wilc, crc, 2)) { 7585625f965SAjay Singh dev_err(&spi->dev, 759c872e7aeSDavid Mosberger-Tang "Failed block CRC read, bus err\n"); 7605625f965SAjay Singh return -EINVAL; 7615625f965SAjay Singh } 762c872e7aeSDavid Mosberger-Tang crc_recv = (crc[0] << 8) | crc[1]; 763c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, &b[ix], nbytes); 764c872e7aeSDavid Mosberger-Tang if (crc_recv != crc_calc) { 765c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "%s: bad CRC 0x%04x " 766c872e7aeSDavid Mosberger-Tang "(calculated 0x%04x)\n", __func__, 767c872e7aeSDavid Mosberger-Tang crc_recv, crc_calc); 768c872e7aeSDavid Mosberger-Tang return -EINVAL; 769c872e7aeSDavid Mosberger-Tang } 770c872e7aeSDavid Mosberger-Tang } 7715625f965SAjay Singh 7725625f965SAjay Singh ix += nbytes; 7735625f965SAjay Singh sz -= nbytes; 7745625f965SAjay Singh } 7755625f965SAjay Singh return 0; 7765625f965SAjay Singh } 7775625f965SAjay Singh 7781bcc0879SAjay Singh static int wilc_spi_special_cmd(struct wilc *wilc, u8 cmd) 7791bcc0879SAjay Singh { 7801bcc0879SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 7811bcc0879SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 7821bcc0879SAjay Singh u8 wb[32], rb[32]; 7831bcc0879SAjay Singh int cmd_len, resp_len = 0; 7841bcc0879SAjay Singh struct wilc_spi_cmd *c; 7851bcc0879SAjay Singh struct wilc_spi_special_cmd_rsp *r; 7861bcc0879SAjay Singh 7871bcc0879SAjay Singh if (cmd != CMD_TERMINATE && cmd != CMD_REPEAT && cmd != CMD_RESET) 7881bcc0879SAjay Singh return -EINVAL; 7891bcc0879SAjay Singh 7901bcc0879SAjay Singh memset(wb, 0x0, sizeof(wb)); 7911bcc0879SAjay Singh memset(rb, 0x0, sizeof(rb)); 7921bcc0879SAjay Singh c = (struct wilc_spi_cmd *)wb; 7931bcc0879SAjay Singh c->cmd_type = cmd; 7941bcc0879SAjay Singh 7951bcc0879SAjay Singh if (cmd == CMD_RESET) 7961bcc0879SAjay Singh memset(c->u.simple_cmd.addr, 0xFF, 3); 7971bcc0879SAjay Singh 7981bcc0879SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc); 7991bcc0879SAjay Singh resp_len = sizeof(*r); 8001bcc0879SAjay Singh 8011bcc0879SAjay Singh if (spi_priv->crc7_enabled) { 8021bcc0879SAjay Singh c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 8031bcc0879SAjay Singh cmd_len += 1; 8041bcc0879SAjay Singh } 8051bcc0879SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 8061bcc0879SAjay Singh dev_err(&spi->dev, "spi buffer size too small (%d) (%d) (%zu)\n", 8071bcc0879SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 8081bcc0879SAjay Singh return -EINVAL; 8091bcc0879SAjay Singh } 8101bcc0879SAjay Singh 8111bcc0879SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 8121bcc0879SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 8131bcc0879SAjay Singh return -EINVAL; 8141bcc0879SAjay Singh } 8151bcc0879SAjay Singh 8161bcc0879SAjay Singh r = (struct wilc_spi_special_cmd_rsp *)&rb[cmd_len]; 8171bcc0879SAjay Singh if (r->rsp_cmd_type != cmd) { 8181bcc0879SAjay Singh if (!spi_priv->probing_crc) 8191bcc0879SAjay Singh dev_err(&spi->dev, 8201bcc0879SAjay Singh "Failed cmd response, cmd (%02x), resp (%02x)\n", 8211bcc0879SAjay Singh cmd, r->rsp_cmd_type); 8221bcc0879SAjay Singh return -EINVAL; 8231bcc0879SAjay Singh } 8241bcc0879SAjay Singh 8251bcc0879SAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { 8261bcc0879SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 8271bcc0879SAjay Singh r->status); 8281bcc0879SAjay Singh return -EINVAL; 8291bcc0879SAjay Singh } 8301bcc0879SAjay Singh return 0; 8311bcc0879SAjay Singh } 8321bcc0879SAjay Singh 8335625f965SAjay Singh static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data) 8345625f965SAjay Singh { 8355625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 8365625f965SAjay Singh int result; 8375625f965SAjay Singh u8 cmd = CMD_SINGLE_READ; 8385625f965SAjay Singh u8 clockless = 0; 8395625f965SAjay Singh 8405625f965SAjay Singh if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) { 8415625f965SAjay Singh /* Clockless register */ 8425625f965SAjay Singh cmd = CMD_INTERNAL_READ; 8435625f965SAjay Singh clockless = 1; 8445625f965SAjay Singh } 8455625f965SAjay Singh 8465625f965SAjay Singh result = wilc_spi_single_read(wilc, cmd, addr, data, clockless); 8475625f965SAjay Singh if (result) { 8485625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr); 8495625f965SAjay Singh return result; 8505625f965SAjay Singh } 8515625f965SAjay Singh 8525625f965SAjay Singh le32_to_cpus(data); 8535625f965SAjay Singh 8545625f965SAjay Singh return 0; 8555625f965SAjay Singh } 8565625f965SAjay Singh 8575625f965SAjay Singh static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) 8585625f965SAjay Singh { 8595625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 8605625f965SAjay Singh int result; 8615625f965SAjay Singh 8625625f965SAjay Singh if (size <= 4) 8635625f965SAjay Singh return -EINVAL; 8645625f965SAjay Singh 8655625f965SAjay Singh result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_READ, addr, buf, size); 8665625f965SAjay Singh if (result) { 8675625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr); 8685625f965SAjay Singh return result; 8695625f965SAjay Singh } 8705625f965SAjay Singh 8715625f965SAjay Singh return 0; 8725625f965SAjay Singh } 8735625f965SAjay Singh 8745625f965SAjay Singh static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat) 8755625f965SAjay Singh { 8765625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 8775625f965SAjay Singh int result; 8785625f965SAjay Singh 8795625f965SAjay Singh result = wilc_spi_write_cmd(wilc, CMD_INTERNAL_WRITE, adr, dat, 0); 8805625f965SAjay Singh if (result) { 8815625f965SAjay Singh dev_err(&spi->dev, "Failed internal write cmd...\n"); 8825625f965SAjay Singh return result; 8835625f965SAjay Singh } 8845625f965SAjay Singh 8855625f965SAjay Singh return 0; 8865625f965SAjay Singh } 8875625f965SAjay Singh 8885625f965SAjay Singh static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data) 8895625f965SAjay Singh { 8905625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 891c872e7aeSDavid Mosberger-Tang struct wilc_spi *spi_priv = wilc->bus_data; 8925625f965SAjay Singh int result; 8935625f965SAjay Singh 8945625f965SAjay Singh result = wilc_spi_single_read(wilc, CMD_INTERNAL_READ, adr, data, 0); 8955625f965SAjay Singh if (result) { 896c872e7aeSDavid Mosberger-Tang if (!spi_priv->probing_crc) 8975625f965SAjay Singh dev_err(&spi->dev, "Failed internal read cmd...\n"); 8985625f965SAjay Singh return result; 8995625f965SAjay Singh } 9005625f965SAjay Singh 9015625f965SAjay Singh le32_to_cpus(data); 9025625f965SAjay Singh 9035625f965SAjay Singh return 0; 9045625f965SAjay Singh } 9055625f965SAjay Singh 9065625f965SAjay Singh /******************************************** 9075625f965SAjay Singh * 9085625f965SAjay Singh * Spi interfaces 9095625f965SAjay Singh * 9105625f965SAjay Singh ********************************************/ 9115625f965SAjay Singh 9125625f965SAjay Singh static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data) 9135625f965SAjay Singh { 9145625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 9155625f965SAjay Singh int result; 9165625f965SAjay Singh u8 cmd = CMD_SINGLE_WRITE; 9175625f965SAjay Singh u8 clockless = 0; 9185625f965SAjay Singh 9195625f965SAjay Singh if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) { 9205625f965SAjay Singh /* Clockless register */ 9215625f965SAjay Singh cmd = CMD_INTERNAL_WRITE; 9225625f965SAjay Singh clockless = 1; 9235625f965SAjay Singh } 9245625f965SAjay Singh 9255625f965SAjay Singh result = wilc_spi_write_cmd(wilc, cmd, addr, data, clockless); 9265625f965SAjay Singh if (result) { 9275625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr); 9285625f965SAjay Singh return result; 9295625f965SAjay Singh } 9305625f965SAjay Singh 9315625f965SAjay Singh return 0; 9325625f965SAjay Singh } 9335625f965SAjay Singh 934ce3b9338SDavid Mosberger-Tang static int spi_data_rsp(struct wilc *wilc, u8 cmd) 935ce3b9338SDavid Mosberger-Tang { 936ce3b9338SDavid Mosberger-Tang struct spi_device *spi = to_spi_device(wilc->dev); 937ce3b9338SDavid Mosberger-Tang int result, i; 938ce3b9338SDavid Mosberger-Tang u8 rsp[4]; 939ce3b9338SDavid Mosberger-Tang 940ce3b9338SDavid Mosberger-Tang /* 941ce3b9338SDavid Mosberger-Tang * The response to data packets is two bytes long. For 942ce3b9338SDavid Mosberger-Tang * efficiency's sake, wilc_spi_write() wisely ignores the 943ce3b9338SDavid Mosberger-Tang * responses for all packets but the final one. The downside 944ce3b9338SDavid Mosberger-Tang * of that optimization is that when the final data packet is 945ce3b9338SDavid Mosberger-Tang * short, we may receive (part of) the response to the 946ce3b9338SDavid Mosberger-Tang * second-to-last packet before the one for the final packet. 947ce3b9338SDavid Mosberger-Tang * To handle this, we always read 4 bytes and then search for 948ce3b9338SDavid Mosberger-Tang * the last byte that contains the "Response Start" code (0xc 949ce3b9338SDavid Mosberger-Tang * in the top 4 bits). We then know that this byte is the 950ce3b9338SDavid Mosberger-Tang * first response byte of the final data packet. 951ce3b9338SDavid Mosberger-Tang */ 952ce3b9338SDavid Mosberger-Tang result = wilc_spi_rx(wilc, rsp, sizeof(rsp)); 953ce3b9338SDavid Mosberger-Tang if (result) { 954ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, "Failed bus error...\n"); 955ce3b9338SDavid Mosberger-Tang return result; 956ce3b9338SDavid Mosberger-Tang } 957ce3b9338SDavid Mosberger-Tang 958ce3b9338SDavid Mosberger-Tang for (i = sizeof(rsp) - 2; i >= 0; --i) 959ce3b9338SDavid Mosberger-Tang if (FIELD_GET(RSP_START_FIELD, rsp[i]) == RSP_START_TAG) 960ce3b9338SDavid Mosberger-Tang break; 961ce3b9338SDavid Mosberger-Tang 962ce3b9338SDavid Mosberger-Tang if (i < 0) { 963ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, 964ce3b9338SDavid Mosberger-Tang "Data packet response missing (%02x %02x %02x %02x)\n", 965ce3b9338SDavid Mosberger-Tang rsp[0], rsp[1], rsp[2], rsp[3]); 966ce3b9338SDavid Mosberger-Tang return -1; 967ce3b9338SDavid Mosberger-Tang } 968ce3b9338SDavid Mosberger-Tang 969ce3b9338SDavid Mosberger-Tang /* rsp[i] is the last response start byte */ 970ce3b9338SDavid Mosberger-Tang 971ce3b9338SDavid Mosberger-Tang if (FIELD_GET(RSP_TYPE_FIELD, rsp[i]) != RSP_TYPE_LAST_PACKET 972ce3b9338SDavid Mosberger-Tang || rsp[i + 1] != RSP_STATE_NO_ERROR) { 973ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, "Data response error (%02x %02x)\n", 974ce3b9338SDavid Mosberger-Tang rsp[i], rsp[i + 1]); 975ce3b9338SDavid Mosberger-Tang return -1; 976ce3b9338SDavid Mosberger-Tang } 977ce3b9338SDavid Mosberger-Tang return 0; 978ce3b9338SDavid Mosberger-Tang } 979ce3b9338SDavid Mosberger-Tang 9805625f965SAjay Singh static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) 9815625f965SAjay Singh { 9825625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 9835625f965SAjay Singh int result; 9845625f965SAjay Singh 9855625f965SAjay Singh /* 9865625f965SAjay Singh * has to be greated than 4 9875625f965SAjay Singh */ 9885625f965SAjay Singh if (size <= 4) 9895625f965SAjay Singh return -EINVAL; 9905625f965SAjay Singh 9915625f965SAjay Singh result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size); 9925625f965SAjay Singh if (result) { 9935625f965SAjay Singh dev_err(&spi->dev, 9945625f965SAjay Singh "Failed cmd, write block (%08x)...\n", addr); 9955625f965SAjay Singh return result; 9965625f965SAjay Singh } 9975625f965SAjay Singh 9985625f965SAjay Singh /* 9995625f965SAjay Singh * Data 10005625f965SAjay Singh */ 10015625f965SAjay Singh result = spi_data_write(wilc, buf, size); 10025625f965SAjay Singh if (result) { 10035625f965SAjay Singh dev_err(&spi->dev, "Failed block data write...\n"); 10045625f965SAjay Singh return result; 10055625f965SAjay Singh } 10065625f965SAjay Singh 1007ce3b9338SDavid Mosberger-Tang /* 1008ce3b9338SDavid Mosberger-Tang * Data response 1009ce3b9338SDavid Mosberger-Tang */ 1010ce3b9338SDavid Mosberger-Tang return spi_data_rsp(wilc, CMD_DMA_EXT_WRITE); 10115625f965SAjay Singh } 10125625f965SAjay Singh 10135625f965SAjay Singh /******************************************** 10145625f965SAjay Singh * 10155625f965SAjay Singh * Bus interfaces 10165625f965SAjay Singh * 10175625f965SAjay Singh ********************************************/ 10185625f965SAjay Singh 1019c2dcb476SAjay Singh static int wilc_spi_reset(struct wilc *wilc) 1020c2dcb476SAjay Singh { 1021c2dcb476SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 1022c2dcb476SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 1023c2dcb476SAjay Singh int result; 1024c2dcb476SAjay Singh 1025c2dcb476SAjay Singh result = wilc_spi_special_cmd(wilc, CMD_RESET); 1026c2dcb476SAjay Singh if (result && !spi_priv->probing_crc) 1027c2dcb476SAjay Singh dev_err(&spi->dev, "Failed cmd reset\n"); 1028c2dcb476SAjay Singh 1029c2dcb476SAjay Singh return result; 1030c2dcb476SAjay Singh } 1031c2dcb476SAjay Singh 1032*39d0f1b0SAjay Singh static bool wilc_spi_is_init(struct wilc *wilc) 1033*39d0f1b0SAjay Singh { 1034*39d0f1b0SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 1035*39d0f1b0SAjay Singh 1036*39d0f1b0SAjay Singh return spi_priv->isinit; 1037*39d0f1b0SAjay Singh } 1038*39d0f1b0SAjay Singh 10395625f965SAjay Singh static int wilc_spi_deinit(struct wilc *wilc) 10405625f965SAjay Singh { 1041ec031ac4SDavid Mosberger-Tang struct wilc_spi *spi_priv = wilc->bus_data; 1042ec031ac4SDavid Mosberger-Tang 1043ec031ac4SDavid Mosberger-Tang spi_priv->isinit = false; 1044ec031ac4SDavid Mosberger-Tang wilc_wlan_power(wilc, false); 10455625f965SAjay Singh return 0; 10465625f965SAjay Singh } 10475625f965SAjay Singh 10485625f965SAjay Singh static int wilc_spi_init(struct wilc *wilc, bool resume) 10495625f965SAjay Singh { 10505625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 10515625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 10525625f965SAjay Singh u32 reg; 10535625f965SAjay Singh u32 chipid; 1054c872e7aeSDavid Mosberger-Tang int ret, i; 10555625f965SAjay Singh 105650cbbfd4SDavid Mosberger-Tang if (spi_priv->isinit) { 105750cbbfd4SDavid Mosberger-Tang /* Confirm we can read chipid register without error: */ 10585625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); 105950cbbfd4SDavid Mosberger-Tang if (ret == 0) 106050cbbfd4SDavid Mosberger-Tang return 0; 10615625f965SAjay Singh 106250cbbfd4SDavid Mosberger-Tang dev_err(&spi->dev, "Fail cmd read chip id...\n"); 10635625f965SAjay Singh } 10645625f965SAjay Singh 1065ec031ac4SDavid Mosberger-Tang wilc_wlan_power(wilc, true); 1066ec031ac4SDavid Mosberger-Tang 10675625f965SAjay Singh /* 10685625f965SAjay Singh * configure protocol 10695625f965SAjay Singh */ 10705625f965SAjay Singh 10715625f965SAjay Singh /* 1072c872e7aeSDavid Mosberger-Tang * Infer the CRC settings that are currently in effect. This 1073c872e7aeSDavid Mosberger-Tang * is necessary because we can't be sure that the chip has 1074c872e7aeSDavid Mosberger-Tang * been RESET (e.g, after module unload and reload). 10755625f965SAjay Singh */ 1076c872e7aeSDavid Mosberger-Tang spi_priv->probing_crc = true; 1077c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = enable_crc7; 1078c872e7aeSDavid Mosberger-Tang spi_priv->crc16_enabled = false; /* don't check CRC16 during probing */ 1079c872e7aeSDavid Mosberger-Tang for (i = 0; i < 2; ++i) { 10805625f965SAjay Singh ret = spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); 1081c872e7aeSDavid Mosberger-Tang if (ret == 0) 1082c872e7aeSDavid Mosberger-Tang break; 1083c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = !enable_crc7; 1084c872e7aeSDavid Mosberger-Tang } 10855625f965SAjay Singh if (ret) { 1086c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "Failed with CRC7 on and off.\n"); 10875625f965SAjay Singh return ret; 10885625f965SAjay Singh } 10895ee2d9ddSDavid Mosberger-Tang 1090c872e7aeSDavid Mosberger-Tang /* set up the desired CRC configuration: */ 1091c872e7aeSDavid Mosberger-Tang reg &= ~(PROTOCOL_REG_CRC7_MASK | PROTOCOL_REG_CRC16_MASK); 1092c872e7aeSDavid Mosberger-Tang if (enable_crc7) 1093c872e7aeSDavid Mosberger-Tang reg |= PROTOCOL_REG_CRC7_MASK; 1094c872e7aeSDavid Mosberger-Tang if (enable_crc16) 1095c872e7aeSDavid Mosberger-Tang reg |= PROTOCOL_REG_CRC16_MASK; 1096c872e7aeSDavid Mosberger-Tang 1097c872e7aeSDavid Mosberger-Tang /* set up the data packet size: */ 10985ee2d9ddSDavid Mosberger-Tang BUILD_BUG_ON(DATA_PKT_LOG_SZ < DATA_PKT_LOG_SZ_MIN 10995ee2d9ddSDavid Mosberger-Tang || DATA_PKT_LOG_SZ > DATA_PKT_LOG_SZ_MAX); 11005ee2d9ddSDavid Mosberger-Tang reg &= ~PROTOCOL_REG_PKT_SZ_MASK; 11015ee2d9ddSDavid Mosberger-Tang reg |= FIELD_PREP(PROTOCOL_REG_PKT_SZ_MASK, 11025ee2d9ddSDavid Mosberger-Tang DATA_PKT_LOG_SZ - DATA_PKT_LOG_SZ_MIN); 11035ee2d9ddSDavid Mosberger-Tang 1104c872e7aeSDavid Mosberger-Tang /* establish the new setup: */ 11055625f965SAjay Singh ret = spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg); 11065625f965SAjay Singh if (ret) { 11075625f965SAjay Singh dev_err(&spi->dev, 11085625f965SAjay Singh "[wilc spi %d]: Failed internal write reg\n", 11095625f965SAjay Singh __LINE__); 11105625f965SAjay Singh return ret; 11115625f965SAjay Singh } 1112c872e7aeSDavid Mosberger-Tang /* update our state to match new protocol settings: */ 1113c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = enable_crc7; 1114c872e7aeSDavid Mosberger-Tang spi_priv->crc16_enabled = enable_crc16; 1115c872e7aeSDavid Mosberger-Tang 1116c872e7aeSDavid Mosberger-Tang /* re-read to make sure new settings are in effect: */ 1117c872e7aeSDavid Mosberger-Tang spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); 1118c872e7aeSDavid Mosberger-Tang 1119c872e7aeSDavid Mosberger-Tang spi_priv->probing_crc = false; 11205625f965SAjay Singh 11215625f965SAjay Singh /* 112250cbbfd4SDavid Mosberger-Tang * make sure can read chip id without protocol error 11235625f965SAjay Singh */ 11245625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); 11255625f965SAjay Singh if (ret) { 11265625f965SAjay Singh dev_err(&spi->dev, "Fail cmd read chip id...\n"); 11275625f965SAjay Singh return ret; 11285625f965SAjay Singh } 11295625f965SAjay Singh 113050cbbfd4SDavid Mosberger-Tang spi_priv->isinit = true; 11315625f965SAjay Singh 11325625f965SAjay Singh return 0; 11335625f965SAjay Singh } 11345625f965SAjay Singh 11355625f965SAjay Singh static int wilc_spi_read_size(struct wilc *wilc, u32 *size) 11365625f965SAjay Singh { 11375625f965SAjay Singh int ret; 11385625f965SAjay Singh 11395625f965SAjay Singh ret = spi_internal_read(wilc, 11405625f965SAjay Singh WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, size); 11415625f965SAjay Singh *size = FIELD_GET(IRQ_DMA_WD_CNT_MASK, *size); 11425625f965SAjay Singh 11435625f965SAjay Singh return ret; 11445625f965SAjay Singh } 11455625f965SAjay Singh 11465625f965SAjay Singh static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status) 11475625f965SAjay Singh { 11485625f965SAjay Singh return spi_internal_read(wilc, WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, 11495625f965SAjay Singh int_status); 11505625f965SAjay Singh } 11515625f965SAjay Singh 11525625f965SAjay Singh static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val) 11535625f965SAjay Singh { 1154382726d1SAjay Singh int ret; 1155382726d1SAjay Singh int retry = SPI_ENABLE_VMM_RETRY_LIMIT; 1156382726d1SAjay Singh u32 check; 1157382726d1SAjay Singh 1158382726d1SAjay Singh while (retry) { 1159382726d1SAjay Singh ret = spi_internal_write(wilc, 1160382726d1SAjay Singh WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE, 11615625f965SAjay Singh val); 1162382726d1SAjay Singh if (ret) 1163382726d1SAjay Singh break; 1164382726d1SAjay Singh 1165382726d1SAjay Singh ret = spi_internal_read(wilc, 1166382726d1SAjay Singh WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE, 1167382726d1SAjay Singh &check); 1168382726d1SAjay Singh if (ret || ((check & EN_VMM) == (val & EN_VMM))) 1169382726d1SAjay Singh break; 1170382726d1SAjay Singh 1171382726d1SAjay Singh retry--; 1172382726d1SAjay Singh } 1173382726d1SAjay Singh return ret; 11745625f965SAjay Singh } 11755625f965SAjay Singh 11765625f965SAjay Singh static int wilc_spi_sync_ext(struct wilc *wilc, int nint) 11775625f965SAjay Singh { 11785625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 11795625f965SAjay Singh u32 reg; 11805625f965SAjay Singh int ret, i; 11815625f965SAjay Singh 11825625f965SAjay Singh if (nint > MAX_NUM_INT) { 11835625f965SAjay Singh dev_err(&spi->dev, "Too many interrupts (%d)...\n", nint); 11845625f965SAjay Singh return -EINVAL; 11855625f965SAjay Singh } 11865625f965SAjay Singh 11875625f965SAjay Singh /* 11885625f965SAjay Singh * interrupt pin mux select 11895625f965SAjay Singh */ 11905625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, ®); 11915625f965SAjay Singh if (ret) { 11925625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 11935625f965SAjay Singh WILC_PIN_MUX_0); 11945625f965SAjay Singh return ret; 11955625f965SAjay Singh } 11965625f965SAjay Singh reg |= BIT(8); 11975625f965SAjay Singh ret = wilc_spi_write_reg(wilc, WILC_PIN_MUX_0, reg); 11985625f965SAjay Singh if (ret) { 11995625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 12005625f965SAjay Singh WILC_PIN_MUX_0); 12015625f965SAjay Singh return ret; 12025625f965SAjay Singh } 12035625f965SAjay Singh 12045625f965SAjay Singh /* 12055625f965SAjay Singh * interrupt enable 12065625f965SAjay Singh */ 12075625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, ®); 12085625f965SAjay Singh if (ret) { 12095625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 12105625f965SAjay Singh WILC_INTR_ENABLE); 12115625f965SAjay Singh return ret; 12125625f965SAjay Singh } 12135625f965SAjay Singh 12145625f965SAjay Singh for (i = 0; (i < 5) && (nint > 0); i++, nint--) 12155625f965SAjay Singh reg |= (BIT((27 + i))); 12165625f965SAjay Singh 12175625f965SAjay Singh ret = wilc_spi_write_reg(wilc, WILC_INTR_ENABLE, reg); 12185625f965SAjay Singh if (ret) { 12195625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 12205625f965SAjay Singh WILC_INTR_ENABLE); 12215625f965SAjay Singh return ret; 12225625f965SAjay Singh } 12235625f965SAjay Singh if (nint) { 12245625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, ®); 12255625f965SAjay Singh if (ret) { 12265625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 12275625f965SAjay Singh WILC_INTR2_ENABLE); 12285625f965SAjay Singh return ret; 12295625f965SAjay Singh } 12305625f965SAjay Singh 12315625f965SAjay Singh for (i = 0; (i < 3) && (nint > 0); i++, nint--) 12325625f965SAjay Singh reg |= BIT(i); 12335625f965SAjay Singh 1234301cfbabSAjay Singh ret = wilc_spi_write_reg(wilc, WILC_INTR2_ENABLE, reg); 12355625f965SAjay Singh if (ret) { 12365625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 12375625f965SAjay Singh WILC_INTR2_ENABLE); 12385625f965SAjay Singh return ret; 12395625f965SAjay Singh } 12405625f965SAjay Singh } 12415625f965SAjay Singh 12425625f965SAjay Singh return 0; 12435625f965SAjay Singh } 12445625f965SAjay Singh 12455625f965SAjay Singh /* Global spi HIF function table */ 12465625f965SAjay Singh static const struct wilc_hif_func wilc_hif_spi = { 12475625f965SAjay Singh .hif_init = wilc_spi_init, 12485625f965SAjay Singh .hif_deinit = wilc_spi_deinit, 12495625f965SAjay Singh .hif_read_reg = wilc_spi_read_reg, 12505625f965SAjay Singh .hif_write_reg = wilc_spi_write_reg, 12515625f965SAjay Singh .hif_block_rx = wilc_spi_read, 12525625f965SAjay Singh .hif_block_tx = wilc_spi_write, 12535625f965SAjay Singh .hif_read_int = wilc_spi_read_int, 12545625f965SAjay Singh .hif_clear_int_ext = wilc_spi_clear_int_ext, 12555625f965SAjay Singh .hif_read_size = wilc_spi_read_size, 12565625f965SAjay Singh .hif_block_tx_ext = wilc_spi_write, 12575625f965SAjay Singh .hif_block_rx_ext = wilc_spi_read, 12585625f965SAjay Singh .hif_sync_ext = wilc_spi_sync_ext, 1259c2dcb476SAjay Singh .hif_reset = wilc_spi_reset, 1260*39d0f1b0SAjay Singh .hif_is_init = wilc_spi_is_init, 12615625f965SAjay Singh }; 1262