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> 10*c872e7aeSDavid Mosberger-Tang #include <linux/crc-itu-t.h> 115625f965SAjay Singh 125625f965SAjay Singh #include "netdev.h" 135625f965SAjay Singh #include "cfg80211.h" 145625f965SAjay Singh 15*c872e7aeSDavid Mosberger-Tang static bool enable_crc7; /* protect SPI commands with CRC7 */ 16*c872e7aeSDavid Mosberger-Tang module_param(enable_crc7, bool, 0644); 17*c872e7aeSDavid Mosberger-Tang MODULE_PARM_DESC(enable_crc7, 18*c872e7aeSDavid Mosberger-Tang "Enable CRC7 checksum to protect command transfers\n" 19*c872e7aeSDavid Mosberger-Tang "\t\t\tagainst corruption during the SPI transfer.\n" 20*c872e7aeSDavid Mosberger-Tang "\t\t\tCommand transfers are short and the CPU-cycle cost\n" 21*c872e7aeSDavid Mosberger-Tang "\t\t\tof enabling this is small."); 22*c872e7aeSDavid Mosberger-Tang 23*c872e7aeSDavid Mosberger-Tang static bool enable_crc16; /* protect SPI data with CRC16 */ 24*c872e7aeSDavid Mosberger-Tang module_param(enable_crc16, bool, 0644); 25*c872e7aeSDavid Mosberger-Tang MODULE_PARM_DESC(enable_crc16, 26*c872e7aeSDavid Mosberger-Tang "Enable CRC16 checksum to protect data transfers\n" 27*c872e7aeSDavid Mosberger-Tang "\t\t\tagainst corruption during the SPI transfer.\n" 28*c872e7aeSDavid Mosberger-Tang "\t\t\tData transfers can be large and the CPU-cycle cost\n" 29*c872e7aeSDavid Mosberger-Tang "\t\t\tof enabling this may be substantial."); 30*c872e7aeSDavid 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*c872e7aeSDavid Mosberger-Tang bool probing_crc; /* true if we're probing chip's CRC config */ 43*c872e7aeSDavid Mosberger-Tang bool crc7_enabled; /* true if crc7 is currently enabled */ 44*c872e7aeSDavid Mosberger-Tang bool crc16_enabled; /* true if crc16 is currently enabled */ 455625f965SAjay Singh }; 465625f965SAjay Singh 475625f965SAjay Singh static const struct wilc_hif_func wilc_hif_spi; 485625f965SAjay Singh 495625f965SAjay Singh /******************************************** 505625f965SAjay Singh * 515625f965SAjay Singh * Spi protocol Function 525625f965SAjay Singh * 535625f965SAjay Singh ********************************************/ 545625f965SAjay Singh 555625f965SAjay Singh #define CMD_DMA_WRITE 0xc1 565625f965SAjay Singh #define CMD_DMA_READ 0xc2 575625f965SAjay Singh #define CMD_INTERNAL_WRITE 0xc3 585625f965SAjay Singh #define CMD_INTERNAL_READ 0xc4 595625f965SAjay Singh #define CMD_TERMINATE 0xc5 605625f965SAjay Singh #define CMD_REPEAT 0xc6 615625f965SAjay Singh #define CMD_DMA_EXT_WRITE 0xc7 625625f965SAjay Singh #define CMD_DMA_EXT_READ 0xc8 635625f965SAjay Singh #define CMD_SINGLE_WRITE 0xc9 645625f965SAjay Singh #define CMD_SINGLE_READ 0xca 655625f965SAjay Singh #define CMD_RESET 0xcf 665625f965SAjay Singh 67382726d1SAjay Singh #define SPI_ENABLE_VMM_RETRY_LIMIT 2 685ee2d9ddSDavid Mosberger-Tang 69ce3b9338SDavid Mosberger-Tang /* SPI response fields (section 11.1.2 in ATWILC1000 User Guide): */ 70ce3b9338SDavid Mosberger-Tang #define RSP_START_FIELD GENMASK(7, 4) 71ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_FIELD GENMASK(3, 0) 72ce3b9338SDavid Mosberger-Tang 73ce3b9338SDavid Mosberger-Tang /* SPI response values for the response fields: */ 74ce3b9338SDavid Mosberger-Tang #define RSP_START_TAG 0xc 75ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_FIRST_PACKET 0x1 76ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_INNER_PACKET 0x2 77ce3b9338SDavid Mosberger-Tang #define RSP_TYPE_LAST_PACKET 0x3 78ce3b9338SDavid Mosberger-Tang #define RSP_STATE_NO_ERROR 0x00 79ce3b9338SDavid Mosberger-Tang 805ee2d9ddSDavid Mosberger-Tang #define PROTOCOL_REG_PKT_SZ_MASK GENMASK(6, 4) 815ee2d9ddSDavid Mosberger-Tang #define PROTOCOL_REG_CRC16_MASK GENMASK(3, 3) 825ee2d9ddSDavid Mosberger-Tang #define PROTOCOL_REG_CRC7_MASK GENMASK(2, 2) 835ee2d9ddSDavid Mosberger-Tang 845ee2d9ddSDavid Mosberger-Tang /* 855ee2d9ddSDavid Mosberger-Tang * The SPI data packet size may be any integer power of two in the 865ee2d9ddSDavid Mosberger-Tang * range from 256 to 8192 bytes. 875ee2d9ddSDavid Mosberger-Tang */ 885ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_LOG_SZ_MIN 8 /* 256 B */ 895ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_LOG_SZ_MAX 13 /* 8 KiB */ 905ee2d9ddSDavid Mosberger-Tang 915ee2d9ddSDavid Mosberger-Tang /* 925ee2d9ddSDavid Mosberger-Tang * Select the data packet size (log2 of number of bytes): Use the 935ee2d9ddSDavid Mosberger-Tang * maximum data packet size. We only retransmit complete packets, so 945ee2d9ddSDavid Mosberger-Tang * there is no benefit from using smaller data packets. 955ee2d9ddSDavid Mosberger-Tang */ 965ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_LOG_SZ DATA_PKT_LOG_SZ_MAX 975ee2d9ddSDavid Mosberger-Tang #define DATA_PKT_SZ (1 << DATA_PKT_LOG_SZ) 985625f965SAjay Singh 995625f965SAjay Singh #define USE_SPI_DMA 0 1005625f965SAjay Singh 1015625f965SAjay Singh #define WILC_SPI_COMMAND_STAT_SUCCESS 0 1025625f965SAjay Singh #define WILC_GET_RESP_HDR_START(h) (((h) >> 4) & 0xf) 1035625f965SAjay Singh 1045625f965SAjay Singh struct wilc_spi_cmd { 1055625f965SAjay Singh u8 cmd_type; 1065625f965SAjay Singh union { 1075625f965SAjay Singh struct { 1085625f965SAjay Singh u8 addr[3]; 1095625f965SAjay Singh u8 crc[]; 1105625f965SAjay Singh } __packed simple_cmd; 1115625f965SAjay Singh struct { 1125625f965SAjay Singh u8 addr[3]; 1135625f965SAjay Singh u8 size[2]; 1145625f965SAjay Singh u8 crc[]; 1155625f965SAjay Singh } __packed dma_cmd; 1165625f965SAjay Singh struct { 1175625f965SAjay Singh u8 addr[3]; 1185625f965SAjay Singh u8 size[3]; 1195625f965SAjay Singh u8 crc[]; 1205625f965SAjay Singh } __packed dma_cmd_ext; 1215625f965SAjay Singh struct { 1225625f965SAjay Singh u8 addr[2]; 1235625f965SAjay Singh __be32 data; 1245625f965SAjay Singh u8 crc[]; 1255625f965SAjay Singh } __packed internal_w_cmd; 1265625f965SAjay Singh struct { 1275625f965SAjay Singh u8 addr[3]; 1285625f965SAjay Singh __be32 data; 1295625f965SAjay Singh u8 crc[]; 1305625f965SAjay Singh } __packed w_cmd; 1315625f965SAjay Singh } u; 1325625f965SAjay Singh } __packed; 1335625f965SAjay Singh 1345625f965SAjay Singh struct wilc_spi_read_rsp_data { 135f2131fa5SDavid Mosberger-Tang u8 header; 136f2131fa5SDavid Mosberger-Tang u8 data[4]; 1375625f965SAjay Singh u8 crc[]; 1385625f965SAjay Singh } __packed; 1395625f965SAjay Singh 1405625f965SAjay Singh struct wilc_spi_rsp_data { 1415625f965SAjay Singh u8 rsp_cmd_type; 1425625f965SAjay Singh u8 status; 143f2131fa5SDavid Mosberger-Tang u8 data[]; 1445625f965SAjay Singh } __packed; 1455625f965SAjay Singh 1465625f965SAjay Singh static int wilc_bus_probe(struct spi_device *spi) 1475625f965SAjay Singh { 1485625f965SAjay Singh int ret; 1495625f965SAjay Singh struct wilc *wilc; 1505625f965SAjay Singh struct wilc_spi *spi_priv; 1515625f965SAjay Singh 1525625f965SAjay Singh spi_priv = kzalloc(sizeof(*spi_priv), GFP_KERNEL); 1535625f965SAjay Singh if (!spi_priv) 1545625f965SAjay Singh return -ENOMEM; 1555625f965SAjay Singh 1565625f965SAjay Singh ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi); 1575625f965SAjay Singh if (ret) { 1585625f965SAjay Singh kfree(spi_priv); 1595625f965SAjay Singh return ret; 1605625f965SAjay Singh } 1615625f965SAjay Singh 1625625f965SAjay Singh spi_set_drvdata(spi, wilc); 1635625f965SAjay Singh wilc->dev = &spi->dev; 1645625f965SAjay Singh wilc->bus_data = spi_priv; 1655625f965SAjay Singh wilc->dev_irq_num = spi->irq; 1665625f965SAjay Singh 1675625f965SAjay Singh wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc_clk"); 168d8eb176dSDinghao Liu if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER) { 169d8eb176dSDinghao Liu kfree(spi_priv); 1705625f965SAjay Singh return -EPROBE_DEFER; 171d8eb176dSDinghao Liu } else if (!IS_ERR(wilc->rtc_clk)) 1725625f965SAjay Singh clk_prepare_enable(wilc->rtc_clk); 1735625f965SAjay Singh 1745625f965SAjay Singh return 0; 1755625f965SAjay Singh } 1765625f965SAjay Singh 1775625f965SAjay Singh static int wilc_bus_remove(struct spi_device *spi) 1785625f965SAjay Singh { 1795625f965SAjay Singh struct wilc *wilc = spi_get_drvdata(spi); 1805625f965SAjay Singh 1815625f965SAjay Singh if (!IS_ERR(wilc->rtc_clk)) 1825625f965SAjay Singh clk_disable_unprepare(wilc->rtc_clk); 1835625f965SAjay Singh 1845625f965SAjay Singh wilc_netdev_cleanup(wilc); 1855625f965SAjay Singh return 0; 1865625f965SAjay Singh } 1875625f965SAjay Singh 1885625f965SAjay Singh static const struct of_device_id wilc_of_match[] = { 1895625f965SAjay Singh { .compatible = "microchip,wilc1000", }, 1905625f965SAjay Singh { /* sentinel */ } 1915625f965SAjay Singh }; 1925625f965SAjay Singh MODULE_DEVICE_TABLE(of, wilc_of_match); 1935625f965SAjay Singh 1945625f965SAjay Singh static struct spi_driver wilc_spi_driver = { 1955625f965SAjay Singh .driver = { 1965625f965SAjay Singh .name = MODALIAS, 1975625f965SAjay Singh .of_match_table = wilc_of_match, 1985625f965SAjay Singh }, 1995625f965SAjay Singh .probe = wilc_bus_probe, 2005625f965SAjay Singh .remove = wilc_bus_remove, 2015625f965SAjay Singh }; 2025625f965SAjay Singh module_spi_driver(wilc_spi_driver); 2035625f965SAjay Singh MODULE_LICENSE("GPL"); 2045625f965SAjay Singh 2055625f965SAjay Singh static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len) 2065625f965SAjay Singh { 2075625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 2085625f965SAjay Singh int ret; 2095625f965SAjay Singh struct spi_message msg; 2105625f965SAjay Singh 2115625f965SAjay Singh if (len > 0 && b) { 2125625f965SAjay Singh struct spi_transfer tr = { 2135625f965SAjay Singh .tx_buf = b, 2145625f965SAjay Singh .len = len, 2155625f965SAjay Singh .delay = { 2165625f965SAjay Singh .value = 0, 2175625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 2185625f965SAjay Singh }, 2195625f965SAjay Singh }; 2205625f965SAjay Singh char *r_buffer = kzalloc(len, GFP_KERNEL); 2215625f965SAjay Singh 2225625f965SAjay Singh if (!r_buffer) 2235625f965SAjay Singh return -ENOMEM; 2245625f965SAjay Singh 2255625f965SAjay Singh tr.rx_buf = r_buffer; 2265625f965SAjay Singh dev_dbg(&spi->dev, "Request writing %d bytes\n", len); 2275625f965SAjay Singh 2285625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 2295625f965SAjay Singh spi_message_init(&msg); 2305625f965SAjay Singh msg.spi = spi; 2315625f965SAjay Singh msg.is_dma_mapped = USE_SPI_DMA; 2325625f965SAjay Singh spi_message_add_tail(&tr, &msg); 2335625f965SAjay Singh 2345625f965SAjay Singh ret = spi_sync(spi, &msg); 2355625f965SAjay Singh if (ret < 0) 2365625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 2375625f965SAjay Singh 2385625f965SAjay Singh kfree(r_buffer); 2395625f965SAjay Singh } else { 2405625f965SAjay Singh dev_err(&spi->dev, 2415625f965SAjay Singh "can't write data with the following length: %d\n", 2425625f965SAjay Singh len); 2435625f965SAjay Singh ret = -EINVAL; 2445625f965SAjay Singh } 2455625f965SAjay Singh 2465625f965SAjay Singh return ret; 2475625f965SAjay Singh } 2485625f965SAjay Singh 2495625f965SAjay Singh static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen) 2505625f965SAjay Singh { 2515625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 2525625f965SAjay Singh int ret; 2535625f965SAjay Singh 2545625f965SAjay Singh if (rlen > 0) { 2555625f965SAjay Singh struct spi_message msg; 2565625f965SAjay Singh struct spi_transfer tr = { 2575625f965SAjay Singh .rx_buf = rb, 2585625f965SAjay Singh .len = rlen, 2595625f965SAjay Singh .delay = { 2605625f965SAjay Singh .value = 0, 2615625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 2625625f965SAjay Singh }, 2635625f965SAjay Singh 2645625f965SAjay Singh }; 2655625f965SAjay Singh char *t_buffer = kzalloc(rlen, GFP_KERNEL); 2665625f965SAjay Singh 2675625f965SAjay Singh if (!t_buffer) 2685625f965SAjay Singh return -ENOMEM; 2695625f965SAjay Singh 2705625f965SAjay Singh tr.tx_buf = t_buffer; 2715625f965SAjay Singh 2725625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 2735625f965SAjay Singh spi_message_init(&msg); 2745625f965SAjay Singh msg.spi = spi; 2755625f965SAjay Singh msg.is_dma_mapped = USE_SPI_DMA; 2765625f965SAjay Singh spi_message_add_tail(&tr, &msg); 2775625f965SAjay Singh 2785625f965SAjay Singh ret = spi_sync(spi, &msg); 2795625f965SAjay Singh if (ret < 0) 2805625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 2815625f965SAjay Singh kfree(t_buffer); 2825625f965SAjay Singh } else { 2835625f965SAjay Singh dev_err(&spi->dev, 2845625f965SAjay Singh "can't read data with the following length: %u\n", 2855625f965SAjay Singh rlen); 2865625f965SAjay Singh ret = -EINVAL; 2875625f965SAjay Singh } 2885625f965SAjay Singh 2895625f965SAjay Singh return ret; 2905625f965SAjay Singh } 2915625f965SAjay Singh 2925625f965SAjay Singh static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen) 2935625f965SAjay Singh { 2945625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 2955625f965SAjay Singh int ret; 2965625f965SAjay Singh 2975625f965SAjay Singh if (rlen > 0) { 2985625f965SAjay Singh struct spi_message msg; 2995625f965SAjay Singh struct spi_transfer tr = { 3005625f965SAjay Singh .rx_buf = rb, 3015625f965SAjay Singh .tx_buf = wb, 3025625f965SAjay Singh .len = rlen, 3035625f965SAjay Singh .bits_per_word = 8, 3045625f965SAjay Singh .delay = { 3055625f965SAjay Singh .value = 0, 3065625f965SAjay Singh .unit = SPI_DELAY_UNIT_USECS 3075625f965SAjay Singh }, 3085625f965SAjay Singh 3095625f965SAjay Singh }; 3105625f965SAjay Singh 3115625f965SAjay Singh memset(&msg, 0, sizeof(msg)); 3125625f965SAjay Singh spi_message_init(&msg); 3135625f965SAjay Singh msg.spi = spi; 3145625f965SAjay Singh msg.is_dma_mapped = USE_SPI_DMA; 3155625f965SAjay Singh 3165625f965SAjay Singh spi_message_add_tail(&tr, &msg); 3175625f965SAjay Singh ret = spi_sync(spi, &msg); 3185625f965SAjay Singh if (ret < 0) 3195625f965SAjay Singh dev_err(&spi->dev, "SPI transaction failed\n"); 3205625f965SAjay Singh } else { 3215625f965SAjay Singh dev_err(&spi->dev, 3225625f965SAjay Singh "can't read data with the following length: %u\n", 3235625f965SAjay Singh rlen); 3245625f965SAjay Singh ret = -EINVAL; 3255625f965SAjay Singh } 3265625f965SAjay Singh 3275625f965SAjay Singh return ret; 3285625f965SAjay Singh } 3295625f965SAjay Singh 3305625f965SAjay Singh static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) 3315625f965SAjay Singh { 3325625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 3335625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 3345625f965SAjay Singh int ix, nbytes; 3355625f965SAjay Singh int result = 0; 336*c872e7aeSDavid Mosberger-Tang u8 cmd, order, crc[2]; 337*c872e7aeSDavid Mosberger-Tang u16 crc_calc; 3385625f965SAjay Singh 3395625f965SAjay Singh /* 3405625f965SAjay Singh * Data 3415625f965SAjay Singh */ 3425625f965SAjay Singh ix = 0; 3435625f965SAjay Singh do { 3445625f965SAjay Singh if (sz <= DATA_PKT_SZ) { 3455625f965SAjay Singh nbytes = sz; 3465625f965SAjay Singh order = 0x3; 3475625f965SAjay Singh } else { 3485625f965SAjay Singh nbytes = DATA_PKT_SZ; 3495625f965SAjay Singh if (ix == 0) 3505625f965SAjay Singh order = 0x1; 3515625f965SAjay Singh else 3525625f965SAjay Singh order = 0x02; 3535625f965SAjay Singh } 3545625f965SAjay Singh 3555625f965SAjay Singh /* 3565625f965SAjay Singh * Write command 3575625f965SAjay Singh */ 3585625f965SAjay Singh cmd = 0xf0; 3595625f965SAjay Singh cmd |= order; 3605625f965SAjay Singh 3615625f965SAjay Singh if (wilc_spi_tx(wilc, &cmd, 1)) { 3625625f965SAjay Singh dev_err(&spi->dev, 3635625f965SAjay Singh "Failed data block cmd write, bus error...\n"); 3645625f965SAjay Singh result = -EINVAL; 3655625f965SAjay Singh break; 3665625f965SAjay Singh } 3675625f965SAjay Singh 3685625f965SAjay Singh /* 3695625f965SAjay Singh * Write data 3705625f965SAjay Singh */ 3715625f965SAjay Singh if (wilc_spi_tx(wilc, &b[ix], nbytes)) { 3725625f965SAjay Singh dev_err(&spi->dev, 3735625f965SAjay Singh "Failed data block write, bus error...\n"); 3745625f965SAjay Singh result = -EINVAL; 3755625f965SAjay Singh break; 3765625f965SAjay Singh } 3775625f965SAjay Singh 3785625f965SAjay Singh /* 379*c872e7aeSDavid Mosberger-Tang * Write CRC 3805625f965SAjay Singh */ 381*c872e7aeSDavid Mosberger-Tang if (spi_priv->crc16_enabled) { 382*c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, &b[ix], nbytes); 383*c872e7aeSDavid Mosberger-Tang crc[0] = crc_calc >> 8; 384*c872e7aeSDavid Mosberger-Tang crc[1] = crc_calc; 3855625f965SAjay Singh if (wilc_spi_tx(wilc, crc, 2)) { 3865625f965SAjay Singh dev_err(&spi->dev, "Failed data block crc write, bus error...\n"); 3875625f965SAjay Singh result = -EINVAL; 3885625f965SAjay Singh break; 3895625f965SAjay Singh } 3905625f965SAjay Singh } 3915625f965SAjay Singh 3925625f965SAjay Singh /* 3935625f965SAjay Singh * No need to wait for response 3945625f965SAjay Singh */ 3955625f965SAjay Singh ix += nbytes; 3965625f965SAjay Singh sz -= nbytes; 3975625f965SAjay Singh } while (sz); 3985625f965SAjay Singh 3995625f965SAjay Singh return result; 4005625f965SAjay Singh } 4015625f965SAjay Singh 4025625f965SAjay Singh /******************************************** 4035625f965SAjay Singh * 4045625f965SAjay Singh * Spi Internal Read/Write Function 4055625f965SAjay Singh * 4065625f965SAjay Singh ********************************************/ 4075625f965SAjay Singh static u8 wilc_get_crc7(u8 *buffer, u32 len) 4085625f965SAjay Singh { 4095625f965SAjay Singh return crc7_be(0xfe, buffer, len); 4105625f965SAjay Singh } 4115625f965SAjay Singh 4125625f965SAjay Singh static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, 4135625f965SAjay Singh u8 clockless) 4145625f965SAjay Singh { 4155625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 4165625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 4175625f965SAjay Singh u8 wb[32], rb[32]; 418f2131fa5SDavid Mosberger-Tang int cmd_len, resp_len, i; 419*c872e7aeSDavid Mosberger-Tang u16 crc_calc, crc_recv; 4205625f965SAjay Singh struct wilc_spi_cmd *c; 421f2131fa5SDavid Mosberger-Tang struct wilc_spi_rsp_data *r; 422*c872e7aeSDavid Mosberger-Tang struct wilc_spi_read_rsp_data *r_data; 4235625f965SAjay Singh 4245625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 4255625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 4265625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 4275625f965SAjay Singh c->cmd_type = cmd; 4285625f965SAjay Singh if (cmd == CMD_SINGLE_READ) { 4295625f965SAjay Singh c->u.simple_cmd.addr[0] = adr >> 16; 4305625f965SAjay Singh c->u.simple_cmd.addr[1] = adr >> 8; 4315625f965SAjay Singh c->u.simple_cmd.addr[2] = adr; 4325625f965SAjay Singh } else if (cmd == CMD_INTERNAL_READ) { 4335625f965SAjay Singh c->u.simple_cmd.addr[0] = adr >> 8; 4345625f965SAjay Singh if (clockless == 1) 4355625f965SAjay Singh c->u.simple_cmd.addr[0] |= BIT(7); 4365625f965SAjay Singh c->u.simple_cmd.addr[1] = adr; 4375625f965SAjay Singh c->u.simple_cmd.addr[2] = 0x0; 4385625f965SAjay Singh } else { 4395625f965SAjay Singh dev_err(&spi->dev, "cmd [%x] not supported\n", cmd); 4405625f965SAjay Singh return -EINVAL; 4415625f965SAjay Singh } 4425625f965SAjay Singh 4435625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc); 444f2131fa5SDavid Mosberger-Tang resp_len = sizeof(*r) + sizeof(*r_data) + WILC_SPI_RSP_HDR_EXTRA_DATA; 445f2131fa5SDavid Mosberger-Tang 446*c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) { 4475625f965SAjay Singh c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 4485625f965SAjay Singh cmd_len += 1; 4495625f965SAjay Singh resp_len += 2; 4505625f965SAjay Singh } 4515625f965SAjay Singh 4525625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 4535625f965SAjay Singh dev_err(&spi->dev, 4545625f965SAjay Singh "spi buffer size too small (%d) (%d) (%zu)\n", 4555625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 4565625f965SAjay Singh return -EINVAL; 4575625f965SAjay Singh } 4585625f965SAjay Singh 4595625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 4605625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 4615625f965SAjay Singh return -EINVAL; 4625625f965SAjay Singh } 4635625f965SAjay Singh 464f2131fa5SDavid Mosberger-Tang r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 4655625f965SAjay Singh if (r->rsp_cmd_type != cmd) { 466*c872e7aeSDavid Mosberger-Tang if (!spi_priv->probing_crc) 4675625f965SAjay Singh dev_err(&spi->dev, 468*c872e7aeSDavid Mosberger-Tang "Failed cmd, cmd (%02x), resp (%02x)\n", 4695625f965SAjay Singh cmd, r->rsp_cmd_type); 4705625f965SAjay Singh return -EINVAL; 4715625f965SAjay Singh } 4725625f965SAjay Singh 4735625f965SAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { 4745625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 4755625f965SAjay Singh r->status); 4765625f965SAjay Singh return -EINVAL; 4775625f965SAjay Singh } 4785625f965SAjay Singh 479f2131fa5SDavid Mosberger-Tang for (i = 0; i < WILC_SPI_RSP_HDR_EXTRA_DATA; ++i) 480f2131fa5SDavid Mosberger-Tang if (WILC_GET_RESP_HDR_START(r->data[i]) == 0xf) 481f2131fa5SDavid Mosberger-Tang break; 482f2131fa5SDavid Mosberger-Tang 483f2131fa5SDavid Mosberger-Tang if (i >= WILC_SPI_RSP_HDR_EXTRA_DATA) { 484f2131fa5SDavid Mosberger-Tang dev_err(&spi->dev, "Error, data start missing\n"); 4855625f965SAjay Singh return -EINVAL; 4865625f965SAjay Singh } 4875625f965SAjay Singh 488f2131fa5SDavid Mosberger-Tang r_data = (struct wilc_spi_read_rsp_data *)&r->data[i]; 489f2131fa5SDavid Mosberger-Tang 4905625f965SAjay Singh if (b) 491f2131fa5SDavid Mosberger-Tang memcpy(b, r_data->data, 4); 4925625f965SAjay Singh 493*c872e7aeSDavid Mosberger-Tang if (!clockless && spi_priv->crc16_enabled) { 494*c872e7aeSDavid Mosberger-Tang crc_recv = (r_data->crc[0] << 8) | r_data->crc[1]; 495*c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, r_data->data, 4); 496*c872e7aeSDavid Mosberger-Tang if (crc_recv != crc_calc) { 497*c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "%s: bad CRC 0x%04x " 498*c872e7aeSDavid Mosberger-Tang "(calculated 0x%04x)\n", __func__, 499*c872e7aeSDavid Mosberger-Tang crc_recv, crc_calc); 500*c872e7aeSDavid Mosberger-Tang return -EINVAL; 501*c872e7aeSDavid Mosberger-Tang } 502*c872e7aeSDavid Mosberger-Tang } 5035625f965SAjay Singh 5045625f965SAjay Singh return 0; 5055625f965SAjay Singh } 5065625f965SAjay Singh 5075625f965SAjay Singh static int wilc_spi_write_cmd(struct wilc *wilc, u8 cmd, u32 adr, u32 data, 5085625f965SAjay Singh u8 clockless) 5095625f965SAjay Singh { 5105625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 5115625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 5125625f965SAjay Singh u8 wb[32], rb[32]; 5135625f965SAjay Singh int cmd_len, resp_len; 5145625f965SAjay Singh struct wilc_spi_cmd *c; 5155625f965SAjay Singh struct wilc_spi_rsp_data *r; 5165625f965SAjay Singh 5175625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 5185625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 5195625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 5205625f965SAjay Singh c->cmd_type = cmd; 5215625f965SAjay Singh if (cmd == CMD_INTERNAL_WRITE) { 5225625f965SAjay Singh c->u.internal_w_cmd.addr[0] = adr >> 8; 5235625f965SAjay Singh if (clockless == 1) 5245625f965SAjay Singh c->u.internal_w_cmd.addr[0] |= BIT(7); 5255625f965SAjay Singh 5265625f965SAjay Singh c->u.internal_w_cmd.addr[1] = adr; 5275625f965SAjay Singh c->u.internal_w_cmd.data = cpu_to_be32(data); 5285625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.internal_w_cmd.crc); 529*c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 5305625f965SAjay Singh c->u.internal_w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 5315625f965SAjay Singh } else if (cmd == CMD_SINGLE_WRITE) { 5325625f965SAjay Singh c->u.w_cmd.addr[0] = adr >> 16; 5335625f965SAjay Singh c->u.w_cmd.addr[1] = adr >> 8; 5345625f965SAjay Singh c->u.w_cmd.addr[2] = adr; 5355625f965SAjay Singh c->u.w_cmd.data = cpu_to_be32(data); 5365625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.w_cmd.crc); 537*c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 5385625f965SAjay Singh c->u.w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 5395625f965SAjay Singh } else { 5405625f965SAjay Singh dev_err(&spi->dev, "write cmd [%x] not supported\n", cmd); 5415625f965SAjay Singh return -EINVAL; 5425625f965SAjay Singh } 5435625f965SAjay Singh 544*c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 5455625f965SAjay Singh cmd_len += 1; 5465625f965SAjay Singh 5475625f965SAjay Singh resp_len = sizeof(*r); 5485625f965SAjay Singh 5495625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 5505625f965SAjay Singh dev_err(&spi->dev, 5515625f965SAjay Singh "spi buffer size too small (%d) (%d) (%zu)\n", 5525625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 5535625f965SAjay Singh return -EINVAL; 5545625f965SAjay Singh } 5555625f965SAjay Singh 5565625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 5575625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 5585625f965SAjay Singh return -EINVAL; 5595625f965SAjay Singh } 5605625f965SAjay Singh 5615625f965SAjay Singh r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 5625625f965SAjay Singh if (r->rsp_cmd_type != cmd) { 5635625f965SAjay Singh dev_err(&spi->dev, 5645625f965SAjay Singh "Failed cmd response, cmd (%02x), resp (%02x)\n", 5655625f965SAjay Singh cmd, r->rsp_cmd_type); 5665625f965SAjay Singh return -EINVAL; 5675625f965SAjay Singh } 5685625f965SAjay Singh 5695625f965SAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { 5705625f965SAjay Singh dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", 5715625f965SAjay Singh r->status); 5725625f965SAjay Singh return -EINVAL; 5735625f965SAjay Singh } 5745625f965SAjay Singh 5755625f965SAjay Singh return 0; 5765625f965SAjay Singh } 5775625f965SAjay Singh 5785625f965SAjay Singh static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz) 5795625f965SAjay Singh { 5805625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 5815625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 582*c872e7aeSDavid Mosberger-Tang u16 crc_recv, crc_calc; 5835625f965SAjay Singh u8 wb[32], rb[32]; 5845625f965SAjay Singh int cmd_len, resp_len; 5855625f965SAjay Singh int retry, ix = 0; 5865625f965SAjay Singh u8 crc[2]; 5875625f965SAjay Singh struct wilc_spi_cmd *c; 5885625f965SAjay Singh struct wilc_spi_rsp_data *r; 5895625f965SAjay Singh 5905625f965SAjay Singh memset(wb, 0x0, sizeof(wb)); 5915625f965SAjay Singh memset(rb, 0x0, sizeof(rb)); 5925625f965SAjay Singh c = (struct wilc_spi_cmd *)wb; 5935625f965SAjay Singh c->cmd_type = cmd; 5945625f965SAjay Singh if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_READ) { 5955625f965SAjay Singh c->u.dma_cmd.addr[0] = adr >> 16; 5965625f965SAjay Singh c->u.dma_cmd.addr[1] = adr >> 8; 5975625f965SAjay Singh c->u.dma_cmd.addr[2] = adr; 5985625f965SAjay Singh c->u.dma_cmd.size[0] = sz >> 8; 5995625f965SAjay Singh c->u.dma_cmd.size[1] = sz; 6005625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd.crc); 601*c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6025625f965SAjay Singh c->u.dma_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); 6035625f965SAjay Singh } else if (cmd == CMD_DMA_EXT_WRITE || cmd == CMD_DMA_EXT_READ) { 6045625f965SAjay Singh c->u.dma_cmd_ext.addr[0] = adr >> 16; 6055625f965SAjay Singh c->u.dma_cmd_ext.addr[1] = adr >> 8; 6065625f965SAjay Singh c->u.dma_cmd_ext.addr[2] = adr; 6075625f965SAjay Singh c->u.dma_cmd_ext.size[0] = sz >> 16; 6085625f965SAjay Singh c->u.dma_cmd_ext.size[1] = sz >> 8; 6095625f965SAjay Singh c->u.dma_cmd_ext.size[2] = sz; 6105625f965SAjay Singh cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd_ext.crc); 611*c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6125625f965SAjay Singh c->u.dma_cmd_ext.crc[0] = wilc_get_crc7(wb, cmd_len); 6135625f965SAjay Singh } else { 6145625f965SAjay Singh dev_err(&spi->dev, "dma read write cmd [%x] not supported\n", 6155625f965SAjay Singh cmd); 6165625f965SAjay Singh return -EINVAL; 6175625f965SAjay Singh } 618*c872e7aeSDavid Mosberger-Tang if (spi_priv->crc7_enabled) 6195625f965SAjay Singh cmd_len += 1; 6205625f965SAjay Singh 6215625f965SAjay Singh resp_len = sizeof(*r); 6225625f965SAjay Singh 6235625f965SAjay Singh if (cmd_len + resp_len > ARRAY_SIZE(wb)) { 6245625f965SAjay Singh dev_err(&spi->dev, "spi buffer size too small (%d)(%d) (%zu)\n", 6255625f965SAjay Singh cmd_len, resp_len, ARRAY_SIZE(wb)); 6265625f965SAjay Singh return -EINVAL; 6275625f965SAjay Singh } 6285625f965SAjay Singh 6295625f965SAjay Singh if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { 6305625f965SAjay Singh dev_err(&spi->dev, "Failed cmd write, bus error...\n"); 6315625f965SAjay Singh return -EINVAL; 6325625f965SAjay Singh } 6335625f965SAjay Singh 6345625f965SAjay Singh r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; 6355625f965SAjay Singh if (r->rsp_cmd_type != cmd) { 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 6425625f965SAjay Singh if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { 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 if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_EXT_WRITE) 6495625f965SAjay Singh return 0; 6505625f965SAjay Singh 6515625f965SAjay Singh while (sz > 0) { 6525625f965SAjay Singh int nbytes; 6535625f965SAjay Singh u8 rsp; 6545625f965SAjay Singh 6555625f965SAjay Singh if (sz <= DATA_PKT_SZ) 6565625f965SAjay Singh nbytes = sz; 6575625f965SAjay Singh else 6585625f965SAjay Singh nbytes = DATA_PKT_SZ; 6595625f965SAjay Singh 6605625f965SAjay Singh /* 6615625f965SAjay Singh * Data Response header 6625625f965SAjay Singh */ 6635625f965SAjay Singh retry = 100; 6645625f965SAjay Singh do { 6655625f965SAjay Singh if (wilc_spi_rx(wilc, &rsp, 1)) { 6665625f965SAjay Singh dev_err(&spi->dev, 6675625f965SAjay Singh "Failed resp read, bus err\n"); 6685625f965SAjay Singh return -EINVAL; 6695625f965SAjay Singh } 6705625f965SAjay Singh if (WILC_GET_RESP_HDR_START(rsp) == 0xf) 6715625f965SAjay Singh break; 6725625f965SAjay Singh } while (retry--); 6735625f965SAjay Singh 6745625f965SAjay Singh /* 6755625f965SAjay Singh * Read bytes 6765625f965SAjay Singh */ 6775625f965SAjay Singh if (wilc_spi_rx(wilc, &b[ix], nbytes)) { 6785625f965SAjay Singh dev_err(&spi->dev, 6795625f965SAjay Singh "Failed block read, bus err\n"); 6805625f965SAjay Singh return -EINVAL; 6815625f965SAjay Singh } 6825625f965SAjay Singh 6835625f965SAjay Singh /* 684*c872e7aeSDavid Mosberger-Tang * Read CRC 6855625f965SAjay Singh */ 686*c872e7aeSDavid Mosberger-Tang if (spi_priv->crc16_enabled) { 687*c872e7aeSDavid Mosberger-Tang if (wilc_spi_rx(wilc, crc, 2)) { 6885625f965SAjay Singh dev_err(&spi->dev, 689*c872e7aeSDavid Mosberger-Tang "Failed block CRC read, bus err\n"); 6905625f965SAjay Singh return -EINVAL; 6915625f965SAjay Singh } 692*c872e7aeSDavid Mosberger-Tang crc_recv = (crc[0] << 8) | crc[1]; 693*c872e7aeSDavid Mosberger-Tang crc_calc = crc_itu_t(0xffff, &b[ix], nbytes); 694*c872e7aeSDavid Mosberger-Tang if (crc_recv != crc_calc) { 695*c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "%s: bad CRC 0x%04x " 696*c872e7aeSDavid Mosberger-Tang "(calculated 0x%04x)\n", __func__, 697*c872e7aeSDavid Mosberger-Tang crc_recv, crc_calc); 698*c872e7aeSDavid Mosberger-Tang return -EINVAL; 699*c872e7aeSDavid Mosberger-Tang } 700*c872e7aeSDavid Mosberger-Tang } 7015625f965SAjay Singh 7025625f965SAjay Singh ix += nbytes; 7035625f965SAjay Singh sz -= nbytes; 7045625f965SAjay Singh } 7055625f965SAjay Singh return 0; 7065625f965SAjay Singh } 7075625f965SAjay Singh 7085625f965SAjay Singh static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data) 7095625f965SAjay Singh { 7105625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 7115625f965SAjay Singh int result; 7125625f965SAjay Singh u8 cmd = CMD_SINGLE_READ; 7135625f965SAjay Singh u8 clockless = 0; 7145625f965SAjay Singh 7155625f965SAjay Singh if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) { 7165625f965SAjay Singh /* Clockless register */ 7175625f965SAjay Singh cmd = CMD_INTERNAL_READ; 7185625f965SAjay Singh clockless = 1; 7195625f965SAjay Singh } 7205625f965SAjay Singh 7215625f965SAjay Singh result = wilc_spi_single_read(wilc, cmd, addr, data, clockless); 7225625f965SAjay Singh if (result) { 7235625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr); 7245625f965SAjay Singh return result; 7255625f965SAjay Singh } 7265625f965SAjay Singh 7275625f965SAjay Singh le32_to_cpus(data); 7285625f965SAjay Singh 7295625f965SAjay Singh return 0; 7305625f965SAjay Singh } 7315625f965SAjay Singh 7325625f965SAjay Singh static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) 7335625f965SAjay Singh { 7345625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 7355625f965SAjay Singh int result; 7365625f965SAjay Singh 7375625f965SAjay Singh if (size <= 4) 7385625f965SAjay Singh return -EINVAL; 7395625f965SAjay Singh 7405625f965SAjay Singh result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_READ, addr, buf, size); 7415625f965SAjay Singh if (result) { 7425625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr); 7435625f965SAjay Singh return result; 7445625f965SAjay Singh } 7455625f965SAjay Singh 7465625f965SAjay Singh return 0; 7475625f965SAjay Singh } 7485625f965SAjay Singh 7495625f965SAjay Singh static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat) 7505625f965SAjay Singh { 7515625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 7525625f965SAjay Singh int result; 7535625f965SAjay Singh 7545625f965SAjay Singh result = wilc_spi_write_cmd(wilc, CMD_INTERNAL_WRITE, adr, dat, 0); 7555625f965SAjay Singh if (result) { 7565625f965SAjay Singh dev_err(&spi->dev, "Failed internal write cmd...\n"); 7575625f965SAjay Singh return result; 7585625f965SAjay Singh } 7595625f965SAjay Singh 7605625f965SAjay Singh return 0; 7615625f965SAjay Singh } 7625625f965SAjay Singh 7635625f965SAjay Singh static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data) 7645625f965SAjay Singh { 7655625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 766*c872e7aeSDavid Mosberger-Tang struct wilc_spi *spi_priv = wilc->bus_data; 7675625f965SAjay Singh int result; 7685625f965SAjay Singh 7695625f965SAjay Singh result = wilc_spi_single_read(wilc, CMD_INTERNAL_READ, adr, data, 0); 7705625f965SAjay Singh if (result) { 771*c872e7aeSDavid Mosberger-Tang if (!spi_priv->probing_crc) 7725625f965SAjay Singh dev_err(&spi->dev, "Failed internal read cmd...\n"); 7735625f965SAjay Singh return result; 7745625f965SAjay Singh } 7755625f965SAjay Singh 7765625f965SAjay Singh le32_to_cpus(data); 7775625f965SAjay Singh 7785625f965SAjay Singh return 0; 7795625f965SAjay Singh } 7805625f965SAjay Singh 7815625f965SAjay Singh /******************************************** 7825625f965SAjay Singh * 7835625f965SAjay Singh * Spi interfaces 7845625f965SAjay Singh * 7855625f965SAjay Singh ********************************************/ 7865625f965SAjay Singh 7875625f965SAjay Singh static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data) 7885625f965SAjay Singh { 7895625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 7905625f965SAjay Singh int result; 7915625f965SAjay Singh u8 cmd = CMD_SINGLE_WRITE; 7925625f965SAjay Singh u8 clockless = 0; 7935625f965SAjay Singh 7945625f965SAjay Singh if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) { 7955625f965SAjay Singh /* Clockless register */ 7965625f965SAjay Singh cmd = CMD_INTERNAL_WRITE; 7975625f965SAjay Singh clockless = 1; 7985625f965SAjay Singh } 7995625f965SAjay Singh 8005625f965SAjay Singh result = wilc_spi_write_cmd(wilc, cmd, addr, data, clockless); 8015625f965SAjay Singh if (result) { 8025625f965SAjay Singh dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr); 8035625f965SAjay Singh return result; 8045625f965SAjay Singh } 8055625f965SAjay Singh 8065625f965SAjay Singh return 0; 8075625f965SAjay Singh } 8085625f965SAjay Singh 809ce3b9338SDavid Mosberger-Tang static int spi_data_rsp(struct wilc *wilc, u8 cmd) 810ce3b9338SDavid Mosberger-Tang { 811ce3b9338SDavid Mosberger-Tang struct spi_device *spi = to_spi_device(wilc->dev); 812ce3b9338SDavid Mosberger-Tang int result, i; 813ce3b9338SDavid Mosberger-Tang u8 rsp[4]; 814ce3b9338SDavid Mosberger-Tang 815ce3b9338SDavid Mosberger-Tang /* 816ce3b9338SDavid Mosberger-Tang * The response to data packets is two bytes long. For 817ce3b9338SDavid Mosberger-Tang * efficiency's sake, wilc_spi_write() wisely ignores the 818ce3b9338SDavid Mosberger-Tang * responses for all packets but the final one. The downside 819ce3b9338SDavid Mosberger-Tang * of that optimization is that when the final data packet is 820ce3b9338SDavid Mosberger-Tang * short, we may receive (part of) the response to the 821ce3b9338SDavid Mosberger-Tang * second-to-last packet before the one for the final packet. 822ce3b9338SDavid Mosberger-Tang * To handle this, we always read 4 bytes and then search for 823ce3b9338SDavid Mosberger-Tang * the last byte that contains the "Response Start" code (0xc 824ce3b9338SDavid Mosberger-Tang * in the top 4 bits). We then know that this byte is the 825ce3b9338SDavid Mosberger-Tang * first response byte of the final data packet. 826ce3b9338SDavid Mosberger-Tang */ 827ce3b9338SDavid Mosberger-Tang result = wilc_spi_rx(wilc, rsp, sizeof(rsp)); 828ce3b9338SDavid Mosberger-Tang if (result) { 829ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, "Failed bus error...\n"); 830ce3b9338SDavid Mosberger-Tang return result; 831ce3b9338SDavid Mosberger-Tang } 832ce3b9338SDavid Mosberger-Tang 833ce3b9338SDavid Mosberger-Tang for (i = sizeof(rsp) - 2; i >= 0; --i) 834ce3b9338SDavid Mosberger-Tang if (FIELD_GET(RSP_START_FIELD, rsp[i]) == RSP_START_TAG) 835ce3b9338SDavid Mosberger-Tang break; 836ce3b9338SDavid Mosberger-Tang 837ce3b9338SDavid Mosberger-Tang if (i < 0) { 838ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, 839ce3b9338SDavid Mosberger-Tang "Data packet response missing (%02x %02x %02x %02x)\n", 840ce3b9338SDavid Mosberger-Tang rsp[0], rsp[1], rsp[2], rsp[3]); 841ce3b9338SDavid Mosberger-Tang return -1; 842ce3b9338SDavid Mosberger-Tang } 843ce3b9338SDavid Mosberger-Tang 844ce3b9338SDavid Mosberger-Tang /* rsp[i] is the last response start byte */ 845ce3b9338SDavid Mosberger-Tang 846ce3b9338SDavid Mosberger-Tang if (FIELD_GET(RSP_TYPE_FIELD, rsp[i]) != RSP_TYPE_LAST_PACKET 847ce3b9338SDavid Mosberger-Tang || rsp[i + 1] != RSP_STATE_NO_ERROR) { 848ce3b9338SDavid Mosberger-Tang dev_err(&spi->dev, "Data response error (%02x %02x)\n", 849ce3b9338SDavid Mosberger-Tang rsp[i], rsp[i + 1]); 850ce3b9338SDavid Mosberger-Tang return -1; 851ce3b9338SDavid Mosberger-Tang } 852ce3b9338SDavid Mosberger-Tang return 0; 853ce3b9338SDavid Mosberger-Tang } 854ce3b9338SDavid Mosberger-Tang 8555625f965SAjay Singh static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) 8565625f965SAjay Singh { 8575625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 8585625f965SAjay Singh int result; 8595625f965SAjay Singh 8605625f965SAjay Singh /* 8615625f965SAjay Singh * has to be greated than 4 8625625f965SAjay Singh */ 8635625f965SAjay Singh if (size <= 4) 8645625f965SAjay Singh return -EINVAL; 8655625f965SAjay Singh 8665625f965SAjay Singh result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size); 8675625f965SAjay Singh if (result) { 8685625f965SAjay Singh dev_err(&spi->dev, 8695625f965SAjay Singh "Failed cmd, write block (%08x)...\n", addr); 8705625f965SAjay Singh return result; 8715625f965SAjay Singh } 8725625f965SAjay Singh 8735625f965SAjay Singh /* 8745625f965SAjay Singh * Data 8755625f965SAjay Singh */ 8765625f965SAjay Singh result = spi_data_write(wilc, buf, size); 8775625f965SAjay Singh if (result) { 8785625f965SAjay Singh dev_err(&spi->dev, "Failed block data write...\n"); 8795625f965SAjay Singh return result; 8805625f965SAjay Singh } 8815625f965SAjay Singh 882ce3b9338SDavid Mosberger-Tang /* 883ce3b9338SDavid Mosberger-Tang * Data response 884ce3b9338SDavid Mosberger-Tang */ 885ce3b9338SDavid Mosberger-Tang return spi_data_rsp(wilc, CMD_DMA_EXT_WRITE); 8865625f965SAjay Singh } 8875625f965SAjay Singh 8885625f965SAjay Singh /******************************************** 8895625f965SAjay Singh * 8905625f965SAjay Singh * Bus interfaces 8915625f965SAjay Singh * 8925625f965SAjay Singh ********************************************/ 8935625f965SAjay Singh 8945625f965SAjay Singh static int wilc_spi_deinit(struct wilc *wilc) 8955625f965SAjay Singh { 8965625f965SAjay Singh /* 8975625f965SAjay Singh * TODO: 8985625f965SAjay Singh */ 8995625f965SAjay Singh return 0; 9005625f965SAjay Singh } 9015625f965SAjay Singh 9025625f965SAjay Singh static int wilc_spi_init(struct wilc *wilc, bool resume) 9035625f965SAjay Singh { 9045625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 9055625f965SAjay Singh struct wilc_spi *spi_priv = wilc->bus_data; 9065625f965SAjay Singh u32 reg; 9075625f965SAjay Singh u32 chipid; 9085625f965SAjay Singh static int isinit; 909*c872e7aeSDavid Mosberger-Tang int ret, i; 9105625f965SAjay Singh 9115625f965SAjay Singh if (isinit) { 9125625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); 9135625f965SAjay Singh if (ret) 9145625f965SAjay Singh dev_err(&spi->dev, "Fail cmd read chip id...\n"); 9155625f965SAjay Singh 9165625f965SAjay Singh return ret; 9175625f965SAjay Singh } 9185625f965SAjay Singh 9195625f965SAjay Singh /* 9205625f965SAjay Singh * configure protocol 9215625f965SAjay Singh */ 9225625f965SAjay Singh 9235625f965SAjay Singh /* 924*c872e7aeSDavid Mosberger-Tang * Infer the CRC settings that are currently in effect. This 925*c872e7aeSDavid Mosberger-Tang * is necessary because we can't be sure that the chip has 926*c872e7aeSDavid Mosberger-Tang * been RESET (e.g, after module unload and reload). 9275625f965SAjay Singh */ 928*c872e7aeSDavid Mosberger-Tang spi_priv->probing_crc = true; 929*c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = enable_crc7; 930*c872e7aeSDavid Mosberger-Tang spi_priv->crc16_enabled = false; /* don't check CRC16 during probing */ 931*c872e7aeSDavid Mosberger-Tang for (i = 0; i < 2; ++i) { 9325625f965SAjay Singh ret = spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); 933*c872e7aeSDavid Mosberger-Tang if (ret == 0) 934*c872e7aeSDavid Mosberger-Tang break; 935*c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = !enable_crc7; 936*c872e7aeSDavid Mosberger-Tang } 9375625f965SAjay Singh if (ret) { 938*c872e7aeSDavid Mosberger-Tang dev_err(&spi->dev, "Failed with CRC7 on and off.\n"); 9395625f965SAjay Singh return ret; 9405625f965SAjay Singh } 9415ee2d9ddSDavid Mosberger-Tang 942*c872e7aeSDavid Mosberger-Tang /* set up the desired CRC configuration: */ 943*c872e7aeSDavid Mosberger-Tang reg &= ~(PROTOCOL_REG_CRC7_MASK | PROTOCOL_REG_CRC16_MASK); 944*c872e7aeSDavid Mosberger-Tang if (enable_crc7) 945*c872e7aeSDavid Mosberger-Tang reg |= PROTOCOL_REG_CRC7_MASK; 946*c872e7aeSDavid Mosberger-Tang if (enable_crc16) 947*c872e7aeSDavid Mosberger-Tang reg |= PROTOCOL_REG_CRC16_MASK; 948*c872e7aeSDavid Mosberger-Tang 949*c872e7aeSDavid Mosberger-Tang /* set up the data packet size: */ 9505ee2d9ddSDavid Mosberger-Tang BUILD_BUG_ON(DATA_PKT_LOG_SZ < DATA_PKT_LOG_SZ_MIN 9515ee2d9ddSDavid Mosberger-Tang || DATA_PKT_LOG_SZ > DATA_PKT_LOG_SZ_MAX); 9525ee2d9ddSDavid Mosberger-Tang reg &= ~PROTOCOL_REG_PKT_SZ_MASK; 9535ee2d9ddSDavid Mosberger-Tang reg |= FIELD_PREP(PROTOCOL_REG_PKT_SZ_MASK, 9545ee2d9ddSDavid Mosberger-Tang DATA_PKT_LOG_SZ - DATA_PKT_LOG_SZ_MIN); 9555ee2d9ddSDavid Mosberger-Tang 956*c872e7aeSDavid Mosberger-Tang /* establish the new setup: */ 9575625f965SAjay Singh ret = spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg); 9585625f965SAjay Singh if (ret) { 9595625f965SAjay Singh dev_err(&spi->dev, 9605625f965SAjay Singh "[wilc spi %d]: Failed internal write reg\n", 9615625f965SAjay Singh __LINE__); 9625625f965SAjay Singh return ret; 9635625f965SAjay Singh } 964*c872e7aeSDavid Mosberger-Tang /* update our state to match new protocol settings: */ 965*c872e7aeSDavid Mosberger-Tang spi_priv->crc7_enabled = enable_crc7; 966*c872e7aeSDavid Mosberger-Tang spi_priv->crc16_enabled = enable_crc16; 967*c872e7aeSDavid Mosberger-Tang 968*c872e7aeSDavid Mosberger-Tang /* re-read to make sure new settings are in effect: */ 969*c872e7aeSDavid Mosberger-Tang spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); 970*c872e7aeSDavid Mosberger-Tang 971*c872e7aeSDavid Mosberger-Tang spi_priv->probing_crc = false; 9725625f965SAjay Singh 9735625f965SAjay Singh /* 9745625f965SAjay Singh * make sure can read back chip id correctly 9755625f965SAjay Singh */ 9765625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); 9775625f965SAjay Singh if (ret) { 9785625f965SAjay Singh dev_err(&spi->dev, "Fail cmd read chip id...\n"); 9795625f965SAjay Singh return ret; 9805625f965SAjay Singh } 9815625f965SAjay Singh 9825625f965SAjay Singh isinit = 1; 9835625f965SAjay Singh 9845625f965SAjay Singh return 0; 9855625f965SAjay Singh } 9865625f965SAjay Singh 9875625f965SAjay Singh static int wilc_spi_read_size(struct wilc *wilc, u32 *size) 9885625f965SAjay Singh { 9895625f965SAjay Singh int ret; 9905625f965SAjay Singh 9915625f965SAjay Singh ret = spi_internal_read(wilc, 9925625f965SAjay Singh WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, size); 9935625f965SAjay Singh *size = FIELD_GET(IRQ_DMA_WD_CNT_MASK, *size); 9945625f965SAjay Singh 9955625f965SAjay Singh return ret; 9965625f965SAjay Singh } 9975625f965SAjay Singh 9985625f965SAjay Singh static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status) 9995625f965SAjay Singh { 10005625f965SAjay Singh return spi_internal_read(wilc, WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, 10015625f965SAjay Singh int_status); 10025625f965SAjay Singh } 10035625f965SAjay Singh 10045625f965SAjay Singh static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val) 10055625f965SAjay Singh { 1006382726d1SAjay Singh int ret; 1007382726d1SAjay Singh int retry = SPI_ENABLE_VMM_RETRY_LIMIT; 1008382726d1SAjay Singh u32 check; 1009382726d1SAjay Singh 1010382726d1SAjay Singh while (retry) { 1011382726d1SAjay Singh ret = spi_internal_write(wilc, 1012382726d1SAjay Singh WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE, 10135625f965SAjay Singh val); 1014382726d1SAjay Singh if (ret) 1015382726d1SAjay Singh break; 1016382726d1SAjay Singh 1017382726d1SAjay Singh ret = spi_internal_read(wilc, 1018382726d1SAjay Singh WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE, 1019382726d1SAjay Singh &check); 1020382726d1SAjay Singh if (ret || ((check & EN_VMM) == (val & EN_VMM))) 1021382726d1SAjay Singh break; 1022382726d1SAjay Singh 1023382726d1SAjay Singh retry--; 1024382726d1SAjay Singh } 1025382726d1SAjay Singh return ret; 10265625f965SAjay Singh } 10275625f965SAjay Singh 10285625f965SAjay Singh static int wilc_spi_sync_ext(struct wilc *wilc, int nint) 10295625f965SAjay Singh { 10305625f965SAjay Singh struct spi_device *spi = to_spi_device(wilc->dev); 10315625f965SAjay Singh u32 reg; 10325625f965SAjay Singh int ret, i; 10335625f965SAjay Singh 10345625f965SAjay Singh if (nint > MAX_NUM_INT) { 10355625f965SAjay Singh dev_err(&spi->dev, "Too many interrupts (%d)...\n", nint); 10365625f965SAjay Singh return -EINVAL; 10375625f965SAjay Singh } 10385625f965SAjay Singh 10395625f965SAjay Singh /* 10405625f965SAjay Singh * interrupt pin mux select 10415625f965SAjay Singh */ 10425625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, ®); 10435625f965SAjay Singh if (ret) { 10445625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 10455625f965SAjay Singh WILC_PIN_MUX_0); 10465625f965SAjay Singh return ret; 10475625f965SAjay Singh } 10485625f965SAjay Singh reg |= BIT(8); 10495625f965SAjay Singh ret = wilc_spi_write_reg(wilc, WILC_PIN_MUX_0, reg); 10505625f965SAjay Singh if (ret) { 10515625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 10525625f965SAjay Singh WILC_PIN_MUX_0); 10535625f965SAjay Singh return ret; 10545625f965SAjay Singh } 10555625f965SAjay Singh 10565625f965SAjay Singh /* 10575625f965SAjay Singh * interrupt enable 10585625f965SAjay Singh */ 10595625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, ®); 10605625f965SAjay Singh if (ret) { 10615625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 10625625f965SAjay Singh WILC_INTR_ENABLE); 10635625f965SAjay Singh return ret; 10645625f965SAjay Singh } 10655625f965SAjay Singh 10665625f965SAjay Singh for (i = 0; (i < 5) && (nint > 0); i++, nint--) 10675625f965SAjay Singh reg |= (BIT((27 + i))); 10685625f965SAjay Singh 10695625f965SAjay Singh ret = wilc_spi_write_reg(wilc, WILC_INTR_ENABLE, reg); 10705625f965SAjay Singh if (ret) { 10715625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 10725625f965SAjay Singh WILC_INTR_ENABLE); 10735625f965SAjay Singh return ret; 10745625f965SAjay Singh } 10755625f965SAjay Singh if (nint) { 10765625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, ®); 10775625f965SAjay Singh if (ret) { 10785625f965SAjay Singh dev_err(&spi->dev, "Failed read reg (%08x)...\n", 10795625f965SAjay Singh WILC_INTR2_ENABLE); 10805625f965SAjay Singh return ret; 10815625f965SAjay Singh } 10825625f965SAjay Singh 10835625f965SAjay Singh for (i = 0; (i < 3) && (nint > 0); i++, nint--) 10845625f965SAjay Singh reg |= BIT(i); 10855625f965SAjay Singh 10865625f965SAjay Singh ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, ®); 10875625f965SAjay Singh if (ret) { 10885625f965SAjay Singh dev_err(&spi->dev, "Failed write reg (%08x)...\n", 10895625f965SAjay Singh WILC_INTR2_ENABLE); 10905625f965SAjay Singh return ret; 10915625f965SAjay Singh } 10925625f965SAjay Singh } 10935625f965SAjay Singh 10945625f965SAjay Singh return 0; 10955625f965SAjay Singh } 10965625f965SAjay Singh 10975625f965SAjay Singh /* Global spi HIF function table */ 10985625f965SAjay Singh static const struct wilc_hif_func wilc_hif_spi = { 10995625f965SAjay Singh .hif_init = wilc_spi_init, 11005625f965SAjay Singh .hif_deinit = wilc_spi_deinit, 11015625f965SAjay Singh .hif_read_reg = wilc_spi_read_reg, 11025625f965SAjay Singh .hif_write_reg = wilc_spi_write_reg, 11035625f965SAjay Singh .hif_block_rx = wilc_spi_read, 11045625f965SAjay Singh .hif_block_tx = wilc_spi_write, 11055625f965SAjay Singh .hif_read_int = wilc_spi_read_int, 11065625f965SAjay Singh .hif_clear_int_ext = wilc_spi_clear_int_ext, 11075625f965SAjay Singh .hif_read_size = wilc_spi_read_size, 11085625f965SAjay Singh .hif_block_tx_ext = wilc_spi_write, 11095625f965SAjay Singh .hif_block_rx_ext = wilc_spi_read, 11105625f965SAjay Singh .hif_sync_ext = wilc_spi_sync_ext, 11115625f965SAjay Singh }; 1112