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> 115625f965SAjay Singh 125625f965SAjay Singh #include "netdev.h" 135625f965SAjay Singh #include "cfg80211.h" 145625f965SAjay Singh 15c872e7aeSDavid Mosberger-Tang static bool enable_crc7; /* protect SPI commands with CRC7 */ 16c872e7aeSDavid Mosberger-Tang module_param(enable_crc7, bool, 0644); 17c872e7aeSDavid Mosberger-Tang MODULE_PARM_DESC(enable_crc7, 18c872e7aeSDavid Mosberger-Tang "Enable CRC7 checksum to protect command transfers\n" 19c872e7aeSDavid Mosberger-Tang "\t\t\tagainst corruption during the SPI transfer.\n" 20c872e7aeSDavid Mosberger-Tang "\t\t\tCommand transfers are short and the CPU-cycle cost\n" 21c872e7aeSDavid Mosberger-Tang "\t\t\tof enabling this is small."); 22c872e7aeSDavid Mosberger-Tang 23c872e7aeSDavid Mosberger-Tang static bool enable_crc16; /* protect SPI data with CRC16 */ 24c872e7aeSDavid Mosberger-Tang module_param(enable_crc16, bool, 0644); 25c872e7aeSDavid Mosberger-Tang MODULE_PARM_DESC(enable_crc16, 26c872e7aeSDavid Mosberger-Tang "Enable CRC16 checksum to protect data transfers\n" 27c872e7aeSDavid Mosberger-Tang "\t\t\tagainst corruption during the SPI transfer.\n" 28c872e7aeSDavid Mosberger-Tang "\t\t\tData transfers can be large and the CPU-cycle cost\n" 29c872e7aeSDavid Mosberger-Tang "\t\t\tof enabling this may be substantial."); 30c872e7aeSDavid Mosberger-Tang 31f2131fa5SDavid Mosberger-Tang /* 32f2131fa5SDavid Mosberger-Tang * For CMD_SINGLE_READ and CMD_INTERNAL_READ, WILC may insert one or 33f2131fa5SDavid Mosberger-Tang * more zero bytes between the command response and the DATA Start tag 34f2131fa5SDavid Mosberger-Tang * (0xf3). This behavior appears to be undocumented in "ATWILC1000 35f2131fa5SDavid Mosberger-Tang * USER GUIDE" (https://tinyurl.com/4hhshdts) but we have observed 1-4 36f2131fa5SDavid Mosberger-Tang * zero bytes when the SPI bus operates at 48MHz and none when it 37f2131fa5SDavid Mosberger-Tang * operates at 1MHz. 38f2131fa5SDavid Mosberger-Tang */ 39f2131fa5SDavid Mosberger-Tang #define WILC_SPI_RSP_HDR_EXTRA_DATA 8 40f2131fa5SDavid Mosberger-Tang 415625f965SAjay Singh struct wilc_spi { 42*50cbbfd4SDavid Mosberger-Tang bool isinit; /* true if SPI protocol has been configured */ 43c872e7aeSDavid Mosberger-Tang bool probing_crc; /* true if we're probing chip's CRC config */ 44c872e7aeSDavid Mosberger-Tang bool crc7_enabled; /* true if crc7 is currently enabled */ 45c872e7aeSDavid Mosberger-Tang bool crc16_enabled; /* true if crc16 is currently enabled */ 465625f965SAjay Singh }; 475625f965SAjay Singh 485625f965SAjay Singh static const struct wilc_hif_func wilc_hif_spi; 495625f965SAjay Singh 505625f965SAjay Singh /******************************************** 515625f965SAjay Singh * 525625f965SAjay Singh * Spi protocol Function 535625f965SAjay Singh * 545625f965SAjay Singh ********************************************/ 555625f965SAjay Singh 565625f965SAjay Singh #define CMD_DMA_WRITE 0xc1 575625f965SAjay Singh #define CMD_DMA_READ 0xc2 585625f965SAjay Singh #define CMD_INTERNAL_WRITE 0xc3 595625f965SAjay Singh #define CMD_INTERNAL_READ 0xc4 605625f965SAjay Singh #define CMD_TERMINATE 0xc5 615625f965SAjay Singh #define CMD_REPEAT 0xc6 625625f965SAjay Singh #define CMD_DMA_EXT_WRITE 0xc7 635625f965SAjay Singh #define CMD_DMA_EXT_READ 0xc8 645625f965SAjay Singh #define CMD_SINGLE_WRITE 0xc9 655625f965SAjay Singh #define CMD_SINGLE_READ 0xca 665625f965SAjay Singh #define CMD_RESET 0xcf 675625f965SAjay Singh 68382726d1SAjay Singh #define SPI_ENABLE_VMM_RETRY_LIMIT 2 695ee2d9ddSDavid Mosberger-Tang 70ce3b9338SDavid Mosberger-Tang /* SPI response fields (section 11.1.2 in ATWILC1000 User Guide): */ 71ce3b9338SDavid Mosberger-Tang #define RSP_START_FIELD GENMASK(7, 4) 72ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_FIELD GENMASK(3, 0) 73ce3b9338SDavid Mosberger-Tang 74ce3b9338SDavid Mosberger-Tang /* SPI response values for the response fields: */ 75ce3b9338SDavid Mosberger-Tang #define RSP_START_TAG 0xc 76ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_FIRST_PACKET 0x1 77ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_INNER_PACKET 0x2 78ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_LAST_PACKET 0x3 79ce3b9338SDavid Mosberger-Tang #define RSP_STATE_NO_ERROR 0x00 80ce3b9338SDavid Mosberger-Tang 815ee2d9ddSDavid Mosberger-Tang #define PROTOCOL_REG_PKT_SZ_MASK GENMASK(6, 4) 825ee2d9ddSDavid Mosberger-Tang #define PROTOCOL_REG_CRC16_MASK GENMASK(3, 3) 835ee2d9ddSDavid Mosberger-Tang #define PROTOCOL_REG_CRC7_MASK GENMASK(2, 2) 845ee2d9ddSDavid Mosberger-Tang 855ee2d9ddSDavid Mosberger-Tang /* 865ee2d9ddSDavid Mosberger-Tang * The SPI data packet size may be any integer power of two in the 875ee2d9ddSDavid Mosberger-Tang * range from 256 to 8192 bytes. 885ee2d9ddSDavid Mosberger-Tang */ 895ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_LOG_SZ_MIN 8 /* 256 B */ 905ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_LOG_SZ_MAX 13 /* 8 KiB */ 915ee2d9ddSDavid Mosberger-Tang 925ee2d9ddSDavid Mosberger-Tang /* 935ee2d9ddSDavid Mosberger-Tang * Select the data packet size (log2 of number of bytes): Use the 945ee2d9ddSDavid Mosberger-Tang * maximum data packet size. We only retransmit complete packets, so 955ee2d9ddSDavid Mosberger-Tang * there is no benefit from using smaller data packets. 965ee2d9ddSDavid Mosberger-Tang */ 975ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_LOG_SZ DATA_PKT_LOG_SZ_MAX 985ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_SZ (1 << DATA_PKT_LOG_SZ) 995625f965SAjay Singh 1005625f965SAjay Singh #define USE_SPI_DMA 0 1015625f965SAjay Singh 1025625f965SAjay Singh #define WILC_SPI_COMMAND_STAT_SUCCESS 0 1035625f965SAjay Singh #define WILC_GET_RESP_HDR_START(h) (((h) >> 4) & 0xf) 1045625f965SAjay Singh 1055625f965SAjay Singh struct wilc_spi_cmd { 1065625f965SAjay Singh u8 cmd_type; 1075625f965SAjay Singh union { 1085625f965SAjay Singh struct { 1095625f965SAjay Singh u8 addr[3]; 1105625f965SAjay Singh u8 crc[]; 1115625f965SAjay Singh } __packed simple_cmd; 1125625f965SAjay Singh struct { 1135625f965SAjay Singh u8 addr[3]; 1145625f965SAjay Singh u8 size[2]; 1155625f965SAjay Singh u8 crc[]; 1165625f965SAjay Singh } __packed dma_cmd; 1175625f965SAjay Singh struct { 1185625f965SAjay Singh u8 addr[3]; 1195625f965SAjay Singh u8 size[3]; 1205625f965SAjay Singh u8 crc[]; 1215625f965SAjay Singh } __packed dma_cmd_ext; 1225625f965SAjay Singh struct { 1235625f965SAjay Singh u8 addr[2]; 1245625f965SAjay Singh __be32 data; 1255625f965SAjay Singh u8 crc[]; 1265625f965SAjay Singh } __packed internal_w_cmd; 1275625f965SAjay Singh struct { 1285625f965SAjay Singh u8 addr[3]; 1295625f965SAjay Singh __be32 data; 1305625f965SAjay Singh u8 crc[]; 1315625f965SAjay Singh } __packed w_cmd; 1325625f965SAjay Singh } u; 1335625f965SAjay Singh } __packed; 1345625f965SAjay Singh 1355625f965SAjay Singh struct wilc_spi_read_rsp_data { 136f2131fa5SDavid Mosberger-Tang u8 header; 137f2131fa5SDavid Mosberger-Tang u8 data[4]; 1385625f965SAjay Singh u8 crc[]; 1395625f965SAjay Singh } __packed; 1405625f965SAjay Singh 1415625f965SAjay Singh struct wilc_spi_rsp_data { 1425625f965SAjay Singh u8 rsp_cmd_type; 1435625f965SAjay Singh u8 status; 144f2131fa5SDavid Mosberger-Tang u8 data[]; 1455625f965SAjay Singh } __packed; 1465625f965SAjay Singh 1475625f965SAjay Singh static int wilc_bus_probe(struct spi_device *spi) 1485625f965SAjay Singh { 1495625f965SAjay Singh int ret; 1505625f965SAjay Singh struct wilc *wilc; 1515625f965SAjay Singh struct wilc_spi *spi_priv; 1525625f965SAjay Singh 1535625f965SAjay Singh spi_priv = kzalloc(sizeof(*spi_priv), GFP_KERNEL); 1545625f965SAjay Singh if (!spi_priv) 1555625f965SAjay Singh return -ENOMEM; 1565625f965SAjay Singh 1575625f965SAjay Singh ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi); 158dc8b338fSClaudiu Beznea if (ret) 159dc8b338fSClaudiu Beznea goto free; 1605625f965SAjay Singh 1615625f965SAjay Singh spi_set_drvdata(spi, wilc); 1625625f965SAjay Singh wilc->dev = &spi->dev; 1635625f965SAjay Singh wilc->bus_data = spi_priv; 1645625f965SAjay Singh wilc->dev_irq_num = spi->irq; 1655625f965SAjay Singh 1661d89fd1aSClaudiu Beznea wilc->rtc_clk = devm_clk_get_optional(&spi->dev, "rtc"); 1671d89fd1aSClaudiu Beznea if (IS_ERR(wilc->rtc_clk)) { 1681d89fd1aSClaudiu Beznea ret = PTR_ERR(wilc->rtc_clk); 169dc8b338fSClaudiu Beznea goto netdev_cleanup; 1701d89fd1aSClaudiu Beznea } 1715625f965SAjay Singh clk_prepare_enable(wilc->rtc_clk); 1725625f965SAjay Singh 1735625f965SAjay Singh return 0; 174dc8b338fSClaudiu Beznea 175dc8b338fSClaudiu Beznea netdev_cleanup: 176dc8b338fSClaudiu Beznea wilc_netdev_cleanup(wilc); 177dc8b338fSClaudiu Beznea free: 178dc8b338fSClaudiu Beznea kfree(spi_priv); 179dc8b338fSClaudiu Beznea return ret; 1805625f965SAjay Singh } 1815625f965SAjay Singh 1825625f965SAjay Singh static int wilc_bus_remove(struct spi_device *spi) 1835625f965SAjay Singh { 1845625f965SAjay Singh struct wilc *wilc = spi_get_drvdata(spi); 1855625f965SAjay Singh 1865625f965SAjay Singh clk_disable_unprepare(wilc->rtc_clk); 1875625f965SAjay Singh wilc_netdev_cleanup(wilc); 1881d89fd1aSClaudiu Beznea 1895625f965SAjay Singh return 0; 1905625f965SAjay Singh } 1915625f965SAjay Singh 1925625f965SAjay Singh static const struct of_device_id wilc_of_match[] = { 1935625f965SAjay Singh { .compatible = "microchip,wilc1000", }, 1945625f965SAjay Singh { /* sentinel */ } 1955625f965SAjay Singh }; 1965625f965SAjay Singh MODULE_DEVICE_TABLE(of, wilc_of_match); 1975625f965SAjay Singh 1985625f965SAjay Singh static struct spi_driver wilc_spi_driver = { 1995625f965SAjay Singh .driver = { 2005625f965SAjay Singh .name = MODALIAS, 2015625f965SAjay Singh .of_match_table = wilc_of_match, 2025625f965SAjay Singh }, 2035625f965SAjay Singh .probe = wilc_bus_probe, 2045625f965SAjay Singh .remove = wilc_bus_remove, 2055625f965SAjay Singh }; 2065625f965SAjay Singh module_spi_driver(wilc_spi_driver); 2075625f965SAjay Singh MODULE_LICENSE("GPL"); 2085625f965SAjay Singh 2095625f965SAjay Singh static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len) 2105625f965SAjay Singh { 2115625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 2125625f965SAjay Singh int ret; 2135625f965SAjay Singh struct spi_message msg; 2145625f965SAjay Singh 2155625f965SAjay Singh if (len > 0 && b) { 2165625f965SAjay Singh struct spi_transfer tr = { 2175625f965SAjay Singh .tx_buf = b, 2185625f965SAjay Singh .len = len, 2195625f965SAjay Singh .delay = { 2205625f965SAjay Singh .value = 0, 2215625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 2225625f965SAjay Singh }, 2235625f965SAjay Singh }; 2245625f965SAjay Singh char *r_buffer = kzalloc(len, GFP_KERNEL); 2255625f965SAjay Singh 2265625f965SAjay Singh if (!r_buffer) 2275625f965SAjay Singh return -ENOMEM; 2285625f965SAjay Singh 2295625f965SAjay Singh tr.rx_buf = r_buffer; 2305625f965SAjay Singh dev_dbg(&spi->dev, "Request writing %d bytes\n", len); 2315625f965SAjay Singh 2325625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 2335625f965SAjay Singh spi_message_init(&msg); 2345625f965SAjay Singh msg.spi = spi; 2355625f965SAjay Singh msg.is_dma_mapped = USE_SPI_DMA; 2365625f965SAjay Singh spi_message_add_tail(&tr, &msg); 2375625f965SAjay Singh 2385625f965SAjay Singh ret = spi_sync(spi, &msg); 2395625f965SAjay Singh if (ret < 0) 2405625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 2415625f965SAjay Singh 2425625f965SAjay Singh kfree(r_buffer); 2435625f965SAjay Singh } else { 2445625f965SAjay Singh dev_err(&spi->dev, 2455625f965SAjay Singh "can't write data with the following length: %d\n", 2465625f965SAjay Singh len); 2475625f965SAjay Singh ret = -EINVAL; 2485625f965SAjay Singh } 2495625f965SAjay Singh 2505625f965SAjay Singh return ret; 2515625f965SAjay Singh } 2525625f965SAjay Singh 2535625f965SAjay Singh static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen) 2545625f965SAjay Singh { 2555625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 2565625f965SAjay Singh int ret; 2575625f965SAjay Singh 2585625f965SAjay Singh if (rlen > 0) { 2595625f965SAjay Singh struct spi_message msg; 2605625f965SAjay Singh struct spi_transfer tr = { 2615625f965SAjay Singh .rx_buf = rb, 2625625f965SAjay Singh .len = rlen, 2635625f965SAjay Singh .delay = { 2645625f965SAjay Singh .value = 0, 2655625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 2665625f965SAjay Singh }, 2675625f965SAjay Singh 2685625f965SAjay Singh }; 2695625f965SAjay Singh char *t_buffer = kzalloc(rlen, GFP_KERNEL); 2705625f965SAjay Singh 2715625f965SAjay Singh if (!t_buffer) 2725625f965SAjay Singh return -ENOMEM; 2735625f965SAjay Singh 2745625f965SAjay Singh tr.tx_buf = t_buffer; 2755625f965SAjay Singh 2765625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 2775625f965SAjay Singh spi_message_init(&msg); 2785625f965SAjay Singh msg.spi = spi; 2795625f965SAjay Singh msg.is_dma_mapped = USE_SPI_DMA; 2805625f965SAjay Singh spi_message_add_tail(&tr, &msg); 2815625f965SAjay Singh 2825625f965SAjay Singh ret = spi_sync(spi, &msg); 2835625f965SAjay Singh if (ret < 0) 2845625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 2855625f965SAjay Singh kfree(t_buffer); 2865625f965SAjay Singh } else { 2875625f965SAjay Singh dev_err(&spi->dev, 2885625f965SAjay Singh "can't read data with the following length: %u\n", 2895625f965SAjay Singh rlen); 2905625f965SAjay Singh ret = -EINVAL; 2915625f965SAjay Singh } 2925625f965SAjay Singh 2935625f965SAjay Singh return ret; 2945625f965SAjay Singh } 2955625f965SAjay Singh 2965625f965SAjay Singh static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen) 2975625f965SAjay Singh { 2985625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 2995625f965SAjay Singh int ret; 3005625f965SAjay Singh 3015625f965SAjay Singh if (rlen > 0) { 3025625f965SAjay Singh struct spi_message msg; 3035625f965SAjay Singh struct spi_transfer tr = { 3045625f965SAjay Singh .rx_buf = rb, 3055625f965SAjay Singh .tx_buf = wb, 3065625f965SAjay Singh .len = rlen, 3075625f965SAjay Singh .bits_per_word = 8, 3085625f965SAjay Singh .delay = { 3095625f965SAjay Singh .value = 0, 3105625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 3115625f965SAjay Singh }, 3125625f965SAjay Singh 3135625f965SAjay Singh }; 3145625f965SAjay Singh 3155625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 3165625f965SAjay Singh spi_message_init(&msg); 3175625f965SAjay Singh msg.spi = spi; 3185625f965SAjay Singh msg.is_dma_mapped = USE_SPI_DMA; 3195625f965SAjay Singh 3205625f965SAjay Singh spi_message_add_tail(&tr, &msg); 3215625f965SAjay Singh ret = spi_sync(spi, &msg); 3225625f965SAjay Singh if (ret < 0) 3235625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 3245625f965SAjay Singh } else { 3255625f965SAjay Singh dev_err(&spi->dev, 3265625f965SAjay Singh "can't read data with the following length: %u\n", 3275625f965SAjay Singh rlen); 3285625f965SAjay Singh ret = -EINVAL; 3295625f965SAjay Singh } 3305625f965SAjay Singh 3315625f965SAjay Singh return ret; 3325625f965SAjay Singh } 3335625f965SAjay Singh 3345625f965SAjay Singh static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) 3355625f965SAjay Singh { 3365625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 3375625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 3385625f965SAjay Singh int ix, nbytes; 3395625f965SAjay Singh int result = 0; 340c872e7aeSDavid Mosberger-Tang u8 cmd, order, crc[2]; 341c872e7aeSDavid Mosberger-Tang u16 crc_calc; 3425625f965SAjay Singh 3435625f965SAjay Singh /* 3445625f965SAjay Singh * Data 3455625f965SAjay Singh */ 3465625f965SAjay Singh ix = 0; 3475625f965SAjay Singh do { 3485625f965SAjay Singh if (sz <= DATA_PKT_SZ) { 3495625f965SAjay Singh nbytes = sz; 3505625f965SAjay Singh order = 0x3; 3515625f965SAjay Singh } else { 3525625f965SAjay Singh nbytes = DATA_PKT_SZ; 3535625f965SAjay Singh if (ix == 0) 3545625f965SAjay Singh order = 0x1; 3555625f965SAjay Singh else 3565625f965SAjay Singh order = 0x02; 3575625f965SAjay Singh } 3585625f965SAjay Singh 3595625f965SAjay Singh /* 3605625f965SAjay Singh * Write command 3615625f965SAjay Singh */ 3625625f965SAjay Singh cmd = 0xf0; 3635625f965SAjay Singh cmd |= order; 3645625f965SAjay Singh 3655625f965SAjay Singh if (wilc_spi_tx(wilc, &cmd, 1)) { 3665625f965SAjay Singh dev_err(&spi->dev, 3675625f965SAjay Singh "Failed data block cmd write, bus error...\n"); 3685625f965SAjay Singh result = -EINVAL; 3695625f965SAjay Singh break; 3705625f965SAjay Singh } 3715625f965SAjay Singh 3725625f965SAjay Singh /* 3735625f965SAjay Singh * Write data 3745625f965SAjay Singh */ 3755625f965SAjay Singh if (wilc_spi_tx(wilc, &b[ix], nbytes)) { 3765625f965SAjay Singh dev_err(&spi->dev, 3775625f965SAjay Singh "Failed data block write, bus error...\n"); 3785625f965SAjay Singh result = -EINVAL; 3795625f965SAjay Singh break; 3805625f965SAjay Singh } 3815625f965SAjay Singh 3825625f965SAjay Singh /* 383c872e7aeSDavid Mosberger-Tang * Write CRC 3845625f965SAjay Singh */ 385c872e7aeSDavid Mosberger-Tang if (spi_priv->crc16_enabled) { 386c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, &b[ix], nbytes); 387c872e7aeSDavid Mosberger-Tang crc[0] = crc_calc >> 8; 388c872e7aeSDavid Mosberger-Tang crc[1] = crc_calc; 3895625f965SAjay Singh if (wilc_spi_tx(wilc, crc, 2)) { 3905625f965SAjay Singh dev_err(&spi->dev, "Failed data block crc write, bus error...\n"); 3915625f965SAjay Singh result = -EINVAL; 3925625f965SAjay Singh break; 3935625f965SAjay Singh } 3945625f965SAjay Singh } 3955625f965SAjay Singh 3965625f965SAjay Singh /* 3975625f965SAjay Singh * No need to wait for response 3985625f965SAjay Singh */ 3995625f965SAjay Singh ix += nbytes; 4005625f965SAjay Singh sz -= nbytes; 4015625f965SAjay Singh } while (sz); 4025625f965SAjay Singh 4035625f965SAjay Singh return result; 4045625f965SAjay Singh } 4055625f965SAjay Singh 4065625f965SAjay Singh /******************************************** 4075625f965SAjay Singh * 4085625f965SAjay Singh * Spi Internal Read/Write Function 4095625f965SAjay Singh * 4105625f965SAjay Singh ********************************************/ 4115625f965SAjay Singh static u8 wilc_get_crc7(u8 *buffer, u32 len) 4125625f965SAjay Singh { 4135625f965SAjay Singh return crc7_be(0xfe, buffer, len); 4145625f965SAjay Singh } 4155625f965SAjay Singh 4165625f965SAjay Singh static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, 4175625f965SAjay Singh u8 clockless) 4185625f965SAjay Singh { 4195625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 4205625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 4215625f965SAjay Singh u8 wb[32], rb[32]; 422f2131fa5SDavid Mosberger-Tang int cmd_len, resp_len, i; 423c872e7aeSDavid Mosberger-Tang u16 crc_calc, crc_recv; 4245625f965SAjay Singh struct wilc_spi_cmd *c; 425f2131fa5SDavid Mosberger-Tang struct wilc_spi_rsp_data *r; 426c872e7aeSDavid Mosberger-Tang struct wilc_spi_read_rsp_data *r_data; 4275625f965SAjay Singh 4285625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 4295625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 4305625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 4315625f965SAjay Singh c->cmd_type = cmd; 4325625f965SAjay Singh if (cmd == CMD_SINGLE_READ) { 4335625f965SAjay Singh c->u.simple_cmd.addr[0] = adr >> 16; 4345625f965SAjay Singh c->u.simple_cmd.addr[1] = adr >> 8; 4355625f965SAjay Singh c->u.simple_cmd.addr[2] = adr; 4365625f965SAjay Singh } else if (cmd == CMD_INTERNAL_READ) { 4375625f965SAjay Singh c->u.simple_cmd.addr[0] = adr >> 8; 4385625f965SAjay Singh if (clockless == 1) 4395625f965SAjay Singh c->u.simple_cmd.addr[0] |= BIT(7); 4405625f965SAjay Singh c->u.simple_cmd.addr[1] = adr; 4415625f965SAjay Singh c->u.simple_cmd.addr[2] = 0x0; 4425625f965SAjay Singh } else { 4435625f965SAjay Singh dev_err(&spi->dev, "cmd [%x] not supported\n", cmd); 4445625f965SAjay Singh return -EINVAL; 4455625f965SAjay Singh } 4465625f965SAjay Singh 4475625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc); 448f2131fa5SDavid Mosberger-Tang resp_len = sizeof(*r) + sizeof(*r_data) + WILC_SPI_RSP_HDR_EXTRA_DATA; 449f2131fa5SDavid Mosberger-Tang 450c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) { 4515625f965SAjay Singh c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 4525625f965SAjay Singh cmd_len += 1; 4535625f965SAjay Singh resp_len += 2; 4545625f965SAjay Singh } 4555625f965SAjay Singh 4565625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 4575625f965SAjay Singh dev_err(&spi->dev, 4585625f965SAjay Singh "spi buffer size too small (%d) (%d) (%zu)\n", 4595625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 4605625f965SAjay Singh return -EINVAL; 4615625f965SAjay Singh } 4625625f965SAjay Singh 4635625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 4645625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 4655625f965SAjay Singh return -EINVAL; 4665625f965SAjay Singh } 4675625f965SAjay Singh 468f2131fa5SDavid Mosberger-Tang r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 4695625f965SAjay Singh if (r->rsp_cmd_type != cmd) { 470c872e7aeSDavid Mosberger-Tang if (!spi_priv->probing_crc) 4715625f965SAjay Singh dev_err(&spi->dev, 472c872e7aeSDavid Mosberger-Tang "Failed cmd, cmd (%02x), resp (%02x)\n", 4735625f965SAjay Singh cmd, r->rsp_cmd_type); 4745625f965SAjay Singh return -EINVAL; 4755625f965SAjay Singh } 4765625f965SAjay Singh 4775625f965SAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { 4785625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 4795625f965SAjay Singh r->status); 4805625f965SAjay Singh return -EINVAL; 4815625f965SAjay Singh } 4825625f965SAjay Singh 483f2131fa5SDavid Mosberger-Tang for (i = 0; i < WILC_SPI_RSP_HDR_EXTRA_DATA; ++i) 484f2131fa5SDavid Mosberger-Tang if (WILC_GET_RESP_HDR_START(r->data[i]) == 0xf) 485f2131fa5SDavid Mosberger-Tang break; 486f2131fa5SDavid Mosberger-Tang 487f2131fa5SDavid Mosberger-Tang if (i >= WILC_SPI_RSP_HDR_EXTRA_DATA) { 488f2131fa5SDavid Mosberger-Tang dev_err(&spi->dev, "Error, data start missing\n"); 4895625f965SAjay Singh return -EINVAL; 4905625f965SAjay Singh } 4915625f965SAjay Singh 492f2131fa5SDavid Mosberger-Tang r_data = (struct wilc_spi_read_rsp_data *)&r->data[i]; 493f2131fa5SDavid Mosberger-Tang 4945625f965SAjay Singh if (b) 495f2131fa5SDavid Mosberger-Tang memcpy(b, r_data->data, 4); 4965625f965SAjay Singh 497c872e7aeSDavid Mosberger-Tang if (!clockless && spi_priv->crc16_enabled) { 498c872e7aeSDavid Mosberger-Tang crc_recv = (r_data->crc[0] << 8) | r_data->crc[1]; 499c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, r_data->data, 4); 500c872e7aeSDavid Mosberger-Tang if (crc_recv != crc_calc) { 501c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "%s: bad CRC 0x%04x " 502c872e7aeSDavid Mosberger-Tang "(calculated 0x%04x)\n", __func__, 503c872e7aeSDavid Mosberger-Tang crc_recv, crc_calc); 504c872e7aeSDavid Mosberger-Tang return -EINVAL; 505c872e7aeSDavid Mosberger-Tang } 506c872e7aeSDavid Mosberger-Tang } 5075625f965SAjay Singh 5085625f965SAjay Singh return 0; 5095625f965SAjay Singh } 5105625f965SAjay Singh 5115625f965SAjay Singh static int wilc_spi_write_cmd(struct wilc *wilc, u8 cmd, u32 adr, u32 data, 5125625f965SAjay Singh u8 clockless) 5135625f965SAjay Singh { 5145625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 5155625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 5165625f965SAjay Singh u8 wb[32], rb[32]; 5175625f965SAjay Singh int cmd_len, resp_len; 5185625f965SAjay Singh struct wilc_spi_cmd *c; 5195625f965SAjay Singh struct wilc_spi_rsp_data *r; 5205625f965SAjay Singh 5215625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 5225625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 5235625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 5245625f965SAjay Singh c->cmd_type = cmd; 5255625f965SAjay Singh if (cmd == CMD_INTERNAL_WRITE) { 5265625f965SAjay Singh c->u.internal_w_cmd.addr[0] = adr >> 8; 5275625f965SAjay Singh if (clockless == 1) 5285625f965SAjay Singh c->u.internal_w_cmd.addr[0] |= BIT(7); 5295625f965SAjay Singh 5305625f965SAjay Singh c->u.internal_w_cmd.addr[1] = adr; 5315625f965SAjay Singh c->u.internal_w_cmd.data = cpu_to_be32(data); 5325625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.internal_w_cmd.crc); 533c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 5345625f965SAjay Singh c->u.internal_w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 5355625f965SAjay Singh } else if (cmd == CMD_SINGLE_WRITE) { 5365625f965SAjay Singh c->u.w_cmd.addr[0] = adr >> 16; 5375625f965SAjay Singh c->u.w_cmd.addr[1] = adr >> 8; 5385625f965SAjay Singh c->u.w_cmd.addr[2] = adr; 5395625f965SAjay Singh c->u.w_cmd.data = cpu_to_be32(data); 5405625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.w_cmd.crc); 541c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 5425625f965SAjay Singh c->u.w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 5435625f965SAjay Singh } else { 5445625f965SAjay Singh dev_err(&spi->dev, "write cmd [%x] not supported\n", cmd); 5455625f965SAjay Singh return -EINVAL; 5465625f965SAjay Singh } 5475625f965SAjay Singh 548c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 5495625f965SAjay Singh cmd_len += 1; 5505625f965SAjay Singh 5515625f965SAjay Singh resp_len = sizeof(*r); 5525625f965SAjay Singh 5535625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 5545625f965SAjay Singh dev_err(&spi->dev, 5555625f965SAjay Singh "spi buffer size too small (%d) (%d) (%zu)\n", 5565625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 5575625f965SAjay Singh return -EINVAL; 5585625f965SAjay Singh } 5595625f965SAjay Singh 5605625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 5615625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 5625625f965SAjay Singh return -EINVAL; 5635625f965SAjay Singh } 5645625f965SAjay Singh 5655625f965SAjay Singh r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 5665625f965SAjay Singh if (r->rsp_cmd_type != cmd) { 5675625f965SAjay Singh dev_err(&spi->dev, 5685625f965SAjay Singh "Failed cmd response, cmd (%02x), resp (%02x)\n", 5695625f965SAjay Singh cmd, r->rsp_cmd_type); 5705625f965SAjay Singh return -EINVAL; 5715625f965SAjay Singh } 5725625f965SAjay Singh 5735625f965SAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { 5745625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 5755625f965SAjay Singh r->status); 5765625f965SAjay Singh return -EINVAL; 5775625f965SAjay Singh } 5785625f965SAjay Singh 5795625f965SAjay Singh return 0; 5805625f965SAjay Singh } 5815625f965SAjay Singh 5825625f965SAjay Singh static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz) 5835625f965SAjay Singh { 5845625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 5855625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 586c872e7aeSDavid Mosberger-Tang u16 crc_recv, crc_calc; 5875625f965SAjay Singh u8 wb[32], rb[32]; 5885625f965SAjay Singh int cmd_len, resp_len; 5895625f965SAjay Singh int retry, ix = 0; 5905625f965SAjay Singh u8 crc[2]; 5915625f965SAjay Singh struct wilc_spi_cmd *c; 5925625f965SAjay Singh struct wilc_spi_rsp_data *r; 5935625f965SAjay Singh 5945625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 5955625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 5965625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 5975625f965SAjay Singh c->cmd_type = cmd; 5985625f965SAjay Singh if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_READ) { 5995625f965SAjay Singh c->u.dma_cmd.addr[0] = adr >> 16; 6005625f965SAjay Singh c->u.dma_cmd.addr[1] = adr >> 8; 6015625f965SAjay Singh c->u.dma_cmd.addr[2] = adr; 6025625f965SAjay Singh c->u.dma_cmd.size[0] = sz >> 8; 6035625f965SAjay Singh c->u.dma_cmd.size[1] = sz; 6045625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd.crc); 605c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6065625f965SAjay Singh c->u.dma_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 6075625f965SAjay Singh } else if (cmd == CMD_DMA_EXT_WRITE || cmd == CMD_DMA_EXT_READ) { 6085625f965SAjay Singh c->u.dma_cmd_ext.addr[0] = adr >> 16; 6095625f965SAjay Singh c->u.dma_cmd_ext.addr[1] = adr >> 8; 6105625f965SAjay Singh c->u.dma_cmd_ext.addr[2] = adr; 6115625f965SAjay Singh c->u.dma_cmd_ext.size[0] = sz >> 16; 6125625f965SAjay Singh c->u.dma_cmd_ext.size[1] = sz >> 8; 6135625f965SAjay Singh c->u.dma_cmd_ext.size[2] = sz; 6145625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd_ext.crc); 615c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6165625f965SAjay Singh c->u.dma_cmd_ext.crc[0] = wilc_get_crc7(wb, cmd_len); 6175625f965SAjay Singh } else { 6185625f965SAjay Singh dev_err(&spi->dev, "dma read write cmd [%x] not supported\n", 6195625f965SAjay Singh cmd); 6205625f965SAjay Singh return -EINVAL; 6215625f965SAjay Singh } 622c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6235625f965SAjay Singh cmd_len += 1; 6245625f965SAjay Singh 6255625f965SAjay Singh resp_len = sizeof(*r); 6265625f965SAjay Singh 6275625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 6285625f965SAjay Singh dev_err(&spi->dev, "spi buffer size too small (%d)(%d) (%zu)\n", 6295625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 6305625f965SAjay Singh return -EINVAL; 6315625f965SAjay Singh } 6325625f965SAjay Singh 6335625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 6345625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 6355625f965SAjay Singh return -EINVAL; 6365625f965SAjay Singh } 6375625f965SAjay Singh 6385625f965SAjay Singh r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 6395625f965SAjay Singh if (r->rsp_cmd_type != cmd) { 6405625f965SAjay Singh dev_err(&spi->dev, 6415625f965SAjay Singh "Failed cmd response, cmd (%02x), resp (%02x)\n", 6425625f965SAjay Singh cmd, r->rsp_cmd_type); 6435625f965SAjay Singh return -EINVAL; 6445625f965SAjay Singh } 6455625f965SAjay Singh 6465625f965SAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { 6475625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 6485625f965SAjay Singh r->status); 6495625f965SAjay Singh return -EINVAL; 6505625f965SAjay Singh } 6515625f965SAjay Singh 6525625f965SAjay Singh if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_EXT_WRITE) 6535625f965SAjay Singh return 0; 6545625f965SAjay Singh 6555625f965SAjay Singh while (sz > 0) { 6565625f965SAjay Singh int nbytes; 6575625f965SAjay Singh u8 rsp; 6585625f965SAjay Singh 6595625f965SAjay Singh if (sz <= DATA_PKT_SZ) 6605625f965SAjay Singh nbytes = sz; 6615625f965SAjay Singh else 6625625f965SAjay Singh nbytes = DATA_PKT_SZ; 6635625f965SAjay Singh 6645625f965SAjay Singh /* 6655625f965SAjay Singh * Data Response header 6665625f965SAjay Singh */ 6675625f965SAjay Singh retry = 100; 6685625f965SAjay Singh do { 6695625f965SAjay Singh if (wilc_spi_rx(wilc, &rsp, 1)) { 6705625f965SAjay Singh dev_err(&spi->dev, 6715625f965SAjay Singh "Failed resp read, bus err\n"); 6725625f965SAjay Singh return -EINVAL; 6735625f965SAjay Singh } 6745625f965SAjay Singh if (WILC_GET_RESP_HDR_START(rsp) == 0xf) 6755625f965SAjay Singh break; 6765625f965SAjay Singh } while (retry--); 6775625f965SAjay Singh 6785625f965SAjay Singh /* 6795625f965SAjay Singh * Read bytes 6805625f965SAjay Singh */ 6815625f965SAjay Singh if (wilc_spi_rx(wilc, &b[ix], nbytes)) { 6825625f965SAjay Singh dev_err(&spi->dev, 6835625f965SAjay Singh "Failed block read, bus err\n"); 6845625f965SAjay Singh return -EINVAL; 6855625f965SAjay Singh } 6865625f965SAjay Singh 6875625f965SAjay Singh /* 688c872e7aeSDavid Mosberger-Tang * Read CRC 6895625f965SAjay Singh */ 690c872e7aeSDavid Mosberger-Tang if (spi_priv->crc16_enabled) { 691c872e7aeSDavid Mosberger-Tang if (wilc_spi_rx(wilc, crc, 2)) { 6925625f965SAjay Singh dev_err(&spi->dev, 693c872e7aeSDavid Mosberger-Tang "Failed block CRC read, bus err\n"); 6945625f965SAjay Singh return -EINVAL; 6955625f965SAjay Singh } 696c872e7aeSDavid Mosberger-Tang crc_recv = (crc[0] << 8) | crc[1]; 697c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, &b[ix], nbytes); 698c872e7aeSDavid Mosberger-Tang if (crc_recv != crc_calc) { 699c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "%s: bad CRC 0x%04x " 700c872e7aeSDavid Mosberger-Tang "(calculated 0x%04x)\n", __func__, 701c872e7aeSDavid Mosberger-Tang crc_recv, crc_calc); 702c872e7aeSDavid Mosberger-Tang return -EINVAL; 703c872e7aeSDavid Mosberger-Tang } 704c872e7aeSDavid Mosberger-Tang } 7055625f965SAjay Singh 7065625f965SAjay Singh ix += nbytes; 7075625f965SAjay Singh sz -= nbytes; 7085625f965SAjay Singh } 7095625f965SAjay Singh return 0; 7105625f965SAjay Singh } 7115625f965SAjay Singh 7125625f965SAjay Singh static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data) 7135625f965SAjay Singh { 7145625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 7155625f965SAjay Singh int result; 7165625f965SAjay Singh u8 cmd = CMD_SINGLE_READ; 7175625f965SAjay Singh u8 clockless = 0; 7185625f965SAjay Singh 7195625f965SAjay Singh if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) { 7205625f965SAjay Singh /* Clockless register */ 7215625f965SAjay Singh cmd = CMD_INTERNAL_READ; 7225625f965SAjay Singh clockless = 1; 7235625f965SAjay Singh } 7245625f965SAjay Singh 7255625f965SAjay Singh result = wilc_spi_single_read(wilc, cmd, addr, data, clockless); 7265625f965SAjay Singh if (result) { 7275625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr); 7285625f965SAjay Singh return result; 7295625f965SAjay Singh } 7305625f965SAjay Singh 7315625f965SAjay Singh le32_to_cpus(data); 7325625f965SAjay Singh 7335625f965SAjay Singh return 0; 7345625f965SAjay Singh } 7355625f965SAjay Singh 7365625f965SAjay Singh static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) 7375625f965SAjay Singh { 7385625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 7395625f965SAjay Singh int result; 7405625f965SAjay Singh 7415625f965SAjay Singh if (size <= 4) 7425625f965SAjay Singh return -EINVAL; 7435625f965SAjay Singh 7445625f965SAjay Singh result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_READ, addr, buf, size); 7455625f965SAjay Singh if (result) { 7465625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr); 7475625f965SAjay Singh return result; 7485625f965SAjay Singh } 7495625f965SAjay Singh 7505625f965SAjay Singh return 0; 7515625f965SAjay Singh } 7525625f965SAjay Singh 7535625f965SAjay Singh static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat) 7545625f965SAjay Singh { 7555625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 7565625f965SAjay Singh int result; 7575625f965SAjay Singh 7585625f965SAjay Singh result = wilc_spi_write_cmd(wilc, CMD_INTERNAL_WRITE, adr, dat, 0); 7595625f965SAjay Singh if (result) { 7605625f965SAjay Singh dev_err(&spi->dev, "Failed internal write cmd...\n"); 7615625f965SAjay Singh return result; 7625625f965SAjay Singh } 7635625f965SAjay Singh 7645625f965SAjay Singh return 0; 7655625f965SAjay Singh } 7665625f965SAjay Singh 7675625f965SAjay Singh static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data) 7685625f965SAjay Singh { 7695625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 770c872e7aeSDavid Mosberger-Tang struct wilc_spi *spi_priv = wilc->bus_data; 7715625f965SAjay Singh int result; 7725625f965SAjay Singh 7735625f965SAjay Singh result = wilc_spi_single_read(wilc, CMD_INTERNAL_READ, adr, data, 0); 7745625f965SAjay Singh if (result) { 775c872e7aeSDavid Mosberger-Tang if (!spi_priv->probing_crc) 7765625f965SAjay Singh dev_err(&spi->dev, "Failed internal read cmd...\n"); 7775625f965SAjay Singh return result; 7785625f965SAjay Singh } 7795625f965SAjay Singh 7805625f965SAjay Singh le32_to_cpus(data); 7815625f965SAjay Singh 7825625f965SAjay Singh return 0; 7835625f965SAjay Singh } 7845625f965SAjay Singh 7855625f965SAjay Singh /******************************************** 7865625f965SAjay Singh * 7875625f965SAjay Singh * Spi interfaces 7885625f965SAjay Singh * 7895625f965SAjay Singh ********************************************/ 7905625f965SAjay Singh 7915625f965SAjay Singh static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data) 7925625f965SAjay Singh { 7935625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 7945625f965SAjay Singh int result; 7955625f965SAjay Singh u8 cmd = CMD_SINGLE_WRITE; 7965625f965SAjay Singh u8 clockless = 0; 7975625f965SAjay Singh 7985625f965SAjay Singh if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) { 7995625f965SAjay Singh /* Clockless register */ 8005625f965SAjay Singh cmd = CMD_INTERNAL_WRITE; 8015625f965SAjay Singh clockless = 1; 8025625f965SAjay Singh } 8035625f965SAjay Singh 8045625f965SAjay Singh result = wilc_spi_write_cmd(wilc, cmd, addr, data, clockless); 8055625f965SAjay Singh if (result) { 8065625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr); 8075625f965SAjay Singh return result; 8085625f965SAjay Singh } 8095625f965SAjay Singh 8105625f965SAjay Singh return 0; 8115625f965SAjay Singh } 8125625f965SAjay Singh 813ce3b9338SDavid Mosberger-Tang static int spi_data_rsp(struct wilc *wilc, u8 cmd) 814ce3b9338SDavid Mosberger-Tang { 815ce3b9338SDavid Mosberger-Tang struct spi_device *spi = to_spi_device(wilc->dev); 816ce3b9338SDavid Mosberger-Tang int result, i; 817ce3b9338SDavid Mosberger-Tang u8 rsp[4]; 818ce3b9338SDavid Mosberger-Tang 819ce3b9338SDavid Mosberger-Tang /* 820ce3b9338SDavid Mosberger-Tang * The response to data packets is two bytes long. For 821ce3b9338SDavid Mosberger-Tang * efficiency's sake, wilc_spi_write() wisely ignores the 822ce3b9338SDavid Mosberger-Tang * responses for all packets but the final one. The downside 823ce3b9338SDavid Mosberger-Tang * of that optimization is that when the final data packet is 824ce3b9338SDavid Mosberger-Tang * short, we may receive (part of) the response to the 825ce3b9338SDavid Mosberger-Tang * second-to-last packet before the one for the final packet. 826ce3b9338SDavid Mosberger-Tang * To handle this, we always read 4 bytes and then search for 827ce3b9338SDavid Mosberger-Tang * the last byte that contains the "Response Start" code (0xc 828ce3b9338SDavid Mosberger-Tang * in the top 4 bits). We then know that this byte is the 829ce3b9338SDavid Mosberger-Tang * first response byte of the final data packet. 830ce3b9338SDavid Mosberger-Tang */ 831ce3b9338SDavid Mosberger-Tang result = wilc_spi_rx(wilc, rsp, sizeof(rsp)); 832ce3b9338SDavid Mosberger-Tang if (result) { 833ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, "Failed bus error...\n"); 834ce3b9338SDavid Mosberger-Tang return result; 835ce3b9338SDavid Mosberger-Tang } 836ce3b9338SDavid Mosberger-Tang 837ce3b9338SDavid Mosberger-Tang for (i = sizeof(rsp) - 2; i >= 0; --i) 838ce3b9338SDavid Mosberger-Tang if (FIELD_GET(RSP_START_FIELD, rsp[i]) == RSP_START_TAG) 839ce3b9338SDavid Mosberger-Tang break; 840ce3b9338SDavid Mosberger-Tang 841ce3b9338SDavid Mosberger-Tang if (i < 0) { 842ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, 843ce3b9338SDavid Mosberger-Tang "Data packet response missing (%02x %02x %02x %02x)\n", 844ce3b9338SDavid Mosberger-Tang rsp[0], rsp[1], rsp[2], rsp[3]); 845ce3b9338SDavid Mosberger-Tang return -1; 846ce3b9338SDavid Mosberger-Tang } 847ce3b9338SDavid Mosberger-Tang 848ce3b9338SDavid Mosberger-Tang /* rsp[i] is the last response start byte */ 849ce3b9338SDavid Mosberger-Tang 850ce3b9338SDavid Mosberger-Tang if (FIELD_GET(RSP_TYPE_FIELD, rsp[i]) != RSP_TYPE_LAST_PACKET 851ce3b9338SDavid Mosberger-Tang || rsp[i + 1] != RSP_STATE_NO_ERROR) { 852ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, "Data response error (%02x %02x)\n", 853ce3b9338SDavid Mosberger-Tang rsp[i], rsp[i + 1]); 854ce3b9338SDavid Mosberger-Tang return -1; 855ce3b9338SDavid Mosberger-Tang } 856ce3b9338SDavid Mosberger-Tang return 0; 857ce3b9338SDavid Mosberger-Tang } 858ce3b9338SDavid Mosberger-Tang 8595625f965SAjay Singh static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) 8605625f965SAjay Singh { 8615625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 8625625f965SAjay Singh int result; 8635625f965SAjay Singh 8645625f965SAjay Singh /* 8655625f965SAjay Singh * has to be greated than 4 8665625f965SAjay Singh */ 8675625f965SAjay Singh if (size <= 4) 8685625f965SAjay Singh return -EINVAL; 8695625f965SAjay Singh 8705625f965SAjay Singh result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size); 8715625f965SAjay Singh if (result) { 8725625f965SAjay Singh dev_err(&spi->dev, 8735625f965SAjay Singh "Failed cmd, write block (%08x)...\n", addr); 8745625f965SAjay Singh return result; 8755625f965SAjay Singh } 8765625f965SAjay Singh 8775625f965SAjay Singh /* 8785625f965SAjay Singh * Data 8795625f965SAjay Singh */ 8805625f965SAjay Singh result = spi_data_write(wilc, buf, size); 8815625f965SAjay Singh if (result) { 8825625f965SAjay Singh dev_err(&spi->dev, "Failed block data write...\n"); 8835625f965SAjay Singh return result; 8845625f965SAjay Singh } 8855625f965SAjay Singh 886ce3b9338SDavid Mosberger-Tang /* 887ce3b9338SDavid Mosberger-Tang * Data response 888ce3b9338SDavid Mosberger-Tang */ 889ce3b9338SDavid Mosberger-Tang return spi_data_rsp(wilc, CMD_DMA_EXT_WRITE); 8905625f965SAjay Singh } 8915625f965SAjay Singh 8925625f965SAjay Singh /******************************************** 8935625f965SAjay Singh * 8945625f965SAjay Singh * Bus interfaces 8955625f965SAjay Singh * 8965625f965SAjay Singh ********************************************/ 8975625f965SAjay Singh 8985625f965SAjay Singh static int wilc_spi_deinit(struct wilc *wilc) 8995625f965SAjay Singh { 9005625f965SAjay Singh /* 9015625f965SAjay Singh * TODO: 9025625f965SAjay Singh */ 9035625f965SAjay Singh return 0; 9045625f965SAjay Singh } 9055625f965SAjay Singh 9065625f965SAjay Singh static int wilc_spi_init(struct wilc *wilc, bool resume) 9075625f965SAjay Singh { 9085625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 9095625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 9105625f965SAjay Singh u32 reg; 9115625f965SAjay Singh u32 chipid; 912c872e7aeSDavid Mosberger-Tang int ret, i; 9135625f965SAjay Singh 914*50cbbfd4SDavid Mosberger-Tang if (spi_priv->isinit) { 915*50cbbfd4SDavid Mosberger-Tang /* Confirm we can read chipid register without error: */ 9165625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); 917*50cbbfd4SDavid Mosberger-Tang if (ret == 0) 918*50cbbfd4SDavid Mosberger-Tang return 0; 9195625f965SAjay Singh 920*50cbbfd4SDavid Mosberger-Tang dev_err(&spi->dev, "Fail cmd read chip id...\n"); 9215625f965SAjay Singh } 9225625f965SAjay Singh 9235625f965SAjay Singh /* 9245625f965SAjay Singh * configure protocol 9255625f965SAjay Singh */ 9265625f965SAjay Singh 9275625f965SAjay Singh /* 928c872e7aeSDavid Mosberger-Tang * Infer the CRC settings that are currently in effect. This 929c872e7aeSDavid Mosberger-Tang * is necessary because we can't be sure that the chip has 930c872e7aeSDavid Mosberger-Tang * been RESET (e.g, after module unload and reload). 9315625f965SAjay Singh */ 932c872e7aeSDavid Mosberger-Tang spi_priv->probing_crc = true; 933c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = enable_crc7; 934c872e7aeSDavid Mosberger-Tang spi_priv->crc16_enabled = false; /* don't check CRC16 during probing */ 935c872e7aeSDavid Mosberger-Tang for (i = 0; i < 2; ++i) { 9365625f965SAjay Singh ret = spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); 937c872e7aeSDavid Mosberger-Tang if (ret == 0) 938c872e7aeSDavid Mosberger-Tang break; 939c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = !enable_crc7; 940c872e7aeSDavid Mosberger-Tang } 9415625f965SAjay Singh if (ret) { 942c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "Failed with CRC7 on and off.\n"); 9435625f965SAjay Singh return ret; 9445625f965SAjay Singh } 9455ee2d9ddSDavid Mosberger-Tang 946c872e7aeSDavid Mosberger-Tang /* set up the desired CRC configuration: */ 947c872e7aeSDavid Mosberger-Tang reg &= ~(PROTOCOL_REG_CRC7_MASK | PROTOCOL_REG_CRC16_MASK); 948c872e7aeSDavid Mosberger-Tang if (enable_crc7) 949c872e7aeSDavid Mosberger-Tang reg |= PROTOCOL_REG_CRC7_MASK; 950c872e7aeSDavid Mosberger-Tang if (enable_crc16) 951c872e7aeSDavid Mosberger-Tang reg |= PROTOCOL_REG_CRC16_MASK; 952c872e7aeSDavid Mosberger-Tang 953c872e7aeSDavid Mosberger-Tang /* set up the data packet size: */ 9545ee2d9ddSDavid Mosberger-Tang BUILD_BUG_ON(DATA_PKT_LOG_SZ < DATA_PKT_LOG_SZ_MIN 9555ee2d9ddSDavid Mosberger-Tang || DATA_PKT_LOG_SZ > DATA_PKT_LOG_SZ_MAX); 9565ee2d9ddSDavid Mosberger-Tang reg &= ~PROTOCOL_REG_PKT_SZ_MASK; 9575ee2d9ddSDavid Mosberger-Tang reg |= FIELD_PREP(PROTOCOL_REG_PKT_SZ_MASK, 9585ee2d9ddSDavid Mosberger-Tang DATA_PKT_LOG_SZ - DATA_PKT_LOG_SZ_MIN); 9595ee2d9ddSDavid Mosberger-Tang 960c872e7aeSDavid Mosberger-Tang /* establish the new setup: */ 9615625f965SAjay Singh ret = spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg); 9625625f965SAjay Singh if (ret) { 9635625f965SAjay Singh dev_err(&spi->dev, 9645625f965SAjay Singh "[wilc spi %d]: Failed internal write reg\n", 9655625f965SAjay Singh __LINE__); 9665625f965SAjay Singh return ret; 9675625f965SAjay Singh } 968c872e7aeSDavid Mosberger-Tang /* update our state to match new protocol settings: */ 969c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = enable_crc7; 970c872e7aeSDavid Mosberger-Tang spi_priv->crc16_enabled = enable_crc16; 971c872e7aeSDavid Mosberger-Tang 972c872e7aeSDavid Mosberger-Tang /* re-read to make sure new settings are in effect: */ 973c872e7aeSDavid Mosberger-Tang spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); 974c872e7aeSDavid Mosberger-Tang 975c872e7aeSDavid Mosberger-Tang spi_priv->probing_crc = false; 9765625f965SAjay Singh 9775625f965SAjay Singh /* 978*50cbbfd4SDavid Mosberger-Tang * make sure can read chip id without protocol error 9795625f965SAjay Singh */ 9805625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); 9815625f965SAjay Singh if (ret) { 9825625f965SAjay Singh dev_err(&spi->dev, "Fail cmd read chip id...\n"); 9835625f965SAjay Singh return ret; 9845625f965SAjay Singh } 9855625f965SAjay Singh 986*50cbbfd4SDavid Mosberger-Tang spi_priv->isinit = true; 9875625f965SAjay Singh 9885625f965SAjay Singh return 0; 9895625f965SAjay Singh } 9905625f965SAjay Singh 9915625f965SAjay Singh static int wilc_spi_read_size(struct wilc *wilc, u32 *size) 9925625f965SAjay Singh { 9935625f965SAjay Singh int ret; 9945625f965SAjay Singh 9955625f965SAjay Singh ret = spi_internal_read(wilc, 9965625f965SAjay Singh WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, size); 9975625f965SAjay Singh *size = FIELD_GET(IRQ_DMA_WD_CNT_MASK, *size); 9985625f965SAjay Singh 9995625f965SAjay Singh return ret; 10005625f965SAjay Singh } 10015625f965SAjay Singh 10025625f965SAjay Singh static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status) 10035625f965SAjay Singh { 10045625f965SAjay Singh return spi_internal_read(wilc, WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, 10055625f965SAjay Singh int_status); 10065625f965SAjay Singh } 10075625f965SAjay Singh 10085625f965SAjay Singh static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val) 10095625f965SAjay Singh { 1010382726d1SAjay Singh int ret; 1011382726d1SAjay Singh int retry = SPI_ENABLE_VMM_RETRY_LIMIT; 1012382726d1SAjay Singh u32 check; 1013382726d1SAjay Singh 1014382726d1SAjay Singh while (retry) { 1015382726d1SAjay Singh ret = spi_internal_write(wilc, 1016382726d1SAjay Singh WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE, 10175625f965SAjay Singh val); 1018382726d1SAjay Singh if (ret) 1019382726d1SAjay Singh break; 1020382726d1SAjay Singh 1021382726d1SAjay Singh ret = spi_internal_read(wilc, 1022382726d1SAjay Singh WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE, 1023382726d1SAjay Singh &check); 1024382726d1SAjay Singh if (ret || ((check & EN_VMM) == (val & EN_VMM))) 1025382726d1SAjay Singh break; 1026382726d1SAjay Singh 1027382726d1SAjay Singh retry--; 1028382726d1SAjay Singh } 1029382726d1SAjay Singh return ret; 10305625f965SAjay Singh } 10315625f965SAjay Singh 10325625f965SAjay Singh static int wilc_spi_sync_ext(struct wilc *wilc, int nint) 10335625f965SAjay Singh { 10345625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 10355625f965SAjay Singh u32 reg; 10365625f965SAjay Singh int ret, i; 10375625f965SAjay Singh 10385625f965SAjay Singh if (nint > MAX_NUM_INT) { 10395625f965SAjay Singh dev_err(&spi->dev, "Too many interrupts (%d)...\n", nint); 10405625f965SAjay Singh return -EINVAL; 10415625f965SAjay Singh } 10425625f965SAjay Singh 10435625f965SAjay Singh /* 10445625f965SAjay Singh * interrupt pin mux select 10455625f965SAjay Singh */ 10465625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, ®); 10475625f965SAjay Singh if (ret) { 10485625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 10495625f965SAjay Singh WILC_PIN_MUX_0); 10505625f965SAjay Singh return ret; 10515625f965SAjay Singh } 10525625f965SAjay Singh reg |= BIT(8); 10535625f965SAjay Singh ret = wilc_spi_write_reg(wilc, WILC_PIN_MUX_0, reg); 10545625f965SAjay Singh if (ret) { 10555625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 10565625f965SAjay Singh WILC_PIN_MUX_0); 10575625f965SAjay Singh return ret; 10585625f965SAjay Singh } 10595625f965SAjay Singh 10605625f965SAjay Singh /* 10615625f965SAjay Singh * interrupt enable 10625625f965SAjay Singh */ 10635625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, ®); 10645625f965SAjay Singh if (ret) { 10655625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 10665625f965SAjay Singh WILC_INTR_ENABLE); 10675625f965SAjay Singh return ret; 10685625f965SAjay Singh } 10695625f965SAjay Singh 10705625f965SAjay Singh for (i = 0; (i < 5) && (nint > 0); i++, nint--) 10715625f965SAjay Singh reg |= (BIT((27 + i))); 10725625f965SAjay Singh 10735625f965SAjay Singh ret = wilc_spi_write_reg(wilc, WILC_INTR_ENABLE, reg); 10745625f965SAjay Singh if (ret) { 10755625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 10765625f965SAjay Singh WILC_INTR_ENABLE); 10775625f965SAjay Singh return ret; 10785625f965SAjay Singh } 10795625f965SAjay Singh if (nint) { 10805625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, ®); 10815625f965SAjay Singh if (ret) { 10825625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 10835625f965SAjay Singh WILC_INTR2_ENABLE); 10845625f965SAjay Singh return ret; 10855625f965SAjay Singh } 10865625f965SAjay Singh 10875625f965SAjay Singh for (i = 0; (i < 3) && (nint > 0); i++, nint--) 10885625f965SAjay Singh reg |= BIT(i); 10895625f965SAjay Singh 10905625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, ®); 10915625f965SAjay Singh if (ret) { 10925625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 10935625f965SAjay Singh WILC_INTR2_ENABLE); 10945625f965SAjay Singh return ret; 10955625f965SAjay Singh } 10965625f965SAjay Singh } 10975625f965SAjay Singh 10985625f965SAjay Singh return 0; 10995625f965SAjay Singh } 11005625f965SAjay Singh 11015625f965SAjay Singh /* Global spi HIF function table */ 11025625f965SAjay Singh static const struct wilc_hif_func wilc_hif_spi = { 11035625f965SAjay Singh .hif_init = wilc_spi_init, 11045625f965SAjay Singh .hif_deinit = wilc_spi_deinit, 11055625f965SAjay Singh .hif_read_reg = wilc_spi_read_reg, 11065625f965SAjay Singh .hif_write_reg = wilc_spi_write_reg, 11075625f965SAjay Singh .hif_block_rx = wilc_spi_read, 11085625f965SAjay Singh .hif_block_tx = wilc_spi_write, 11095625f965SAjay Singh .hif_read_int = wilc_spi_read_int, 11105625f965SAjay Singh .hif_clear_int_ext = wilc_spi_clear_int_ext, 11115625f965SAjay Singh .hif_read_size = wilc_spi_read_size, 11125625f965SAjay Singh .hif_block_tx_ext = wilc_spi_write, 11135625f965SAjay Singh .hif_block_rx_ext = wilc_spi_read, 11145625f965SAjay Singh .hif_sync_ext = wilc_spi_sync_ext, 11155625f965SAjay Singh }; 1116