1 | /* Realtek USB Memstick Card Interface driver |
2 | * |
3 | * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 |
7 | * as published by the Free Software Foundation. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License along |
15 | * with this program; if not, see <http://www.gnu.org/licenses/>. |
16 | * |
17 | * Author: |
18 | * Roger Tseng <rogerable@realtek.com> |
19 | */ |
20 | |
21 | #include <linux/module.h> |
22 | #include <linux/highmem.h> |
23 | #include <linux/delay.h> |
24 | #include <linux/platform_device.h> |
25 | #include <linux/workqueue.h> |
26 | #include <linux/memstick.h> |
27 | #include <linux/kthread.h> |
28 | #include <linux/rtsx_usb.h> |
29 | #include <linux/pm_runtime.h> |
30 | #include <linux/mutex.h> |
31 | #include <linux/sched.h> |
32 | #include <linux/completion.h> |
33 | #include <asm/unaligned.h> |
34 | |
35 | struct rtsx_usb_ms { |
36 | struct platform_device *pdev; |
37 | struct rtsx_ucr *ucr; |
38 | struct memstick_host *msh; |
39 | struct memstick_request *req; |
40 | |
41 | struct mutex host_mutex; |
42 | struct work_struct handle_req; |
43 | struct delayed_work poll_card; |
44 | |
45 | u8 ssc_depth; |
46 | unsigned int clock; |
47 | int power_mode; |
48 | unsigned char ifmode; |
49 | bool eject; |
50 | bool system_suspending; |
51 | }; |
52 | |
53 | static inline struct device *ms_dev(struct rtsx_usb_ms *host) |
54 | { |
55 | return &(host->pdev->dev); |
56 | } |
57 | |
58 | static inline void ms_clear_error(struct rtsx_usb_ms *host) |
59 | { |
60 | struct rtsx_ucr *ucr = host->ucr; |
61 | rtsx_usb_ep0_write_register(ucr, CARD_STOP, |
62 | MS_STOP | MS_CLR_ERR, |
63 | MS_STOP | MS_CLR_ERR); |
64 | |
65 | rtsx_usb_clear_dma_err(ucr); |
66 | rtsx_usb_clear_fsm_err(ucr); |
67 | } |
68 | |
69 | #ifdef DEBUG |
70 | |
71 | static void ms_print_debug_regs(struct rtsx_usb_ms *host) |
72 | { |
73 | struct rtsx_ucr *ucr = host->ucr; |
74 | u16 i; |
75 | u8 *ptr; |
76 | |
77 | /* Print MS host internal registers */ |
78 | rtsx_usb_init_cmd(ucr); |
79 | |
80 | /* MS_CFG to MS_INT_REG */ |
81 | for (i = 0xFD40; i <= 0xFD44; i++) |
82 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0); |
83 | |
84 | /* CARD_SHARE_MODE to CARD_GPIO */ |
85 | for (i = 0xFD51; i <= 0xFD56; i++) |
86 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0); |
87 | |
88 | /* CARD_PULL_CTLx */ |
89 | for (i = 0xFD60; i <= 0xFD65; i++) |
90 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0); |
91 | |
92 | /* CARD_DATA_SOURCE, CARD_SELECT, CARD_CLK_EN, CARD_PWR_CTL */ |
93 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_DATA_SOURCE, 0, 0); |
94 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_SELECT, 0, 0); |
95 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_CLK_EN, 0, 0); |
96 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_PWR_CTL, 0, 0); |
97 | |
98 | rtsx_usb_send_cmd(ucr, MODE_CR, 100); |
99 | rtsx_usb_get_rsp(ucr, 21, 100); |
100 | |
101 | ptr = ucr->rsp_buf; |
102 | for (i = 0xFD40; i <= 0xFD44; i++) |
103 | dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n" , i, *(ptr++)); |
104 | for (i = 0xFD51; i <= 0xFD56; i++) |
105 | dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n" , i, *(ptr++)); |
106 | for (i = 0xFD60; i <= 0xFD65; i++) |
107 | dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n" , i, *(ptr++)); |
108 | |
109 | dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n" , CARD_DATA_SOURCE, *(ptr++)); |
110 | dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n" , CARD_SELECT, *(ptr++)); |
111 | dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n" , CARD_CLK_EN, *(ptr++)); |
112 | dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n" , CARD_PWR_CTL, *(ptr++)); |
113 | } |
114 | |
115 | #else |
116 | |
117 | static void ms_print_debug_regs(struct rtsx_usb_ms *host) |
118 | { |
119 | } |
120 | |
121 | #endif |
122 | |
123 | static int ms_pull_ctl_disable_lqfp48(struct rtsx_ucr *ucr) |
124 | { |
125 | rtsx_usb_init_cmd(ucr); |
126 | |
127 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55); |
128 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); |
129 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); |
130 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); |
131 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55); |
132 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5); |
133 | |
134 | return rtsx_usb_send_cmd(ucr, MODE_C, 100); |
135 | } |
136 | |
137 | static int ms_pull_ctl_disable_qfn24(struct rtsx_ucr *ucr) |
138 | { |
139 | rtsx_usb_init_cmd(ucr); |
140 | |
141 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65); |
142 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); |
143 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); |
144 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); |
145 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56); |
146 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59); |
147 | |
148 | return rtsx_usb_send_cmd(ucr, MODE_C, 100); |
149 | } |
150 | |
151 | static int ms_pull_ctl_enable_lqfp48(struct rtsx_ucr *ucr) |
152 | { |
153 | rtsx_usb_init_cmd(ucr); |
154 | |
155 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55); |
156 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); |
157 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); |
158 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); |
159 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55); |
160 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5); |
161 | |
162 | return rtsx_usb_send_cmd(ucr, MODE_C, 100); |
163 | } |
164 | |
165 | static int ms_pull_ctl_enable_qfn24(struct rtsx_ucr *ucr) |
166 | { |
167 | rtsx_usb_init_cmd(ucr); |
168 | |
169 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65); |
170 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); |
171 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); |
172 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); |
173 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55); |
174 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59); |
175 | |
176 | return rtsx_usb_send_cmd(ucr, MODE_C, 100); |
177 | } |
178 | |
179 | static int ms_power_on(struct rtsx_usb_ms *host) |
180 | { |
181 | struct rtsx_ucr *ucr = host->ucr; |
182 | int err; |
183 | |
184 | dev_dbg(ms_dev(host), "%s\n" , __func__); |
185 | |
186 | rtsx_usb_init_cmd(ucr); |
187 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, MS_MOD_SEL); |
188 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SHARE_MODE, |
189 | CARD_SHARE_MASK, CARD_SHARE_MS); |
190 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, |
191 | MS_CLK_EN, MS_CLK_EN); |
192 | err = rtsx_usb_send_cmd(ucr, MODE_C, 100); |
193 | if (err < 0) |
194 | return err; |
195 | |
196 | if (CHECK_PKG(ucr, LQFP48)) |
197 | err = ms_pull_ctl_enable_lqfp48(ucr); |
198 | else |
199 | err = ms_pull_ctl_enable_qfn24(ucr); |
200 | if (err < 0) |
201 | return err; |
202 | |
203 | err = rtsx_usb_write_register(ucr, CARD_PWR_CTL, |
204 | POWER_MASK, PARTIAL_POWER_ON); |
205 | if (err) |
206 | return err; |
207 | |
208 | usleep_range(800, 1000); |
209 | |
210 | rtsx_usb_init_cmd(ucr); |
211 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, |
212 | POWER_MASK, POWER_ON); |
213 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, |
214 | MS_OUTPUT_EN, MS_OUTPUT_EN); |
215 | |
216 | return rtsx_usb_send_cmd(ucr, MODE_C, 100); |
217 | } |
218 | |
219 | static int ms_power_off(struct rtsx_usb_ms *host) |
220 | { |
221 | struct rtsx_ucr *ucr = host->ucr; |
222 | int err; |
223 | |
224 | dev_dbg(ms_dev(host), "%s\n" , __func__); |
225 | |
226 | rtsx_usb_init_cmd(ucr); |
227 | |
228 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0); |
229 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0); |
230 | |
231 | err = rtsx_usb_send_cmd(ucr, MODE_C, 100); |
232 | if (err < 0) |
233 | return err; |
234 | |
235 | if (CHECK_PKG(ucr, LQFP48)) |
236 | return ms_pull_ctl_disable_lqfp48(ucr); |
237 | |
238 | return ms_pull_ctl_disable_qfn24(ucr); |
239 | } |
240 | |
241 | static int ms_transfer_data(struct rtsx_usb_ms *host, unsigned char data_dir, |
242 | u8 tpc, u8 cfg, struct scatterlist *sg) |
243 | { |
244 | struct rtsx_ucr *ucr = host->ucr; |
245 | int err; |
246 | unsigned int length = sg->length; |
247 | u16 sec_cnt = (u16)(length / 512); |
248 | u8 trans_mode, dma_dir, flag; |
249 | unsigned int pipe; |
250 | struct memstick_dev *card = host->msh->card; |
251 | |
252 | dev_dbg(ms_dev(host), "%s: tpc = 0x%02x, data_dir = %s, length = %d\n" , |
253 | __func__, tpc, (data_dir == READ) ? "READ" : "WRITE" , |
254 | length); |
255 | |
256 | if (data_dir == READ) { |
257 | flag = MODE_CDIR; |
258 | dma_dir = DMA_DIR_FROM_CARD; |
259 | if (card->id.type != MEMSTICK_TYPE_PRO) |
260 | trans_mode = MS_TM_NORMAL_READ; |
261 | else |
262 | trans_mode = MS_TM_AUTO_READ; |
263 | pipe = usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN); |
264 | } else { |
265 | flag = MODE_CDOR; |
266 | dma_dir = DMA_DIR_TO_CARD; |
267 | if (card->id.type != MEMSTICK_TYPE_PRO) |
268 | trans_mode = MS_TM_NORMAL_WRITE; |
269 | else |
270 | trans_mode = MS_TM_AUTO_WRITE; |
271 | pipe = usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT); |
272 | } |
273 | |
274 | rtsx_usb_init_cmd(ucr); |
275 | |
276 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); |
277 | if (card->id.type == MEMSTICK_TYPE_PRO) { |
278 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_SECTOR_CNT_H, |
279 | 0xFF, (u8)(sec_cnt >> 8)); |
280 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_SECTOR_CNT_L, |
281 | 0xFF, (u8)sec_cnt); |
282 | } |
283 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); |
284 | |
285 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC3, |
286 | 0xFF, (u8)(length >> 24)); |
287 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC2, |
288 | 0xFF, (u8)(length >> 16)); |
289 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC1, |
290 | 0xFF, (u8)(length >> 8)); |
291 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC0, 0xFF, |
292 | (u8)length); |
293 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL, |
294 | 0x03 | DMA_PACK_SIZE_MASK, dma_dir | DMA_EN | DMA_512); |
295 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE, |
296 | 0x01, RING_BUFFER); |
297 | |
298 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER, |
299 | 0xFF, MS_TRANSFER_START | trans_mode); |
300 | rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER, |
301 | MS_TRANSFER_END, MS_TRANSFER_END); |
302 | |
303 | err = rtsx_usb_send_cmd(ucr, flag | STAGE_MS_STATUS, 100); |
304 | if (err) |
305 | return err; |
306 | |
307 | err = rtsx_usb_transfer_data(ucr, pipe, sg, length, |
308 | 1, NULL, 10000); |
309 | if (err) |
310 | goto err_out; |
311 | |
312 | err = rtsx_usb_get_rsp(ucr, 3, 15000); |
313 | if (err) |
314 | goto err_out; |
315 | |
316 | if (ucr->rsp_buf[0] & MS_TRANSFER_ERR || |
317 | ucr->rsp_buf[1] & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) { |
318 | err = -EIO; |
319 | goto err_out; |
320 | } |
321 | return 0; |
322 | err_out: |
323 | ms_clear_error(host); |
324 | return err; |
325 | } |
326 | |
327 | static int ms_write_bytes(struct rtsx_usb_ms *host, u8 tpc, |
328 | u8 cfg, u8 cnt, u8 *data, u8 *int_reg) |
329 | { |
330 | struct rtsx_ucr *ucr = host->ucr; |
331 | int err, i; |
332 | |
333 | dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n" , __func__, tpc); |
334 | |
335 | rtsx_usb_init_cmd(ucr); |
336 | |
337 | for (i = 0; i < cnt; i++) |
338 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, |
339 | PPBUF_BASE2 + i, 0xFF, data[i]); |
340 | |
341 | if (cnt % 2) |
342 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, |
343 | PPBUF_BASE2 + i, 0xFF, 0xFF); |
344 | |
345 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); |
346 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); |
347 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); |
348 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE, |
349 | 0x01, PINGPONG_BUFFER); |
350 | |
351 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER, |
352 | 0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES); |
353 | rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER, |
354 | MS_TRANSFER_END, MS_TRANSFER_END); |
355 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, MS_TRANS_CFG, 0, 0); |
356 | |
357 | err = rtsx_usb_send_cmd(ucr, MODE_CR, 100); |
358 | if (err) |
359 | return err; |
360 | |
361 | err = rtsx_usb_get_rsp(ucr, 2, 5000); |
362 | if (err || (ucr->rsp_buf[0] & MS_TRANSFER_ERR)) { |
363 | u8 val; |
364 | |
365 | rtsx_usb_ep0_read_register(ucr, MS_TRANS_CFG, &val); |
366 | dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n" , val); |
367 | |
368 | if (int_reg) |
369 | *int_reg = val & 0x0F; |
370 | |
371 | ms_print_debug_regs(host); |
372 | |
373 | ms_clear_error(host); |
374 | |
375 | if (!(tpc & 0x08)) { |
376 | if (val & MS_CRC16_ERR) |
377 | return -EIO; |
378 | } else { |
379 | if (!(val & 0x80)) { |
380 | if (val & (MS_INT_ERR | MS_INT_CMDNK)) |
381 | return -EIO; |
382 | } |
383 | } |
384 | |
385 | return -ETIMEDOUT; |
386 | } |
387 | |
388 | if (int_reg) |
389 | *int_reg = ucr->rsp_buf[1] & 0x0F; |
390 | |
391 | return 0; |
392 | } |
393 | |
394 | static int ms_read_bytes(struct rtsx_usb_ms *host, u8 tpc, |
395 | u8 cfg, u8 cnt, u8 *data, u8 *int_reg) |
396 | { |
397 | struct rtsx_ucr *ucr = host->ucr; |
398 | int err, i; |
399 | u8 *ptr; |
400 | |
401 | dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n" , __func__, tpc); |
402 | |
403 | rtsx_usb_init_cmd(ucr); |
404 | |
405 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); |
406 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); |
407 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); |
408 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE, |
409 | 0x01, PINGPONG_BUFFER); |
410 | |
411 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER, |
412 | 0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES); |
413 | rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER, |
414 | MS_TRANSFER_END, MS_TRANSFER_END); |
415 | for (i = 0; i < cnt - 1; i++) |
416 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0); |
417 | if (cnt % 2) |
418 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, PPBUF_BASE2 + cnt, 0, 0); |
419 | else |
420 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, |
421 | PPBUF_BASE2 + cnt - 1, 0, 0); |
422 | |
423 | rtsx_usb_add_cmd(ucr, READ_REG_CMD, MS_TRANS_CFG, 0, 0); |
424 | |
425 | err = rtsx_usb_send_cmd(ucr, MODE_CR, 100); |
426 | if (err) |
427 | return err; |
428 | |
429 | err = rtsx_usb_get_rsp(ucr, cnt + 2, 5000); |
430 | if (err || (ucr->rsp_buf[0] & MS_TRANSFER_ERR)) { |
431 | u8 val; |
432 | |
433 | rtsx_usb_ep0_read_register(ucr, MS_TRANS_CFG, &val); |
434 | dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n" , val); |
435 | |
436 | if (int_reg && (host->ifmode != MEMSTICK_SERIAL)) |
437 | *int_reg = val & 0x0F; |
438 | |
439 | ms_print_debug_regs(host); |
440 | |
441 | ms_clear_error(host); |
442 | |
443 | if (!(tpc & 0x08)) { |
444 | if (val & MS_CRC16_ERR) |
445 | return -EIO; |
446 | } else { |
447 | if (!(val & 0x80)) { |
448 | if (val & (MS_INT_ERR | MS_INT_CMDNK)) |
449 | return -EIO; |
450 | } |
451 | } |
452 | |
453 | return -ETIMEDOUT; |
454 | } |
455 | |
456 | ptr = ucr->rsp_buf + 1; |
457 | for (i = 0; i < cnt; i++) |
458 | data[i] = *ptr++; |
459 | |
460 | |
461 | if (int_reg && (host->ifmode != MEMSTICK_SERIAL)) |
462 | *int_reg = *ptr & 0x0F; |
463 | |
464 | return 0; |
465 | } |
466 | |
467 | static int rtsx_usb_ms_issue_cmd(struct rtsx_usb_ms *host) |
468 | { |
469 | struct memstick_request *req = host->req; |
470 | int err = 0; |
471 | u8 cfg = 0, int_reg; |
472 | |
473 | dev_dbg(ms_dev(host), "%s\n" , __func__); |
474 | |
475 | if (req->need_card_int) { |
476 | if (host->ifmode != MEMSTICK_SERIAL) |
477 | cfg = WAIT_INT; |
478 | } |
479 | |
480 | if (req->long_data) { |
481 | err = ms_transfer_data(host, req->data_dir, |
482 | req->tpc, cfg, &(req->sg)); |
483 | } else { |
484 | if (req->data_dir == READ) |
485 | err = ms_read_bytes(host, req->tpc, cfg, |
486 | req->data_len, req->data, &int_reg); |
487 | else |
488 | err = ms_write_bytes(host, req->tpc, cfg, |
489 | req->data_len, req->data, &int_reg); |
490 | } |
491 | if (err < 0) |
492 | return err; |
493 | |
494 | if (req->need_card_int) { |
495 | if (host->ifmode == MEMSTICK_SERIAL) { |
496 | err = ms_read_bytes(host, MS_TPC_GET_INT, |
497 | NO_WAIT_INT, 1, &req->int_reg, NULL); |
498 | if (err < 0) |
499 | return err; |
500 | } else { |
501 | |
502 | if (int_reg & MS_INT_CMDNK) |
503 | req->int_reg |= MEMSTICK_INT_CMDNAK; |
504 | if (int_reg & MS_INT_BREQ) |
505 | req->int_reg |= MEMSTICK_INT_BREQ; |
506 | if (int_reg & MS_INT_ERR) |
507 | req->int_reg |= MEMSTICK_INT_ERR; |
508 | if (int_reg & MS_INT_CED) |
509 | req->int_reg |= MEMSTICK_INT_CED; |
510 | } |
511 | dev_dbg(ms_dev(host), "int_reg: 0x%02x\n" , req->int_reg); |
512 | } |
513 | |
514 | return 0; |
515 | } |
516 | |
517 | static void rtsx_usb_ms_handle_req(struct work_struct *work) |
518 | { |
519 | struct rtsx_usb_ms *host = container_of(work, |
520 | struct rtsx_usb_ms, handle_req); |
521 | struct rtsx_ucr *ucr = host->ucr; |
522 | struct memstick_host *msh = host->msh; |
523 | int rc; |
524 | |
525 | if (!host->req) { |
526 | pm_runtime_get_sync(ms_dev(host)); |
527 | do { |
528 | rc = memstick_next_req(msh, &host->req); |
529 | dev_dbg(ms_dev(host), "next req %d\n" , rc); |
530 | |
531 | if (!rc) { |
532 | mutex_lock(&ucr->dev_mutex); |
533 | |
534 | if (rtsx_usb_card_exclusive_check(ucr, |
535 | RTSX_USB_MS_CARD)) |
536 | host->req->error = -EIO; |
537 | else |
538 | host->req->error = |
539 | rtsx_usb_ms_issue_cmd(host); |
540 | |
541 | mutex_unlock(&ucr->dev_mutex); |
542 | |
543 | dev_dbg(ms_dev(host), "req result %d\n" , |
544 | host->req->error); |
545 | } |
546 | } while (!rc); |
547 | pm_runtime_put_sync(ms_dev(host)); |
548 | } |
549 | |
550 | } |
551 | |
552 | static void rtsx_usb_ms_request(struct memstick_host *msh) |
553 | { |
554 | struct rtsx_usb_ms *host = memstick_priv(msh); |
555 | |
556 | dev_dbg(ms_dev(host), "--> %s\n" , __func__); |
557 | |
558 | if (!host->eject) |
559 | schedule_work(&host->handle_req); |
560 | } |
561 | |
562 | static int rtsx_usb_ms_set_param(struct memstick_host *msh, |
563 | enum memstick_param param, int value) |
564 | { |
565 | struct rtsx_usb_ms *host = memstick_priv(msh); |
566 | struct rtsx_ucr *ucr = host->ucr; |
567 | unsigned int clock = 0; |
568 | u8 ssc_depth = 0; |
569 | int err; |
570 | |
571 | dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n" , |
572 | __func__, param, value); |
573 | |
574 | pm_runtime_get_sync(ms_dev(host)); |
575 | mutex_lock(&ucr->dev_mutex); |
576 | |
577 | err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_MS_CARD); |
578 | if (err) |
579 | goto out; |
580 | |
581 | switch (param) { |
582 | case MEMSTICK_POWER: |
583 | if (value == host->power_mode) |
584 | break; |
585 | |
586 | if (value == MEMSTICK_POWER_ON) { |
587 | pm_runtime_get_noresume(ms_dev(host)); |
588 | err = ms_power_on(host); |
589 | if (err) |
590 | pm_runtime_put_noidle(ms_dev(host)); |
591 | } else if (value == MEMSTICK_POWER_OFF) { |
592 | err = ms_power_off(host); |
593 | if (!err) |
594 | pm_runtime_put_noidle(ms_dev(host)); |
595 | } else |
596 | err = -EINVAL; |
597 | if (!err) |
598 | host->power_mode = value; |
599 | break; |
600 | |
601 | case MEMSTICK_INTERFACE: |
602 | if (value == MEMSTICK_SERIAL) { |
603 | clock = 19000000; |
604 | ssc_depth = SSC_DEPTH_512K; |
605 | err = rtsx_usb_write_register(ucr, MS_CFG, 0x5A, |
606 | MS_BUS_WIDTH_1 | PUSH_TIME_DEFAULT); |
607 | if (err < 0) |
608 | break; |
609 | } else if (value == MEMSTICK_PAR4) { |
610 | clock = 39000000; |
611 | ssc_depth = SSC_DEPTH_1M; |
612 | |
613 | err = rtsx_usb_write_register(ucr, MS_CFG, 0x5A, |
614 | MS_BUS_WIDTH_4 | PUSH_TIME_ODD | |
615 | MS_NO_CHECK_INT); |
616 | if (err < 0) |
617 | break; |
618 | } else { |
619 | err = -EINVAL; |
620 | break; |
621 | } |
622 | |
623 | err = rtsx_usb_switch_clock(ucr, clock, |
624 | ssc_depth, false, true, false); |
625 | if (err < 0) { |
626 | dev_dbg(ms_dev(host), "switch clock failed\n" ); |
627 | break; |
628 | } |
629 | |
630 | host->ssc_depth = ssc_depth; |
631 | host->clock = clock; |
632 | host->ifmode = value; |
633 | break; |
634 | default: |
635 | err = -EINVAL; |
636 | break; |
637 | } |
638 | out: |
639 | mutex_unlock(&ucr->dev_mutex); |
640 | pm_runtime_put_sync(ms_dev(host)); |
641 | |
642 | /* power-on delay */ |
643 | if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON) { |
644 | usleep_range(10000, 12000); |
645 | |
646 | if (!host->eject) |
647 | schedule_delayed_work(&host->poll_card, 100); |
648 | } |
649 | |
650 | dev_dbg(ms_dev(host), "%s: return = %d\n" , __func__, err); |
651 | return err; |
652 | } |
653 | |
654 | #ifdef CONFIG_PM_SLEEP |
655 | static int rtsx_usb_ms_suspend(struct device *dev) |
656 | { |
657 | struct rtsx_usb_ms *host = dev_get_drvdata(dev); |
658 | struct memstick_host *msh = host->msh; |
659 | |
660 | /* Since we use rtsx_usb's resume callback to runtime resume its |
661 | * children to implement remote wakeup signaling, this causes |
662 | * rtsx_usb_ms' runtime resume callback runs after its suspend |
663 | * callback: |
664 | * rtsx_usb_ms_suspend() |
665 | * rtsx_usb_resume() |
666 | * -> rtsx_usb_ms_runtime_resume() |
667 | * -> memstick_detect_change() |
668 | * |
669 | * rtsx_usb_suspend() |
670 | * |
671 | * To avoid this, skip runtime resume/suspend if system suspend is |
672 | * underway. |
673 | */ |
674 | |
675 | host->system_suspending = true; |
676 | memstick_suspend_host(msh); |
677 | |
678 | return 0; |
679 | } |
680 | |
681 | static int rtsx_usb_ms_resume(struct device *dev) |
682 | { |
683 | struct rtsx_usb_ms *host = dev_get_drvdata(dev); |
684 | struct memstick_host *msh = host->msh; |
685 | |
686 | memstick_resume_host(msh); |
687 | host->system_suspending = false; |
688 | |
689 | return 0; |
690 | } |
691 | #endif /* CONFIG_PM_SLEEP */ |
692 | |
693 | #ifdef CONFIG_PM |
694 | static int rtsx_usb_ms_runtime_suspend(struct device *dev) |
695 | { |
696 | struct rtsx_usb_ms *host = dev_get_drvdata(dev); |
697 | |
698 | if (host->system_suspending) |
699 | return 0; |
700 | |
701 | if (host->msh->card || host->power_mode != MEMSTICK_POWER_OFF) |
702 | return -EAGAIN; |
703 | |
704 | return 0; |
705 | } |
706 | |
707 | static int rtsx_usb_ms_runtime_resume(struct device *dev) |
708 | { |
709 | struct rtsx_usb_ms *host = dev_get_drvdata(dev); |
710 | |
711 | |
712 | if (host->system_suspending) |
713 | return 0; |
714 | |
715 | memstick_detect_change(host->msh); |
716 | |
717 | return 0; |
718 | } |
719 | #endif /* CONFIG_PM */ |
720 | |
721 | static const struct dev_pm_ops rtsx_usb_ms_pm_ops = { |
722 | SET_SYSTEM_SLEEP_PM_OPS(rtsx_usb_ms_suspend, rtsx_usb_ms_resume) |
723 | SET_RUNTIME_PM_OPS(rtsx_usb_ms_runtime_suspend, rtsx_usb_ms_runtime_resume, NULL) |
724 | }; |
725 | |
726 | |
727 | static void rtsx_usb_ms_poll_card(struct work_struct *work) |
728 | { |
729 | struct rtsx_usb_ms *host = container_of(work, struct rtsx_usb_ms, |
730 | poll_card.work); |
731 | struct rtsx_ucr *ucr = host->ucr; |
732 | int err; |
733 | u8 val; |
734 | |
735 | if (host->eject || host->power_mode != MEMSTICK_POWER_ON) |
736 | return; |
737 | |
738 | pm_runtime_get_sync(ms_dev(host)); |
739 | mutex_lock(&ucr->dev_mutex); |
740 | |
741 | /* Check pending MS card changes */ |
742 | err = rtsx_usb_read_register(ucr, CARD_INT_PEND, &val); |
743 | if (err) { |
744 | mutex_unlock(&ucr->dev_mutex); |
745 | goto poll_again; |
746 | } |
747 | |
748 | /* Clear the pending */ |
749 | rtsx_usb_write_register(ucr, CARD_INT_PEND, |
750 | XD_INT | MS_INT | SD_INT, |
751 | XD_INT | MS_INT | SD_INT); |
752 | |
753 | mutex_unlock(&ucr->dev_mutex); |
754 | |
755 | if (val & MS_INT) { |
756 | dev_dbg(ms_dev(host), "MS slot change detected\n" ); |
757 | memstick_detect_change(host->msh); |
758 | } |
759 | |
760 | poll_again: |
761 | pm_runtime_put_sync(ms_dev(host)); |
762 | |
763 | if (!host->eject && host->power_mode == MEMSTICK_POWER_ON) |
764 | schedule_delayed_work(&host->poll_card, 100); |
765 | } |
766 | |
767 | static int rtsx_usb_ms_drv_probe(struct platform_device *pdev) |
768 | { |
769 | struct memstick_host *msh; |
770 | struct rtsx_usb_ms *host; |
771 | struct rtsx_ucr *ucr; |
772 | int err; |
773 | |
774 | ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent)); |
775 | if (!ucr) |
776 | return -ENXIO; |
777 | |
778 | dev_dbg(&(pdev->dev), |
779 | "Realtek USB Memstick controller found\n" ); |
780 | |
781 | msh = memstick_alloc_host(sizeof(*host), &pdev->dev); |
782 | if (!msh) |
783 | return -ENOMEM; |
784 | |
785 | host = memstick_priv(msh); |
786 | host->ucr = ucr; |
787 | host->msh = msh; |
788 | host->pdev = pdev; |
789 | host->power_mode = MEMSTICK_POWER_OFF; |
790 | platform_set_drvdata(pdev, host); |
791 | |
792 | mutex_init(&host->host_mutex); |
793 | INIT_WORK(&host->handle_req, rtsx_usb_ms_handle_req); |
794 | |
795 | INIT_DELAYED_WORK(&host->poll_card, rtsx_usb_ms_poll_card); |
796 | |
797 | msh->request = rtsx_usb_ms_request; |
798 | msh->set_param = rtsx_usb_ms_set_param; |
799 | msh->caps = MEMSTICK_CAP_PAR4; |
800 | |
801 | pm_runtime_get_noresume(ms_dev(host)); |
802 | pm_runtime_set_active(ms_dev(host)); |
803 | pm_runtime_enable(ms_dev(host)); |
804 | |
805 | err = memstick_add_host(msh); |
806 | if (err) |
807 | goto err_out; |
808 | |
809 | pm_runtime_put(ms_dev(host)); |
810 | |
811 | return 0; |
812 | err_out: |
813 | memstick_free_host(msh); |
814 | pm_runtime_disable(ms_dev(host)); |
815 | pm_runtime_put_noidle(ms_dev(host)); |
816 | return err; |
817 | } |
818 | |
819 | static int rtsx_usb_ms_drv_remove(struct platform_device *pdev) |
820 | { |
821 | struct rtsx_usb_ms *host = platform_get_drvdata(pdev); |
822 | struct memstick_host *msh = host->msh; |
823 | int err; |
824 | |
825 | host->eject = true; |
826 | cancel_work_sync(&host->handle_req); |
827 | |
828 | mutex_lock(&host->host_mutex); |
829 | if (host->req) { |
830 | dev_dbg(ms_dev(host), |
831 | "%s: Controller removed during transfer\n" , |
832 | dev_name(&msh->dev)); |
833 | host->req->error = -ENOMEDIUM; |
834 | do { |
835 | err = memstick_next_req(msh, &host->req); |
836 | if (!err) |
837 | host->req->error = -ENOMEDIUM; |
838 | } while (!err); |
839 | } |
840 | mutex_unlock(&host->host_mutex); |
841 | |
842 | memstick_remove_host(msh); |
843 | memstick_free_host(msh); |
844 | |
845 | /* Balance possible unbalanced usage count |
846 | * e.g. unconditional module removal |
847 | */ |
848 | if (pm_runtime_active(ms_dev(host))) |
849 | pm_runtime_put(ms_dev(host)); |
850 | |
851 | pm_runtime_disable(ms_dev(host)); |
852 | platform_set_drvdata(pdev, NULL); |
853 | |
854 | dev_dbg(ms_dev(host), |
855 | ": Realtek USB Memstick controller has been removed\n" ); |
856 | |
857 | return 0; |
858 | } |
859 | |
860 | static struct platform_device_id rtsx_usb_ms_ids[] = { |
861 | { |
862 | .name = "rtsx_usb_ms" , |
863 | }, { |
864 | /* sentinel */ |
865 | } |
866 | }; |
867 | MODULE_DEVICE_TABLE(platform, rtsx_usb_ms_ids); |
868 | |
869 | static struct platform_driver rtsx_usb_ms_driver = { |
870 | .probe = rtsx_usb_ms_drv_probe, |
871 | .remove = rtsx_usb_ms_drv_remove, |
872 | .id_table = rtsx_usb_ms_ids, |
873 | .driver = { |
874 | .name = "rtsx_usb_ms" , |
875 | .pm = &rtsx_usb_ms_pm_ops, |
876 | }, |
877 | }; |
878 | module_platform_driver(rtsx_usb_ms_driver); |
879 | |
880 | MODULE_LICENSE("GPL v2" ); |
881 | MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>" ); |
882 | MODULE_DESCRIPTION("Realtek USB Memstick Card Host Driver" ); |
883 | |