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/mmc/sdio_func.h>
9c83e2a6eSAjay Singh #include <linux/mmc/sdio_ids.h>
105625f965SAjay Singh #include <linux/mmc/host.h>
115625f965SAjay Singh #include <linux/mmc/sdio.h>
125625f965SAjay Singh #include <linux/of_irq.h>
135625f965SAjay Singh 
145625f965SAjay Singh #include "netdev.h"
155625f965SAjay Singh #include "cfg80211.h"
165625f965SAjay Singh 
175625f965SAjay Singh #define SDIO_MODALIAS "wilc1000_sdio"
185625f965SAjay Singh 
195625f965SAjay Singh static const struct sdio_device_id wilc_sdio_ids[] = {
20c83e2a6eSAjay Singh 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MICROCHIP_WILC, SDIO_DEVICE_ID_MICROCHIP_WILC1000) },
215625f965SAjay Singh 	{ },
225625f965SAjay Singh };
23*57d545b5SMichael Walle MODULE_DEVICE_TABLE(sdio, wilc_sdio_ids);
245625f965SAjay Singh 
255625f965SAjay Singh #define WILC_SDIO_BLOCK_SIZE 512
265625f965SAjay Singh 
275625f965SAjay Singh struct wilc_sdio {
285625f965SAjay Singh 	bool irq_gpio;
295625f965SAjay Singh 	u32 block_size;
3039d0f1b0SAjay Singh 	bool isinit;
315625f965SAjay Singh 	int has_thrpt_enh3;
3240b717bfSAjay.Kathat@microchip.com 	u8 *cmd53_buf;
335625f965SAjay Singh };
345625f965SAjay Singh 
355625f965SAjay Singh struct sdio_cmd52 {
365625f965SAjay Singh 	u32 read_write:		1;
375625f965SAjay Singh 	u32 function:		3;
385625f965SAjay Singh 	u32 raw:		1;
395625f965SAjay Singh 	u32 address:		17;
405625f965SAjay Singh 	u32 data:		8;
415625f965SAjay Singh };
425625f965SAjay Singh 
435625f965SAjay Singh struct sdio_cmd53 {
445625f965SAjay Singh 	u32 read_write:		1;
455625f965SAjay Singh 	u32 function:		3;
465625f965SAjay Singh 	u32 block_mode:		1;
475625f965SAjay Singh 	u32 increment:		1;
485625f965SAjay Singh 	u32 address:		17;
495625f965SAjay Singh 	u32 count:		9;
505625f965SAjay Singh 	u8 *buffer;
515625f965SAjay Singh 	u32 block_size;
5240b717bfSAjay.Kathat@microchip.com 	bool use_global_buf;
535625f965SAjay Singh };
545625f965SAjay Singh 
555625f965SAjay Singh static const struct wilc_hif_func wilc_hif_sdio;
565625f965SAjay Singh 
575625f965SAjay Singh static void wilc_sdio_interrupt(struct sdio_func *func)
585625f965SAjay Singh {
595625f965SAjay Singh 	sdio_release_host(func);
605625f965SAjay Singh 	wilc_handle_isr(sdio_get_drvdata(func));
615625f965SAjay Singh 	sdio_claim_host(func);
625625f965SAjay Singh }
635625f965SAjay Singh 
645625f965SAjay Singh static int wilc_sdio_cmd52(struct wilc *wilc, struct sdio_cmd52 *cmd)
655625f965SAjay Singh {
665625f965SAjay Singh 	struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev);
675625f965SAjay Singh 	int ret;
685625f965SAjay Singh 	u8 data;
695625f965SAjay Singh 
705625f965SAjay Singh 	sdio_claim_host(func);
715625f965SAjay Singh 
725625f965SAjay Singh 	func->num = cmd->function;
735625f965SAjay Singh 	if (cmd->read_write) {  /* write */
745625f965SAjay Singh 		if (cmd->raw) {
755625f965SAjay Singh 			sdio_writeb(func, cmd->data, cmd->address, &ret);
765625f965SAjay Singh 			data = sdio_readb(func, cmd->address, &ret);
775625f965SAjay Singh 			cmd->data = data;
785625f965SAjay Singh 		} else {
795625f965SAjay Singh 			sdio_writeb(func, cmd->data, cmd->address, &ret);
805625f965SAjay Singh 		}
815625f965SAjay Singh 	} else {        /* read */
825625f965SAjay Singh 		data = sdio_readb(func, cmd->address, &ret);
835625f965SAjay Singh 		cmd->data = data;
845625f965SAjay Singh 	}
855625f965SAjay Singh 
865625f965SAjay Singh 	sdio_release_host(func);
875625f965SAjay Singh 
885625f965SAjay Singh 	if (ret)
895625f965SAjay Singh 		dev_err(&func->dev, "%s..failed, err(%d)\n", __func__, ret);
905625f965SAjay Singh 	return ret;
915625f965SAjay Singh }
925625f965SAjay Singh 
935625f965SAjay Singh static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd)
945625f965SAjay Singh {
955625f965SAjay Singh 	struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev);
965625f965SAjay Singh 	int size, ret;
9740b717bfSAjay.Kathat@microchip.com 	struct wilc_sdio *sdio_priv = wilc->bus_data;
9840b717bfSAjay.Kathat@microchip.com 	u8 *buf = cmd->buffer;
995625f965SAjay Singh 
1005625f965SAjay Singh 	sdio_claim_host(func);
1015625f965SAjay Singh 
1025625f965SAjay Singh 	func->num = cmd->function;
1035625f965SAjay Singh 	func->cur_blksize = cmd->block_size;
1045625f965SAjay Singh 	if (cmd->block_mode)
1055625f965SAjay Singh 		size = cmd->count * cmd->block_size;
1065625f965SAjay Singh 	else
1075625f965SAjay Singh 		size = cmd->count;
1085625f965SAjay Singh 
10940b717bfSAjay.Kathat@microchip.com 	if (cmd->use_global_buf) {
11040b717bfSAjay.Kathat@microchip.com 		if (size > sizeof(u32))
11140b717bfSAjay.Kathat@microchip.com 			return -EINVAL;
11240b717bfSAjay.Kathat@microchip.com 
11340b717bfSAjay.Kathat@microchip.com 		buf = sdio_priv->cmd53_buf;
11440b717bfSAjay.Kathat@microchip.com 	}
11540b717bfSAjay.Kathat@microchip.com 
1165625f965SAjay Singh 	if (cmd->read_write) {  /* write */
11740b717bfSAjay.Kathat@microchip.com 		if (cmd->use_global_buf)
11840b717bfSAjay.Kathat@microchip.com 			memcpy(buf, cmd->buffer, size);
11940b717bfSAjay.Kathat@microchip.com 
12040b717bfSAjay.Kathat@microchip.com 		ret = sdio_memcpy_toio(func, cmd->address, buf, size);
1215625f965SAjay Singh 	} else {        /* read */
12240b717bfSAjay.Kathat@microchip.com 		ret = sdio_memcpy_fromio(func, buf, cmd->address, size);
12340b717bfSAjay.Kathat@microchip.com 
12440b717bfSAjay.Kathat@microchip.com 		if (cmd->use_global_buf)
12540b717bfSAjay.Kathat@microchip.com 			memcpy(cmd->buffer, buf, size);
1265625f965SAjay Singh 	}
1275625f965SAjay Singh 
1285625f965SAjay Singh 	sdio_release_host(func);
1295625f965SAjay Singh 
1305625f965SAjay Singh 	if (ret)
1315625f965SAjay Singh 		dev_err(&func->dev, "%s..failed, err(%d)\n", __func__,  ret);
1325625f965SAjay Singh 
1335625f965SAjay Singh 	return ret;
1345625f965SAjay Singh }
1355625f965SAjay Singh 
1365625f965SAjay Singh static int wilc_sdio_probe(struct sdio_func *func,
1375625f965SAjay Singh 			   const struct sdio_device_id *id)
1385625f965SAjay Singh {
1395625f965SAjay Singh 	struct wilc *wilc;
1405625f965SAjay Singh 	int ret;
1415625f965SAjay Singh 	struct wilc_sdio *sdio_priv;
1425625f965SAjay Singh 
1435625f965SAjay Singh 	sdio_priv = kzalloc(sizeof(*sdio_priv), GFP_KERNEL);
1445625f965SAjay Singh 	if (!sdio_priv)
1455625f965SAjay Singh 		return -ENOMEM;
1465625f965SAjay Singh 
14740b717bfSAjay.Kathat@microchip.com 	sdio_priv->cmd53_buf = kzalloc(sizeof(u32), GFP_KERNEL);
14840b717bfSAjay.Kathat@microchip.com 	if (!sdio_priv->cmd53_buf) {
14940b717bfSAjay.Kathat@microchip.com 		ret = -ENOMEM;
15040b717bfSAjay.Kathat@microchip.com 		goto free;
15140b717bfSAjay.Kathat@microchip.com 	}
15240b717bfSAjay.Kathat@microchip.com 
1535625f965SAjay Singh 	ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO,
1545625f965SAjay Singh 				 &wilc_hif_sdio);
155dc8b338fSClaudiu Beznea 	if (ret)
156dc8b338fSClaudiu Beznea 		goto free;
1575625f965SAjay Singh 
1585625f965SAjay Singh 	if (IS_ENABLED(CONFIG_WILC1000_HW_OOB_INTR)) {
1595625f965SAjay Singh 		struct device_node *np = func->card->dev.of_node;
1605625f965SAjay Singh 		int irq_num = of_irq_get(np, 0);
1615625f965SAjay Singh 
1625625f965SAjay Singh 		if (irq_num > 0) {
1635625f965SAjay Singh 			wilc->dev_irq_num = irq_num;
1645625f965SAjay Singh 			sdio_priv->irq_gpio = true;
1655625f965SAjay Singh 		}
1665625f965SAjay Singh 	}
1675625f965SAjay Singh 
1685625f965SAjay Singh 	sdio_set_drvdata(func, wilc);
1695625f965SAjay Singh 	wilc->bus_data = sdio_priv;
1705625f965SAjay Singh 	wilc->dev = &func->dev;
1715625f965SAjay Singh 
1721d89fd1aSClaudiu Beznea 	wilc->rtc_clk = devm_clk_get_optional(&func->card->dev, "rtc");
1731d89fd1aSClaudiu Beznea 	if (IS_ERR(wilc->rtc_clk)) {
1741d89fd1aSClaudiu Beznea 		ret = PTR_ERR(wilc->rtc_clk);
175f36a0ee5SClaudiu Beznea 		goto dispose_irq;
1761d89fd1aSClaudiu Beznea 	}
1775625f965SAjay Singh 	clk_prepare_enable(wilc->rtc_clk);
1785625f965SAjay Singh 
1795625f965SAjay Singh 	dev_info(&func->dev, "Driver Initializing success\n");
1805625f965SAjay Singh 	return 0;
181dc8b338fSClaudiu Beznea 
182f36a0ee5SClaudiu Beznea dispose_irq:
183f36a0ee5SClaudiu Beznea 	irq_dispose_mapping(wilc->dev_irq_num);
184dc8b338fSClaudiu Beznea 	wilc_netdev_cleanup(wilc);
185dc8b338fSClaudiu Beznea free:
18640b717bfSAjay.Kathat@microchip.com 	kfree(sdio_priv->cmd53_buf);
187dc8b338fSClaudiu Beznea 	kfree(sdio_priv);
188dc8b338fSClaudiu Beznea 	return ret;
1895625f965SAjay Singh }
1905625f965SAjay Singh 
1915625f965SAjay Singh static void wilc_sdio_remove(struct sdio_func *func)
1925625f965SAjay Singh {
1935625f965SAjay Singh 	struct wilc *wilc = sdio_get_drvdata(func);
1944894edacSDan Carpenter 	struct wilc_sdio *sdio_priv = wilc->bus_data;
1955625f965SAjay Singh 
1965625f965SAjay Singh 	clk_disable_unprepare(wilc->rtc_clk);
1975625f965SAjay Singh 	wilc_netdev_cleanup(wilc);
19840b717bfSAjay.Kathat@microchip.com 	kfree(sdio_priv->cmd53_buf);
1994894edacSDan Carpenter 	kfree(sdio_priv);
2005625f965SAjay Singh }
2015625f965SAjay Singh 
2025625f965SAjay Singh static int wilc_sdio_reset(struct wilc *wilc)
2035625f965SAjay Singh {
2045625f965SAjay Singh 	struct sdio_cmd52 cmd;
2055625f965SAjay Singh 	int ret;
2065625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
2075625f965SAjay Singh 
2085625f965SAjay Singh 	cmd.read_write = 1;
2095625f965SAjay Singh 	cmd.function = 0;
2105625f965SAjay Singh 	cmd.raw = 0;
2115625f965SAjay Singh 	cmd.address = SDIO_CCCR_ABORT;
2125625f965SAjay Singh 	cmd.data = WILC_SDIO_CCCR_ABORT_RESET;
2135625f965SAjay Singh 	ret = wilc_sdio_cmd52(wilc, &cmd);
2145625f965SAjay Singh 	if (ret) {
2155625f965SAjay Singh 		dev_err(&func->dev, "Fail cmd 52, reset cmd ...\n");
2165625f965SAjay Singh 		return ret;
2175625f965SAjay Singh 	}
2185625f965SAjay Singh 	return 0;
2195625f965SAjay Singh }
2205625f965SAjay Singh 
22139d0f1b0SAjay Singh static bool wilc_sdio_is_init(struct wilc *wilc)
22239d0f1b0SAjay Singh {
22339d0f1b0SAjay Singh 	struct wilc_sdio *sdio_priv = wilc->bus_data;
22439d0f1b0SAjay Singh 
22539d0f1b0SAjay Singh 	return sdio_priv->isinit;
22639d0f1b0SAjay Singh }
22739d0f1b0SAjay Singh 
2285625f965SAjay Singh static int wilc_sdio_suspend(struct device *dev)
2295625f965SAjay Singh {
2305625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(dev);
2315625f965SAjay Singh 	struct wilc *wilc = sdio_get_drvdata(func);
2325625f965SAjay Singh 	int ret;
2335625f965SAjay Singh 
2345625f965SAjay Singh 	dev_info(dev, "sdio suspend\n");
2355625f965SAjay Singh 	chip_wakeup(wilc);
2365625f965SAjay Singh 
2375625f965SAjay Singh 	if (!IS_ERR(wilc->rtc_clk))
2385625f965SAjay Singh 		clk_disable_unprepare(wilc->rtc_clk);
2395625f965SAjay Singh 
2405625f965SAjay Singh 	if (wilc->suspend_event) {
2415625f965SAjay Singh 		host_sleep_notify(wilc);
2425625f965SAjay Singh 		chip_allow_sleep(wilc);
2435625f965SAjay Singh 	}
2445625f965SAjay Singh 
2455625f965SAjay Singh 	ret = wilc_sdio_reset(wilc);
2465625f965SAjay Singh 	if (ret) {
2475625f965SAjay Singh 		dev_err(&func->dev, "Fail reset sdio\n");
2485625f965SAjay Singh 		return ret;
2495625f965SAjay Singh 	}
2505625f965SAjay Singh 	sdio_claim_host(func);
2515625f965SAjay Singh 
2525625f965SAjay Singh 	return 0;
2535625f965SAjay Singh }
2545625f965SAjay Singh 
2555625f965SAjay Singh static int wilc_sdio_enable_interrupt(struct wilc *dev)
2565625f965SAjay Singh {
2575625f965SAjay Singh 	struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev);
2585625f965SAjay Singh 	int ret = 0;
2595625f965SAjay Singh 
2605625f965SAjay Singh 	sdio_claim_host(func);
2615625f965SAjay Singh 	ret = sdio_claim_irq(func, wilc_sdio_interrupt);
2625625f965SAjay Singh 	sdio_release_host(func);
2635625f965SAjay Singh 
2645625f965SAjay Singh 	if (ret < 0) {
2655625f965SAjay Singh 		dev_err(&func->dev, "can't claim sdio_irq, err(%d)\n", ret);
2665625f965SAjay Singh 		ret = -EIO;
2675625f965SAjay Singh 	}
2685625f965SAjay Singh 	return ret;
2695625f965SAjay Singh }
2705625f965SAjay Singh 
2715625f965SAjay Singh static void wilc_sdio_disable_interrupt(struct wilc *dev)
2725625f965SAjay Singh {
2735625f965SAjay Singh 	struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev);
2745625f965SAjay Singh 	int ret;
2755625f965SAjay Singh 
2765625f965SAjay Singh 	sdio_claim_host(func);
2775625f965SAjay Singh 	ret = sdio_release_irq(func);
2785625f965SAjay Singh 	if (ret < 0)
2795625f965SAjay Singh 		dev_err(&func->dev, "can't release sdio_irq, err(%d)\n", ret);
2805625f965SAjay Singh 	sdio_release_host(func);
2815625f965SAjay Singh }
2825625f965SAjay Singh 
2835625f965SAjay Singh /********************************************
2845625f965SAjay Singh  *
2855625f965SAjay Singh  *      Function 0
2865625f965SAjay Singh  *
2875625f965SAjay Singh  ********************************************/
2885625f965SAjay Singh 
2895625f965SAjay Singh static int wilc_sdio_set_func0_csa_address(struct wilc *wilc, u32 adr)
2905625f965SAjay Singh {
2915625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
2925625f965SAjay Singh 	struct sdio_cmd52 cmd;
2935625f965SAjay Singh 	int ret;
2945625f965SAjay Singh 
2955625f965SAjay Singh 	/**
2965625f965SAjay Singh 	 *      Review: BIG ENDIAN
2975625f965SAjay Singh 	 **/
2985625f965SAjay Singh 	cmd.read_write = 1;
2995625f965SAjay Singh 	cmd.function = 0;
3005625f965SAjay Singh 	cmd.raw = 0;
3015625f965SAjay Singh 	cmd.address = WILC_SDIO_FBR_CSA_REG;
3025625f965SAjay Singh 	cmd.data = (u8)adr;
3035625f965SAjay Singh 	ret = wilc_sdio_cmd52(wilc, &cmd);
3045625f965SAjay Singh 	if (ret) {
3055625f965SAjay Singh 		dev_err(&func->dev, "Failed cmd52, set %04x data...\n",
3065625f965SAjay Singh 			cmd.address);
3075625f965SAjay Singh 		return ret;
3085625f965SAjay Singh 	}
3095625f965SAjay Singh 
3105625f965SAjay Singh 	cmd.address = WILC_SDIO_FBR_CSA_REG + 1;
3115625f965SAjay Singh 	cmd.data = (u8)(adr >> 8);
3125625f965SAjay Singh 	ret = wilc_sdio_cmd52(wilc, &cmd);
3135625f965SAjay Singh 	if (ret) {
3145625f965SAjay Singh 		dev_err(&func->dev, "Failed cmd52, set %04x data...\n",
3155625f965SAjay Singh 			cmd.address);
3165625f965SAjay Singh 		return ret;
3175625f965SAjay Singh 	}
3185625f965SAjay Singh 
3195625f965SAjay Singh 	cmd.address = WILC_SDIO_FBR_CSA_REG + 2;
3205625f965SAjay Singh 	cmd.data = (u8)(adr >> 16);
3215625f965SAjay Singh 	ret = wilc_sdio_cmd52(wilc, &cmd);
3225625f965SAjay Singh 	if (ret) {
3235625f965SAjay Singh 		dev_err(&func->dev, "Failed cmd52, set %04x data...\n",
3245625f965SAjay Singh 			cmd.address);
3255625f965SAjay Singh 		return ret;
3265625f965SAjay Singh 	}
3275625f965SAjay Singh 
3285625f965SAjay Singh 	return 0;
3295625f965SAjay Singh }
3305625f965SAjay Singh 
3315625f965SAjay Singh static int wilc_sdio_set_block_size(struct wilc *wilc, u8 func_num,
3325625f965SAjay Singh 				    u32 block_size)
3335625f965SAjay Singh {
3345625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
3355625f965SAjay Singh 	struct sdio_cmd52 cmd;
3365625f965SAjay Singh 	int ret;
3375625f965SAjay Singh 
3385625f965SAjay Singh 	cmd.read_write = 1;
3395625f965SAjay Singh 	cmd.function = 0;
3405625f965SAjay Singh 	cmd.raw = 0;
3415625f965SAjay Singh 	cmd.address = SDIO_FBR_BASE(func_num) + SDIO_CCCR_BLKSIZE;
3425625f965SAjay Singh 	cmd.data = (u8)block_size;
3435625f965SAjay Singh 	ret = wilc_sdio_cmd52(wilc, &cmd);
3445625f965SAjay Singh 	if (ret) {
3455625f965SAjay Singh 		dev_err(&func->dev, "Failed cmd52, set %04x data...\n",
3465625f965SAjay Singh 			cmd.address);
3475625f965SAjay Singh 		return ret;
3485625f965SAjay Singh 	}
3495625f965SAjay Singh 
3505625f965SAjay Singh 	cmd.address = SDIO_FBR_BASE(func_num) + SDIO_CCCR_BLKSIZE +  1;
3515625f965SAjay Singh 	cmd.data = (u8)(block_size >> 8);
3525625f965SAjay Singh 	ret = wilc_sdio_cmd52(wilc, &cmd);
3535625f965SAjay Singh 	if (ret) {
3545625f965SAjay Singh 		dev_err(&func->dev, "Failed cmd52, set %04x data...\n",
3555625f965SAjay Singh 			cmd.address);
3565625f965SAjay Singh 		return ret;
3575625f965SAjay Singh 	}
3585625f965SAjay Singh 
3595625f965SAjay Singh 	return 0;
3605625f965SAjay Singh }
3615625f965SAjay Singh 
3625625f965SAjay Singh /********************************************
3635625f965SAjay Singh  *
3645625f965SAjay Singh  *      Sdio interfaces
3655625f965SAjay Singh  *
3665625f965SAjay Singh  ********************************************/
3675625f965SAjay Singh static int wilc_sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
3685625f965SAjay Singh {
3695625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
3705625f965SAjay Singh 	struct wilc_sdio *sdio_priv = wilc->bus_data;
3715625f965SAjay Singh 	int ret;
3725625f965SAjay Singh 
3735625f965SAjay Singh 	cpu_to_le32s(&data);
3745625f965SAjay Singh 
3755625f965SAjay Singh 	if (addr >= 0xf0 && addr <= 0xff) { /* only vendor specific registers */
3765625f965SAjay Singh 		struct sdio_cmd52 cmd;
3775625f965SAjay Singh 
3785625f965SAjay Singh 		cmd.read_write = 1;
3795625f965SAjay Singh 		cmd.function = 0;
3805625f965SAjay Singh 		cmd.raw = 0;
3815625f965SAjay Singh 		cmd.address = addr;
3825625f965SAjay Singh 		cmd.data = data;
3835625f965SAjay Singh 		ret = wilc_sdio_cmd52(wilc, &cmd);
3845625f965SAjay Singh 		if (ret)
3855625f965SAjay Singh 			dev_err(&func->dev,
3865625f965SAjay Singh 				"Failed cmd 52, read reg (%08x) ...\n", addr);
3875625f965SAjay Singh 	} else {
3885625f965SAjay Singh 		struct sdio_cmd53 cmd;
3895625f965SAjay Singh 
3905625f965SAjay Singh 		/**
3915625f965SAjay Singh 		 *      set the AHB address
3925625f965SAjay Singh 		 **/
3935625f965SAjay Singh 		ret = wilc_sdio_set_func0_csa_address(wilc, addr);
3945625f965SAjay Singh 		if (ret)
3955625f965SAjay Singh 			return ret;
3965625f965SAjay Singh 
3975625f965SAjay Singh 		cmd.read_write = 1;
3985625f965SAjay Singh 		cmd.function = 0;
3995625f965SAjay Singh 		cmd.address = WILC_SDIO_FBR_DATA_REG;
4005625f965SAjay Singh 		cmd.block_mode = 0;
4015625f965SAjay Singh 		cmd.increment = 1;
40240b717bfSAjay.Kathat@microchip.com 		cmd.count = sizeof(u32);
4035625f965SAjay Singh 		cmd.buffer = (u8 *)&data;
40440b717bfSAjay.Kathat@microchip.com 		cmd.use_global_buf = true;
4055625f965SAjay Singh 		cmd.block_size = sdio_priv->block_size;
4065625f965SAjay Singh 		ret = wilc_sdio_cmd53(wilc, &cmd);
4075625f965SAjay Singh 		if (ret)
4085625f965SAjay Singh 			dev_err(&func->dev,
4095625f965SAjay Singh 				"Failed cmd53, write reg (%08x)...\n", addr);
4105625f965SAjay Singh 	}
4115625f965SAjay Singh 
4125625f965SAjay Singh 	return ret;
4135625f965SAjay Singh }
4145625f965SAjay Singh 
4155625f965SAjay Singh static int wilc_sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
4165625f965SAjay Singh {
4175625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
4185625f965SAjay Singh 	struct wilc_sdio *sdio_priv = wilc->bus_data;
4195625f965SAjay Singh 	u32 block_size = sdio_priv->block_size;
4205625f965SAjay Singh 	struct sdio_cmd53 cmd;
4215625f965SAjay Singh 	int nblk, nleft, ret;
4225625f965SAjay Singh 
4235625f965SAjay Singh 	cmd.read_write = 1;
4245625f965SAjay Singh 	if (addr > 0) {
4255625f965SAjay Singh 		/**
4265625f965SAjay Singh 		 *      func 0 access
4275625f965SAjay Singh 		 **/
4285625f965SAjay Singh 		cmd.function = 0;
4295625f965SAjay Singh 		cmd.address = WILC_SDIO_FBR_DATA_REG;
4305625f965SAjay Singh 	} else {
4315625f965SAjay Singh 		/**
4325625f965SAjay Singh 		 *      func 1 access
4335625f965SAjay Singh 		 **/
4345625f965SAjay Singh 		cmd.function = 1;
4355625f965SAjay Singh 		cmd.address = WILC_SDIO_F1_DATA_REG;
4365625f965SAjay Singh 	}
4375625f965SAjay Singh 
4385625f965SAjay Singh 	size = ALIGN(size, 4);
4395625f965SAjay Singh 	nblk = size / block_size;
4405625f965SAjay Singh 	nleft = size % block_size;
4415625f965SAjay Singh 
44240b717bfSAjay.Kathat@microchip.com 	cmd.use_global_buf = false;
4435625f965SAjay Singh 	if (nblk > 0) {
4445625f965SAjay Singh 		cmd.block_mode = 1;
4455625f965SAjay Singh 		cmd.increment = 1;
4465625f965SAjay Singh 		cmd.count = nblk;
4475625f965SAjay Singh 		cmd.buffer = buf;
4485625f965SAjay Singh 		cmd.block_size = block_size;
4495625f965SAjay Singh 		if (addr > 0) {
4505625f965SAjay Singh 			ret = wilc_sdio_set_func0_csa_address(wilc, addr);
4515625f965SAjay Singh 			if (ret)
4525625f965SAjay Singh 				return ret;
4535625f965SAjay Singh 		}
4545625f965SAjay Singh 		ret = wilc_sdio_cmd53(wilc, &cmd);
4555625f965SAjay Singh 		if (ret) {
4565625f965SAjay Singh 			dev_err(&func->dev,
4575625f965SAjay Singh 				"Failed cmd53 [%x], block send...\n", addr);
4585625f965SAjay Singh 			return ret;
4595625f965SAjay Singh 		}
4605625f965SAjay Singh 		if (addr > 0)
4615625f965SAjay Singh 			addr += nblk * block_size;
4625625f965SAjay Singh 		buf += nblk * block_size;
4635625f965SAjay Singh 	}
4645625f965SAjay Singh 
4655625f965SAjay Singh 	if (nleft > 0) {
4665625f965SAjay Singh 		cmd.block_mode = 0;
4675625f965SAjay Singh 		cmd.increment = 1;
4685625f965SAjay Singh 		cmd.count = nleft;
4695625f965SAjay Singh 		cmd.buffer = buf;
4705625f965SAjay Singh 
4715625f965SAjay Singh 		cmd.block_size = block_size;
4725625f965SAjay Singh 
4735625f965SAjay Singh 		if (addr > 0) {
4745625f965SAjay Singh 			ret = wilc_sdio_set_func0_csa_address(wilc, addr);
4755625f965SAjay Singh 			if (ret)
4765625f965SAjay Singh 				return ret;
4775625f965SAjay Singh 		}
4785625f965SAjay Singh 		ret = wilc_sdio_cmd53(wilc, &cmd);
4795625f965SAjay Singh 		if (ret) {
4805625f965SAjay Singh 			dev_err(&func->dev,
4815625f965SAjay Singh 				"Failed cmd53 [%x], bytes send...\n", addr);
4825625f965SAjay Singh 			return ret;
4835625f965SAjay Singh 		}
4845625f965SAjay Singh 	}
4855625f965SAjay Singh 
4865625f965SAjay Singh 	return 0;
4875625f965SAjay Singh }
4885625f965SAjay Singh 
4895625f965SAjay Singh static int wilc_sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
4905625f965SAjay Singh {
4915625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
4925625f965SAjay Singh 	struct wilc_sdio *sdio_priv = wilc->bus_data;
4935625f965SAjay Singh 	int ret;
4945625f965SAjay Singh 
4955625f965SAjay Singh 	if (addr >= 0xf0 && addr <= 0xff) { /* only vendor specific registers */
4965625f965SAjay Singh 		struct sdio_cmd52 cmd;
4975625f965SAjay Singh 
4985625f965SAjay Singh 		cmd.read_write = 0;
4995625f965SAjay Singh 		cmd.function = 0;
5005625f965SAjay Singh 		cmd.raw = 0;
5015625f965SAjay Singh 		cmd.address = addr;
5025625f965SAjay Singh 		ret = wilc_sdio_cmd52(wilc, &cmd);
5035625f965SAjay Singh 		if (ret) {
5045625f965SAjay Singh 			dev_err(&func->dev,
5055625f965SAjay Singh 				"Failed cmd 52, read reg (%08x) ...\n", addr);
5065625f965SAjay Singh 			return ret;
5075625f965SAjay Singh 		}
5085625f965SAjay Singh 		*data = cmd.data;
5095625f965SAjay Singh 	} else {
5105625f965SAjay Singh 		struct sdio_cmd53 cmd;
5115625f965SAjay Singh 
5125625f965SAjay Singh 		ret = wilc_sdio_set_func0_csa_address(wilc, addr);
5135625f965SAjay Singh 		if (ret)
5145625f965SAjay Singh 			return ret;
5155625f965SAjay Singh 
5165625f965SAjay Singh 		cmd.read_write = 0;
5175625f965SAjay Singh 		cmd.function = 0;
5185625f965SAjay Singh 		cmd.address = WILC_SDIO_FBR_DATA_REG;
5195625f965SAjay Singh 		cmd.block_mode = 0;
5205625f965SAjay Singh 		cmd.increment = 1;
52140b717bfSAjay.Kathat@microchip.com 		cmd.count = sizeof(u32);
5225625f965SAjay Singh 		cmd.buffer = (u8 *)data;
52340b717bfSAjay.Kathat@microchip.com 		cmd.use_global_buf = true;
5245625f965SAjay Singh 
5255625f965SAjay Singh 		cmd.block_size = sdio_priv->block_size;
5265625f965SAjay Singh 		ret = wilc_sdio_cmd53(wilc, &cmd);
5275625f965SAjay Singh 		if (ret) {
5285625f965SAjay Singh 			dev_err(&func->dev,
5295625f965SAjay Singh 				"Failed cmd53, read reg (%08x)...\n", addr);
5305625f965SAjay Singh 			return ret;
5315625f965SAjay Singh 		}
5325625f965SAjay Singh 	}
5335625f965SAjay Singh 
5345625f965SAjay Singh 	le32_to_cpus(data);
5355625f965SAjay Singh 	return 0;
5365625f965SAjay Singh }
5375625f965SAjay Singh 
5385625f965SAjay Singh static int wilc_sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
5395625f965SAjay Singh {
5405625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
5415625f965SAjay Singh 	struct wilc_sdio *sdio_priv = wilc->bus_data;
5425625f965SAjay Singh 	u32 block_size = sdio_priv->block_size;
5435625f965SAjay Singh 	struct sdio_cmd53 cmd;
5445625f965SAjay Singh 	int nblk, nleft, ret;
5455625f965SAjay Singh 
5465625f965SAjay Singh 	cmd.read_write = 0;
5475625f965SAjay Singh 	if (addr > 0) {
5485625f965SAjay Singh 		/**
5495625f965SAjay Singh 		 *      func 0 access
5505625f965SAjay Singh 		 **/
5515625f965SAjay Singh 		cmd.function = 0;
5525625f965SAjay Singh 		cmd.address = WILC_SDIO_FBR_DATA_REG;
5535625f965SAjay Singh 	} else {
5545625f965SAjay Singh 		/**
5555625f965SAjay Singh 		 *      func 1 access
5565625f965SAjay Singh 		 **/
5575625f965SAjay Singh 		cmd.function = 1;
5585625f965SAjay Singh 		cmd.address = WILC_SDIO_F1_DATA_REG;
5595625f965SAjay Singh 	}
5605625f965SAjay Singh 
5615625f965SAjay Singh 	size = ALIGN(size, 4);
5625625f965SAjay Singh 	nblk = size / block_size;
5635625f965SAjay Singh 	nleft = size % block_size;
5645625f965SAjay Singh 
56540b717bfSAjay.Kathat@microchip.com 	cmd.use_global_buf = false;
5665625f965SAjay Singh 	if (nblk > 0) {
5675625f965SAjay Singh 		cmd.block_mode = 1;
5685625f965SAjay Singh 		cmd.increment = 1;
5695625f965SAjay Singh 		cmd.count = nblk;
5705625f965SAjay Singh 		cmd.buffer = buf;
5715625f965SAjay Singh 		cmd.block_size = block_size;
5725625f965SAjay Singh 		if (addr > 0) {
5735625f965SAjay Singh 			ret = wilc_sdio_set_func0_csa_address(wilc, addr);
5745625f965SAjay Singh 			if (ret)
5755625f965SAjay Singh 				return ret;
5765625f965SAjay Singh 		}
5775625f965SAjay Singh 		ret = wilc_sdio_cmd53(wilc, &cmd);
5785625f965SAjay Singh 		if (ret) {
5795625f965SAjay Singh 			dev_err(&func->dev,
5805625f965SAjay Singh 				"Failed cmd53 [%x], block read...\n", addr);
5815625f965SAjay Singh 			return ret;
5825625f965SAjay Singh 		}
5835625f965SAjay Singh 		if (addr > 0)
5845625f965SAjay Singh 			addr += nblk * block_size;
5855625f965SAjay Singh 		buf += nblk * block_size;
5865625f965SAjay Singh 	}       /* if (nblk > 0) */
5875625f965SAjay Singh 
5885625f965SAjay Singh 	if (nleft > 0) {
5895625f965SAjay Singh 		cmd.block_mode = 0;
5905625f965SAjay Singh 		cmd.increment = 1;
5915625f965SAjay Singh 		cmd.count = nleft;
5925625f965SAjay Singh 		cmd.buffer = buf;
5935625f965SAjay Singh 
5945625f965SAjay Singh 		cmd.block_size = block_size;
5955625f965SAjay Singh 
5965625f965SAjay Singh 		if (addr > 0) {
5975625f965SAjay Singh 			ret = wilc_sdio_set_func0_csa_address(wilc, addr);
5985625f965SAjay Singh 			if (ret)
5995625f965SAjay Singh 				return ret;
6005625f965SAjay Singh 		}
6015625f965SAjay Singh 		ret = wilc_sdio_cmd53(wilc, &cmd);
6025625f965SAjay Singh 		if (ret) {
6035625f965SAjay Singh 			dev_err(&func->dev,
6045625f965SAjay Singh 				"Failed cmd53 [%x], bytes read...\n", addr);
6055625f965SAjay Singh 			return ret;
6065625f965SAjay Singh 		}
6075625f965SAjay Singh 	}
6085625f965SAjay Singh 
6095625f965SAjay Singh 	return 0;
6105625f965SAjay Singh }
6115625f965SAjay Singh 
6125625f965SAjay Singh /********************************************
6135625f965SAjay Singh  *
6145625f965SAjay Singh  *      Bus interfaces
6155625f965SAjay Singh  *
6165625f965SAjay Singh  ********************************************/
6175625f965SAjay Singh 
6185625f965SAjay Singh static int wilc_sdio_deinit(struct wilc *wilc)
6195625f965SAjay Singh {
62039d0f1b0SAjay Singh 	struct wilc_sdio *sdio_priv = wilc->bus_data;
62139d0f1b0SAjay Singh 
62239d0f1b0SAjay Singh 	sdio_priv->isinit = false;
6235625f965SAjay Singh 	return 0;
6245625f965SAjay Singh }
6255625f965SAjay Singh 
6265625f965SAjay Singh static int wilc_sdio_init(struct wilc *wilc, bool resume)
6275625f965SAjay Singh {
6285625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
6295625f965SAjay Singh 	struct wilc_sdio *sdio_priv = wilc->bus_data;
6305625f965SAjay Singh 	struct sdio_cmd52 cmd;
6315625f965SAjay Singh 	int loop, ret;
6325625f965SAjay Singh 	u32 chipid;
6335625f965SAjay Singh 
6345625f965SAjay Singh 	/**
6355625f965SAjay Singh 	 *      function 0 csa enable
6365625f965SAjay Singh 	 **/
6375625f965SAjay Singh 	cmd.read_write = 1;
6385625f965SAjay Singh 	cmd.function = 0;
6395625f965SAjay Singh 	cmd.raw = 1;
64072ebd675SAjay Singh 	cmd.address = SDIO_FBR_BASE(1);
6415625f965SAjay Singh 	cmd.data = SDIO_FBR_ENABLE_CSA;
6425625f965SAjay Singh 	ret = wilc_sdio_cmd52(wilc, &cmd);
6435625f965SAjay Singh 	if (ret) {
6445625f965SAjay Singh 		dev_err(&func->dev, "Fail cmd 52, enable csa...\n");
6455625f965SAjay Singh 		return ret;
6465625f965SAjay Singh 	}
6475625f965SAjay Singh 
6485625f965SAjay Singh 	/**
6495625f965SAjay Singh 	 *      function 0 block size
6505625f965SAjay Singh 	 **/
6515625f965SAjay Singh 	ret = wilc_sdio_set_block_size(wilc, 0, WILC_SDIO_BLOCK_SIZE);
6525625f965SAjay Singh 	if (ret) {
6535625f965SAjay Singh 		dev_err(&func->dev, "Fail cmd 52, set func 0 block size...\n");
6545625f965SAjay Singh 		return ret;
6555625f965SAjay Singh 	}
6565625f965SAjay Singh 	sdio_priv->block_size = WILC_SDIO_BLOCK_SIZE;
6575625f965SAjay Singh 
6585625f965SAjay Singh 	/**
6595625f965SAjay Singh 	 *      enable func1 IO
6605625f965SAjay Singh 	 **/
6615625f965SAjay Singh 	cmd.read_write = 1;
6625625f965SAjay Singh 	cmd.function = 0;
6635625f965SAjay Singh 	cmd.raw = 1;
6645625f965SAjay Singh 	cmd.address = SDIO_CCCR_IOEx;
6655625f965SAjay Singh 	cmd.data = WILC_SDIO_CCCR_IO_EN_FUNC1;
6665625f965SAjay Singh 	ret = wilc_sdio_cmd52(wilc, &cmd);
6675625f965SAjay Singh 	if (ret) {
6685625f965SAjay Singh 		dev_err(&func->dev,
6695625f965SAjay Singh 			"Fail cmd 52, set IOE register...\n");
6705625f965SAjay Singh 		return ret;
6715625f965SAjay Singh 	}
6725625f965SAjay Singh 
6735625f965SAjay Singh 	/**
6745625f965SAjay Singh 	 *      make sure func 1 is up
6755625f965SAjay Singh 	 **/
6765625f965SAjay Singh 	cmd.read_write = 0;
6775625f965SAjay Singh 	cmd.function = 0;
6785625f965SAjay Singh 	cmd.raw = 0;
6795625f965SAjay Singh 	cmd.address = SDIO_CCCR_IORx;
6805625f965SAjay Singh 	loop = 3;
6815625f965SAjay Singh 	do {
6825625f965SAjay Singh 		cmd.data = 0;
6835625f965SAjay Singh 		ret = wilc_sdio_cmd52(wilc, &cmd);
6845625f965SAjay Singh 		if (ret) {
6855625f965SAjay Singh 			dev_err(&func->dev,
6865625f965SAjay Singh 				"Fail cmd 52, get IOR register...\n");
6875625f965SAjay Singh 			return ret;
6885625f965SAjay Singh 		}
6895625f965SAjay Singh 		if (cmd.data == WILC_SDIO_CCCR_IO_EN_FUNC1)
6905625f965SAjay Singh 			break;
6915625f965SAjay Singh 	} while (loop--);
6925625f965SAjay Singh 
6935625f965SAjay Singh 	if (loop <= 0) {
6945625f965SAjay Singh 		dev_err(&func->dev, "Fail func 1 is not ready...\n");
6955625f965SAjay Singh 		return -EINVAL;
6965625f965SAjay Singh 	}
6975625f965SAjay Singh 
6985625f965SAjay Singh 	/**
6995625f965SAjay Singh 	 *      func 1 is ready, set func 1 block size
7005625f965SAjay Singh 	 **/
7015625f965SAjay Singh 	ret = wilc_sdio_set_block_size(wilc, 1, WILC_SDIO_BLOCK_SIZE);
7025625f965SAjay Singh 	if (ret) {
7035625f965SAjay Singh 		dev_err(&func->dev, "Fail set func 1 block size...\n");
7045625f965SAjay Singh 		return ret;
7055625f965SAjay Singh 	}
7065625f965SAjay Singh 
7075625f965SAjay Singh 	/**
7085625f965SAjay Singh 	 *      func 1 interrupt enable
7095625f965SAjay Singh 	 **/
7105625f965SAjay Singh 	cmd.read_write = 1;
7115625f965SAjay Singh 	cmd.function = 0;
7125625f965SAjay Singh 	cmd.raw = 1;
7135625f965SAjay Singh 	cmd.address = SDIO_CCCR_IENx;
7145625f965SAjay Singh 	cmd.data = WILC_SDIO_CCCR_IEN_MASTER | WILC_SDIO_CCCR_IEN_FUNC1;
7155625f965SAjay Singh 	ret = wilc_sdio_cmd52(wilc, &cmd);
7165625f965SAjay Singh 	if (ret) {
7175625f965SAjay Singh 		dev_err(&func->dev, "Fail cmd 52, set IEN register...\n");
7185625f965SAjay Singh 		return ret;
7195625f965SAjay Singh 	}
7205625f965SAjay Singh 
7215625f965SAjay Singh 	/**
7225625f965SAjay Singh 	 *      make sure can read back chip id correctly
7235625f965SAjay Singh 	 **/
7245625f965SAjay Singh 	if (!resume) {
7255625f965SAjay Singh 		int rev;
7265625f965SAjay Singh 
7275625f965SAjay Singh 		ret = wilc_sdio_read_reg(wilc, WILC_CHIPID, &chipid);
7285625f965SAjay Singh 		if (ret) {
7295625f965SAjay Singh 			dev_err(&func->dev, "Fail cmd read chip id...\n");
7305625f965SAjay Singh 			return ret;
7315625f965SAjay Singh 		}
7325625f965SAjay Singh 		dev_err(&func->dev, "chipid (%08x)\n", chipid);
7335625f965SAjay Singh 		rev = FIELD_GET(WILC_CHIP_REV_FIELD, chipid);
7345625f965SAjay Singh 		if (rev > FIELD_GET(WILC_CHIP_REV_FIELD, WILC_1000_BASE_ID_2A))
7355625f965SAjay Singh 			sdio_priv->has_thrpt_enh3 = 1;
7365625f965SAjay Singh 		else
7375625f965SAjay Singh 			sdio_priv->has_thrpt_enh3 = 0;
7385625f965SAjay Singh 		dev_info(&func->dev, "has_thrpt_enh3 = %d...\n",
7395625f965SAjay Singh 			 sdio_priv->has_thrpt_enh3);
7405625f965SAjay Singh 	}
7415625f965SAjay Singh 
74239d0f1b0SAjay Singh 	sdio_priv->isinit = true;
7435625f965SAjay Singh 	return 0;
7445625f965SAjay Singh }
7455625f965SAjay Singh 
7465625f965SAjay Singh static int wilc_sdio_read_size(struct wilc *wilc, u32 *size)
7475625f965SAjay Singh {
7485625f965SAjay Singh 	u32 tmp;
7495625f965SAjay Singh 	struct sdio_cmd52 cmd;
7505625f965SAjay Singh 
7515625f965SAjay Singh 	/**
7525625f965SAjay Singh 	 *      Read DMA count in words
7535625f965SAjay Singh 	 **/
7545625f965SAjay Singh 	cmd.read_write = 0;
7555625f965SAjay Singh 	cmd.function = 0;
7565625f965SAjay Singh 	cmd.raw = 0;
7575625f965SAjay Singh 	cmd.address = WILC_SDIO_INTERRUPT_DATA_SZ_REG;
7585625f965SAjay Singh 	cmd.data = 0;
7595625f965SAjay Singh 	wilc_sdio_cmd52(wilc, &cmd);
7605625f965SAjay Singh 	tmp = cmd.data;
7615625f965SAjay Singh 
7625625f965SAjay Singh 	cmd.address = WILC_SDIO_INTERRUPT_DATA_SZ_REG + 1;
7635625f965SAjay Singh 	cmd.data = 0;
7645625f965SAjay Singh 	wilc_sdio_cmd52(wilc, &cmd);
7655625f965SAjay Singh 	tmp |= (cmd.data << 8);
7665625f965SAjay Singh 
7675625f965SAjay Singh 	*size = tmp;
7685625f965SAjay Singh 	return 0;
7695625f965SAjay Singh }
7705625f965SAjay Singh 
7715625f965SAjay Singh static int wilc_sdio_read_int(struct wilc *wilc, u32 *int_status)
7725625f965SAjay Singh {
7735625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
7745625f965SAjay Singh 	struct wilc_sdio *sdio_priv = wilc->bus_data;
7755625f965SAjay Singh 	u32 tmp;
7765625f965SAjay Singh 	u8 irq_flags;
7775625f965SAjay Singh 	struct sdio_cmd52 cmd;
7785625f965SAjay Singh 
7795625f965SAjay Singh 	wilc_sdio_read_size(wilc, &tmp);
7805625f965SAjay Singh 
7815625f965SAjay Singh 	/**
7825625f965SAjay Singh 	 *      Read IRQ flags
7835625f965SAjay Singh 	 **/
7845625f965SAjay Singh 	if (!sdio_priv->irq_gpio) {
7855625f965SAjay Singh 		cmd.function = 1;
7865625f965SAjay Singh 		cmd.address = WILC_SDIO_EXT_IRQ_FLAG_REG;
7875625f965SAjay Singh 	} else {
7885625f965SAjay Singh 		cmd.function = 0;
7895625f965SAjay Singh 		cmd.address = WILC_SDIO_IRQ_FLAG_REG;
7905625f965SAjay Singh 	}
7915625f965SAjay Singh 	cmd.raw = 0;
7925625f965SAjay Singh 	cmd.read_write = 0;
7935625f965SAjay Singh 	cmd.data = 0;
7945625f965SAjay Singh 	wilc_sdio_cmd52(wilc, &cmd);
7955625f965SAjay Singh 	irq_flags = cmd.data;
7965625f965SAjay Singh 	tmp |= FIELD_PREP(IRG_FLAGS_MASK, cmd.data);
7975625f965SAjay Singh 
7985625f965SAjay Singh 	if (FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags))
7995625f965SAjay Singh 		dev_err(&func->dev, "Unexpected interrupt (1) int=%lx\n",
8005625f965SAjay Singh 			FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags));
8015625f965SAjay Singh 
8025625f965SAjay Singh 	*int_status = tmp;
8035625f965SAjay Singh 
8045625f965SAjay Singh 	return 0;
8055625f965SAjay Singh }
8065625f965SAjay Singh 
8075625f965SAjay Singh static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val)
8085625f965SAjay Singh {
8095625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
8105625f965SAjay Singh 	struct wilc_sdio *sdio_priv = wilc->bus_data;
8115625f965SAjay Singh 	int ret;
8125625f965SAjay Singh 	int vmm_ctl;
8135625f965SAjay Singh 
8145625f965SAjay Singh 	if (sdio_priv->has_thrpt_enh3) {
8155625f965SAjay Singh 		u32 reg = 0;
8165625f965SAjay Singh 
8175625f965SAjay Singh 		if (sdio_priv->irq_gpio)
8185625f965SAjay Singh 			reg = val & (BIT(MAX_NUM_INT) - 1);
8195625f965SAjay Singh 
8205625f965SAjay Singh 		/* select VMM table 0 */
8215625f965SAjay Singh 		if (val & SEL_VMM_TBL0)
8225625f965SAjay Singh 			reg |= BIT(5);
8235625f965SAjay Singh 		/* select VMM table 1 */
8245625f965SAjay Singh 		if (val & SEL_VMM_TBL1)
8255625f965SAjay Singh 			reg |= BIT(6);
8265625f965SAjay Singh 		/* enable VMM */
8275625f965SAjay Singh 		if (val & EN_VMM)
8285625f965SAjay Singh 			reg |= BIT(7);
8295625f965SAjay Singh 		if (reg) {
8305625f965SAjay Singh 			struct sdio_cmd52 cmd;
8315625f965SAjay Singh 
8325625f965SAjay Singh 			cmd.read_write = 1;
8335625f965SAjay Singh 			cmd.function = 0;
8345625f965SAjay Singh 			cmd.raw = 0;
8355625f965SAjay Singh 			cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG;
8365625f965SAjay Singh 			cmd.data = reg;
8375625f965SAjay Singh 
8385625f965SAjay Singh 			ret = wilc_sdio_cmd52(wilc, &cmd);
8395625f965SAjay Singh 			if (ret) {
8405625f965SAjay Singh 				dev_err(&func->dev,
8415625f965SAjay Singh 					"Failed cmd52, set (%02x) data (%d) ...\n",
8425625f965SAjay Singh 					cmd.address, __LINE__);
8435625f965SAjay Singh 				return ret;
8445625f965SAjay Singh 			}
8455625f965SAjay Singh 		}
8465625f965SAjay Singh 		return 0;
8475625f965SAjay Singh 	}
8485625f965SAjay Singh 	if (sdio_priv->irq_gpio) {
8495625f965SAjay Singh 		/* has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
8505625f965SAjay Singh 		/*
8515625f965SAjay Singh 		 * Cannot clear multiple interrupts.
8525625f965SAjay Singh 		 * Must clear each interrupt individually.
8535625f965SAjay Singh 		 */
8545625f965SAjay Singh 		u32 flags;
8555625f965SAjay Singh 		int i;
8565625f965SAjay Singh 
8575625f965SAjay Singh 		flags = val & (BIT(MAX_NUM_INT) - 1);
8585625f965SAjay Singh 		for (i = 0; i < NUM_INT_EXT && flags; i++) {
8595625f965SAjay Singh 			if (flags & BIT(i)) {
8605625f965SAjay Singh 				struct sdio_cmd52 cmd;
8615625f965SAjay Singh 
8625625f965SAjay Singh 				cmd.read_write = 1;
8635625f965SAjay Singh 				cmd.function = 0;
8645625f965SAjay Singh 				cmd.raw = 0;
8655625f965SAjay Singh 				cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG;
8665625f965SAjay Singh 				cmd.data = BIT(i);
8675625f965SAjay Singh 
8685625f965SAjay Singh 				ret = wilc_sdio_cmd52(wilc, &cmd);
8695625f965SAjay Singh 				if (ret) {
8705625f965SAjay Singh 					dev_err(&func->dev,
8715625f965SAjay Singh 						"Failed cmd52, set (%02x) data (%d) ...\n",
8725625f965SAjay Singh 						cmd.address, __LINE__);
8735625f965SAjay Singh 					return ret;
8745625f965SAjay Singh 				}
8755625f965SAjay Singh 				flags &= ~BIT(i);
8765625f965SAjay Singh 			}
8775625f965SAjay Singh 		}
8785625f965SAjay Singh 
8795625f965SAjay Singh 		for (i = NUM_INT_EXT; i < MAX_NUM_INT && flags; i++) {
8805625f965SAjay Singh 			if (flags & BIT(i)) {
8815625f965SAjay Singh 				dev_err(&func->dev,
8825625f965SAjay Singh 					"Unexpected interrupt cleared %d...\n",
8835625f965SAjay Singh 					i);
8845625f965SAjay Singh 				flags &= ~BIT(i);
8855625f965SAjay Singh 			}
8865625f965SAjay Singh 		}
8875625f965SAjay Singh 	}
8885625f965SAjay Singh 
8895625f965SAjay Singh 	vmm_ctl = 0;
8905625f965SAjay Singh 	/* select VMM table 0 */
8915625f965SAjay Singh 	if (val & SEL_VMM_TBL0)
8925625f965SAjay Singh 		vmm_ctl |= BIT(0);
8935625f965SAjay Singh 	/* select VMM table 1 */
8945625f965SAjay Singh 	if (val & SEL_VMM_TBL1)
8955625f965SAjay Singh 		vmm_ctl |= BIT(1);
8965625f965SAjay Singh 	/* enable VMM */
8975625f965SAjay Singh 	if (val & EN_VMM)
8985625f965SAjay Singh 		vmm_ctl |= BIT(2);
8995625f965SAjay Singh 
9005625f965SAjay Singh 	if (vmm_ctl) {
9015625f965SAjay Singh 		struct sdio_cmd52 cmd;
9025625f965SAjay Singh 
9035625f965SAjay Singh 		cmd.read_write = 1;
9045625f965SAjay Singh 		cmd.function = 0;
9055625f965SAjay Singh 		cmd.raw = 0;
9065625f965SAjay Singh 		cmd.address = WILC_SDIO_VMM_TBL_CTRL_REG;
9075625f965SAjay Singh 		cmd.data = vmm_ctl;
9085625f965SAjay Singh 		ret = wilc_sdio_cmd52(wilc, &cmd);
9095625f965SAjay Singh 		if (ret) {
9105625f965SAjay Singh 			dev_err(&func->dev,
9115625f965SAjay Singh 				"Failed cmd52, set (%02x) data (%d) ...\n",
9125625f965SAjay Singh 				cmd.address, __LINE__);
9135625f965SAjay Singh 			return ret;
9145625f965SAjay Singh 		}
9155625f965SAjay Singh 	}
9165625f965SAjay Singh 	return 0;
9175625f965SAjay Singh }
9185625f965SAjay Singh 
9195625f965SAjay Singh static int wilc_sdio_sync_ext(struct wilc *wilc, int nint)
9205625f965SAjay Singh {
9215625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
9225625f965SAjay Singh 	struct wilc_sdio *sdio_priv = wilc->bus_data;
9235625f965SAjay Singh 	u32 reg;
9245625f965SAjay Singh 
9255625f965SAjay Singh 	if (nint > MAX_NUM_INT) {
9265625f965SAjay Singh 		dev_err(&func->dev, "Too many interrupts (%d)...\n", nint);
9275625f965SAjay Singh 		return -EINVAL;
9285625f965SAjay Singh 	}
9295625f965SAjay Singh 
9305625f965SAjay Singh 	/**
9315625f965SAjay Singh 	 *      Disable power sequencer
9325625f965SAjay Singh 	 **/
9335625f965SAjay Singh 	if (wilc_sdio_read_reg(wilc, WILC_MISC, &reg)) {
9345625f965SAjay Singh 		dev_err(&func->dev, "Failed read misc reg...\n");
9355625f965SAjay Singh 		return -EINVAL;
9365625f965SAjay Singh 	}
9375625f965SAjay Singh 
9385625f965SAjay Singh 	reg &= ~BIT(8);
9395625f965SAjay Singh 	if (wilc_sdio_write_reg(wilc, WILC_MISC, reg)) {
9405625f965SAjay Singh 		dev_err(&func->dev, "Failed write misc reg...\n");
9415625f965SAjay Singh 		return -EINVAL;
9425625f965SAjay Singh 	}
9435625f965SAjay Singh 
9445625f965SAjay Singh 	if (sdio_priv->irq_gpio) {
9455625f965SAjay Singh 		u32 reg;
9465625f965SAjay Singh 		int ret, i;
9475625f965SAjay Singh 
9485625f965SAjay Singh 		/**
9495625f965SAjay Singh 		 *      interrupt pin mux select
9505625f965SAjay Singh 		 **/
9515625f965SAjay Singh 		ret = wilc_sdio_read_reg(wilc, WILC_PIN_MUX_0, &reg);
9525625f965SAjay Singh 		if (ret) {
9535625f965SAjay Singh 			dev_err(&func->dev, "Failed read reg (%08x)...\n",
9545625f965SAjay Singh 				WILC_PIN_MUX_0);
9555625f965SAjay Singh 			return ret;
9565625f965SAjay Singh 		}
9575625f965SAjay Singh 		reg |= BIT(8);
9585625f965SAjay Singh 		ret = wilc_sdio_write_reg(wilc, WILC_PIN_MUX_0, reg);
9595625f965SAjay Singh 		if (ret) {
9605625f965SAjay Singh 			dev_err(&func->dev, "Failed write reg (%08x)...\n",
9615625f965SAjay Singh 				WILC_PIN_MUX_0);
9625625f965SAjay Singh 			return ret;
9635625f965SAjay Singh 		}
9645625f965SAjay Singh 
9655625f965SAjay Singh 		/**
9665625f965SAjay Singh 		 *      interrupt enable
9675625f965SAjay Singh 		 **/
9685625f965SAjay Singh 		ret = wilc_sdio_read_reg(wilc, WILC_INTR_ENABLE, &reg);
9695625f965SAjay Singh 		if (ret) {
9705625f965SAjay Singh 			dev_err(&func->dev, "Failed read reg (%08x)...\n",
9715625f965SAjay Singh 				WILC_INTR_ENABLE);
9725625f965SAjay Singh 			return ret;
9735625f965SAjay Singh 		}
9745625f965SAjay Singh 
9755625f965SAjay Singh 		for (i = 0; (i < 5) && (nint > 0); i++, nint--)
9765625f965SAjay Singh 			reg |= BIT((27 + i));
9775625f965SAjay Singh 		ret = wilc_sdio_write_reg(wilc, WILC_INTR_ENABLE, reg);
9785625f965SAjay Singh 		if (ret) {
9795625f965SAjay Singh 			dev_err(&func->dev, "Failed write reg (%08x)...\n",
9805625f965SAjay Singh 				WILC_INTR_ENABLE);
9815625f965SAjay Singh 			return ret;
9825625f965SAjay Singh 		}
9835625f965SAjay Singh 		if (nint) {
9845625f965SAjay Singh 			ret = wilc_sdio_read_reg(wilc, WILC_INTR2_ENABLE, &reg);
9855625f965SAjay Singh 			if (ret) {
9865625f965SAjay Singh 				dev_err(&func->dev,
9875625f965SAjay Singh 					"Failed read reg (%08x)...\n",
9885625f965SAjay Singh 					WILC_INTR2_ENABLE);
9895625f965SAjay Singh 				return ret;
9905625f965SAjay Singh 			}
9915625f965SAjay Singh 
9925625f965SAjay Singh 			for (i = 0; (i < 3) && (nint > 0); i++, nint--)
9935625f965SAjay Singh 				reg |= BIT(i);
9945625f965SAjay Singh 
995e21b6e5aSMarcus Folkesson 			ret = wilc_sdio_write_reg(wilc, WILC_INTR2_ENABLE, reg);
9965625f965SAjay Singh 			if (ret) {
9975625f965SAjay Singh 				dev_err(&func->dev,
9985625f965SAjay Singh 					"Failed write reg (%08x)...\n",
9995625f965SAjay Singh 					WILC_INTR2_ENABLE);
10005625f965SAjay Singh 				return ret;
10015625f965SAjay Singh 			}
10025625f965SAjay Singh 		}
10035625f965SAjay Singh 	}
10045625f965SAjay Singh 	return 0;
10055625f965SAjay Singh }
10065625f965SAjay Singh 
10075625f965SAjay Singh /* Global sdio HIF function table */
10085625f965SAjay Singh static const struct wilc_hif_func wilc_hif_sdio = {
10095625f965SAjay Singh 	.hif_init = wilc_sdio_init,
10105625f965SAjay Singh 	.hif_deinit = wilc_sdio_deinit,
10115625f965SAjay Singh 	.hif_read_reg = wilc_sdio_read_reg,
10125625f965SAjay Singh 	.hif_write_reg = wilc_sdio_write_reg,
10135625f965SAjay Singh 	.hif_block_rx = wilc_sdio_read,
10145625f965SAjay Singh 	.hif_block_tx = wilc_sdio_write,
10155625f965SAjay Singh 	.hif_read_int = wilc_sdio_read_int,
10165625f965SAjay Singh 	.hif_clear_int_ext = wilc_sdio_clear_int_ext,
10175625f965SAjay Singh 	.hif_read_size = wilc_sdio_read_size,
10185625f965SAjay Singh 	.hif_block_tx_ext = wilc_sdio_write,
10195625f965SAjay Singh 	.hif_block_rx_ext = wilc_sdio_read,
10205625f965SAjay Singh 	.hif_sync_ext = wilc_sdio_sync_ext,
10215625f965SAjay Singh 	.enable_interrupt = wilc_sdio_enable_interrupt,
10225625f965SAjay Singh 	.disable_interrupt = wilc_sdio_disable_interrupt,
1023c2dcb476SAjay Singh 	.hif_reset = wilc_sdio_reset,
102439d0f1b0SAjay Singh 	.hif_is_init = wilc_sdio_is_init,
10255625f965SAjay Singh };
10265625f965SAjay Singh 
10275625f965SAjay Singh static int wilc_sdio_resume(struct device *dev)
10285625f965SAjay Singh {
10295625f965SAjay Singh 	struct sdio_func *func = dev_to_sdio_func(dev);
10305625f965SAjay Singh 	struct wilc *wilc = sdio_get_drvdata(func);
10315625f965SAjay Singh 
10325625f965SAjay Singh 	dev_info(dev, "sdio resume\n");
10335625f965SAjay Singh 	sdio_release_host(func);
10345625f965SAjay Singh 	chip_wakeup(wilc);
10355625f965SAjay Singh 	wilc_sdio_init(wilc, true);
10365625f965SAjay Singh 
10375625f965SAjay Singh 	if (wilc->suspend_event)
10385625f965SAjay Singh 		host_wakeup_notify(wilc);
10395625f965SAjay Singh 
10405625f965SAjay Singh 	chip_allow_sleep(wilc);
10415625f965SAjay Singh 
10425625f965SAjay Singh 	return 0;
10435625f965SAjay Singh }
10445625f965SAjay Singh 
10455625f965SAjay Singh static const struct of_device_id wilc_of_match[] = {
10465625f965SAjay Singh 	{ .compatible = "microchip,wilc1000", },
10475625f965SAjay Singh 	{ /* sentinel */ }
10485625f965SAjay Singh };
10495625f965SAjay Singh MODULE_DEVICE_TABLE(of, wilc_of_match);
10505625f965SAjay Singh 
10515625f965SAjay Singh static const struct dev_pm_ops wilc_sdio_pm_ops = {
10525625f965SAjay Singh 	.suspend = wilc_sdio_suspend,
10535625f965SAjay Singh 	.resume = wilc_sdio_resume,
10545625f965SAjay Singh };
10555625f965SAjay Singh 
10565625f965SAjay Singh static struct sdio_driver wilc_sdio_driver = {
10575625f965SAjay Singh 	.name		= SDIO_MODALIAS,
10585625f965SAjay Singh 	.id_table	= wilc_sdio_ids,
10595625f965SAjay Singh 	.probe		= wilc_sdio_probe,
10605625f965SAjay Singh 	.remove		= wilc_sdio_remove,
10615625f965SAjay Singh 	.drv = {
10625625f965SAjay Singh 		.pm = &wilc_sdio_pm_ops,
10635625f965SAjay Singh 		.of_match_table = wilc_of_match,
10645625f965SAjay Singh 	}
10655625f965SAjay Singh };
10665625f965SAjay Singh module_driver(wilc_sdio_driver,
10675625f965SAjay Singh 	      sdio_register_driver,
10685625f965SAjay Singh 	      sdio_unregister_driver);
10695625f965SAjay Singh MODULE_LICENSE("GPL");
1070