1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c7f6558dSRoger Tseng /* Realtek USB SD/MMC Card Interface driver
3c7f6558dSRoger Tseng  *
4c7f6558dSRoger Tseng  * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
5c7f6558dSRoger Tseng  *
6c7f6558dSRoger Tseng  * Author:
7c7f6558dSRoger Tseng  *   Roger Tseng <rogerable@realtek.com>
8c7f6558dSRoger Tseng  */
9c7f6558dSRoger Tseng 
10c7f6558dSRoger Tseng #include <linux/module.h>
11c7f6558dSRoger Tseng #include <linux/slab.h>
12c7f6558dSRoger Tseng #include <linux/delay.h>
13c7f6558dSRoger Tseng #include <linux/platform_device.h>
14c7f6558dSRoger Tseng #include <linux/usb.h>
15c7f6558dSRoger Tseng #include <linux/mmc/host.h>
16c7f6558dSRoger Tseng #include <linux/mmc/mmc.h>
17c7f6558dSRoger Tseng #include <linux/mmc/sd.h>
18c7f6558dSRoger Tseng #include <linux/mmc/card.h>
19c7f6558dSRoger Tseng #include <linux/scatterlist.h>
204dad599bSUlf Hansson #include <linux/pm.h>
21c7f6558dSRoger Tseng #include <linux/pm_runtime.h>
22c7f6558dSRoger Tseng 
23e455b69dSRui Feng #include <linux/rtsx_usb.h>
24c7f6558dSRoger Tseng #include <asm/unaligned.h>
25c7f6558dSRoger Tseng 
26b677b885SArnd Bergmann #if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \
27b677b885SArnd Bergmann 		defined(CONFIG_MMC_REALTEK_USB_MODULE))
28c7f6558dSRoger Tseng #include <linux/leds.h>
29c7f6558dSRoger Tseng #include <linux/workqueue.h>
30c7f6558dSRoger Tseng #define RTSX_USB_USE_LEDS_CLASS
31c7f6558dSRoger Tseng #endif
32c7f6558dSRoger Tseng 
33c7f6558dSRoger Tseng struct rtsx_usb_sdmmc {
34c7f6558dSRoger Tseng 	struct platform_device	*pdev;
35c7f6558dSRoger Tseng 	struct rtsx_ucr	*ucr;
36c7f6558dSRoger Tseng 	struct mmc_host		*mmc;
37c7f6558dSRoger Tseng 	struct mmc_request	*mrq;
38c7f6558dSRoger Tseng 
39c7f6558dSRoger Tseng 	struct mutex		host_mutex;
40c7f6558dSRoger Tseng 
41c7f6558dSRoger Tseng 	u8			ssc_depth;
42c7f6558dSRoger Tseng 	unsigned int		clock;
43c7f6558dSRoger Tseng 	bool			vpclk;
44c7f6558dSRoger Tseng 	bool			double_clk;
45c7f6558dSRoger Tseng 	bool			host_removal;
46c7f6558dSRoger Tseng 	bool			card_exist;
47c7f6558dSRoger Tseng 	bool			initial_mode;
48c7f6558dSRoger Tseng 	bool			ddr_mode;
49c7f6558dSRoger Tseng 
50c7f6558dSRoger Tseng 	unsigned char		power_mode;
51c7f6558dSRoger Tseng 
52b677b885SArnd Bergmann #ifdef RTSX_USB_USE_LEDS_CLASS
53c7f6558dSRoger Tseng 	struct led_classdev	led;
54c7f6558dSRoger Tseng 	char			led_name[32];
55c7f6558dSRoger Tseng 	struct work_struct	led_work;
56c7f6558dSRoger Tseng #endif
57c7f6558dSRoger Tseng };
58c7f6558dSRoger Tseng 
sdmmc_dev(struct rtsx_usb_sdmmc * host)59c7f6558dSRoger Tseng static inline struct device *sdmmc_dev(struct rtsx_usb_sdmmc *host)
60c7f6558dSRoger Tseng {
61c7f6558dSRoger Tseng 	return &(host->pdev->dev);
62c7f6558dSRoger Tseng }
63c7f6558dSRoger Tseng 
sd_clear_error(struct rtsx_usb_sdmmc * host)64c7f6558dSRoger Tseng static inline void sd_clear_error(struct rtsx_usb_sdmmc *host)
65c7f6558dSRoger Tseng {
66c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
67c7f6558dSRoger Tseng 	rtsx_usb_ep0_write_register(ucr, CARD_STOP,
68c7f6558dSRoger Tseng 				  SD_STOP | SD_CLR_ERR,
69c7f6558dSRoger Tseng 				  SD_STOP | SD_CLR_ERR);
70c7f6558dSRoger Tseng 
71c7f6558dSRoger Tseng 	rtsx_usb_clear_dma_err(ucr);
72c7f6558dSRoger Tseng 	rtsx_usb_clear_fsm_err(ucr);
73c7f6558dSRoger Tseng }
74c7f6558dSRoger Tseng 
75c7f6558dSRoger Tseng #ifdef DEBUG
sd_print_debug_regs(struct rtsx_usb_sdmmc * host)76c7f6558dSRoger Tseng static void sd_print_debug_regs(struct rtsx_usb_sdmmc *host)
77c7f6558dSRoger Tseng {
78c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
79c7f6558dSRoger Tseng 	u8 val = 0;
80c7f6558dSRoger Tseng 
81c7f6558dSRoger Tseng 	rtsx_usb_ep0_read_register(ucr, SD_STAT1, &val);
82c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "SD_STAT1: 0x%x\n", val);
83c7f6558dSRoger Tseng 	rtsx_usb_ep0_read_register(ucr, SD_STAT2, &val);
84c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "SD_STAT2: 0x%x\n", val);
85c7f6558dSRoger Tseng 	rtsx_usb_ep0_read_register(ucr, SD_BUS_STAT, &val);
86c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "SD_BUS_STAT: 0x%x\n", val);
87c7f6558dSRoger Tseng }
88c7f6558dSRoger Tseng #else
89c7f6558dSRoger Tseng #define sd_print_debug_regs(host)
90c7f6558dSRoger Tseng #endif /* DEBUG */
91c7f6558dSRoger Tseng 
sd_read_data(struct rtsx_usb_sdmmc * host,struct mmc_command * cmd,u16 byte_cnt,u8 * buf,int buf_len,int timeout)92c7f6558dSRoger Tseng static int sd_read_data(struct rtsx_usb_sdmmc *host, struct mmc_command *cmd,
93c7f6558dSRoger Tseng 	       u16 byte_cnt, u8 *buf, int buf_len, int timeout)
94c7f6558dSRoger Tseng {
95c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
96c7f6558dSRoger Tseng 	int err;
97c7f6558dSRoger Tseng 	u8 trans_mode;
98c7f6558dSRoger Tseng 
99c7f6558dSRoger Tseng 	if (!buf)
100c7f6558dSRoger Tseng 		buf_len = 0;
101c7f6558dSRoger Tseng 
102c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
103c7f6558dSRoger Tseng 	if (cmd != NULL) {
104c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__
105c7f6558dSRoger Tseng 				, cmd->opcode);
106c7f6558dSRoger Tseng 		if (cmd->opcode == MMC_SEND_TUNING_BLOCK)
107c7f6558dSRoger Tseng 			trans_mode = SD_TM_AUTO_TUNING;
108c7f6558dSRoger Tseng 		else
109c7f6558dSRoger Tseng 			trans_mode = SD_TM_NORMAL_READ;
110c7f6558dSRoger Tseng 
111c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
112c7f6558dSRoger Tseng 				SD_CMD0, 0xFF, (u8)(cmd->opcode) | 0x40);
113c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
114c7f6558dSRoger Tseng 				SD_CMD1, 0xFF, (u8)(cmd->arg >> 24));
115c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
116c7f6558dSRoger Tseng 				SD_CMD2, 0xFF, (u8)(cmd->arg >> 16));
117c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
118c7f6558dSRoger Tseng 				SD_CMD3, 0xFF, (u8)(cmd->arg >> 8));
119c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
120c7f6558dSRoger Tseng 				SD_CMD4, 0xFF, (u8)cmd->arg);
121c7f6558dSRoger Tseng 	} else {
122c7f6558dSRoger Tseng 		trans_mode = SD_TM_AUTO_READ_3;
123c7f6558dSRoger Tseng 	}
124c7f6558dSRoger Tseng 
125c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt);
126c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H,
127c7f6558dSRoger Tseng 			0xFF, (u8)(byte_cnt >> 8));
128c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1);
129c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0);
130c7f6558dSRoger Tseng 
131c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF,
132c7f6558dSRoger Tseng 			SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
133c7f6558dSRoger Tseng 			SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
134c7f6558dSRoger Tseng 	if (trans_mode != SD_TM_AUTO_TUNING)
135c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
136c7f6558dSRoger Tseng 				CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER);
137c7f6558dSRoger Tseng 
138c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER,
139c7f6558dSRoger Tseng 			0xFF, trans_mode | SD_TRANSFER_START);
140c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
141c7f6558dSRoger Tseng 			SD_TRANSFER_END, SD_TRANSFER_END);
142c7f6558dSRoger Tseng 
143c7f6558dSRoger Tseng 	if (cmd != NULL) {
144c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD1, 0, 0);
145c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD2, 0, 0);
146c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD3, 0, 0);
147c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD4, 0, 0);
148c7f6558dSRoger Tseng 	}
149c7f6558dSRoger Tseng 
150c7f6558dSRoger Tseng 	err = rtsx_usb_send_cmd(ucr, MODE_CR, timeout);
151c7f6558dSRoger Tseng 	if (err) {
152c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host),
153c7f6558dSRoger Tseng 			"rtsx_usb_send_cmd failed (err = %d)\n", err);
154c7f6558dSRoger Tseng 		return err;
155c7f6558dSRoger Tseng 	}
156c7f6558dSRoger Tseng 
157c7f6558dSRoger Tseng 	err = rtsx_usb_get_rsp(ucr, !cmd ? 1 : 5, timeout);
158c7f6558dSRoger Tseng 	if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) {
159c7f6558dSRoger Tseng 		sd_print_debug_regs(host);
160c7f6558dSRoger Tseng 
161c7f6558dSRoger Tseng 		if (!err) {
162c7f6558dSRoger Tseng 			dev_dbg(sdmmc_dev(host),
163c7f6558dSRoger Tseng 				"Transfer failed (SD_TRANSFER = %02x)\n",
164c7f6558dSRoger Tseng 				ucr->rsp_buf[0]);
165c7f6558dSRoger Tseng 			err = -EIO;
166c7f6558dSRoger Tseng 		} else {
167c7f6558dSRoger Tseng 			dev_dbg(sdmmc_dev(host),
168c7f6558dSRoger Tseng 				"rtsx_usb_get_rsp failed (err = %d)\n", err);
169c7f6558dSRoger Tseng 		}
170c7f6558dSRoger Tseng 
171c7f6558dSRoger Tseng 		return err;
172c7f6558dSRoger Tseng 	}
173c7f6558dSRoger Tseng 
174c7f6558dSRoger Tseng 	if (cmd != NULL) {
175c7f6558dSRoger Tseng 		cmd->resp[0] = get_unaligned_be32(ucr->rsp_buf + 1);
176c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n",
177c7f6558dSRoger Tseng 				cmd->resp[0]);
178c7f6558dSRoger Tseng 	}
179c7f6558dSRoger Tseng 
180c7f6558dSRoger Tseng 	if (buf && buf_len) {
181c7f6558dSRoger Tseng 		/* 2-byte aligned part */
182c7f6558dSRoger Tseng 		err = rtsx_usb_read_ppbuf(ucr, buf, byte_cnt - (byte_cnt % 2));
183c7f6558dSRoger Tseng 		if (err) {
184c7f6558dSRoger Tseng 			dev_dbg(sdmmc_dev(host),
185c7f6558dSRoger Tseng 				"rtsx_usb_read_ppbuf failed (err = %d)\n", err);
186c7f6558dSRoger Tseng 			return err;
187c7f6558dSRoger Tseng 		}
188c7f6558dSRoger Tseng 
189c7f6558dSRoger Tseng 		/* unaligned byte */
190c7f6558dSRoger Tseng 		if (byte_cnt % 2)
191c7f6558dSRoger Tseng 			return rtsx_usb_read_register(ucr,
192c7f6558dSRoger Tseng 					PPBUF_BASE2 + byte_cnt,
193c7f6558dSRoger Tseng 					buf + byte_cnt - 1);
194c7f6558dSRoger Tseng 	}
195c7f6558dSRoger Tseng 
196c7f6558dSRoger Tseng 	return 0;
197c7f6558dSRoger Tseng }
198c7f6558dSRoger Tseng 
sd_write_data(struct rtsx_usb_sdmmc * host,struct mmc_command * cmd,u16 byte_cnt,u8 * buf,int buf_len,int timeout)199c7f6558dSRoger Tseng static int sd_write_data(struct rtsx_usb_sdmmc *host, struct mmc_command *cmd,
200c7f6558dSRoger Tseng 		u16 byte_cnt, u8 *buf, int buf_len, int timeout)
201c7f6558dSRoger Tseng {
202c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
203c7f6558dSRoger Tseng 	int err;
204c7f6558dSRoger Tseng 	u8 trans_mode;
205c7f6558dSRoger Tseng 
206c7f6558dSRoger Tseng 	if (!buf)
207c7f6558dSRoger Tseng 		buf_len = 0;
208c7f6558dSRoger Tseng 
209c7f6558dSRoger Tseng 	if (buf && buf_len) {
210c7f6558dSRoger Tseng 		err = rtsx_usb_write_ppbuf(ucr, buf, buf_len);
211c7f6558dSRoger Tseng 		if (err) {
212c7f6558dSRoger Tseng 			dev_dbg(sdmmc_dev(host),
213c7f6558dSRoger Tseng 				"rtsx_usb_write_ppbuf failed (err = %d)\n",
214c7f6558dSRoger Tseng 				err);
215c7f6558dSRoger Tseng 			return err;
216c7f6558dSRoger Tseng 		}
217c7f6558dSRoger Tseng 	}
218c7f6558dSRoger Tseng 
219c7f6558dSRoger Tseng 	trans_mode = (cmd != NULL) ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3;
220c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
221c7f6558dSRoger Tseng 
222c7f6558dSRoger Tseng 	if (cmd != NULL) {
223c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__,
224c7f6558dSRoger Tseng 				cmd->opcode);
225c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
226c7f6558dSRoger Tseng 				SD_CMD0, 0xFF, (u8)(cmd->opcode) | 0x40);
227c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
228c7f6558dSRoger Tseng 				SD_CMD1, 0xFF, (u8)(cmd->arg >> 24));
229c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
230c7f6558dSRoger Tseng 				SD_CMD2, 0xFF, (u8)(cmd->arg >> 16));
231c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
232c7f6558dSRoger Tseng 				SD_CMD3, 0xFF, (u8)(cmd->arg >> 8));
233c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
234c7f6558dSRoger Tseng 				SD_CMD4, 0xFF, (u8)cmd->arg);
235c7f6558dSRoger Tseng 	}
236c7f6558dSRoger Tseng 
237c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt);
238c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H,
239c7f6558dSRoger Tseng 			0xFF, (u8)(byte_cnt >> 8));
240c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1);
241c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0);
242c7f6558dSRoger Tseng 
243c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF,
244c7f6558dSRoger Tseng 		SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
245c7f6558dSRoger Tseng 		SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
246c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
247c7f6558dSRoger Tseng 			CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER);
248c7f6558dSRoger Tseng 
249c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
250c7f6558dSRoger Tseng 			trans_mode | SD_TRANSFER_START);
251c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
252c7f6558dSRoger Tseng 			SD_TRANSFER_END, SD_TRANSFER_END);
253c7f6558dSRoger Tseng 
254c7f6558dSRoger Tseng 	if (cmd != NULL) {
255c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD1, 0, 0);
256c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD2, 0, 0);
257c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD3, 0, 0);
258c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD4, 0, 0);
259c7f6558dSRoger Tseng 	}
260c7f6558dSRoger Tseng 
261c7f6558dSRoger Tseng 	err = rtsx_usb_send_cmd(ucr, MODE_CR, timeout);
262c7f6558dSRoger Tseng 	if (err) {
263c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host),
264c7f6558dSRoger Tseng 			"rtsx_usb_send_cmd failed (err = %d)\n", err);
265c7f6558dSRoger Tseng 		return err;
266c7f6558dSRoger Tseng 	}
267c7f6558dSRoger Tseng 
268c7f6558dSRoger Tseng 	err = rtsx_usb_get_rsp(ucr, !cmd ? 1 : 5, timeout);
269c7f6558dSRoger Tseng 	if (err) {
270c7f6558dSRoger Tseng 		sd_print_debug_regs(host);
271c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host),
272c7f6558dSRoger Tseng 			"rtsx_usb_get_rsp failed (err = %d)\n", err);
273c7f6558dSRoger Tseng 		return err;
274c7f6558dSRoger Tseng 	}
275c7f6558dSRoger Tseng 
276c7f6558dSRoger Tseng 	if (cmd != NULL) {
277c7f6558dSRoger Tseng 		cmd->resp[0] = get_unaligned_be32(ucr->rsp_buf + 1);
278c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n",
279c7f6558dSRoger Tseng 				cmd->resp[0]);
280c7f6558dSRoger Tseng 	}
281c7f6558dSRoger Tseng 
282c7f6558dSRoger Tseng 	return 0;
283c7f6558dSRoger Tseng }
284c7f6558dSRoger Tseng 
sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc * host,struct mmc_command * cmd)285c7f6558dSRoger Tseng static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host,
286c7f6558dSRoger Tseng 		struct mmc_command *cmd)
287c7f6558dSRoger Tseng {
288c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
289c7f6558dSRoger Tseng 	u8 cmd_idx = (u8)cmd->opcode;
290c7f6558dSRoger Tseng 	u32 arg = cmd->arg;
291c7f6558dSRoger Tseng 	int err = 0;
292c7f6558dSRoger Tseng 	int timeout = 100;
293c7f6558dSRoger Tseng 	int i;
294c7f6558dSRoger Tseng 	u8 *ptr;
295c7f6558dSRoger Tseng 	int stat_idx = 0;
296c7f6558dSRoger Tseng 	int len = 2;
297c7f6558dSRoger Tseng 	u8 rsp_type;
298c7f6558dSRoger Tseng 
299c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
300c7f6558dSRoger Tseng 			__func__, cmd_idx, arg);
301c7f6558dSRoger Tseng 
302c7f6558dSRoger Tseng 	/* Response type:
303c7f6558dSRoger Tseng 	 * R0
304c7f6558dSRoger Tseng 	 * R1, R5, R6, R7
305c7f6558dSRoger Tseng 	 * R1b
306c7f6558dSRoger Tseng 	 * R2
307c7f6558dSRoger Tseng 	 * R3, R4
308c7f6558dSRoger Tseng 	 */
309c7f6558dSRoger Tseng 	switch (mmc_resp_type(cmd)) {
310c7f6558dSRoger Tseng 	case MMC_RSP_NONE:
311c7f6558dSRoger Tseng 		rsp_type = SD_RSP_TYPE_R0;
312c7f6558dSRoger Tseng 		break;
313c7f6558dSRoger Tseng 	case MMC_RSP_R1:
314c7f6558dSRoger Tseng 		rsp_type = SD_RSP_TYPE_R1;
315c7f6558dSRoger Tseng 		break;
316f7dd5462SWolfram Sang 	case MMC_RSP_R1_NO_CRC:
317c7f6558dSRoger Tseng 		rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
318c7f6558dSRoger Tseng 		break;
319c7f6558dSRoger Tseng 	case MMC_RSP_R1B:
320c7f6558dSRoger Tseng 		rsp_type = SD_RSP_TYPE_R1b;
321c7f6558dSRoger Tseng 		break;
322c7f6558dSRoger Tseng 	case MMC_RSP_R2:
323c7f6558dSRoger Tseng 		rsp_type = SD_RSP_TYPE_R2;
324c7f6558dSRoger Tseng 		break;
325c7f6558dSRoger Tseng 	case MMC_RSP_R3:
326c7f6558dSRoger Tseng 		rsp_type = SD_RSP_TYPE_R3;
327c7f6558dSRoger Tseng 		break;
328c7f6558dSRoger Tseng 	default:
329c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n");
330c7f6558dSRoger Tseng 		err = -EINVAL;
331c7f6558dSRoger Tseng 		goto out;
332c7f6558dSRoger Tseng 	}
333c7f6558dSRoger Tseng 
334c7f6558dSRoger Tseng 	if (rsp_type == SD_RSP_TYPE_R1b)
335ec30f11eSUlf Hansson 		timeout = cmd->busy_timeout ? cmd->busy_timeout : 3000;
336c7f6558dSRoger Tseng 
337c7f6558dSRoger Tseng 	if (cmd->opcode == SD_SWITCH_VOLTAGE) {
338c7f6558dSRoger Tseng 		err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
339c7f6558dSRoger Tseng 				SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
340c7f6558dSRoger Tseng 				SD_CLK_TOGGLE_EN);
341c7f6558dSRoger Tseng 		if (err)
342c7f6558dSRoger Tseng 			goto out;
343c7f6558dSRoger Tseng 	}
344c7f6558dSRoger Tseng 
345c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
346c7f6558dSRoger Tseng 
347c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx);
348c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24));
349c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16));
350c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8));
351c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg);
352c7f6558dSRoger Tseng 
353c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type);
354c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
355c7f6558dSRoger Tseng 			0x01, PINGPONG_BUFFER);
356c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER,
357c7f6558dSRoger Tseng 			0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START);
358c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
359c7f6558dSRoger Tseng 		     SD_TRANSFER_END | SD_STAT_IDLE,
360c7f6558dSRoger Tseng 		     SD_TRANSFER_END | SD_STAT_IDLE);
361c7f6558dSRoger Tseng 
362c7f6558dSRoger Tseng 	if (rsp_type == SD_RSP_TYPE_R2) {
363c7f6558dSRoger Tseng 		/* Read data from ping-pong buffer */
364c7f6558dSRoger Tseng 		for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
365c7f6558dSRoger Tseng 			rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0);
366c7f6558dSRoger Tseng 		stat_idx = 16;
367c7f6558dSRoger Tseng 	} else if (rsp_type != SD_RSP_TYPE_R0) {
368c7f6558dSRoger Tseng 		/* Read data from SD_CMDx registers */
369c7f6558dSRoger Tseng 		for (i = SD_CMD0; i <= SD_CMD4; i++)
370c7f6558dSRoger Tseng 			rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0);
371c7f6558dSRoger Tseng 		stat_idx = 5;
372c7f6558dSRoger Tseng 	}
373c7f6558dSRoger Tseng 	len += stat_idx;
374c7f6558dSRoger Tseng 
375c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_STAT1, 0, 0);
376c7f6558dSRoger Tseng 
377c7f6558dSRoger Tseng 	err = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
378c7f6558dSRoger Tseng 	if (err) {
379c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host),
380c7f6558dSRoger Tseng 			"rtsx_usb_send_cmd error (err = %d)\n", err);
381c7f6558dSRoger Tseng 		goto out;
382c7f6558dSRoger Tseng 	}
383c7f6558dSRoger Tseng 
384c7f6558dSRoger Tseng 	err = rtsx_usb_get_rsp(ucr, len, timeout);
385c7f6558dSRoger Tseng 	if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) {
386c7f6558dSRoger Tseng 		sd_print_debug_regs(host);
387c7f6558dSRoger Tseng 		sd_clear_error(host);
388c7f6558dSRoger Tseng 
389c7f6558dSRoger Tseng 		if (!err) {
390c7f6558dSRoger Tseng 			dev_dbg(sdmmc_dev(host),
391c7f6558dSRoger Tseng 				"Transfer failed (SD_TRANSFER = %02x)\n",
392c7f6558dSRoger Tseng 					ucr->rsp_buf[0]);
393c7f6558dSRoger Tseng 			err = -EIO;
394c7f6558dSRoger Tseng 		} else {
395c7f6558dSRoger Tseng 			dev_dbg(sdmmc_dev(host),
396c7f6558dSRoger Tseng 				"rtsx_usb_get_rsp failed (err = %d)\n", err);
397c7f6558dSRoger Tseng 		}
398c7f6558dSRoger Tseng 
399c7f6558dSRoger Tseng 		goto out;
400c7f6558dSRoger Tseng 	}
401c7f6558dSRoger Tseng 
402c7f6558dSRoger Tseng 	if (rsp_type == SD_RSP_TYPE_R0) {
403c7f6558dSRoger Tseng 		err = 0;
404c7f6558dSRoger Tseng 		goto out;
405c7f6558dSRoger Tseng 	}
406c7f6558dSRoger Tseng 
407c7f6558dSRoger Tseng 	/* Skip result of CHECK_REG_CMD */
408c7f6558dSRoger Tseng 	ptr = ucr->rsp_buf + 1;
409c7f6558dSRoger Tseng 
410c7f6558dSRoger Tseng 	/* Check (Start,Transmission) bit of Response */
411c7f6558dSRoger Tseng 	if ((ptr[0] & 0xC0) != 0) {
412c7f6558dSRoger Tseng 		err = -EILSEQ;
413c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "Invalid response bit\n");
414c7f6558dSRoger Tseng 		goto out;
415c7f6558dSRoger Tseng 	}
416c7f6558dSRoger Tseng 
417c7f6558dSRoger Tseng 	/* Check CRC7 */
418c7f6558dSRoger Tseng 	if (!(rsp_type & SD_NO_CHECK_CRC7)) {
419c7f6558dSRoger Tseng 		if (ptr[stat_idx] & SD_CRC7_ERR) {
420c7f6558dSRoger Tseng 			err = -EILSEQ;
421c7f6558dSRoger Tseng 			dev_dbg(sdmmc_dev(host), "CRC7 error\n");
422c7f6558dSRoger Tseng 			goto out;
423c7f6558dSRoger Tseng 		}
424c7f6558dSRoger Tseng 	}
425c7f6558dSRoger Tseng 
426c7f6558dSRoger Tseng 	if (rsp_type == SD_RSP_TYPE_R2) {
4276f67cc6fSRoger Tseng 		/*
4286f67cc6fSRoger Tseng 		 * The controller offloads the last byte {CRC-7, end bit 1'b1}
4296f67cc6fSRoger Tseng 		 * of response type R2. Assign dummy CRC, 0, and end bit to the
4306f67cc6fSRoger Tseng 		 * byte(ptr[16], goes into the LSB of resp[3] later).
4316f67cc6fSRoger Tseng 		 */
4326f67cc6fSRoger Tseng 		ptr[16] = 1;
4336f67cc6fSRoger Tseng 
434c7f6558dSRoger Tseng 		for (i = 0; i < 4; i++) {
435c7f6558dSRoger Tseng 			cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4);
436c7f6558dSRoger Tseng 			dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n",
437c7f6558dSRoger Tseng 					i, cmd->resp[i]);
438c7f6558dSRoger Tseng 		}
439c7f6558dSRoger Tseng 	} else {
440c7f6558dSRoger Tseng 		cmd->resp[0] = get_unaligned_be32(ptr + 1);
441c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n",
442c7f6558dSRoger Tseng 				cmd->resp[0]);
443c7f6558dSRoger Tseng 	}
444c7f6558dSRoger Tseng 
445c7f6558dSRoger Tseng out:
446c7f6558dSRoger Tseng 	cmd->error = err;
447c7f6558dSRoger Tseng }
448c7f6558dSRoger Tseng 
sd_rw_multi(struct rtsx_usb_sdmmc * host,struct mmc_request * mrq)449c7f6558dSRoger Tseng static int sd_rw_multi(struct rtsx_usb_sdmmc *host, struct mmc_request *mrq)
450c7f6558dSRoger Tseng {
451c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
452c7f6558dSRoger Tseng 	struct mmc_data *data = mrq->data;
453c7f6558dSRoger Tseng 	int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
454c7f6558dSRoger Tseng 	u8 cfg2, trans_mode;
455c7f6558dSRoger Tseng 	int err;
456c7f6558dSRoger Tseng 	u8 flag;
457c7f6558dSRoger Tseng 	size_t data_len = data->blksz * data->blocks;
458c7f6558dSRoger Tseng 	unsigned int pipe;
459c7f6558dSRoger Tseng 
460c7f6558dSRoger Tseng 	if (read) {
461c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "%s: read %zu bytes\n",
462c7f6558dSRoger Tseng 				__func__, data_len);
463c7f6558dSRoger Tseng 		cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
464c7f6558dSRoger Tseng 			SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0;
465c7f6558dSRoger Tseng 		trans_mode = SD_TM_AUTO_READ_3;
466c7f6558dSRoger Tseng 	} else {
467c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "%s: write %zu bytes\n",
468c7f6558dSRoger Tseng 				__func__, data_len);
469c7f6558dSRoger Tseng 		cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 |
470c7f6558dSRoger Tseng 			SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0;
471c7f6558dSRoger Tseng 		trans_mode = SD_TM_AUTO_WRITE_3;
472c7f6558dSRoger Tseng 	}
473c7f6558dSRoger Tseng 
474c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
475c7f6558dSRoger Tseng 
476c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00);
477c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02);
478c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L,
479c7f6558dSRoger Tseng 			0xFF, (u8)data->blocks);
480c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H,
481c7f6558dSRoger Tseng 			0xFF, (u8)(data->blocks >> 8));
482c7f6558dSRoger Tseng 
483c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
484c7f6558dSRoger Tseng 			0x01, RING_BUFFER);
485c7f6558dSRoger Tseng 
486c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC3,
487c7f6558dSRoger Tseng 			0xFF, (u8)(data_len >> 24));
488c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC2,
489c7f6558dSRoger Tseng 			0xFF, (u8)(data_len >> 16));
490c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC1,
491c7f6558dSRoger Tseng 			0xFF, (u8)(data_len >> 8));
492c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC0,
493c7f6558dSRoger Tseng 			0xFF, (u8)data_len);
494c7f6558dSRoger Tseng 	if (read) {
495c7f6558dSRoger Tseng 		flag = MODE_CDIR;
496c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL,
497c7f6558dSRoger Tseng 				0x03 | DMA_PACK_SIZE_MASK,
498c7f6558dSRoger Tseng 				DMA_DIR_FROM_CARD | DMA_EN | DMA_512);
499c7f6558dSRoger Tseng 	} else {
500c7f6558dSRoger Tseng 		flag = MODE_CDOR;
501c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL,
502c7f6558dSRoger Tseng 				0x03 | DMA_PACK_SIZE_MASK,
503c7f6558dSRoger Tseng 				DMA_DIR_TO_CARD | DMA_EN | DMA_512);
504c7f6558dSRoger Tseng 	}
505c7f6558dSRoger Tseng 
506c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2);
507c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
508c7f6558dSRoger Tseng 			trans_mode | SD_TRANSFER_START);
509c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
510c7f6558dSRoger Tseng 			SD_TRANSFER_END, SD_TRANSFER_END);
511c7f6558dSRoger Tseng 
512c7f6558dSRoger Tseng 	err = rtsx_usb_send_cmd(ucr, flag, 100);
513c7f6558dSRoger Tseng 	if (err)
514c7f6558dSRoger Tseng 		return err;
515c7f6558dSRoger Tseng 
516c7f6558dSRoger Tseng 	if (read)
517c7f6558dSRoger Tseng 		pipe = usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN);
518c7f6558dSRoger Tseng 	else
519c7f6558dSRoger Tseng 		pipe = usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT);
520c7f6558dSRoger Tseng 
521c7f6558dSRoger Tseng 	err = rtsx_usb_transfer_data(ucr, pipe, data->sg, data_len,
522c7f6558dSRoger Tseng 			data->sg_len,  NULL, 10000);
523c7f6558dSRoger Tseng 	if (err) {
524c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "rtsx_usb_transfer_data error %d\n"
525c7f6558dSRoger Tseng 				, err);
526c7f6558dSRoger Tseng 		sd_clear_error(host);
527c7f6558dSRoger Tseng 		return err;
528c7f6558dSRoger Tseng 	}
529c7f6558dSRoger Tseng 
530c7f6558dSRoger Tseng 	return rtsx_usb_get_rsp(ucr, 1, 2000);
531c7f6558dSRoger Tseng }
532c7f6558dSRoger Tseng 
sd_enable_initial_mode(struct rtsx_usb_sdmmc * host)533c7f6558dSRoger Tseng static inline void sd_enable_initial_mode(struct rtsx_usb_sdmmc *host)
534c7f6558dSRoger Tseng {
535c7f6558dSRoger Tseng 	rtsx_usb_write_register(host->ucr, SD_CFG1,
536c7f6558dSRoger Tseng 			SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128);
537c7f6558dSRoger Tseng }
538c7f6558dSRoger Tseng 
sd_disable_initial_mode(struct rtsx_usb_sdmmc * host)539c7f6558dSRoger Tseng static inline void sd_disable_initial_mode(struct rtsx_usb_sdmmc *host)
540c7f6558dSRoger Tseng {
541c7f6558dSRoger Tseng 	rtsx_usb_write_register(host->ucr, SD_CFG1,
542c7f6558dSRoger Tseng 			SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0);
543c7f6558dSRoger Tseng }
544c7f6558dSRoger Tseng 
sd_normal_rw(struct rtsx_usb_sdmmc * host,struct mmc_request * mrq)545c7f6558dSRoger Tseng static void sd_normal_rw(struct rtsx_usb_sdmmc *host,
546c7f6558dSRoger Tseng 		struct mmc_request *mrq)
547c7f6558dSRoger Tseng {
548c7f6558dSRoger Tseng 	struct mmc_command *cmd = mrq->cmd;
549c7f6558dSRoger Tseng 	struct mmc_data *data = mrq->data;
550c7f6558dSRoger Tseng 	u8 *buf;
551c7f6558dSRoger Tseng 
552c7f6558dSRoger Tseng 	buf = kzalloc(data->blksz, GFP_NOIO);
553c7f6558dSRoger Tseng 	if (!buf) {
554c7f6558dSRoger Tseng 		cmd->error = -ENOMEM;
555c7f6558dSRoger Tseng 		return;
556c7f6558dSRoger Tseng 	}
557c7f6558dSRoger Tseng 
558c7f6558dSRoger Tseng 	if (data->flags & MMC_DATA_READ) {
559c7f6558dSRoger Tseng 		if (host->initial_mode)
560c7f6558dSRoger Tseng 			sd_disable_initial_mode(host);
561c7f6558dSRoger Tseng 
562c7f6558dSRoger Tseng 		cmd->error = sd_read_data(host, cmd, (u16)data->blksz, buf,
563c7f6558dSRoger Tseng 				data->blksz, 200);
564c7f6558dSRoger Tseng 
565c7f6558dSRoger Tseng 		if (host->initial_mode)
566c7f6558dSRoger Tseng 			sd_enable_initial_mode(host);
567c7f6558dSRoger Tseng 
568c7f6558dSRoger Tseng 		sg_copy_from_buffer(data->sg, data->sg_len, buf, data->blksz);
569c7f6558dSRoger Tseng 	} else {
570c7f6558dSRoger Tseng 		sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz);
571c7f6558dSRoger Tseng 
572c7f6558dSRoger Tseng 		cmd->error = sd_write_data(host, cmd, (u16)data->blksz, buf,
573c7f6558dSRoger Tseng 				data->blksz, 200);
574c7f6558dSRoger Tseng 	}
575c7f6558dSRoger Tseng 
576c7f6558dSRoger Tseng 	kfree(buf);
577c7f6558dSRoger Tseng }
578c7f6558dSRoger Tseng 
sd_change_phase(struct rtsx_usb_sdmmc * host,u8 sample_point,int tx)579c7f6558dSRoger Tseng static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx)
580c7f6558dSRoger Tseng {
581c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
582c7f6558dSRoger Tseng 
583c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "%s: %s sample_point = %d\n",
584c7f6558dSRoger Tseng 			__func__, tx ? "TX" : "RX", sample_point);
585c7f6558dSRoger Tseng 
586c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
587c7f6558dSRoger Tseng 
588c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
589c7f6558dSRoger Tseng 
590c7f6558dSRoger Tseng 	if (tx)
591c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
592c7f6558dSRoger Tseng 				0x0F, sample_point);
593c7f6558dSRoger Tseng 	else
594c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK1_CTL,
595c7f6558dSRoger Tseng 				0x0F, sample_point);
596c7f6558dSRoger Tseng 
597c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
598c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
599c7f6558dSRoger Tseng 			PHASE_NOT_RESET, PHASE_NOT_RESET);
600c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0);
601c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_RST, 0);
602c7f6558dSRoger Tseng 
6038dae6a24SQinglang Miao 	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
604c7f6558dSRoger Tseng }
605c7f6558dSRoger Tseng 
get_phase_point(u32 phase_map,unsigned int idx)606c7f6558dSRoger Tseng static inline u32 get_phase_point(u32 phase_map, unsigned int idx)
607c7f6558dSRoger Tseng {
608c7f6558dSRoger Tseng 	idx &= MAX_PHASE;
609c7f6558dSRoger Tseng 	return phase_map & (1 << idx);
610c7f6558dSRoger Tseng }
611c7f6558dSRoger Tseng 
get_phase_len(u32 phase_map,unsigned int idx)612c7f6558dSRoger Tseng static int get_phase_len(u32 phase_map, unsigned int idx)
613c7f6558dSRoger Tseng {
614c7f6558dSRoger Tseng 	int i;
615c7f6558dSRoger Tseng 
616c7f6558dSRoger Tseng 	for (i = 0; i < MAX_PHASE + 1; i++) {
617c7f6558dSRoger Tseng 		if (get_phase_point(phase_map, idx + i) == 0)
618c7f6558dSRoger Tseng 			return i;
619c7f6558dSRoger Tseng 	}
620c7f6558dSRoger Tseng 	return MAX_PHASE + 1;
621c7f6558dSRoger Tseng }
622c7f6558dSRoger Tseng 
sd_search_final_phase(struct rtsx_usb_sdmmc * host,u32 phase_map)623c7f6558dSRoger Tseng static u8 sd_search_final_phase(struct rtsx_usb_sdmmc *host, u32 phase_map)
624c7f6558dSRoger Tseng {
625c7f6558dSRoger Tseng 	int start = 0, len = 0;
626c7f6558dSRoger Tseng 	int start_final = 0, len_final = 0;
627c7f6558dSRoger Tseng 	u8 final_phase = 0xFF;
628c7f6558dSRoger Tseng 
629c7f6558dSRoger Tseng 	if (phase_map == 0) {
630c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "Phase: [map:%x]\n", phase_map);
631c7f6558dSRoger Tseng 		return final_phase;
632c7f6558dSRoger Tseng 	}
633c7f6558dSRoger Tseng 
634c7f6558dSRoger Tseng 	while (start < MAX_PHASE + 1) {
635c7f6558dSRoger Tseng 		len = get_phase_len(phase_map, start);
636c7f6558dSRoger Tseng 		if (len_final < len) {
637c7f6558dSRoger Tseng 			start_final = start;
638c7f6558dSRoger Tseng 			len_final = len;
639c7f6558dSRoger Tseng 		}
640c7f6558dSRoger Tseng 		start += len ? len : 1;
641c7f6558dSRoger Tseng 	}
642c7f6558dSRoger Tseng 
643c7f6558dSRoger Tseng 	final_phase = (start_final + len_final / 2) & MAX_PHASE;
644c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "Phase: [map:%x] [maxlen:%d] [final:%d]\n",
645c7f6558dSRoger Tseng 		phase_map, len_final, final_phase);
646c7f6558dSRoger Tseng 
647c7f6558dSRoger Tseng 	return final_phase;
648c7f6558dSRoger Tseng }
649c7f6558dSRoger Tseng 
sd_wait_data_idle(struct rtsx_usb_sdmmc * host)650c7f6558dSRoger Tseng static void sd_wait_data_idle(struct rtsx_usb_sdmmc *host)
651c7f6558dSRoger Tseng {
652d463cf4eSLee Jones 	int i;
653c7f6558dSRoger Tseng 	u8 val = 0;
654c7f6558dSRoger Tseng 
655c7f6558dSRoger Tseng 	for (i = 0; i < 100; i++) {
656d463cf4eSLee Jones 		rtsx_usb_ep0_read_register(host->ucr, SD_DATA_STATE, &val);
657c7f6558dSRoger Tseng 		if (val & SD_DATA_IDLE)
658c7f6558dSRoger Tseng 			return;
659c7f6558dSRoger Tseng 
660c7f6558dSRoger Tseng 		usleep_range(100, 1000);
661c7f6558dSRoger Tseng 	}
662c7f6558dSRoger Tseng }
663c7f6558dSRoger Tseng 
sd_tuning_rx_cmd(struct rtsx_usb_sdmmc * host,u8 opcode,u8 sample_point)664c7f6558dSRoger Tseng static int sd_tuning_rx_cmd(struct rtsx_usb_sdmmc *host,
665c7f6558dSRoger Tseng 		u8 opcode, u8 sample_point)
666c7f6558dSRoger Tseng {
667c7f6558dSRoger Tseng 	int err;
668c7836d15SMasahiro Yamada 	struct mmc_command cmd = {};
669c7f6558dSRoger Tseng 
670c7f6558dSRoger Tseng 	err = sd_change_phase(host, sample_point, 0);
671c7f6558dSRoger Tseng 	if (err)
672c7f6558dSRoger Tseng 		return err;
673c7f6558dSRoger Tseng 
674c7f6558dSRoger Tseng 	cmd.opcode = MMC_SEND_TUNING_BLOCK;
675c7f6558dSRoger Tseng 	err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100);
676c7f6558dSRoger Tseng 	if (err) {
677c7f6558dSRoger Tseng 		/* Wait till SD DATA IDLE */
678c7f6558dSRoger Tseng 		sd_wait_data_idle(host);
679c7f6558dSRoger Tseng 		sd_clear_error(host);
680c7f6558dSRoger Tseng 		return err;
681c7f6558dSRoger Tseng 	}
682c7f6558dSRoger Tseng 
683c7f6558dSRoger Tseng 	return 0;
684c7f6558dSRoger Tseng }
685c7f6558dSRoger Tseng 
sd_tuning_phase(struct rtsx_usb_sdmmc * host,u8 opcode,u16 * phase_map)686c7f6558dSRoger Tseng static void sd_tuning_phase(struct rtsx_usb_sdmmc *host,
687c7f6558dSRoger Tseng 		u8 opcode, u16 *phase_map)
688c7f6558dSRoger Tseng {
689c7f6558dSRoger Tseng 	int err, i;
690c7f6558dSRoger Tseng 	u16 raw_phase_map = 0;
691c7f6558dSRoger Tseng 
692c7f6558dSRoger Tseng 	for (i = MAX_PHASE; i >= 0; i--) {
693c7f6558dSRoger Tseng 		err = sd_tuning_rx_cmd(host, opcode, (u8)i);
694c7f6558dSRoger Tseng 		if (!err)
695c7f6558dSRoger Tseng 			raw_phase_map |= 1 << i;
696c7f6558dSRoger Tseng 	}
697c7f6558dSRoger Tseng 
698c7f6558dSRoger Tseng 	if (phase_map)
699c7f6558dSRoger Tseng 		*phase_map = raw_phase_map;
700c7f6558dSRoger Tseng }
701c7f6558dSRoger Tseng 
sd_tuning_rx(struct rtsx_usb_sdmmc * host,u8 opcode)702c7f6558dSRoger Tseng static int sd_tuning_rx(struct rtsx_usb_sdmmc *host, u8 opcode)
703c7f6558dSRoger Tseng {
704c7f6558dSRoger Tseng 	int err, i;
705c7f6558dSRoger Tseng 	u16 raw_phase_map[RX_TUNING_CNT] = {0}, phase_map;
706c7f6558dSRoger Tseng 	u8 final_phase;
707c7f6558dSRoger Tseng 
708c7f6558dSRoger Tseng 	/* setting fixed default TX phase */
709c7f6558dSRoger Tseng 	err = sd_change_phase(host, 0x01, 1);
710c7f6558dSRoger Tseng 	if (err) {
711c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "TX phase setting failed\n");
712c7f6558dSRoger Tseng 		return err;
713c7f6558dSRoger Tseng 	}
714c7f6558dSRoger Tseng 
715c7f6558dSRoger Tseng 	/* tuning RX phase */
716c7f6558dSRoger Tseng 	for (i = 0; i < RX_TUNING_CNT; i++) {
717c7f6558dSRoger Tseng 		sd_tuning_phase(host, opcode, &(raw_phase_map[i]));
718c7f6558dSRoger Tseng 
719c7f6558dSRoger Tseng 		if (raw_phase_map[i] == 0)
720c7f6558dSRoger Tseng 			break;
721c7f6558dSRoger Tseng 	}
722c7f6558dSRoger Tseng 
723c7f6558dSRoger Tseng 	phase_map = 0xFFFF;
724c7f6558dSRoger Tseng 	for (i = 0; i < RX_TUNING_CNT; i++) {
725c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "RX raw_phase_map[%d] = 0x%04x\n",
726c7f6558dSRoger Tseng 				i, raw_phase_map[i]);
727c7f6558dSRoger Tseng 		phase_map &= raw_phase_map[i];
728c7f6558dSRoger Tseng 	}
729c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "RX phase_map = 0x%04x\n", phase_map);
730c7f6558dSRoger Tseng 
731c7f6558dSRoger Tseng 	if (phase_map) {
732c7f6558dSRoger Tseng 		final_phase = sd_search_final_phase(host, phase_map);
733c7f6558dSRoger Tseng 		if (final_phase == 0xFF)
734c7f6558dSRoger Tseng 			return -EINVAL;
735c7f6558dSRoger Tseng 
736c7f6558dSRoger Tseng 		err = sd_change_phase(host, final_phase, 0);
737c7f6558dSRoger Tseng 		if (err)
738c7f6558dSRoger Tseng 			return err;
739c7f6558dSRoger Tseng 	} else {
740c7f6558dSRoger Tseng 		return -EINVAL;
741c7f6558dSRoger Tseng 	}
742c7f6558dSRoger Tseng 
743c7f6558dSRoger Tseng 	return 0;
744c7f6558dSRoger Tseng }
745c7f6558dSRoger Tseng 
sdmmc_get_ro(struct mmc_host * mmc)746c7f6558dSRoger Tseng static int sdmmc_get_ro(struct mmc_host *mmc)
747c7f6558dSRoger Tseng {
748c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
749c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
750c7f6558dSRoger Tseng 	int err;
751c7f6558dSRoger Tseng 	u16 val;
752c7f6558dSRoger Tseng 
753c7f6558dSRoger Tseng 	if (host->host_removal)
754c7f6558dSRoger Tseng 		return -ENOMEDIUM;
755c7f6558dSRoger Tseng 
756c7f6558dSRoger Tseng 	mutex_lock(&ucr->dev_mutex);
757c7f6558dSRoger Tseng 
758c7f6558dSRoger Tseng 	/* Check SD card detect */
759c7f6558dSRoger Tseng 	err = rtsx_usb_get_card_status(ucr, &val);
760c7f6558dSRoger Tseng 
761c7f6558dSRoger Tseng 	mutex_unlock(&ucr->dev_mutex);
762c7f6558dSRoger Tseng 
763c7f6558dSRoger Tseng 
764c7f6558dSRoger Tseng 	/* Treat failed detection as non-ro */
765c7f6558dSRoger Tseng 	if (err)
766c7f6558dSRoger Tseng 		return 0;
767c7f6558dSRoger Tseng 
768c7f6558dSRoger Tseng 	if (val & SD_WP)
769c7f6558dSRoger Tseng 		return 1;
770c7f6558dSRoger Tseng 
771c7f6558dSRoger Tseng 	return 0;
772c7f6558dSRoger Tseng }
773c7f6558dSRoger Tseng 
sdmmc_get_cd(struct mmc_host * mmc)774c7f6558dSRoger Tseng static int sdmmc_get_cd(struct mmc_host *mmc)
775c7f6558dSRoger Tseng {
776c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
777c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
778c7f6558dSRoger Tseng 	int err;
779c7f6558dSRoger Tseng 	u16 val;
780c7f6558dSRoger Tseng 
781c7f6558dSRoger Tseng 	if (host->host_removal)
782c7f6558dSRoger Tseng 		return -ENOMEDIUM;
783c7f6558dSRoger Tseng 
784c7f6558dSRoger Tseng 	mutex_lock(&ucr->dev_mutex);
785c7f6558dSRoger Tseng 
786c7f6558dSRoger Tseng 	/* Check SD card detect */
787c7f6558dSRoger Tseng 	err = rtsx_usb_get_card_status(ucr, &val);
788c7f6558dSRoger Tseng 
789c7f6558dSRoger Tseng 	mutex_unlock(&ucr->dev_mutex);
790c7f6558dSRoger Tseng 
791c7f6558dSRoger Tseng 	/* Treat failed detection as non-exist */
792c7f6558dSRoger Tseng 	if (err)
793c7f6558dSRoger Tseng 		goto no_card;
794c7f6558dSRoger Tseng 
795c7f6558dSRoger Tseng 	if (val & SD_CD) {
796c7f6558dSRoger Tseng 		host->card_exist = true;
797c7f6558dSRoger Tseng 		return 1;
798c7f6558dSRoger Tseng 	}
799c7f6558dSRoger Tseng 
800c7f6558dSRoger Tseng no_card:
801c7f6558dSRoger Tseng 	host->card_exist = false;
802c7f6558dSRoger Tseng 	return 0;
803c7f6558dSRoger Tseng }
804c7f6558dSRoger Tseng 
sdmmc_request(struct mmc_host * mmc,struct mmc_request * mrq)805c7f6558dSRoger Tseng static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
806c7f6558dSRoger Tseng {
807c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
808c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
809c7f6558dSRoger Tseng 	struct mmc_command *cmd = mrq->cmd;
810c7f6558dSRoger Tseng 	struct mmc_data *data = mrq->data;
811c7f6558dSRoger Tseng 	unsigned int data_size = 0;
812c7f6558dSRoger Tseng 
813c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "%s\n", __func__);
814c7f6558dSRoger Tseng 
815c7f6558dSRoger Tseng 	if (host->host_removal) {
816c7f6558dSRoger Tseng 		cmd->error = -ENOMEDIUM;
817c7f6558dSRoger Tseng 		goto finish;
818c7f6558dSRoger Tseng 	}
819c7f6558dSRoger Tseng 
820c7f6558dSRoger Tseng 	if ((!host->card_exist)) {
821c7f6558dSRoger Tseng 		cmd->error = -ENOMEDIUM;
822c7f6558dSRoger Tseng 		goto finish_detect_card;
823c7f6558dSRoger Tseng 	}
824c7f6558dSRoger Tseng 
825c7f6558dSRoger Tseng 	mutex_lock(&ucr->dev_mutex);
826c7f6558dSRoger Tseng 
827c7f6558dSRoger Tseng 	mutex_lock(&host->host_mutex);
828c7f6558dSRoger Tseng 	host->mrq = mrq;
829c7f6558dSRoger Tseng 	mutex_unlock(&host->host_mutex);
830c7f6558dSRoger Tseng 
831c7f6558dSRoger Tseng 	if (mrq->data)
832c7f6558dSRoger Tseng 		data_size = data->blocks * data->blksz;
833c7f6558dSRoger Tseng 
834c7f6558dSRoger Tseng 	if (!data_size) {
835c7f6558dSRoger Tseng 		sd_send_cmd_get_rsp(host, cmd);
836c7f6558dSRoger Tseng 	} else if ((!(data_size % 512) && cmd->opcode != MMC_SEND_EXT_CSD) ||
837c7f6558dSRoger Tseng 		   mmc_op_multi(cmd->opcode)) {
838c7f6558dSRoger Tseng 		sd_send_cmd_get_rsp(host, cmd);
839c7f6558dSRoger Tseng 
840c7f6558dSRoger Tseng 		if (!cmd->error) {
841c7f6558dSRoger Tseng 			sd_rw_multi(host, mrq);
842c7f6558dSRoger Tseng 
843c7f6558dSRoger Tseng 			if (mmc_op_multi(cmd->opcode) && mrq->stop) {
844c7f6558dSRoger Tseng 				sd_send_cmd_get_rsp(host, mrq->stop);
845c7f6558dSRoger Tseng 				rtsx_usb_write_register(ucr, MC_FIFO_CTL,
846c7f6558dSRoger Tseng 						FIFO_FLUSH, FIFO_FLUSH);
847c7f6558dSRoger Tseng 			}
848c7f6558dSRoger Tseng 		}
849c7f6558dSRoger Tseng 	} else {
850c7f6558dSRoger Tseng 		sd_normal_rw(host, mrq);
851c7f6558dSRoger Tseng 	}
852c7f6558dSRoger Tseng 
853c7f6558dSRoger Tseng 	if (mrq->data) {
854c7f6558dSRoger Tseng 		if (cmd->error || data->error)
855c7f6558dSRoger Tseng 			data->bytes_xfered = 0;
856c7f6558dSRoger Tseng 		else
857c7f6558dSRoger Tseng 			data->bytes_xfered = data->blocks * data->blksz;
858c7f6558dSRoger Tseng 	}
859c7f6558dSRoger Tseng 
860c7f6558dSRoger Tseng 	mutex_unlock(&ucr->dev_mutex);
861c7f6558dSRoger Tseng 
862c7f6558dSRoger Tseng finish_detect_card:
863c7f6558dSRoger Tseng 	if (cmd->error) {
864c7f6558dSRoger Tseng 		/*
865c7f6558dSRoger Tseng 		 * detect card when fail to update card existence state and
866c7f6558dSRoger Tseng 		 * speed up card removal when retry
867c7f6558dSRoger Tseng 		 */
868c7f6558dSRoger Tseng 		sdmmc_get_cd(mmc);
869c7f6558dSRoger Tseng 		dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error);
870c7f6558dSRoger Tseng 	}
871c7f6558dSRoger Tseng 
872c7f6558dSRoger Tseng finish:
873c7f6558dSRoger Tseng 	mutex_lock(&host->host_mutex);
874c7f6558dSRoger Tseng 	host->mrq = NULL;
875c7f6558dSRoger Tseng 	mutex_unlock(&host->host_mutex);
876c7f6558dSRoger Tseng 
877c7f6558dSRoger Tseng 	mmc_request_done(mmc, mrq);
878c7f6558dSRoger Tseng }
879c7f6558dSRoger Tseng 
sd_set_bus_width(struct rtsx_usb_sdmmc * host,unsigned char bus_width)880c7f6558dSRoger Tseng static int sd_set_bus_width(struct rtsx_usb_sdmmc *host,
881c7f6558dSRoger Tseng 		unsigned char bus_width)
882c7f6558dSRoger Tseng {
883c7f6558dSRoger Tseng 	int err = 0;
884b388dc3cSColin Ian King 	static const u8 width[] = {
885c7f6558dSRoger Tseng 		[MMC_BUS_WIDTH_1] = SD_BUS_WIDTH_1BIT,
886c7f6558dSRoger Tseng 		[MMC_BUS_WIDTH_4] = SD_BUS_WIDTH_4BIT,
887c7f6558dSRoger Tseng 		[MMC_BUS_WIDTH_8] = SD_BUS_WIDTH_8BIT,
888c7f6558dSRoger Tseng 	};
889c7f6558dSRoger Tseng 
890c7f6558dSRoger Tseng 	if (bus_width <= MMC_BUS_WIDTH_8)
891c7f6558dSRoger Tseng 		err = rtsx_usb_write_register(host->ucr, SD_CFG1,
892c7f6558dSRoger Tseng 				0x03, width[bus_width]);
893c7f6558dSRoger Tseng 
894c7f6558dSRoger Tseng 	return err;
895c7f6558dSRoger Tseng }
896c7f6558dSRoger Tseng 
sd_pull_ctl_disable_lqfp48(struct rtsx_ucr * ucr)897c7f6558dSRoger Tseng static int sd_pull_ctl_disable_lqfp48(struct rtsx_ucr *ucr)
898c7f6558dSRoger Tseng {
899c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
900c7f6558dSRoger Tseng 
901c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
902c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
903c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
904c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
905c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
906c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
907c7f6558dSRoger Tseng 
908c7f6558dSRoger Tseng 	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
909c7f6558dSRoger Tseng }
910c7f6558dSRoger Tseng 
sd_pull_ctl_disable_qfn24(struct rtsx_ucr * ucr)911c7f6558dSRoger Tseng static int sd_pull_ctl_disable_qfn24(struct rtsx_ucr *ucr)
912c7f6558dSRoger Tseng {
913c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
914c7f6558dSRoger Tseng 
915c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65);
916c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
917c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
918c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
919c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56);
920c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
921c7f6558dSRoger Tseng 
922c7f6558dSRoger Tseng 	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
923c7f6558dSRoger Tseng }
924c7f6558dSRoger Tseng 
sd_pull_ctl_enable_lqfp48(struct rtsx_ucr * ucr)925c7f6558dSRoger Tseng static int sd_pull_ctl_enable_lqfp48(struct rtsx_ucr *ucr)
926c7f6558dSRoger Tseng {
927c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
928c7f6558dSRoger Tseng 
929c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xAA);
930c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0xAA);
931c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA9);
932c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
933c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
934c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
935c7f6558dSRoger Tseng 
936c7f6558dSRoger Tseng 	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
937c7f6558dSRoger Tseng }
938c7f6558dSRoger Tseng 
sd_pull_ctl_enable_qfn24(struct rtsx_ucr * ucr)939c7f6558dSRoger Tseng static int sd_pull_ctl_enable_qfn24(struct rtsx_ucr *ucr)
940c7f6558dSRoger Tseng {
941c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
942c7f6558dSRoger Tseng 
943c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xA5);
944c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x9A);
945c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA5);
946c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x9A);
947c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x65);
948c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x5A);
949c7f6558dSRoger Tseng 
950c7f6558dSRoger Tseng 	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
951c7f6558dSRoger Tseng }
952c7f6558dSRoger Tseng 
sd_power_on(struct rtsx_usb_sdmmc * host)953c7f6558dSRoger Tseng static int sd_power_on(struct rtsx_usb_sdmmc *host)
954c7f6558dSRoger Tseng {
955c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
956c7f6558dSRoger Tseng 	int err;
957c7f6558dSRoger Tseng 
958c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "%s\n", __func__);
959c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
960c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL);
961c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SHARE_MODE,
962c7f6558dSRoger Tseng 			CARD_SHARE_MASK, CARD_SHARE_SD);
963c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN,
964c7f6558dSRoger Tseng 			SD_CLK_EN, SD_CLK_EN);
965c7f6558dSRoger Tseng 	err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
966c7f6558dSRoger Tseng 	if (err)
967c7f6558dSRoger Tseng 		return err;
968c7f6558dSRoger Tseng 
969c7f6558dSRoger Tseng 	if (CHECK_PKG(ucr, LQFP48))
970c7f6558dSRoger Tseng 		err = sd_pull_ctl_enable_lqfp48(ucr);
971c7f6558dSRoger Tseng 	else
972c7f6558dSRoger Tseng 		err = sd_pull_ctl_enable_qfn24(ucr);
973c7f6558dSRoger Tseng 	if (err)
974c7f6558dSRoger Tseng 		return err;
975c7f6558dSRoger Tseng 
976c7f6558dSRoger Tseng 	err = rtsx_usb_write_register(ucr, CARD_PWR_CTL,
977c7f6558dSRoger Tseng 			POWER_MASK, PARTIAL_POWER_ON);
978c7f6558dSRoger Tseng 	if (err)
979c7f6558dSRoger Tseng 		return err;
980c7f6558dSRoger Tseng 
981c7f6558dSRoger Tseng 	usleep_range(800, 1000);
982c7f6558dSRoger Tseng 
983c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
984c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
985c7f6558dSRoger Tseng 			POWER_MASK|LDO3318_PWR_MASK, POWER_ON|LDO_ON);
986c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE,
987c7f6558dSRoger Tseng 			SD_OUTPUT_EN, SD_OUTPUT_EN);
988c7f6558dSRoger Tseng 
989c7f6558dSRoger Tseng 	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
990c7f6558dSRoger Tseng }
991c7f6558dSRoger Tseng 
sd_power_off(struct rtsx_usb_sdmmc * host)992c7f6558dSRoger Tseng static int sd_power_off(struct rtsx_usb_sdmmc *host)
993c7f6558dSRoger Tseng {
994c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
995c7f6558dSRoger Tseng 	int err;
996c7f6558dSRoger Tseng 
997c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "%s\n", __func__);
998c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
999c7f6558dSRoger Tseng 
1000c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0);
1001c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0);
1002c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
1003c7f6558dSRoger Tseng 			POWER_MASK, POWER_OFF);
1004c7f6558dSRoger Tseng 	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
1005c7f6558dSRoger Tseng 			POWER_MASK|LDO3318_PWR_MASK, POWER_OFF|LDO_SUSPEND);
1006c7f6558dSRoger Tseng 
1007c7f6558dSRoger Tseng 	err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
1008c7f6558dSRoger Tseng 	if (err)
1009c7f6558dSRoger Tseng 		return err;
1010c7f6558dSRoger Tseng 
1011c7f6558dSRoger Tseng 	if (CHECK_PKG(ucr, LQFP48))
1012c7f6558dSRoger Tseng 			return sd_pull_ctl_disable_lqfp48(ucr);
1013c7f6558dSRoger Tseng 	return sd_pull_ctl_disable_qfn24(ucr);
1014c7f6558dSRoger Tseng }
1015c7f6558dSRoger Tseng 
sd_set_power_mode(struct rtsx_usb_sdmmc * host,unsigned char power_mode)1016c7f6558dSRoger Tseng static int sd_set_power_mode(struct rtsx_usb_sdmmc *host,
1017c7f6558dSRoger Tseng 		unsigned char power_mode)
1018c7f6558dSRoger Tseng {
1019c7f6558dSRoger Tseng 	int err;
1020c7f6558dSRoger Tseng 
1021c7f6558dSRoger Tseng 	if (power_mode != MMC_POWER_OFF)
1022c7f6558dSRoger Tseng 		power_mode = MMC_POWER_ON;
1023c7f6558dSRoger Tseng 
1024c7f6558dSRoger Tseng 	if (power_mode == host->power_mode)
1025c7f6558dSRoger Tseng 		return 0;
1026c7f6558dSRoger Tseng 
1027c7f6558dSRoger Tseng 	if (power_mode == MMC_POWER_OFF) {
1028c7f6558dSRoger Tseng 		err = sd_power_off(host);
1029f275179fSUlf Hansson 		pm_runtime_put_noidle(sdmmc_dev(host));
1030c7f6558dSRoger Tseng 	} else {
1031f275179fSUlf Hansson 		pm_runtime_get_noresume(sdmmc_dev(host));
1032c7f6558dSRoger Tseng 		err = sd_power_on(host);
1033c7f6558dSRoger Tseng 	}
1034c7f6558dSRoger Tseng 
1035c7f6558dSRoger Tseng 	if (!err)
1036c7f6558dSRoger Tseng 		host->power_mode = power_mode;
1037c7f6558dSRoger Tseng 
1038c7f6558dSRoger Tseng 	return err;
1039c7f6558dSRoger Tseng }
1040c7f6558dSRoger Tseng 
sd_set_timing(struct rtsx_usb_sdmmc * host,unsigned char timing,bool * ddr_mode)1041c7f6558dSRoger Tseng static int sd_set_timing(struct rtsx_usb_sdmmc *host,
1042c7f6558dSRoger Tseng 		unsigned char timing, bool *ddr_mode)
1043c7f6558dSRoger Tseng {
1044c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
1045c7f6558dSRoger Tseng 
1046c7f6558dSRoger Tseng 	*ddr_mode = false;
1047c7f6558dSRoger Tseng 
1048c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
1049c7f6558dSRoger Tseng 
1050c7f6558dSRoger Tseng 	switch (timing) {
1051c7f6558dSRoger Tseng 	case MMC_TIMING_UHS_SDR104:
1052c7f6558dSRoger Tseng 	case MMC_TIMING_UHS_SDR50:
1053c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1,
1054c7f6558dSRoger Tseng 				0x0C | SD_ASYNC_FIFO_RST,
1055c7f6558dSRoger Tseng 				SD_30_MODE | SD_ASYNC_FIFO_RST);
1056c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
1057c7f6558dSRoger Tseng 				CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
1058c7f6558dSRoger Tseng 		break;
1059c7f6558dSRoger Tseng 
1060c7f6558dSRoger Tseng 	case MMC_TIMING_UHS_DDR50:
1061c7f6558dSRoger Tseng 		*ddr_mode = true;
1062c7f6558dSRoger Tseng 
1063c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1,
1064c7f6558dSRoger Tseng 				0x0C | SD_ASYNC_FIFO_RST,
1065c7f6558dSRoger Tseng 				SD_DDR_MODE | SD_ASYNC_FIFO_RST);
1066c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
1067c7f6558dSRoger Tseng 				CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
1068c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PUSH_POINT_CTL,
1069c7f6558dSRoger Tseng 				DDR_VAR_TX_CMD_DAT, DDR_VAR_TX_CMD_DAT);
1070c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
1071c7f6558dSRoger Tseng 				DDR_VAR_RX_DAT | DDR_VAR_RX_CMD,
1072c7f6558dSRoger Tseng 				DDR_VAR_RX_DAT | DDR_VAR_RX_CMD);
1073c7f6558dSRoger Tseng 		break;
1074c7f6558dSRoger Tseng 
1075c7f6558dSRoger Tseng 	case MMC_TIMING_MMC_HS:
1076c7f6558dSRoger Tseng 	case MMC_TIMING_SD_HS:
1077c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1,
1078c7f6558dSRoger Tseng 				0x0C, SD_20_MODE);
1079c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
1080c7f6558dSRoger Tseng 				CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1);
1081c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PUSH_POINT_CTL,
1082c7f6558dSRoger Tseng 				SD20_TX_SEL_MASK, SD20_TX_14_AHEAD);
1083c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
1084c7f6558dSRoger Tseng 				SD20_RX_SEL_MASK, SD20_RX_14_DELAY);
1085c7f6558dSRoger Tseng 		break;
1086c7f6558dSRoger Tseng 
1087c7f6558dSRoger Tseng 	default:
1088c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
1089c7f6558dSRoger Tseng 				SD_CFG1, 0x0C, SD_20_MODE);
1090c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
1091c7f6558dSRoger Tseng 				CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1);
1092c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
1093c7f6558dSRoger Tseng 				SD_PUSH_POINT_CTL, 0xFF, 0);
1094c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
1095c7f6558dSRoger Tseng 				SD20_RX_SEL_MASK, SD20_RX_POS_EDGE);
1096c7f6558dSRoger Tseng 		break;
1097c7f6558dSRoger Tseng 	}
1098c7f6558dSRoger Tseng 
1099aa8c8cd0Sye xingchen 	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
1100c7f6558dSRoger Tseng }
1101c7f6558dSRoger Tseng 
sdmmc_set_ios(struct mmc_host * mmc,struct mmc_ios * ios)1102c7f6558dSRoger Tseng static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1103c7f6558dSRoger Tseng {
1104c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
1105c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
1106c7f6558dSRoger Tseng 
1107c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "%s\n", __func__);
1108c7f6558dSRoger Tseng 	mutex_lock(&ucr->dev_mutex);
1109c7f6558dSRoger Tseng 
1110c7f6558dSRoger Tseng 	sd_set_power_mode(host, ios->power_mode);
1111c7f6558dSRoger Tseng 	sd_set_bus_width(host, ios->bus_width);
1112c7f6558dSRoger Tseng 	sd_set_timing(host, ios->timing, &host->ddr_mode);
1113c7f6558dSRoger Tseng 
1114c7f6558dSRoger Tseng 	host->vpclk = false;
1115c7f6558dSRoger Tseng 	host->double_clk = true;
1116c7f6558dSRoger Tseng 
1117c7f6558dSRoger Tseng 	switch (ios->timing) {
1118c7f6558dSRoger Tseng 	case MMC_TIMING_UHS_SDR104:
1119c7f6558dSRoger Tseng 	case MMC_TIMING_UHS_SDR50:
1120c7f6558dSRoger Tseng 		host->ssc_depth = SSC_DEPTH_2M;
1121c7f6558dSRoger Tseng 		host->vpclk = true;
1122c7f6558dSRoger Tseng 		host->double_clk = false;
1123c7f6558dSRoger Tseng 		break;
1124c7f6558dSRoger Tseng 	case MMC_TIMING_UHS_DDR50:
1125c7f6558dSRoger Tseng 	case MMC_TIMING_UHS_SDR25:
1126c7f6558dSRoger Tseng 		host->ssc_depth = SSC_DEPTH_1M;
1127c7f6558dSRoger Tseng 		break;
1128c7f6558dSRoger Tseng 	default:
1129c7f6558dSRoger Tseng 		host->ssc_depth = SSC_DEPTH_512K;
1130c7f6558dSRoger Tseng 		break;
1131c7f6558dSRoger Tseng 	}
1132c7f6558dSRoger Tseng 
1133c7f6558dSRoger Tseng 	host->initial_mode = (ios->clock <= 1000000) ? true : false;
1134c7f6558dSRoger Tseng 	host->clock = ios->clock;
1135c7f6558dSRoger Tseng 
1136c7f6558dSRoger Tseng 	rtsx_usb_switch_clock(host->ucr, host->clock, host->ssc_depth,
1137c7f6558dSRoger Tseng 			host->initial_mode, host->double_clk, host->vpclk);
1138c7f6558dSRoger Tseng 
1139c7f6558dSRoger Tseng 	mutex_unlock(&ucr->dev_mutex);
1140c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "%s end\n", __func__);
1141c7f6558dSRoger Tseng }
1142c7f6558dSRoger Tseng 
sdmmc_switch_voltage(struct mmc_host * mmc,struct mmc_ios * ios)1143c7f6558dSRoger Tseng static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
1144c7f6558dSRoger Tseng {
1145c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
1146c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
1147c7f6558dSRoger Tseng 	int err = 0;
1148c7f6558dSRoger Tseng 
1149c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "%s: signal_voltage = %d\n",
1150c7f6558dSRoger Tseng 			__func__, ios->signal_voltage);
1151c7f6558dSRoger Tseng 
1152c7f6558dSRoger Tseng 	if (host->host_removal)
1153c7f6558dSRoger Tseng 		return -ENOMEDIUM;
1154c7f6558dSRoger Tseng 
1155c7f6558dSRoger Tseng 	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120)
1156c7f6558dSRoger Tseng 		return -EPERM;
1157c7f6558dSRoger Tseng 
1158c7f6558dSRoger Tseng 	mutex_lock(&ucr->dev_mutex);
1159c7f6558dSRoger Tseng 
1160c7f6558dSRoger Tseng 	err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD);
1161c7f6558dSRoger Tseng 	if (err) {
1162c7f6558dSRoger Tseng 		mutex_unlock(&ucr->dev_mutex);
1163c7f6558dSRoger Tseng 		return err;
1164c7f6558dSRoger Tseng 	}
1165c7f6558dSRoger Tseng 
1166c7f6558dSRoger Tseng 	/* Let mmc core do the busy checking, simply stop the forced-toggle
1167c7f6558dSRoger Tseng 	 * clock(while issuing CMD11) and switch voltage.
1168c7f6558dSRoger Tseng 	 */
1169c7f6558dSRoger Tseng 	rtsx_usb_init_cmd(ucr);
1170c7f6558dSRoger Tseng 
1171c7f6558dSRoger Tseng 	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
1172c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PAD_CTL,
1173c7f6558dSRoger Tseng 				SD_IO_USING_1V8, SD_IO_USING_3V3);
1174c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG,
1175c7f6558dSRoger Tseng 				TUNE_SD18_MASK, TUNE_SD18_3V3);
1176c7f6558dSRoger Tseng 	} else {
1177c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BUS_STAT,
1178c7f6558dSRoger Tseng 				SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
1179c7f6558dSRoger Tseng 				SD_CLK_FORCE_STOP);
1180c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PAD_CTL,
1181c7f6558dSRoger Tseng 				SD_IO_USING_1V8, SD_IO_USING_1V8);
1182c7f6558dSRoger Tseng 		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG,
1183c7f6558dSRoger Tseng 				TUNE_SD18_MASK, TUNE_SD18_1V8);
1184c7f6558dSRoger Tseng 	}
1185c7f6558dSRoger Tseng 
1186c7f6558dSRoger Tseng 	err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
1187c7f6558dSRoger Tseng 	mutex_unlock(&ucr->dev_mutex);
1188c7f6558dSRoger Tseng 
1189c7f6558dSRoger Tseng 	return err;
1190c7f6558dSRoger Tseng }
1191c7f6558dSRoger Tseng 
sdmmc_card_busy(struct mmc_host * mmc)1192c7f6558dSRoger Tseng static int sdmmc_card_busy(struct mmc_host *mmc)
1193c7f6558dSRoger Tseng {
1194c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
1195c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
1196c7f6558dSRoger Tseng 	int err;
1197c7f6558dSRoger Tseng 	u8 stat;
1198c7f6558dSRoger Tseng 	u8 mask = SD_DAT3_STATUS | SD_DAT2_STATUS | SD_DAT1_STATUS
1199c7f6558dSRoger Tseng 		| SD_DAT0_STATUS;
1200c7f6558dSRoger Tseng 
1201c7f6558dSRoger Tseng 	dev_dbg(sdmmc_dev(host), "%s\n", __func__);
1202c7f6558dSRoger Tseng 
1203c7f6558dSRoger Tseng 	mutex_lock(&ucr->dev_mutex);
1204c7f6558dSRoger Tseng 
1205c7f6558dSRoger Tseng 	err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
1206c7f6558dSRoger Tseng 			SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
1207c7f6558dSRoger Tseng 			SD_CLK_TOGGLE_EN);
1208c7f6558dSRoger Tseng 	if (err)
1209c7f6558dSRoger Tseng 		goto out;
1210c7f6558dSRoger Tseng 
1211c7f6558dSRoger Tseng 	mdelay(1);
1212c7f6558dSRoger Tseng 
1213c7f6558dSRoger Tseng 	err = rtsx_usb_read_register(ucr, SD_BUS_STAT, &stat);
1214c7f6558dSRoger Tseng 	if (err)
1215c7f6558dSRoger Tseng 		goto out;
1216c7f6558dSRoger Tseng 
1217c7f6558dSRoger Tseng 	err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
1218c7f6558dSRoger Tseng 			SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
1219c7f6558dSRoger Tseng out:
1220c7f6558dSRoger Tseng 	mutex_unlock(&ucr->dev_mutex);
1221c7f6558dSRoger Tseng 
1222c7f6558dSRoger Tseng 	if (err)
1223c7f6558dSRoger Tseng 		return err;
1224c7f6558dSRoger Tseng 
1225c7f6558dSRoger Tseng 	/* check if any pin between dat[0:3] is low */
1226c7f6558dSRoger Tseng 	if ((stat & mask) != mask)
1227c7f6558dSRoger Tseng 		return 1;
1228c7f6558dSRoger Tseng 	else
1229c7f6558dSRoger Tseng 		return 0;
1230c7f6558dSRoger Tseng }
1231c7f6558dSRoger Tseng 
sdmmc_execute_tuning(struct mmc_host * mmc,u32 opcode)1232c7f6558dSRoger Tseng static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
1233c7f6558dSRoger Tseng {
1234c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
1235c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
1236c7f6558dSRoger Tseng 	int err = 0;
1237c7f6558dSRoger Tseng 
1238c7f6558dSRoger Tseng 	if (host->host_removal)
1239c7f6558dSRoger Tseng 		return -ENOMEDIUM;
1240c7f6558dSRoger Tseng 
1241c7f6558dSRoger Tseng 	mutex_lock(&ucr->dev_mutex);
1242c7f6558dSRoger Tseng 
1243c7f6558dSRoger Tseng 	if (!host->ddr_mode)
1244c7f6558dSRoger Tseng 		err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK);
1245c7f6558dSRoger Tseng 
1246c7f6558dSRoger Tseng 	mutex_unlock(&ucr->dev_mutex);
1247c7f6558dSRoger Tseng 
1248c7f6558dSRoger Tseng 	return err;
1249c7f6558dSRoger Tseng }
1250c7f6558dSRoger Tseng 
1251c7f6558dSRoger Tseng static const struct mmc_host_ops rtsx_usb_sdmmc_ops = {
1252c7f6558dSRoger Tseng 	.request = sdmmc_request,
1253c7f6558dSRoger Tseng 	.set_ios = sdmmc_set_ios,
1254c7f6558dSRoger Tseng 	.get_ro = sdmmc_get_ro,
1255c7f6558dSRoger Tseng 	.get_cd = sdmmc_get_cd,
1256c7f6558dSRoger Tseng 	.start_signal_voltage_switch = sdmmc_switch_voltage,
1257c7f6558dSRoger Tseng 	.card_busy = sdmmc_card_busy,
1258c7f6558dSRoger Tseng 	.execute_tuning = sdmmc_execute_tuning,
1259c7f6558dSRoger Tseng };
1260c7f6558dSRoger Tseng 
1261c7f6558dSRoger Tseng #ifdef RTSX_USB_USE_LEDS_CLASS
rtsx_usb_led_control(struct led_classdev * led,enum led_brightness brightness)1262c7f6558dSRoger Tseng static void rtsx_usb_led_control(struct led_classdev *led,
1263c7f6558dSRoger Tseng 	enum led_brightness brightness)
1264c7f6558dSRoger Tseng {
1265c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host = container_of(led,
1266c7f6558dSRoger Tseng 			struct rtsx_usb_sdmmc, led);
1267c7f6558dSRoger Tseng 
1268c7f6558dSRoger Tseng 	if (host->host_removal)
1269c7f6558dSRoger Tseng 		return;
1270c7f6558dSRoger Tseng 
1271c7f6558dSRoger Tseng 	host->led.brightness = brightness;
1272c7f6558dSRoger Tseng 	schedule_work(&host->led_work);
1273c7f6558dSRoger Tseng }
1274c7f6558dSRoger Tseng 
rtsx_usb_update_led(struct work_struct * work)1275c7f6558dSRoger Tseng static void rtsx_usb_update_led(struct work_struct *work)
1276c7f6558dSRoger Tseng {
1277c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host =
1278c7f6558dSRoger Tseng 		container_of(work, struct rtsx_usb_sdmmc, led_work);
1279c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr = host->ucr;
1280c7f6558dSRoger Tseng 
12814bfdd76dSUlf Hansson 	pm_runtime_get_noresume(sdmmc_dev(host));
1282c7f6558dSRoger Tseng 	mutex_lock(&ucr->dev_mutex);
1283c7f6558dSRoger Tseng 
12844bfdd76dSUlf Hansson 	if (host->power_mode == MMC_POWER_OFF)
12854bfdd76dSUlf Hansson 		goto out;
12864bfdd76dSUlf Hansson 
1287c7f6558dSRoger Tseng 	if (host->led.brightness == LED_OFF)
1288c7f6558dSRoger Tseng 		rtsx_usb_turn_off_led(ucr);
1289c7f6558dSRoger Tseng 	else
1290c7f6558dSRoger Tseng 		rtsx_usb_turn_on_led(ucr);
1291c7f6558dSRoger Tseng 
12924bfdd76dSUlf Hansson out:
1293c7f6558dSRoger Tseng 	mutex_unlock(&ucr->dev_mutex);
1294f275179fSUlf Hansson 	pm_runtime_put_sync_suspend(sdmmc_dev(host));
1295c7f6558dSRoger Tseng }
1296c7f6558dSRoger Tseng #endif
1297c7f6558dSRoger Tseng 
rtsx_usb_init_host(struct rtsx_usb_sdmmc * host)1298c7f6558dSRoger Tseng static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
1299c7f6558dSRoger Tseng {
1300c7f6558dSRoger Tseng 	struct mmc_host *mmc = host->mmc;
1301c7f6558dSRoger Tseng 
1302c7f6558dSRoger Tseng 	mmc->f_min = 250000;
1303c7f6558dSRoger Tseng 	mmc->f_max = 208000000;
1304c7f6558dSRoger Tseng 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
1305c7f6558dSRoger Tseng 	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
1306c7f6558dSRoger Tseng 		MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
1307c7f6558dSRoger Tseng 		MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
13081be64c79SUlf Hansson 		MMC_CAP_SYNC_RUNTIME_PM;
13094b7d4545SUlf Hansson 	mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE |
13104b7d4545SUlf Hansson 		MMC_CAP2_NO_SDIO;
1311c7f6558dSRoger Tseng 
1312c7f6558dSRoger Tseng 	mmc->max_current_330 = 400;
1313c7f6558dSRoger Tseng 	mmc->max_current_180 = 800;
1314c7f6558dSRoger Tseng 	mmc->ops = &rtsx_usb_sdmmc_ops;
1315c7f6558dSRoger Tseng 	mmc->max_segs = 256;
1316c7f6558dSRoger Tseng 	mmc->max_seg_size = 65536;
1317c7f6558dSRoger Tseng 	mmc->max_blk_size = 512;
1318c7f6558dSRoger Tseng 	mmc->max_blk_count = 65535;
1319c7f6558dSRoger Tseng 	mmc->max_req_size = 524288;
1320c7f6558dSRoger Tseng 
1321c7f6558dSRoger Tseng 	host->power_mode = MMC_POWER_OFF;
1322c7f6558dSRoger Tseng }
1323c7f6558dSRoger Tseng 
rtsx_usb_sdmmc_drv_probe(struct platform_device * pdev)1324c7f6558dSRoger Tseng static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
1325c7f6558dSRoger Tseng {
1326c7f6558dSRoger Tseng 	struct mmc_host *mmc;
1327c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host;
1328c7f6558dSRoger Tseng 	struct rtsx_ucr *ucr;
1329c7f6558dSRoger Tseng #ifdef RTSX_USB_USE_LEDS_CLASS
1330c7f6558dSRoger Tseng 	int err;
1331c7f6558dSRoger Tseng #endif
1332fc38a5a1SYang Yingliang 	int ret;
1333c7f6558dSRoger Tseng 
1334c7f6558dSRoger Tseng 	ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent));
1335c7f6558dSRoger Tseng 	if (!ucr)
1336c7f6558dSRoger Tseng 		return -ENXIO;
1337c7f6558dSRoger Tseng 
1338c7f6558dSRoger Tseng 	dev_dbg(&(pdev->dev), ": Realtek USB SD/MMC controller found\n");
1339c7f6558dSRoger Tseng 
1340c7f6558dSRoger Tseng 	mmc = mmc_alloc_host(sizeof(*host), &pdev->dev);
1341c7f6558dSRoger Tseng 	if (!mmc)
1342c7f6558dSRoger Tseng 		return -ENOMEM;
1343c7f6558dSRoger Tseng 
1344c7f6558dSRoger Tseng 	host = mmc_priv(mmc);
1345c7f6558dSRoger Tseng 	host->ucr = ucr;
1346c7f6558dSRoger Tseng 	host->mmc = mmc;
1347c7f6558dSRoger Tseng 	host->pdev = pdev;
1348c7f6558dSRoger Tseng 	platform_set_drvdata(pdev, host);
1349c7f6558dSRoger Tseng 
1350c7f6558dSRoger Tseng 	mutex_init(&host->host_mutex);
1351c7f6558dSRoger Tseng 	rtsx_usb_init_host(host);
1352c7f6558dSRoger Tseng 	pm_runtime_enable(&pdev->dev);
1353c7f6558dSRoger Tseng 
1354c7f6558dSRoger Tseng #ifdef RTSX_USB_USE_LEDS_CLASS
1355c7f6558dSRoger Tseng 	snprintf(host->led_name, sizeof(host->led_name),
1356c7f6558dSRoger Tseng 		"%s::", mmc_hostname(mmc));
1357c7f6558dSRoger Tseng 	host->led.name = host->led_name;
1358c7f6558dSRoger Tseng 	host->led.brightness = LED_OFF;
1359c7f6558dSRoger Tseng 	host->led.default_trigger = mmc_hostname(mmc);
1360c7f6558dSRoger Tseng 	host->led.brightness_set = rtsx_usb_led_control;
1361c7f6558dSRoger Tseng 
1362c7f6558dSRoger Tseng 	err = led_classdev_register(mmc_dev(mmc), &host->led);
1363c7f6558dSRoger Tseng 	if (err)
1364c7f6558dSRoger Tseng 		dev_err(&(pdev->dev),
1365c7f6558dSRoger Tseng 				"Failed to register LED device: %d\n", err);
1366c7f6558dSRoger Tseng 	INIT_WORK(&host->led_work, rtsx_usb_update_led);
1367c7f6558dSRoger Tseng 
1368c7f6558dSRoger Tseng #endif
1369fc38a5a1SYang Yingliang 	ret = mmc_add_host(mmc);
1370fc38a5a1SYang Yingliang 	if (ret) {
1371fc38a5a1SYang Yingliang #ifdef RTSX_USB_USE_LEDS_CLASS
1372fc38a5a1SYang Yingliang 		led_classdev_unregister(&host->led);
1373fc38a5a1SYang Yingliang #endif
1374fc38a5a1SYang Yingliang 		mmc_free_host(mmc);
1375fc38a5a1SYang Yingliang 		pm_runtime_disable(&pdev->dev);
1376fc38a5a1SYang Yingliang 		return ret;
1377fc38a5a1SYang Yingliang 	}
1378c7f6558dSRoger Tseng 
1379c7f6558dSRoger Tseng 	return 0;
1380c7f6558dSRoger Tseng }
1381c7f6558dSRoger Tseng 
rtsx_usb_sdmmc_drv_remove(struct platform_device * pdev)1382*f8c9b415SYangtao Li static void rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
1383c7f6558dSRoger Tseng {
1384c7f6558dSRoger Tseng 	struct rtsx_usb_sdmmc *host = platform_get_drvdata(pdev);
1385c7f6558dSRoger Tseng 	struct mmc_host *mmc;
1386c7f6558dSRoger Tseng 
1387c7f6558dSRoger Tseng 	if (!host)
1388*f8c9b415SYangtao Li 		return;
1389c7f6558dSRoger Tseng 
1390c7f6558dSRoger Tseng 	mmc = host->mmc;
1391c7f6558dSRoger Tseng 	host->host_removal = true;
1392c7f6558dSRoger Tseng 
1393c7f6558dSRoger Tseng 	mutex_lock(&host->host_mutex);
1394c7f6558dSRoger Tseng 	if (host->mrq) {
1395c7f6558dSRoger Tseng 		dev_dbg(&(pdev->dev),
1396c7f6558dSRoger Tseng 			"%s: Controller removed during transfer\n",
1397c7f6558dSRoger Tseng 			mmc_hostname(mmc));
1398c7f6558dSRoger Tseng 		host->mrq->cmd->error = -ENOMEDIUM;
1399c7f6558dSRoger Tseng 		if (host->mrq->stop)
1400c7f6558dSRoger Tseng 			host->mrq->stop->error = -ENOMEDIUM;
1401c7f6558dSRoger Tseng 		mmc_request_done(mmc, host->mrq);
1402c7f6558dSRoger Tseng 	}
1403c7f6558dSRoger Tseng 	mutex_unlock(&host->host_mutex);
1404c7f6558dSRoger Tseng 
1405c7f6558dSRoger Tseng 	mmc_remove_host(mmc);
1406c7f6558dSRoger Tseng 
1407c7f6558dSRoger Tseng #ifdef RTSX_USB_USE_LEDS_CLASS
1408c7f6558dSRoger Tseng 	cancel_work_sync(&host->led_work);
1409c7f6558dSRoger Tseng 	led_classdev_unregister(&host->led);
1410c7f6558dSRoger Tseng #endif
1411c7f6558dSRoger Tseng 
1412c7f6558dSRoger Tseng 	mmc_free_host(mmc);
1413c7f6558dSRoger Tseng 	pm_runtime_disable(&pdev->dev);
1414c7f6558dSRoger Tseng 	platform_set_drvdata(pdev, NULL);
1415c7f6558dSRoger Tseng 
1416c7f6558dSRoger Tseng 	dev_dbg(&(pdev->dev),
1417c7f6558dSRoger Tseng 		": Realtek USB SD/MMC module has been removed\n");
1418c7f6558dSRoger Tseng }
1419c7f6558dSRoger Tseng 
14204dad599bSUlf Hansson #ifdef CONFIG_PM
rtsx_usb_sdmmc_runtime_suspend(struct device * dev)14214dad599bSUlf Hansson static int rtsx_usb_sdmmc_runtime_suspend(struct device *dev)
14224dad599bSUlf Hansson {
14234dad599bSUlf Hansson 	struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
14244dad599bSUlf Hansson 
14254dad599bSUlf Hansson 	host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
14264dad599bSUlf Hansson 	return 0;
14274dad599bSUlf Hansson }
14284dad599bSUlf Hansson 
rtsx_usb_sdmmc_runtime_resume(struct device * dev)14294dad599bSUlf Hansson static int rtsx_usb_sdmmc_runtime_resume(struct device *dev)
14304dad599bSUlf Hansson {
14314dad599bSUlf Hansson 	struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
14324dad599bSUlf Hansson 
14334dad599bSUlf Hansson 	host->mmc->caps |= MMC_CAP_NEEDS_POLL;
14344dad599bSUlf Hansson 	if (sdmmc_get_cd(host->mmc) == 1)
14354dad599bSUlf Hansson 		mmc_detect_change(host->mmc, 0);
14364dad599bSUlf Hansson 	return 0;
14374dad599bSUlf Hansson }
14384dad599bSUlf Hansson #endif
14394dad599bSUlf Hansson 
14404dad599bSUlf Hansson static const struct dev_pm_ops rtsx_usb_sdmmc_dev_pm_ops = {
14414dad599bSUlf Hansson 	SET_RUNTIME_PM_OPS(rtsx_usb_sdmmc_runtime_suspend,
14424dad599bSUlf Hansson 			   rtsx_usb_sdmmc_runtime_resume, NULL)
14434dad599bSUlf Hansson };
14444dad599bSUlf Hansson 
1445f2483b0dSKrzysztof Kozlowski static const struct platform_device_id rtsx_usb_sdmmc_ids[] = {
1446c7f6558dSRoger Tseng 	{
1447c7f6558dSRoger Tseng 		.name = "rtsx_usb_sdmmc",
1448c7f6558dSRoger Tseng 	}, {
1449c7f6558dSRoger Tseng 		/* sentinel */
1450c7f6558dSRoger Tseng 	}
1451c7f6558dSRoger Tseng };
1452c7f6558dSRoger Tseng MODULE_DEVICE_TABLE(platform, rtsx_usb_sdmmc_ids);
1453c7f6558dSRoger Tseng 
1454c7f6558dSRoger Tseng static struct platform_driver rtsx_usb_sdmmc_driver = {
1455c7f6558dSRoger Tseng 	.probe		= rtsx_usb_sdmmc_drv_probe,
1456*f8c9b415SYangtao Li 	.remove_new	= rtsx_usb_sdmmc_drv_remove,
1457c7f6558dSRoger Tseng 	.id_table       = rtsx_usb_sdmmc_ids,
1458c7f6558dSRoger Tseng 	.driver		= {
1459c7f6558dSRoger Tseng 		.name	= "rtsx_usb_sdmmc",
146021b2cec6SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
14614dad599bSUlf Hansson 		.pm	= &rtsx_usb_sdmmc_dev_pm_ops,
1462c7f6558dSRoger Tseng 	},
1463c7f6558dSRoger Tseng };
1464c7f6558dSRoger Tseng module_platform_driver(rtsx_usb_sdmmc_driver);
1465c7f6558dSRoger Tseng 
1466c7f6558dSRoger Tseng MODULE_LICENSE("GPL v2");
1467c7f6558dSRoger Tseng MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>");
1468c7f6558dSRoger Tseng MODULE_DESCRIPTION("Realtek USB SD/MMC Card Host Driver");
1469