diff --git a/wilcsbridge/wilc_sbridge.h b/wilcsbridge/wilc_sbridge.h index 490248c..64f9193 100644 --- a/wilcsbridge/wilc_sbridge.h +++ b/wilcsbridge/wilc_sbridge.h @@ -1,58 +1,277 @@ - -#ifndef WILC_SBRIDGE_H -#define WILC_SBRIDGE_H - -#include - -enum wilc_chip_type { - WILC_1000, - WILC_3000, -}; - + +#ifndef WILC_SBRIDGE_H +#define WILC_SBRIDGE_H + +#include +#include + + +#define DEV_MAX 2 + +/*wlan*/ +#define GPIO_NUM_CHIP_EN 94 +#define GPIO_NUM_RESET 60 + + + +enum wilc_chip_type { + WILC_1000, + WILC_3000, +}; + +struct wilc_power_gpios { + int reset; + int chip_en; +}; + +struct wilc_power { + struct wilc_power_gpios gpios; + u8 status[DEV_MAX]; +}; + struct wilc { - struct device *dev; - enum wilc_chip_type chip; - struct mutex hif_cs; -}; - -struct sdio_cmd52 { - u32 read_write: 1; - u32 function: 3; - u32 raw: 1; - u32 address: 17; - u32 data: 8; -}; - -struct sdio_cmd53 { - u32 read_write: 1; - u32 function: 3; - u32 block_mode: 1; - u32 increment: 1; - u32 address: 17; - u32 count: 9; - u8 *buffer; - u32 block_size; -}; - - -static inline bool is_wilc1000(u32 id) -{ - return ((id & 0xfffff000) == 0x100000 ? true : false); -} - -static inline bool is_wilc3000(u32 id) -{ - return ((id & 0xfffff000) == 0x300000 ? true : false); -} - + struct device *dev; + struct device *dt_dev; + int io_type; + enum wilc_chip_type chip; + struct mutex hif_cs; + struct wilc_power power; + void *bus_data; + u32 chipid; + +}; + +struct sdio_cmd52 { + u32 read_write: 1; + u32 function: 3; + u32 raw: 1; + u32 address: 17; + u32 data: 8; +}; + +struct sdio_cmd53 { + u32 read_write: 1; + u32 function: 3; + u32 block_mode: 1; + u32 increment: 1; + u32 address: 17; + u32 count: 9; + u8 *buffer; + u32 block_size; + bool use_global_buf; + +}; + +enum { + WILC_HIF_SDIO = 0, + WILC_HIF_SPI = BIT(0), + WILC_HIF_SDIO_GPIO_IRQ = BIT(1) +}; + +static inline bool is_wilc1000(u32 id) +{ + return ((id & 0xfffff000) == 0x100000 ? true : false); +} + +static inline bool is_wilc3000(u32 id) +{ + return ((id & 0xfffff000) == 0x300000 ? true : false); +} + +enum bus_acquire { + WILC_BUS_ACQUIRE_ONLY = 0, + WILC_BUS_ACQUIRE_AND_WAKEUP = 1, +}; + +enum bus_release { + WILC_BUS_RELEASE_ONLY = 0, + WILC_BUS_RELEASE_ALLOW_SLEEP = 1, +}; + +/* Functions IO enables bits */ +#define WILC_SDIO_CCCR_IO_EN_FUNC1 BIT(1) + +/* Function/Interrupt enables bits */ +#define WILC_SDIO_CCCR_IEN_MASTER BIT(0) +#define WILC_SDIO_CCCR_IEN_FUNC1 BIT(1) + +/* Abort CCCR register bits */ +#define WILC_SDIO_CCCR_ABORT_RESET BIT(3) + +/* Vendor specific CCCR registers */ +/* WILC1000 */ +#define WILC1000_SDIO_WAKEUP_REG 0xf0 +#define WILC1000_SDIO_WAKEUP_BIT BIT(0) + +#define WILC1000_SDIO_CLK_STATUS_REG 0xf1 +#define WILC1000_SDIO_CLK_STATUS_BIT BIT(0) + +#define WILC1000_SDIO_IRQ_FLAG_REG 0xf7 +#define WILC1000_SDIO_IRQ_CLEAR_FLAG_REG 0xf8 + +/* WILC3000 specific */ +#define WILC3000_SDIO_WAKEUP_REG 0xf0 +#define WILC3000_SDIO_WAKEUP_BIT BIT(0) + +#define WILC3000_SDIO_CLK_STATUS_REG 0xf0 /* clk & wakeup are on same reg*/ +#define WILC3000_SDIO_CLK_STATUS_BIT BIT(4) + +#define WILC3000_SDIO_IRQ_FLAG_REG 0xfe +#define WILC3000_SDIO_IRQ_CLEAR_FLAG_REG 0xfe +#define WILC3000_SDIO_VMM_TBL_CTRL_REG 0xf1 + +/* Common vendor specific CCCR register */ +#define WILC_SDIO_INTERRUPT_DATA_SZ_REG 0xf2 /* Read size (2 bytes) */ +#define WILC_SDIO_HOST_TO_FW_REG 0xfa +#define WILC_SDIO_HOST_TO_FW_BIT BIT(0) + +#define WILC_SDIO_FW_TO_HOST_REG 0xfc +#define WILC_SDIO_FW_TO_HOST_BIT BIT(0) + #define WILC_SPI_REG_BASE 0xe800 #define WILC_SPI_CTL WILC_SPI_REG_BASE -#define WILC_SPI_PROTOCOL_CONFIG (WILC_SPI_REG_BASE + 0x24) - +#define WILC_SPI_PROTOCOL_CONFIG (WILC_SPI_REG_BASE + 0x24) + #define WILC_SPI_PROTOCOL_OFFSET (WILC_SPI_PROTOCOL_CONFIG - \ WILC_SPI_REG_BASE) - -#define MODALIAS "WILC_SPI" - -#endif /** WILC_SBRIDGE_H */ - + +#define MODALIAS "WILC_SPI" + + +/* Function 1 specific FBR register */ +#define WILC_SDIO_FBR_CSA_REG 0x10C /* CSA pointer (3 bytes) */ +#define WILC_SDIO_FBR_DATA_REG 0x10F + +#define WILC_SDIO_F1_DATA_REG 0x0 +#define WILC_SDIO_EXT_IRQ_FLAG_REG 0x4 + +#define WILC_AHB_DATA_MEM_BASE 0x30000 +#define WILC_AHB_SHARE_MEM_BASE 0xd0000 + +#define WILC_VMM_TBL_RX_SHADOW_BASE WILC_AHB_SHARE_MEM_BASE +#define WILC_VMM_TBL_RX_SHADOW_SIZE 256 + +#define WILC_GP_REG_0 0x149c +#define WILC_GP_REG_1 0x14a0 + +#define GLOBAL_MODE_CONTROL 0x1614 +#define PWR_SEQ_MISC_CTRL 0x3008 + +#define WILC_GLOBAL_MODE_ENABLE_WIFI BIT(0) +#define WILC_PWR_SEQ_ENABLE_WIFI_SLEEP BIT(28) + +#define COE_AUTO_PS_ON_NULL_PKT 0x160468 +#define COE_AUTO_PS_OFF_NULL_PKT 0x16046C +#define CCA_CTL_2 (0x160EF4) +#define CCA_CTL_7 (0x160F08) + +#define WILC_HAVE_SDIO_IRQ_GPIO BIT(0) +#define WILC_HAVE_SLEEP_CLK_SRC_RTC BIT(2) +#define WILC_HAVE_SLEEP_CLK_SRC_XO BIT(3) + + + +/*******************************************/ +/* E0 and later Interrupt flags. */ +/*******************************************/ +/*******************************************/ +/* E0 and later Interrupt flags. */ +/* IRQ Status word */ +/* 15:0 = DMA count in words. */ +/* 16: INT0 flag */ +/* 17: INT1 flag */ +/* 18: INT2 flag */ +/* 19: INT3 flag */ +/* 20: INT4 flag */ +/* 21: INT5 flag */ +/*******************************************/ +#define IRG_FLAGS_OFFSET 16 +#define IRQ_DMA_WD_CNT_MASK GENMASK(IRG_FLAGS_OFFSET - 1, 0) +#define INT_0 BIT(IRG_FLAGS_OFFSET) +#define INT_1 BIT(IRG_FLAGS_OFFSET + 1) +#define INT_2 BIT(IRG_FLAGS_OFFSET + 2) +#define INT_3 BIT(IRG_FLAGS_OFFSET + 3) +#define INT_4 BIT(IRG_FLAGS_OFFSET + 4) +#define MAX_NUM_INT 5 +#define IRG_FLAGS_MASK GENMASK(IRG_FLAGS_OFFSET + MAX_NUM_INT, \ + IRG_FLAGS_OFFSET) + +/*******************************************/ +/* E0 and later Interrupt flags. */ +/* IRQ Clear word */ +/* 0: Clear INT0 */ +/* 1: Clear INT1 */ +/* 2: Clear INT2 */ +/* 3: Clear INT3 */ +/* 4: Clear INT4 */ +/* 5: Clear INT5 */ +/* 6: Select VMM table 1 */ +/* 7: Select VMM table 2 */ +/* 8: Enable VMM */ +/*******************************************/ +#define CLR_INT0 BIT(0) +#define CLR_INT1 BIT(1) +#define CLR_INT2 BIT(2) +#define CLR_INT3 BIT(3) +#define CLR_INT4 BIT(4) +#define CLR_INT5 BIT(5) +#define SEL_VMM_TBL0 BIT(6) +#define SEL_VMM_TBL1 BIT(7) +#define EN_VMM BIT(8) + +#define DATA_INT_EXT INT_0 +#define ALL_INT_EXT DATA_INT_EXT +#define NUM_INT_EXT 1 +#define UNHANDLED_IRQ_MASK GENMASK(MAX_NUM_INT - 1, NUM_INT_EXT) + + +/******************************************** + * + * Register Defines + * + ********************************************/ +#define WILC_PERIPH_REG_BASE 0x1000 +#define WILC_CHIPID WILC_PERIPH_REG_BASE +#define WILC_GLB_RESET_0 (WILC_PERIPH_REG_BASE + 0x400) +#define WILC_PIN_MUX_0 (WILC_PERIPH_REG_BASE + 0x408) +#define WILC_HOST_TX_CTRL (WILC_PERIPH_REG_BASE + 0x6c) +#define WILC_HOST_RX_CTRL_0 (WILC_PERIPH_REG_BASE + 0x70) +#define WILC_HOST_RX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x74) +#define WILC_HOST_VMM_CTL (WILC_PERIPH_REG_BASE + 0x78) +#define WILC_HOST_RX_CTRL (WILC_PERIPH_REG_BASE + 0x80) +#define WILC_HOST_RX_EXTRA_SIZE (WILC_PERIPH_REG_BASE + 0x84) +#define WILC_HOST_TX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x88) +#define WILC_MISC (WILC_PERIPH_REG_BASE + 0x428) +#define WILC_INTR_REG_BASE (WILC_PERIPH_REG_BASE + 0xa00) + +#define WILC_INTERRUPT_CORTUS_0 (WILC_PERIPH_REG_BASE + 0xa8) +#define WILC1000_CORTUS_INTERRUPT_1 (WILC_INTERRUPT_CORTUS_0 + 0x4) +#define WILC3000_CORTUS_INTERRUPT_1 (WILC_INTERRUPT_CORTUS_0 + 0x14) + + +#define WILC_MISC (WILC_PERIPH_REG_BASE + 0x428) +#define WILC_INTR_ENABLE WILC_INTR_REG_BASE +#define WILC_INTR2_ENABLE (WILC_INTR_REG_BASE + 4) + +#define WILC_CORTUS_RESET_MUX_SEL 0x1118 +#define WILC_CORTUS_BOOT_REGISTER 0xc0000 +#define WILC3000_CHIP_ID 0x3b0000 + + +#define WILC_1000_BASE_ID 0x100000 + +#define WILC_1000_BASE_ID_2A 0x1002A0 +#define WILC_1000_BASE_ID_2A_REV1 (WILC_1000_BASE_ID_2A + 1) + +#define WILC_1000_BASE_ID_2B 0x1002B0 +#define WILC_1000_BASE_ID_2B_REV1 (WILC_1000_BASE_ID_2B + 1) +#define WILC_1000_BASE_ID_2B_REV2 (WILC_1000_BASE_ID_2B + 2) + +#define WILC_3000_BASE_ID 0x300000 + +#define WILC_CHIP_REV_FIELD GENMASK(11, 0) +#define WILC_RF_REVISION_ID 0x13f4 + + +#endif /** WILC_SBRIDGE_H */ + diff --git a/wilcsbridge/wilcsbridge_sdio.c b/wilcsbridge/wilcsbridge_sdio.c index 3faa61c..9086552 100644 --- a/wilcsbridge/wilcsbridge_sdio.c +++ b/wilcsbridge/wilcsbridge_sdio.c @@ -1,37 +1,36 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ -#include -#include "wilc_sbridge.h" +#include #include -#include #include -#include #include +#include #include -#define SAMA5D4_ARDUINO_CONNECTOR 1 - -#define SDIO_MODALIAS "wilc_sdio" -/*WILC RESET/CHIP_EN/IRQN PIN CONNECTION*/ -#ifdef SAMA5D4_ARDUINO_CONNECTOR -#define GPIO_NUM 58 -#define GPIO_CHIP_EN 94 -#define GPIO_RESET 60 -#else /*SAMA5D4_EXT1_CONNECTOR*/ -#define GPIO_NUM 58 -#define GPIO_CHIP_EN 59 -#define GPIO_RESET 149 -#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include "netdev.h" +//#include "cfg80211.h" +#include "wilc_sbridge.h" + + + +#define SDIO_VENDOR_ID_MICROCHIP_WILC 0x0296 +#define SDIO_DEVICE_ID_MICROCHIP_WILC1000 0x5347 + + +/* ioctl old */ typedef struct { uint32_t cmd; @@ -52,355 +51,44 @@ typedef struct { #define CMD_READ_BLOCK_REG _IOR('q', 3, cmd_hdr *) #define CMD_WRITE_BLOCK_REG _IOW('q', 4, cmd_hdr *) -#define SDIO_VENDOR_ID_WILC 0x0296 -#define SDIO_DEVICE_ID_WILC 0x5347 - -static const struct sdio_device_id wilc_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) }, - { }, -}; - #define FIRST_MINOR 0 #define MINOR_CNT 1 -#define WILC_SDIO_BLOCK_SIZE 512 - -struct wilc_sdio { - u32 block_size; - int nint; -#define MAX_NUN_INT_THRPT_ENH2 (5) /* Max num interrupts allowed in registers 0xf7, 0xf8 */ - int has_thrpt_enh3; -}; - -static struct wilc_sdio g_sdio; -static int sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size); -static int sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size); -static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data); -static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data); -static int sdio_init(struct wilc *wilc, bool resume); - static dev_t dev; static struct cdev c_dev; static struct class *cl; struct wilc *wilc; struct device *dt_dev= NULL; +static int query_ioctl_init( void ); +static void query_ioctl_exit(void ); +/*****/ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) -static void wilc_wlan_power(struct wilc *wilc, int power) -{ - struct gpio_desc *gpio_reset; - struct gpio_desc *gpio_chip_en; - - pr_info("wifi_pm : %d\n", power); - - gpio_reset = gpiod_get(wilc->dev, "reset-gpios", GPIOD_ASIS); - if (IS_ERR(gpio_reset)) { - printk( "failed to get Reset GPIO, try default\r\n"); - gpio_reset = gpio_to_desc(GPIO_RESET); - if (!gpio_reset) { - printk("failed to get default Reset GPIO\r\n"); - return; - } - } else { - printk( "succesfully got gpio_reset\r\n"); - } - - gpio_chip_en = gpiod_get(wilc->dev, "chip_en-gpios", GPIOD_ASIS); - if (IS_ERR(gpio_chip_en)) { - printk( "failed to get Chi_en GPIO, try default\r\n"); - gpio_chip_en = gpio_to_desc(GPIO_CHIP_EN); - if (!gpio_chip_en) { - printk("failed to get default chip_en GPIO\r\n"); - gpiod_put(gpio_reset); - return; - } - } else { - printk("succesfully got gpio_chip_en\r\n"); - } - - if (power) { - gpiod_direction_output(gpio_chip_en, 1); - mdelay(100); - gpiod_direction_output(gpio_reset, 1); - } else { - gpiod_direction_output(gpio_reset, 0); - gpiod_direction_output(gpio_chip_en, 0); - } - gpiod_put(gpio_chip_en); - gpiod_put(gpio_reset); -} -#else -static void wilc_wlan_power(struct wilc *wilc, int power) -{ - int gpio_reset; - int gpio_chip_en; - struct device_node *of_node = wilc->dev->of_node; - - pr_info("wifi_pm : %d\n", power); - - gpio_reset = of_get_named_gpio_flags(of_node, "reset-gpios", 0, NULL); - - if (gpio_reset < 0) { - gpio_reset = GPIO_RESET; - pr_info("wifi_pm : load default reset GPIO %d\n", gpio_reset); - } - - gpio_chip_en = of_get_named_gpio_flags(of_node, "chip_en-gpios", 0, - NULL); - - if (gpio_chip_en < 0) { - gpio_chip_en = GPIO_CHIP_EN; - pr_info("wifi_pm : load default chip_en GPIO %d\n", - gpio_chip_en); - } - - if (gpio_request(gpio_chip_en, "CHIP_EN") == 0 && - gpio_request(gpio_reset, "RESET") == 0) { - gpio_direction_output(gpio_chip_en, 0); - gpio_direction_output(gpio_reset, 0); - if (power) { - gpio_set_value(gpio_chip_en, 1); - mdelay(5); - gpio_set_value(gpio_reset, 1); - } else { - gpio_set_value(gpio_reset, 0); - gpio_set_value(gpio_chip_en, 0); - } - gpio_free(gpio_chip_en); - gpio_free(gpio_reset); - } else { - dev_err(wilc->dev, - "Error requesting GPIOs for CHIP_EN and RESET"); - } - -} -#endif - -void wilc_wlan_power_on_sequence(void) -{ - wilc_wlan_power(wilc, 0); - wilc_wlan_power(wilc, 1); -} - -void wilc_wlan_power_off_sequence(void) -{ - wilc_wlan_power(wilc, 0); -} - -static int my_open(struct inode *i, struct file *f) -{ - return 0; -} -static int my_close(struct inode *i, struct file *f) -{ - return 0; -} -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) -static int my_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) -#else -static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -#endif -{ - cmd_hdr dat; - block_cmd_hdr b_dat; - unsigned int val32=0; - - switch (cmd) - { - case CMD_READ_REG: - if (copy_from_user(&dat, (cmd_hdr *)arg, sizeof(cmd_hdr))) - { - return -EACCES; - } - sdio_read_reg(wilc, dat.addr, &val32); - dat.val = (int) val32; - if (copy_to_user((cmd_hdr *)arg, &dat, sizeof(cmd_hdr))) - { - return -EACCES; - } - break; - case CMD_WRITE_REG: - if (copy_from_user(&dat, (cmd_hdr *)arg, sizeof(cmd_hdr))) - { - return -EACCES; - } - sdio_write_reg(wilc, dat.addr, dat.val); - break; - case CMD_WRITE_BLOCK_REG: - if (copy_from_user(&b_dat, (block_cmd_hdr *)arg, sizeof(block_cmd_hdr))) - { - return -EACCES; - } - sdio_write(wilc, b_dat.addr, b_dat.b_buffer, (b_dat.cmd>>16) & 0xFFFF); - break; - case CMD_READ_BLOCK_REG: - if (copy_from_user(&b_dat, (block_cmd_hdr *)arg, sizeof(block_cmd_hdr))) - { - return -EACCES; - } - sdio_read(wilc, b_dat.addr, b_dat.b_buffer, (b_dat.cmd>>16) & 0xFFFF); - if (copy_to_user((block_cmd_hdr *)arg, &b_dat, sizeof(block_cmd_hdr))) - { - return -EACCES; - } - break; - default: - return -EINVAL; - } - return 0; -} - - -static struct file_operations query_fops = -{ - .owner = THIS_MODULE, - .open = my_open, - .release = my_close, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) - .ioctl = my_ioctl -#else - .unlocked_ioctl = my_ioctl -#endif +enum sdio_host_lock { + WILC_SDIO_HOST_NO_TAKEN = 0, + WILC_SDIO_HOST_IRQ_TAKEN = 1, + WILC_SDIO_HOST_DIS_TAKEN = 2, }; - -static int query_ioctl_init(void) -{ - int ret; - struct device *dev_ret; - - if ((ret = alloc_chrdev_region(&dev, FIRST_MINOR, MINOR_CNT, "query_ioctl")) < 0) - { - return ret; - } - - cdev_init(&c_dev, &query_fops); - - if ((ret = cdev_add(&c_dev, dev, MINOR_CNT)) < 0) - { - return ret; - } - - if (IS_ERR(cl = class_create(THIS_MODULE, "char"))) - { - cdev_del(&c_dev); - unregister_chrdev_region(dev, MINOR_CNT); - return PTR_ERR(cl); - } - if (IS_ERR(dev_ret = device_create(cl, NULL, dev, NULL, "query"))) - { - class_destroy(cl); - cdev_del(&c_dev); - unregister_chrdev_region(dev, MINOR_CNT); - return PTR_ERR(dev_ret); - } - - return 0; -} - -static void query_ioctl_exit(void) -{ - device_destroy(cl, dev); - class_destroy(cl); - cdev_del(&c_dev); - unregister_chrdev_region(dev, MINOR_CNT); -} - -u32 wilc_get_chipid(struct wilc *wilc) -{ - u32 chipid = 0; - int ret = 0; - - ret = sdio_read_reg(wilc, 0x3b0000, &chipid); - if (!ret) - printk("[wilc start]: fail read reg 0x3b0000\n"); - if (!is_wilc3000(chipid)) { - sdio_read_reg(wilc, 0x1000,&chipid); - if (!is_wilc1000(chipid)) { - printk("Its not WILC1000 Chipid: %x\n", chipid); - chipid = 0; - } - if (chipid < 0x1003a0) { - printk("WILC1002 isn't suported %x\n", chipid); - chipid = 0; - } - } - return chipid; -} - -int init_wilc_chip(struct wilc *wilc) -{ - u32 chipid; - u32 reg, ret = 0; - struct sdio_func *func = dev_to_sdio_func(wilc->dev); - - chipid = wilc_get_chipid(wilc); - printk("WILC ChipID: %x \n",chipid); - - ret = sdio_read_reg(wilc, 0x1118, ®); - if (!ret) { - dev_err(&func->dev, "fail read reg 0x1118\n"); - return ret; - } - reg |= BIT(0); - ret = sdio_write_reg(wilc, 0x1118, reg); - if (!ret) { - dev_err(&func->dev, "fail write reg 0x1118\n"); - return ret; - } - ret = sdio_write_reg(wilc, 0xc0000, 0x71); - if (!ret) { - dev_err(&func->dev, "fail write reg 0xc0000\n"); - return ret; - } - //if (is_wilc3000(chipid)) { - ret =sdio_read_reg(wilc, 0x207ac, ®); - ret = sdio_write_reg(wilc, 0x4f0000,0x71); - if (!ret) { - dev_err(&func->dev, "fail write reg 0x4f0000\n"); - return ret; - } - //} - return ret; -} +static enum sdio_host_lock sdio_intr_lock = WILC_SDIO_HOST_NO_TAKEN; +static wait_queue_head_t sdio_intr_waitqueue; +#define SDIO_MODALIAS "wilcsbridge_sdio" +static const struct sdio_device_id wilc_sdio_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_MICROCHIP_WILC, SDIO_DEVICE_ID_MICROCHIP_WILC1000) }, + { }, +}; +MODULE_DEVICE_TABLE(sdio, wilc_sdio_ids); -static int wilc_bus_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - dt_dev = &func->card->dev; - - printk("This is wilc bus probe\n"); - wilc = kzalloc(sizeof(*wilc), GFP_KERNEL); - if (!wilc) - return -ENOMEM; - printk("after power on sequence\n"); - - mutex_init(&wilc->hif_cs); - sdio_set_drvdata(func, wilc); - wilc->dev = &func->dev; -/* To be enabled when using the custom WILC board */ -/* Not for WILC1000 SD / WICL3000 SD/Shield Boards*/ -#ifdef WILC_PWR_ON - wilc_wlan_power_on_sequence(); -#endif - query_ioctl_init(); - //msleep(100); - sdio_init(wilc,false); - //msleep(100); - init_wilc_chip(wilc); - pm_runtime_get_sync(mmc_dev(func->card->host)); - printk("WILC SDIO probe success\n"); - return 0; -} +#define WILC_SDIO_BLOCK_SIZE 512 -static void wilc_bus_remove(struct sdio_func *func) -{ - printk("wilc_bus_remove SDIO card removed \n"); - query_ioctl_exit(); -} +struct wilc_sdio { + bool irq_gpio; + u32 block_size; + struct wilc *wl; + u8 *cmd53_buf; +}; static int wilc_sdio_cmd52(struct wilc *wilc, struct sdio_cmd52 *cmd) { @@ -435,6 +123,8 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) { struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev); int size, ret; + struct wilc_sdio *sdio_priv = wilc->bus_data; + u8 *buf = cmd->buffer; sdio_claim_host(func); @@ -445,14 +135,26 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) else size = cmd->count; + if (cmd->use_global_buf) { + if (size > sizeof(u32)) { + ret = -EINVAL; + goto out; + } + buf = sdio_priv->cmd53_buf; + } + if (cmd->read_write) { /* write */ - ret = sdio_memcpy_toio(func, cmd->address, - (void *)cmd->buffer, size); + if (cmd->use_global_buf) + memcpy(buf, cmd->buffer, size); + + ret = sdio_memcpy_toio(func, cmd->address, buf, size); } else { /* read */ - ret = sdio_memcpy_fromio(func, (void *)cmd->buffer, - cmd->address, size); - } + ret = sdio_memcpy_fromio(func, buf, cmd->address, size); + if (cmd->use_global_buf) + memcpy(cmd->buffer, buf, size); + } +out: sdio_release_host(func); if (ret) @@ -460,59 +162,75 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) return ret; } -static int sdio_reset(struct wilc *wilc) + + +/** + * wilc_of_parse_power_pins() - parse power sequence pins; to keep backward + * compatibility with old device trees that doesn't provide + * power sequence pins we check for default pins on proper boards + * + * @wilc: wilc data structure + * + * Returns: 0 on success, negative error number on failures. + */ +int wilc_of_parse_power_pins(struct wilc *wilc) { - struct sdio_cmd52 cmd; + static const struct wilc_power_gpios default_gpios[] = { + { .reset = GPIO_NUM_RESET, .chip_en = GPIO_NUM_CHIP_EN, }, + }; + struct device_node *of = wilc->dt_dev->of_node; + struct wilc_power *power = &wilc->power; + const struct wilc_power_gpios *gpios = &default_gpios[0]; int ret; - struct sdio_func *func = dev_to_sdio_func(wilc->dev); - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0x6; - cmd.data = 0x8; - ret = wilc_sdio_cmd52(wilc, &cmd); + power->gpios.reset = of_get_named_gpio(of, "reset-gpios", 0); + if (!gpio_is_valid(power->gpios.reset)) + power->gpios.reset = gpios->reset; + + power->gpios.chip_en = of_get_named_gpio(of, "chip_en-gpios", 0); + if (!gpio_is_valid(power->gpios.chip_en)) + power->gpios.chip_en = gpios->chip_en; + + if (!gpio_is_valid(power->gpios.chip_en) || + !gpio_is_valid(power->gpios.reset)) + return -EINVAL; + + ret = devm_gpio_request(wilc->dev, power->gpios.chip_en, "CHIP_EN"); if (ret) - dev_err(&func->dev, "Fail cmd 52, reset cmd\n"); + return ret; + + ret = devm_gpio_request(wilc->dev, power->gpios.reset, "RESET"); return ret; } -static int wilc_sdio_suspend(struct device *dev) +/** + * wilc_wlan_power() - handle power on/off commands + * + * @wilc: wilc data structure + * @on: requested power status + * + * Returns: none + */ +void wilc_wlan_power(struct wilc *wilc, bool on) { - return 0; -} + if (!gpio_is_valid(wilc->power.gpios.chip_en) || + !gpio_is_valid(wilc->power.gpios.reset)) { + /* In case SDIO power sequence driver is used to power this + * device then the powering sequence is handled by the bus + * via pm_runtime_* functions. */ + return; + } -static int wilc_sdio_resume(struct device *dev) -{ - return 0; + if (on) { + gpio_direction_output(wilc->power.gpios.chip_en, 1); + mdelay(5); + gpio_direction_output(wilc->power.gpios.reset, 1); + } else { + gpio_direction_output(wilc->power.gpios.chip_en, 0); + gpio_direction_output(wilc->power.gpios.reset, 0); + } } -static const struct of_device_id wilc_of_match[] = { - { .compatible = "microchip,wilc1000", }, - { .compatible = "microchip,wilc3000", }, - { /* sentinel */} -}; -MODULE_DEVICE_TABLE(of, wilc_of_match); - -static const struct dev_pm_ops wilc_sdio_pm_ops = { - .suspend = wilc_sdio_suspend, - .resume = wilc_sdio_resume, -}; - -static struct sdio_driver wilc_sdio_driver = { - .name = SDIO_MODALIAS, - .id_table = wilc_sdio_ids, - .probe = wilc_bus_probe, - .remove = wilc_bus_remove, - .drv = { - .pm = &wilc_sdio_pm_ops, - .of_match_table = wilc_of_match, - } -}; -module_driver(wilc_sdio_driver, - sdio_register_driver, - sdio_unregister_driver); -MODULE_LICENSE("GPL"); /******************************************** * @@ -520,7 +238,7 @@ MODULE_LICENSE("GPL"); * ********************************************/ -static int sdio_set_func0_csa_address(struct wilc *wilc, u32 adr) +static int wilc_sdio_set_func0_csa_address(struct wilc *wilc, u32 adr) { struct sdio_func *func = dev_to_sdio_func(wilc->dev); struct sdio_cmd52 cmd; @@ -532,36 +250,38 @@ static int sdio_set_func0_csa_address(struct wilc *wilc, u32 adr) cmd.read_write = 1; cmd.function = 0; cmd.raw = 0; - cmd.address = 0x10c; + cmd.address = WILC_SDIO_FBR_CSA_REG; cmd.data = (u8)adr; ret = wilc_sdio_cmd52(wilc, &cmd); if (ret) { - dev_err(&func->dev, "Failed cmd52, set 0x10c data...\n"); - goto fail; + dev_err(&func->dev, "Failed cmd52, set %04x data...\n", + cmd.address); + return ret; } - cmd.address = 0x10d; + cmd.address = WILC_SDIO_FBR_CSA_REG + 1; cmd.data = (u8)(adr >> 8); ret = wilc_sdio_cmd52(wilc, &cmd); if (ret) { - dev_err(&func->dev, "Failed cmd52, set 0x10d data...\n"); - goto fail; + dev_err(&func->dev, "Failed cmd52, set %04x data...\n", + cmd.address); + return ret; } - cmd.address = 0x10e; + cmd.address = WILC_SDIO_FBR_CSA_REG + 2; cmd.data = (u8)(adr >> 16); ret = wilc_sdio_cmd52(wilc, &cmd); if (ret) { - dev_err(&func->dev, "Failed cmd52, set 0x10e data...\n"); - goto fail; + dev_err(&func->dev, "Failed cmd52, set %04x data...\n", + cmd.address); + return ret; } - return 1; -fail: return 0; } -static int sdio_set_func0_block_size(struct wilc *wilc, u32 block_size) +static int wilc_sdio_set_block_size(struct wilc *wilc, u8 func_num, + u32 block_size) { struct sdio_func *func = dev_to_sdio_func(wilc->dev); struct sdio_cmd52 cmd; @@ -570,161 +290,58 @@ static int sdio_set_func0_block_size(struct wilc *wilc, u32 block_size) cmd.read_write = 1; cmd.function = 0; cmd.raw = 0; - cmd.address = 0x10; + cmd.address = SDIO_FBR_BASE(func_num) + SDIO_CCCR_BLKSIZE; cmd.data = (u8)block_size; ret = wilc_sdio_cmd52(wilc, &cmd); if (ret) { - dev_err(&func->dev, "Failed cmd52, set 0x10 data...\n"); - goto fail; + dev_err(&func->dev, "Failed cmd52, set %04x data...\n", + cmd.address); + return ret; } - cmd.address = 0x11; + cmd.address = SDIO_FBR_BASE(func_num) + SDIO_CCCR_BLKSIZE + 1; cmd.data = (u8)(block_size >> 8); ret = wilc_sdio_cmd52(wilc, &cmd); if (ret) { - dev_err(&func->dev, "Failed cmd52, set 0x11 data...\n"); - goto fail; - } - - return 1; -fail: - return 0; -} - -/******************************************** - * - * Function 1 - * - ********************************************/ - -static int sdio_set_func1_block_size(struct wilc *wilc, u32 block_size) -{ - struct sdio_func *func = dev_to_sdio_func(wilc->dev); - struct sdio_cmd52 cmd; - int ret; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0x110; - cmd.data = (u8)block_size; - ret = wilc_sdio_cmd52(wilc, &cmd); - if (ret) { - dev_err(&func->dev, "Failed cmd52, set 0x110 data...\n"); - goto fail; - } - cmd.address = 0x111; - cmd.data = (u8)(block_size >> 8); - ret = wilc_sdio_cmd52(wilc, &cmd); - if (ret) { - dev_err(&func->dev, "Failed cmd52, set 0x111 data...\n"); - goto fail; + dev_err(&func->dev, "Failed cmd52, set %04x data...\n", + cmd.address); + return ret; } - return 1; -fail: return 0; } -/******************************************** - * - * Sdio interfaces - * - ********************************************/ -static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data) -{ - struct sdio_func *func = dev_to_sdio_func(wilc->dev); - int ret; - - cpu_to_le32s(&data); - - if (addr >= 0xf0 && addr <= 0xff) { - struct sdio_cmd52 cmd; - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = addr; - cmd.data = data; - ret = wilc_sdio_cmd52(wilc, &cmd); - if (ret) { - dev_err(&func->dev, - "Failed cmd 52, write reg %08x ...\n", addr); - goto fail; - } - } else { - struct sdio_cmd53 cmd; - /** - * set the AHB address - **/ - if (!sdio_set_func0_csa_address(wilc, addr)) - goto fail; - cmd.read_write = 1; - cmd.function = 0; - cmd.address = 0x10f; - cmd.block_mode = 0; - cmd.increment = 1; - cmd.count = 4; - cmd.buffer = (u8 *)&data; - cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */ - ret = wilc_sdio_cmd53(wilc, &cmd); - if (ret) { - dev_err(&func->dev, - "Failed cmd53, write reg (%08x)...\n", addr); - goto fail; - } - } - - return 1; - -fail: - - return 0; -} - -static int sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) +static int wilc_sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) { struct sdio_func *func = dev_to_sdio_func(wilc->dev); - u32 block_size = g_sdio.block_size; + struct wilc_sdio *sdio_priv = wilc->bus_data; + u32 block_size = sdio_priv->block_size; struct sdio_cmd53 cmd; int nblk, nleft, ret; cmd.read_write = 1; if (addr > 0) { - /** - * has to be word aligned... - **/ - if (size & 0x3) { - size += 4; - size &= ~0x3; - } - /** * func 0 access **/ cmd.function = 0; - cmd.address = 0x10f; + cmd.address = WILC_SDIO_FBR_DATA_REG; } else { - /** - * has to be word aligned... - **/ - if (size & 0x3) { - size += 4; - size &= ~0x3; - } - /** * func 1 access **/ cmd.function = 1; - cmd.address = 0; + cmd.address = WILC_SDIO_F1_DATA_REG; } + size = ALIGN(size, 4); nblk = size / block_size; nleft = size % block_size; + cmd.use_global_buf = false; if (nblk > 0) { cmd.block_mode = 1; cmd.increment = 1; @@ -732,14 +349,15 @@ static int sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) cmd.buffer = buf; cmd.block_size = block_size; if (addr > 0) { - if (!sdio_set_func0_csa_address(wilc, addr)) - goto fail; + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; } ret = wilc_sdio_cmd53(wilc, &cmd); if (ret) { dev_err(&func->dev, "Failed cmd53 [%x], block send...\n", addr); - goto fail; + return ret; } if (addr > 0) addr += nblk * block_size; @@ -755,30 +373,28 @@ static int sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) cmd.block_size = block_size; if (addr > 0) { - if (!sdio_set_func0_csa_address(wilc, addr)) - goto fail; + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; } ret = wilc_sdio_cmd53(wilc, &cmd); if (ret) { dev_err(&func->dev, "Failed cmd53 [%x], bytes send...\n", addr); - goto fail; + return ret; } } - return 1; - -fail: - return 0; } -static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data) +static int wilc_sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data) { struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; int ret; - if (addr >= 0xf0 && addr <= 0xff) { + if (addr >= 0xf0 && addr <= 0xff) { /* only vendor specific registers */ struct sdio_cmd52 cmd; cmd.read_write = 0; @@ -789,82 +405,120 @@ static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data) if (ret) { dev_err(&func->dev, "Failed cmd 52, read reg (%08x) ...\n", addr); - goto fail; + return ret; } *data = cmd.data; } else { struct sdio_cmd53 cmd; - if (!sdio_set_func0_csa_address(wilc, addr)) - goto fail; + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; cmd.read_write = 0; cmd.function = 0; - cmd.address = 0x10f; + cmd.address = WILC_SDIO_FBR_DATA_REG; cmd.block_mode = 0; cmd.increment = 1; - cmd.count = 4; + cmd.count = sizeof(u32); cmd.buffer = (u8 *)data; + cmd.use_global_buf = true; - cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */ + cmd.block_size = sdio_priv->block_size; ret = wilc_sdio_cmd53(wilc, &cmd); if (ret) { dev_err(&func->dev, "Failed cmd53, read reg (%08x)...\n", addr); - goto fail; + return ret; } } le32_to_cpus(data); + return 0; +} - return 1; +/******************************************** + * + * Sdio interfaces + * + ********************************************/ +static int wilc_sdio_write_reg(struct wilc *wilc, u32 addr, u32 data) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + int ret; -fail: + cpu_to_le32s(&data); - return 0; + if (addr >= 0xf0 && addr <= 0xff) { /* only vendor specific registers */ + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = addr; + cmd.data = data; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) + dev_err(&func->dev, + "Failed cmd 52, write reg (%08x) ...\n", addr); + } else { + struct sdio_cmd53 cmd; + + /** + * set the AHB address + **/ + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; + + cmd.read_write = 1; + cmd.function = 0; + cmd.address = WILC_SDIO_FBR_DATA_REG; + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = sizeof(u32); + cmd.buffer = (u8 *)&data; + cmd.use_global_buf = true; + cmd.block_size = sdio_priv->block_size; + ret = wilc_sdio_cmd53(wilc, &cmd); + if (ret) + dev_err(&func->dev, + "Failed cmd53, write reg (%08x)...\n", addr); + } + + return ret; } -static int sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) + +static int wilc_sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) { struct sdio_func *func = dev_to_sdio_func(wilc->dev); - u32 block_size = g_sdio.block_size; + struct wilc_sdio *sdio_priv = wilc->bus_data; + u32 block_size = sdio_priv->block_size; struct sdio_cmd53 cmd; int nblk, nleft, ret; cmd.read_write = 0; if (addr > 0) { - /** - * has to be word aligned... - **/ - if (size & 0x3) { - size += 4; - size &= ~0x3; - } - /** * func 0 access **/ cmd.function = 0; - cmd.address = 0x10f; + cmd.address = WILC_SDIO_FBR_DATA_REG; } else { - /** - * has to be word aligned... - **/ - if (size & 0x3) { - size += 4; - size &= ~0x3; - } - /** * func 1 access **/ cmd.function = 1; - cmd.address = 0; + cmd.address = WILC_SDIO_F1_DATA_REG; } + size = ALIGN(size, 4); nblk = size / block_size; nleft = size % block_size; + cmd.use_global_buf = false; if (nblk > 0) { cmd.block_mode = 1; cmd.increment = 1; @@ -872,14 +526,15 @@ static int sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) cmd.buffer = buf; cmd.block_size = block_size; if (addr > 0) { - if (!sdio_set_func0_csa_address(wilc, addr)) - goto fail; + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; } ret = wilc_sdio_cmd53(wilc, &cmd); if (ret) { dev_err(&func->dev, "Failed cmd53 [%x], block read...\n", addr); - goto fail; + return ret; } if (addr > 0) addr += nblk * block_size; @@ -892,73 +547,158 @@ static int sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) cmd.count = nleft; cmd.buffer = buf; - cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ + cmd.block_size = block_size; if (addr > 0) { - if (!sdio_set_func0_csa_address(wilc, addr)) - goto fail; + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; } ret = wilc_sdio_cmd53(wilc, &cmd); if (ret) { dev_err(&func->dev, "Failed cmd53 [%x], bytes read...\n", addr); - goto fail; + return ret; + } + } + + return 0; +} + +u32 wilc_get_chipid(struct wilc *wilc, bool update) +{ + int ret; + u32 chipid = 0; + u32 rfrevid = 0; + + if (wilc->chipid == 0 || update) { + ret = wilc_sdio_read_reg(wilc, WILC3000_CHIP_ID, + &chipid); + if (!is_wilc3000(chipid)) { + wilc_sdio_read_reg(wilc, WILC_CHIPID, &chipid); + wilc_sdio_read_reg(wilc, WILC_RF_REVISION_ID, + &rfrevid); + + if (!is_wilc1000(chipid)) { + wilc->chipid = 0; + return wilc->chipid; + } + if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */ + if (rfrevid != 0x1) + chipid = WILC_1000_BASE_ID_2A_REV1; + } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */ + if (rfrevid == 0x4) + chipid = WILC_1000_BASE_ID_2B_REV1; + else if (rfrevid != 0x3) + chipid = WILC_1000_BASE_ID_2B_REV2; + } } + wilc->chipid = chipid; } + return wilc->chipid; +} - return 1; +int init_wilc_chip(struct wilc *wilc) +{ + u32 chipid; + u32 reg, ret = 0; + struct sdio_func *func = dev_to_sdio_func(wilc->dev); -fail: + chipid = wilc_get_chipid(wilc,true); + printk("WILC ChipID: %x \n",chipid); - return 0; + ret = wilc_sdio_read_reg(wilc,WILC_CORTUS_RESET_MUX_SEL, ®); + if (ret) { + dev_err(&func->dev, "fail read reg 0x1118\n"); + return ret; + } + reg |= BIT(0); + ret = wilc_sdio_write_reg(wilc,WILC_CORTUS_RESET_MUX_SEL, reg); + if (ret) { + dev_err(&func->dev, "fail write reg 0x1118\n"); + return ret; + } + ret = wilc_sdio_write_reg(wilc, WILC_CORTUS_BOOT_REGISTER, 0x71); + if (ret) { + dev_err(&func->dev, "fail write reg 0xc0000\n"); + return ret; + } + //if (is_wilc3000(chipid)) { + ret = wilc_sdio_read_reg(wilc, 0x207ac, ®); + + ret = wilc_sdio_write_reg(wilc, 0x4f0000,0x71); + if (ret) { + dev_err(&func->dev, "fail write reg 0x4f0000\n"); + return ret; + } + //} + return ret; } + + + + /******************************************** * * Bus interfaces * ********************************************/ -static int sdio_init(struct wilc *wilc, bool resume) +static int wilc_sdio_deinit(struct wilc *wilc) { struct sdio_func *func = dev_to_sdio_func(wilc->dev); + + pm_runtime_put_sync_autosuspend(mmc_dev(func->card->host)); + wilc_wlan_power(wilc, false); + + return 0; +} + +static int wilc_sdio_init(struct wilc *wilc, bool resume) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; struct sdio_cmd52 cmd; int loop, ret; u32 chipid; - static bool init_done; - /** Patch for sdio interrupt latency issue*/ - pm_runtime_get_sync(mmc_dev(func->card->host)); - - if (init_done) - return 1; + dev_info(&func->dev, "SDIO speed: %d\n", + func->card->host->ios.clock); - if (!resume) { - memset(&g_sdio, 0, sizeof(struct wilc_sdio)); + /* Patch for sdio interrupt latency issue */ + ret = pm_runtime_get_sync(mmc_dev(func->card->host)); + if (ret < 0) { + pm_runtime_put_noidle(mmc_dev(func->card->host)); + return ret; } + init_waitqueue_head(&sdio_intr_waitqueue); + sdio_priv->irq_gpio = (wilc->io_type == WILC_HIF_SDIO_GPIO_IRQ); + /** * function 0 csa enable **/ cmd.read_write = 1; cmd.function = 0; cmd.raw = 1; - cmd.address = 0x100; - cmd.data = 0x80; + cmd.address = SDIO_FBR_BASE(1); + cmd.data = SDIO_FBR_ENABLE_CSA; ret = wilc_sdio_cmd52(wilc, &cmd); if (ret) { dev_err(&func->dev, "Fail cmd 52, enable csa...\n"); - goto fail; + goto pm_runtime_put; } /** * function 0 block size **/ - if (!sdio_set_func0_block_size(wilc, WILC_SDIO_BLOCK_SIZE)) { + ret = wilc_sdio_set_block_size(wilc, 0, WILC_SDIO_BLOCK_SIZE); + if (ret) { dev_err(&func->dev, "Fail cmd 52, set func 0 block size...\n"); - goto fail; + goto pm_runtime_put; } - g_sdio.block_size = WILC_SDIO_BLOCK_SIZE; + sdio_priv->block_size = WILC_SDIO_BLOCK_SIZE; /** * enable func1 IO @@ -966,13 +706,13 @@ static int sdio_init(struct wilc *wilc, bool resume) cmd.read_write = 1; cmd.function = 0; cmd.raw = 1; - cmd.address = 0x2; - cmd.data = 0x2; + cmd.address = SDIO_CCCR_IOEx; + cmd.data = WILC_SDIO_CCCR_IO_EN_FUNC1; ret = wilc_sdio_cmd52(wilc, &cmd); if (ret) { dev_err(&func->dev, "Fail cmd 52, set IOE register...\n"); - goto fail; + goto pm_runtime_put; } /** @@ -981,7 +721,7 @@ static int sdio_init(struct wilc *wilc, bool resume) cmd.read_write = 0; cmd.function = 0; cmd.raw = 0; - cmd.address = 0x3; + cmd.address = SDIO_CCCR_IORx; loop = 3; do { cmd.data = 0; @@ -989,23 +729,24 @@ static int sdio_init(struct wilc *wilc, bool resume) if (ret) { dev_err(&func->dev, "Fail cmd 52, get IOR register...\n"); - goto fail; + goto pm_runtime_put; } - if (cmd.data == 0x2) + if (cmd.data == WILC_SDIO_CCCR_IO_EN_FUNC1) break; } while (loop--); if (loop <= 0) { dev_err(&func->dev, "Fail func 1 is not ready...\n"); - goto fail; + goto pm_runtime_put; } /** * func 1 is ready, set func 1 block size **/ - if (!sdio_set_func1_block_size(wilc, WILC_SDIO_BLOCK_SIZE)) { + ret = wilc_sdio_set_block_size(wilc, 1, WILC_SDIO_BLOCK_SIZE); + if (ret) { dev_err(&func->dev, "Fail set func 1 block size...\n"); - goto fail; + goto pm_runtime_put; } /** @@ -1014,35 +755,560 @@ static int sdio_init(struct wilc *wilc, bool resume) cmd.read_write = 1; cmd.function = 0; cmd.raw = 1; - cmd.address = 0x4; - cmd.data = 0x3; + cmd.address = SDIO_CCCR_IENx; + cmd.data = WILC_SDIO_CCCR_IEN_MASTER | WILC_SDIO_CCCR_IEN_FUNC1; ret = wilc_sdio_cmd52(wilc, &cmd); if (ret) { dev_err(&func->dev, "Fail cmd 52, set IEN register...\n"); - goto fail; + goto pm_runtime_put; } /** * make sure can read back chip id correctly **/ if (!resume) { - chipid = wilc_get_chipid(wilc); - if (is_wilc3000(chipid)) { - goto _pass_; + chipid = wilc_get_chipid(wilc, true); + if (is_wilc3000(chipid)) { + wilc->chip = WILC_3000; + } else if (is_wilc1000(chipid)) { + wilc->chip = WILC_1000; + } else { + dev_err(&func->dev, "Unsupported chipid: %x\n", chipid); + goto pm_runtime_put; + } + dev_info(&func->dev, "chipid %08x\n", chipid); + } + + return 0; + +pm_runtime_put: + pm_runtime_put_sync_autosuspend(mmc_dev(func->card->host)); + return ret; +} + +static int wilc_sdio_read_size(struct wilc *wilc, u32 *size) +{ + u32 tmp; + struct sdio_cmd52 cmd; + + /** + * Read DMA count in words + **/ + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC_SDIO_INTERRUPT_DATA_SZ_REG; + cmd.data = 0; + wilc_sdio_cmd52(wilc, &cmd); + tmp = cmd.data; + + cmd.address = WILC_SDIO_INTERRUPT_DATA_SZ_REG + 1; + cmd.data = 0; + wilc_sdio_cmd52(wilc, &cmd); + tmp |= (cmd.data << 8); + + *size = tmp; + return 0; +} + +static int wilc_sdio_read_int(struct wilc *wilc, u32 *int_status) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + u32 tmp; + struct sdio_cmd52 cmd; + u32 irq_flags; + + if (sdio_priv->irq_gpio) { + wilc_sdio_read_size(wilc, &tmp); + + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.data = 0; + if (wilc->chip == WILC_1000) { + cmd.address = WILC1000_SDIO_IRQ_FLAG_REG; + wilc_sdio_cmd52(wilc, &cmd); + irq_flags = cmd.data & 0x1f; + } else { + cmd.address = WILC3000_SDIO_IRQ_FLAG_REG; + wilc_sdio_cmd52(wilc, &cmd); + irq_flags = cmd.data & 0x0f; + } + tmp |= FIELD_PREP(IRG_FLAGS_MASK, cmd.data); + + *int_status = tmp; + } else { + wilc_sdio_read_size(wilc, &tmp); + cmd.read_write = 0; + cmd.function = 1; + cmd.address = WILC_SDIO_EXT_IRQ_FLAG_REG; + cmd.data = 0; + wilc_sdio_cmd52(wilc, &cmd); + + irq_flags = cmd.data; + tmp |= FIELD_PREP(IRG_FLAGS_MASK, cmd.data); + + if (FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags)) { + dev_err(&func->dev, "Unexpected interrupt (1) int=%lx\n", + FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags)); + } + + *int_status = tmp; + } + + return 0; +} + +static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + int ret; + u32 reg = 0; + + if (wilc->chip == WILC_1000) { + if (sdio_priv->irq_gpio) + reg = val & (BIT(MAX_NUM_INT) - 1); + + /* select VMM table 0 */ + if (val & SEL_VMM_TBL0) + reg |= BIT(5); + /* select VMM table 1 */ + if (val & SEL_VMM_TBL1) + reg |= BIT(6); + /* enable VMM */ + if (val & EN_VMM) + reg |= BIT(7); + if (reg) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC1000_SDIO_IRQ_CLEAR_FLAG_REG; + cmd.data = reg; + + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set 0xf8 data (%d) ...\n", + __LINE__); + return ret; } - else if (is_wilc1000(chipid)) { - goto _pass_; + } + } else { + if (sdio_priv->irq_gpio) { + reg = val & (BIT(MAX_NUM_INT) - 1); + if (reg) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC3000_SDIO_IRQ_CLEAR_FLAG_REG; + cmd.data = reg; + + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set 0xfe data (%d) ...\n", + __LINE__); + return ret; + } + } + } + reg = 0; + /* select VMM table 0 */ + if (val & SEL_VMM_TBL0) + reg |= BIT(0); + /* select VMM table 1 */ + if (val & SEL_VMM_TBL1) + reg |= BIT(1); + /* enable VMM */ + if (val & EN_VMM) + reg |= BIT(2); + + if (reg) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC3000_SDIO_VMM_TBL_CTRL_REG; + cmd.data = reg; + + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set 0xf6 data (%d) ...\n", + __LINE__); + return ret; } - else { - dev_err(&func->dev, "Fail cmd read chip id...\n"); - goto fail; } } -_pass_: - init_done = 1; - return 1; -fail: + return 0; +} + +static int wilc_sdio_sync_ext(struct wilc *wilc, int nint) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + u32 reg; + int ret, i; + + if (nint > MAX_NUM_INT) { + dev_err(&func->dev, "Too many interrupts %d\n", nint); + return -EINVAL; + } + +/* WILC3000 only. Was removed in WILC1000 on revision 6200. + * Might be related to suspend/resume + */ + if (wilc->chip == WILC_3000) { + /** + * Disable power sequencer + **/ + if (wilc_sdio_read_reg(wilc, WILC_MISC, ®)) { + dev_err(&func->dev, "Failed read misc reg\n"); + return -EINVAL; + } + reg &= ~BIT(8); + if (wilc_sdio_write_reg(wilc, WILC_MISC, reg)) { + dev_err(&func->dev, "Failed write misc reg\n"); + return -EINVAL; + } + } + + if (sdio_priv->irq_gpio) { + /** + * interrupt pin mux select + **/ + ret = wilc_sdio_read_reg(wilc, WILC_PIN_MUX_0, ®); + if (ret) { + dev_err(&func->dev, "Failed read reg (%08x)...\n", + WILC_PIN_MUX_0); + return ret; + } + reg |= BIT(8); + ret = wilc_sdio_write_reg(wilc, WILC_PIN_MUX_0, reg); + if (ret) { + dev_err(&func->dev, "Failed write reg (%08x)...\n", + WILC_PIN_MUX_0); + return ret; + } + + /** + * interrupt enable + **/ + ret = wilc_sdio_read_reg(wilc, WILC_INTR_ENABLE, ®); + if (ret) { + dev_err(&func->dev, "Failed read reg (%08x)...\n", + WILC_INTR_ENABLE); + return ret; + } + + for (i = 0; (i < 5) && (nint > 0); i++, nint--) + reg |= BIT((27 + i)); + ret = wilc_sdio_write_reg(wilc, WILC_INTR_ENABLE, reg); + if (ret) { + dev_err(&func->dev, "Failed write reg (%08x)...\n", + WILC_INTR_ENABLE); + return ret; + } + if (nint) { + ret = wilc_sdio_read_reg(wilc, WILC_INTR2_ENABLE, ®); + if (ret) { + dev_err(&func->dev, + "Failed read reg (%08x)...\n", + WILC_INTR2_ENABLE); + return ret; + } + + for (i = 0; (i < 3) && (nint > 0); i++, nint--) + reg |= BIT(i); + ret = wilc_sdio_write_reg(wilc, WILC_INTR2_ENABLE, reg); + if (ret) { + dev_err(&func->dev, + "Failed write reg (%08x)...\n", + WILC_INTR2_ENABLE); + return ret; + } + } + } return 0; } + +/**********ioctl */ + + +static int my_open(struct inode *i, struct file *f) +{ + return 0; +} + +static int my_close(struct inode *i, struct file *f) +{ + return 0; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) +static int my_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) +#else +static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg) +#endif +{ + cmd_hdr dat; + block_cmd_hdr b_dat; + unsigned int val32=0; + + switch (cmd) + { + case CMD_READ_REG: + if (copy_from_user(&dat, (cmd_hdr *)arg, sizeof(cmd_hdr))) + { + return -EACCES; + } + wilc_sdio_read_reg(wilc, dat.addr, &val32); + dat.val = (int) val32; + if (copy_to_user((cmd_hdr *)arg, &dat, sizeof(cmd_hdr))) + { + return -EACCES; + } + break; + case CMD_WRITE_REG: + if (copy_from_user(&dat, (cmd_hdr *)arg, sizeof(cmd_hdr))) + { + return -EACCES; + } + wilc_sdio_write_reg(wilc, dat.addr, dat.val); + break; + case CMD_WRITE_BLOCK_REG: + if (copy_from_user(&b_dat, (block_cmd_hdr *)arg, sizeof(block_cmd_hdr))) + { + return -EACCES; + } + wilc_sdio_write(wilc, b_dat.addr, b_dat.b_buffer, (b_dat.cmd>>16) & 0xFFFF); + break; + case CMD_READ_BLOCK_REG: + if (copy_from_user(&b_dat, (block_cmd_hdr *)arg, sizeof(block_cmd_hdr))) + { + return -EACCES; + } + wilc_sdio_read(wilc, b_dat.addr, b_dat.b_buffer, (b_dat.cmd>>16) & 0xFFFF); + if (copy_to_user((block_cmd_hdr *)arg, &b_dat, sizeof(block_cmd_hdr))) + { + return -EACCES; + } + break; + default: + return -EINVAL; + } + return 0; +} + + +static struct file_operations query_fops = +{ + .owner = THIS_MODULE, + .open = my_open, + .release = my_close, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) + .ioctl = my_ioctl +#else + .unlocked_ioctl = my_ioctl +#endif +}; + +static int query_ioctl_init(void) +{ + int ret; + struct device *dev_ret; + + if ((ret = alloc_chrdev_region(&dev, FIRST_MINOR, MINOR_CNT, "query_ioctl")) < 0) + { + printk("Failed alloc_chrdev %s %d \n",__func__,__LINE__); + return ret; + } + + cdev_init(&c_dev, &query_fops); + c_dev.owner = THIS_MODULE; + + if ((ret = cdev_add(&c_dev, dev, MINOR_CNT)) < 0) + { + printk("Failed cdev_add %s %d \n",__func__,__LINE__); + return ret; + } + + if (IS_ERR(cl = class_create(THIS_MODULE,"wilcs_sdio"))) + { + cdev_del(&c_dev); + unregister_chrdev_region(dev, MINOR_CNT); + printk("Failed class_create %s %d \n",__func__,__LINE__); + return PTR_ERR(cl); + } + if (IS_ERR(dev_ret = device_create(cl, NULL, dev, NULL, "query"))) + { + class_destroy(cl); + cdev_del(&c_dev); + unregister_chrdev_region(dev, MINOR_CNT); + printk("Failed device_create %s %d",__func__,__LINE__); + return PTR_ERR(dev_ret); + } + + return 0; +} + +static void query_ioctl_exit(void) +{ + device_destroy(cl, dev); + class_destroy(cl); + cdev_del(&c_dev); + unregister_chrdev_region(dev, MINOR_CNT); +} + +static int wilc_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret, io_type; + static bool init_power; + struct wilc_sdio *sdio_priv; + struct device_node *np; + int irq_num; + + printk("Updated DRiver ###### \n"); + wilc = kzalloc(sizeof(*wilc), GFP_KERNEL); + if (!wilc) + return -ENOMEM; + + sdio_priv = kzalloc(sizeof(*sdio_priv), GFP_KERNEL); + if (!sdio_priv) { + ret = -ENOMEM; + goto free; + } + + sdio_priv->cmd53_buf = kzalloc(sizeof(u32), GFP_KERNEL); + if (!sdio_priv->cmd53_buf) { + ret = -ENOMEM; + goto free; + } + + if( query_ioctl_init() != 0 ) + { + printk("ioctl init error\n"); + } + + + sdio_set_drvdata(func, wilc); + wilc->bus_data = sdio_priv; + wilc->dev = &func->dev; + wilc->dt_dev = &func->card->dev; + sdio_priv->wl = wilc; + wilc_sdio_init(wilc,false); + init_wilc_chip(wilc); + +#if 0 + // wilc_of_parse_power_pins(wilc); + // + // + /* + * Some WILC SDIO setups needs a SD power sequence driver to be able + * to power the WILC devices before reaching this function. For those + * devices the power sequence driver already provides reset-gpios + * and chip_en-gpios. + */ + np = of_parse_phandle(func->card->host->parent->of_node, "mmc-pwrseq", + 0); + if (np && of_device_is_available(np)) { + init_power = 1; + of_node_put(np); + } else { + ret = wilc_of_parse_power_pins(wilc); + //if (ret) + // goto disable_rtc_clk; + } +#endif + + if (!init_power) { + wilc_wlan_power(wilc, false); + init_power = 1; + wilc_wlan_power(wilc, true); + } + + dev_info(&func->dev, "WILC SDIO Probe success \n"); + return 0; +free: + if (wilc) + kfree(wilc); + if (sdio_priv) + kfree(sdio_priv); + + return ret; +} + +static void wilc_sdio_remove(struct sdio_func *func) +{ + printk("wilc_bus_remove SDIO card removed \n"); + query_ioctl_exit(); +} + +static int wilc_sdio_reset(struct wilc *wilc) +{ + struct sdio_cmd52 cmd; + int ret; + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + + dev_info(&func->dev, "De Init SDIO\n"); + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = SDIO_CCCR_ABORT; + cmd.data = WILC_SDIO_CCCR_ABORT_RESET; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, "Fail cmd 52, reset cmd ...\n"); + return ret; + } + return 0; +} + +static int wilc_sdio_suspend(struct device *dev) +{ + return 0; +} + +static int wilc_sdio_resume(struct device *dev) +{ + return 0; +} + +static const struct of_device_id wilc_of_match[] = { + { .compatible = "microchip,wilc1000", }, + { .compatible = "microchip,wilc3000", }, + { /* sentinel */} +}; +MODULE_DEVICE_TABLE(of, wilc_of_match); + +static const struct dev_pm_ops wilc_sdio_pm_ops = { + .suspend = wilc_sdio_suspend, + .resume = wilc_sdio_resume, +}; + +static struct sdio_driver wilc_sdio_driver = { + .name = SDIO_MODALIAS, + .id_table = wilc_sdio_ids, + .probe = wilc_sdio_probe, + .remove = wilc_sdio_remove, + .drv = { + .pm = &wilc_sdio_pm_ops, + .of_match_table = wilc_of_match, + }, +}; +module_driver(wilc_sdio_driver, + sdio_register_driver, + sdio_unregister_driver); +MODULE_DESCRIPTION("Atmel WILC1000 SDIO wireless driver"); +MODULE_LICENSE("GPL");