18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of wl1251 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/irq.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/swab.h> 138c2ecf20Sopenharmony_ci#include <linux/crc7.h> 148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 158c2ecf20Sopenharmony_ci#include <linux/wl12xx.h> 168c2ecf20Sopenharmony_ci#include <linux/gpio.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 198c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "wl1251.h" 228c2ecf20Sopenharmony_ci#include "reg.h" 238c2ecf20Sopenharmony_ci#include "spi.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic irqreturn_t wl1251_irq(int irq, void *cookie) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct wl1251 *wl; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci wl1251_debug(DEBUG_IRQ, "IRQ"); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci wl = cookie; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci ieee80211_queue_work(wl->hw, &wl->irq_work); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return IRQ_HANDLED; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic struct spi_device *wl_to_spi(struct wl1251 *wl) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci return wl->if_priv; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void wl1251_spi_reset(struct wl1251 *wl) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci u8 *cmd; 468c2ecf20Sopenharmony_ci struct spi_transfer t; 478c2ecf20Sopenharmony_ci struct spi_message m; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); 508c2ecf20Sopenharmony_ci if (!cmd) { 518c2ecf20Sopenharmony_ci wl1251_error("could not allocate cmd for spi reset"); 528c2ecf20Sopenharmony_ci return; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci memset(&t, 0, sizeof(t)); 568c2ecf20Sopenharmony_ci spi_message_init(&m); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci memset(cmd, 0xff, WSPI_INIT_CMD_LEN); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci t.tx_buf = cmd; 618c2ecf20Sopenharmony_ci t.len = WSPI_INIT_CMD_LEN; 628c2ecf20Sopenharmony_ci spi_message_add_tail(&t, &m); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci spi_sync(wl_to_spi(wl), &m); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci kfree(cmd); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void wl1251_spi_wake(struct wl1251 *wl) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct spi_transfer t; 748c2ecf20Sopenharmony_ci struct spi_message m; 758c2ecf20Sopenharmony_ci u8 *cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (!cmd) { 788c2ecf20Sopenharmony_ci wl1251_error("could not allocate cmd for spi init"); 798c2ecf20Sopenharmony_ci return; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci memset(&t, 0, sizeof(t)); 838c2ecf20Sopenharmony_ci spi_message_init(&m); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* Set WSPI_INIT_COMMAND 868c2ecf20Sopenharmony_ci * the data is being send from the MSB to LSB 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_ci cmd[0] = 0xff; 898c2ecf20Sopenharmony_ci cmd[1] = 0xff; 908c2ecf20Sopenharmony_ci cmd[2] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; 918c2ecf20Sopenharmony_ci cmd[3] = 0; 928c2ecf20Sopenharmony_ci cmd[4] = 0; 938c2ecf20Sopenharmony_ci cmd[5] = HW_ACCESS_WSPI_INIT_CMD_MASK << 3; 948c2ecf20Sopenharmony_ci cmd[5] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci cmd[6] = WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS 978c2ecf20Sopenharmony_ci | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) 1008c2ecf20Sopenharmony_ci cmd[6] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; 1018c2ecf20Sopenharmony_ci else 1028c2ecf20Sopenharmony_ci cmd[6] |= WSPI_INIT_CMD_EN_FIXEDBUSY; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci cmd[7] = crc7_be(0, cmd+2, WSPI_INIT_CMD_CRC_LEN) | WSPI_INIT_CMD_END; 1058c2ecf20Sopenharmony_ci /* 1068c2ecf20Sopenharmony_ci * The above is the logical order; it must actually be stored 1078c2ecf20Sopenharmony_ci * in the buffer byte-swapped. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci __swab32s((u32 *)cmd); 1108c2ecf20Sopenharmony_ci __swab32s((u32 *)cmd+1); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci t.tx_buf = cmd; 1138c2ecf20Sopenharmony_ci t.len = WSPI_INIT_CMD_LEN; 1148c2ecf20Sopenharmony_ci spi_message_add_tail(&t, &m); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci spi_sync(wl_to_spi(wl), &m); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci kfree(cmd); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void wl1251_spi_reset_wake(struct wl1251 *wl) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci wl1251_spi_reset(wl); 1268c2ecf20Sopenharmony_ci wl1251_spi_wake(wl); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, 1308c2ecf20Sopenharmony_ci size_t len) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct spi_transfer t[3]; 1338c2ecf20Sopenharmony_ci struct spi_message m; 1348c2ecf20Sopenharmony_ci u8 *busy_buf; 1358c2ecf20Sopenharmony_ci u32 *cmd; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci cmd = &wl->buffer_cmd; 1388c2ecf20Sopenharmony_ci busy_buf = wl->buffer_busyword; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci *cmd = 0; 1418c2ecf20Sopenharmony_ci *cmd |= WSPI_CMD_READ; 1428c2ecf20Sopenharmony_ci *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; 1438c2ecf20Sopenharmony_ci *cmd |= addr & WSPI_CMD_BYTE_ADDR; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci spi_message_init(&m); 1468c2ecf20Sopenharmony_ci memset(t, 0, sizeof(t)); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci t[0].tx_buf = cmd; 1498c2ecf20Sopenharmony_ci t[0].len = 4; 1508c2ecf20Sopenharmony_ci spi_message_add_tail(&t[0], &m); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* Busy and non busy words read */ 1538c2ecf20Sopenharmony_ci t[1].rx_buf = busy_buf; 1548c2ecf20Sopenharmony_ci t[1].len = WL1251_BUSY_WORD_LEN; 1558c2ecf20Sopenharmony_ci spi_message_add_tail(&t[1], &m); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci t[2].rx_buf = buf; 1588c2ecf20Sopenharmony_ci t[2].len = len; 1598c2ecf20Sopenharmony_ci spi_message_add_tail(&t[2], &m); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci spi_sync(wl_to_spi(wl), &m); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* FIXME: check busy words */ 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); 1668c2ecf20Sopenharmony_ci wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, 1708c2ecf20Sopenharmony_ci size_t len) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct spi_transfer t[2]; 1738c2ecf20Sopenharmony_ci struct spi_message m; 1748c2ecf20Sopenharmony_ci u32 *cmd; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci cmd = &wl->buffer_cmd; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci *cmd = 0; 1798c2ecf20Sopenharmony_ci *cmd |= WSPI_CMD_WRITE; 1808c2ecf20Sopenharmony_ci *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; 1818c2ecf20Sopenharmony_ci *cmd |= addr & WSPI_CMD_BYTE_ADDR; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci spi_message_init(&m); 1848c2ecf20Sopenharmony_ci memset(t, 0, sizeof(t)); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci t[0].tx_buf = cmd; 1878c2ecf20Sopenharmony_ci t[0].len = sizeof(*cmd); 1888c2ecf20Sopenharmony_ci spi_message_add_tail(&t[0], &m); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci t[1].tx_buf = buf; 1918c2ecf20Sopenharmony_ci t[1].len = len; 1928c2ecf20Sopenharmony_ci spi_message_add_tail(&t[1], &m); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci spi_sync(wl_to_spi(wl), &m); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); 1978c2ecf20Sopenharmony_ci wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void wl1251_spi_enable_irq(struct wl1251 *wl) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci return enable_irq(wl->irq); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic void wl1251_spi_disable_irq(struct wl1251 *wl) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci return disable_irq(wl->irq); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int wl1251_spi_set_power(struct wl1251 *wl, bool enable) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci if (gpio_is_valid(wl->power_gpio)) 2138c2ecf20Sopenharmony_ci gpio_set_value(wl->power_gpio, enable); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic const struct wl1251_if_operations wl1251_spi_ops = { 2198c2ecf20Sopenharmony_ci .read = wl1251_spi_read, 2208c2ecf20Sopenharmony_ci .write = wl1251_spi_write, 2218c2ecf20Sopenharmony_ci .reset = wl1251_spi_reset_wake, 2228c2ecf20Sopenharmony_ci .enable_irq = wl1251_spi_enable_irq, 2238c2ecf20Sopenharmony_ci .disable_irq = wl1251_spi_disable_irq, 2248c2ecf20Sopenharmony_ci .power = wl1251_spi_set_power, 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic int wl1251_spi_probe(struct spi_device *spi) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct wl1251_platform_data *pdata = dev_get_platdata(&spi->dev); 2308c2ecf20Sopenharmony_ci struct device_node *np = spi->dev.of_node; 2318c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 2328c2ecf20Sopenharmony_ci struct wl1251 *wl; 2338c2ecf20Sopenharmony_ci int ret; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!np && !pdata) { 2368c2ecf20Sopenharmony_ci wl1251_error("no platform data"); 2378c2ecf20Sopenharmony_ci return -ENODEV; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci hw = wl1251_alloc_hw(); 2418c2ecf20Sopenharmony_ci if (IS_ERR(hw)) 2428c2ecf20Sopenharmony_ci return PTR_ERR(hw); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci wl = hw->priv; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci SET_IEEE80211_DEV(hw, &spi->dev); 2478c2ecf20Sopenharmony_ci spi_set_drvdata(spi, wl); 2488c2ecf20Sopenharmony_ci wl->if_priv = spi; 2498c2ecf20Sopenharmony_ci wl->if_ops = &wl1251_spi_ops; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* This is the only SPI value that we need to set here, the rest 2528c2ecf20Sopenharmony_ci * comes from the board-peripherals file 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ci spi->bits_per_word = 32; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci ret = spi_setup(spi); 2578c2ecf20Sopenharmony_ci if (ret < 0) { 2588c2ecf20Sopenharmony_ci wl1251_error("spi_setup failed"); 2598c2ecf20Sopenharmony_ci goto out_free; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (np) { 2638c2ecf20Sopenharmony_ci wl->use_eeprom = of_property_read_bool(np, "ti,wl1251-has-eeprom"); 2648c2ecf20Sopenharmony_ci wl->power_gpio = of_get_named_gpio(np, "ti,power-gpio", 0); 2658c2ecf20Sopenharmony_ci } else if (pdata) { 2668c2ecf20Sopenharmony_ci wl->power_gpio = pdata->power_gpio; 2678c2ecf20Sopenharmony_ci wl->use_eeprom = pdata->use_eeprom; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (wl->power_gpio == -EPROBE_DEFER) { 2718c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 2728c2ecf20Sopenharmony_ci goto out_free; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (gpio_is_valid(wl->power_gpio)) { 2768c2ecf20Sopenharmony_ci ret = devm_gpio_request_one(&spi->dev, wl->power_gpio, 2778c2ecf20Sopenharmony_ci GPIOF_OUT_INIT_LOW, "wl1251 power"); 2788c2ecf20Sopenharmony_ci if (ret) { 2798c2ecf20Sopenharmony_ci wl1251_error("Failed to request gpio: %d\n", ret); 2808c2ecf20Sopenharmony_ci goto out_free; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci } else { 2838c2ecf20Sopenharmony_ci wl1251_error("set power gpio missing in platform data"); 2848c2ecf20Sopenharmony_ci ret = -ENODEV; 2858c2ecf20Sopenharmony_ci goto out_free; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci wl->irq = spi->irq; 2898c2ecf20Sopenharmony_ci if (wl->irq < 0) { 2908c2ecf20Sopenharmony_ci wl1251_error("irq missing in platform data"); 2918c2ecf20Sopenharmony_ci ret = -ENODEV; 2928c2ecf20Sopenharmony_ci goto out_free; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); 2968c2ecf20Sopenharmony_ci ret = devm_request_irq(&spi->dev, wl->irq, wl1251_irq, 0, 2978c2ecf20Sopenharmony_ci DRIVER_NAME, wl); 2988c2ecf20Sopenharmony_ci if (ret < 0) { 2998c2ecf20Sopenharmony_ci wl1251_error("request_irq() failed: %d", ret); 3008c2ecf20Sopenharmony_ci goto out_free; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci wl->vio = devm_regulator_get(&spi->dev, "vio"); 3068c2ecf20Sopenharmony_ci if (IS_ERR(wl->vio)) { 3078c2ecf20Sopenharmony_ci ret = PTR_ERR(wl->vio); 3088c2ecf20Sopenharmony_ci wl1251_error("vio regulator missing: %d", ret); 3098c2ecf20Sopenharmony_ci goto out_free; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ret = regulator_enable(wl->vio); 3138c2ecf20Sopenharmony_ci if (ret) 3148c2ecf20Sopenharmony_ci goto out_free; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci ret = wl1251_init_ieee80211(wl); 3178c2ecf20Sopenharmony_ci if (ret) 3188c2ecf20Sopenharmony_ci goto disable_regulator; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cidisable_regulator: 3238c2ecf20Sopenharmony_ci regulator_disable(wl->vio); 3248c2ecf20Sopenharmony_ciout_free: 3258c2ecf20Sopenharmony_ci ieee80211_free_hw(hw); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return ret; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int wl1251_spi_remove(struct spi_device *spi) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct wl1251 *wl = spi_get_drvdata(spi); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci wl1251_free_hw(wl); 3358c2ecf20Sopenharmony_ci regulator_disable(wl->vio); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic struct spi_driver wl1251_spi_driver = { 3418c2ecf20Sopenharmony_ci .driver = { 3428c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 3438c2ecf20Sopenharmony_ci }, 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci .probe = wl1251_spi_probe, 3468c2ecf20Sopenharmony_ci .remove = wl1251_spi_remove, 3478c2ecf20Sopenharmony_ci}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cimodule_spi_driver(wl1251_spi_driver); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); 3538c2ecf20Sopenharmony_ciMODULE_ALIAS("spi:wl1251"); 354