📄 sdio_protocol.c
字号:
/* Core MMC driver functions * * Copyright (c) 2002 Hewlett-Packard Company * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Many thanks to Alessandro Rubini and Jonathan Corbet! * * Author: Andrew Christian * 6 May 2002 *//* * sdio_protocol.c - SDIO protocol driver * * Copyright (C) 2006 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Bridge Wu <bridge.wu@intel.com> * *(C) Copyright 2006 Marvell International Ltd. * All Rights Reserved */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/list.h>#include <linux/sysctl.h>#include <linux/suspend.h>#include <linux/mm.h>#include <asm/scatterlist.h>#include <linux/mmc/mss_core.h>#include <linux/mmc/sdio_protocol.h>/***************************************************************************** * * internal functions * ****************************************************************************/#define KBPS 1#define MBPS 1000static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 };static u32 ts_mul[] = { 0, 1000, 1200, 1300, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 };static u32 sdio_tran_speed( u8 ts ){ u32 clock = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3]; return clock;}static int sdio_unpack_r1(struct mss_cmd *cmd, struct sdio_response_r1 *r1, struct sdio_card *sdio_card){ u8 *buf = cmd->response; sdio_card->errno = SDIO_ERROR_NONE; r1->cmd = unstuff_bits(buf, 40, 8, 6); r1->status = unstuff_bits(buf, 8, 32, 6); dbg("status 0x%x", r1->status); if (R1_STATUS(r1->status)) { if (r1->status & R1_OUT_OF_RANGE) sdio_card->errno = SDIO_ERROR_OUT_OF_RANGE; if (r1->status & R1_COM_CRC_ERROR) sdio_card->errno = SDIO_ERROR_COM_CRC; if (r1->status & R1_ILLEGAL_COMMAND) sdio_card->errno = SDIO_ERROR_ILLEGAL_COMMAND; if (r1->status & R1_ERROR) sdio_card->errno = SDIO_ERROR_GENERAL; } if (r1->cmd != cmd->opcode) sdio_card->errno = SDIO_ERROR_HEADER_MISMATCH; /* This should be last - it's the least dangerous error */ if (sdio_card->errno != SDIO_ERROR_NONE) return MSS_ERROR_RESP_UNPACK; return MSS_ERROR_NONE;}static int sdio_unpack_r4(struct mss_cmd *cmd, struct sdio_response_r4 *r4, struct sdio_card *sdio_card){ u8 *buf = cmd->response; r4->ocr = unstuff_bits(buf, 8, 24, 6); r4->ready = unstuff_bits(buf, 39, 1, 6); r4->mem_present = unstuff_bits(buf, 35, 1, 6); r4->func_num = unstuff_bits(buf, 36, 3, 6); dbg("ocr=%08x,ready=%d,mp=%d,fun_num:%d\n", r4->ocr, r4->ready, r4->mem_present, r4->func_num); return 0;}static int sdio_unpack_r5(struct mss_cmd *cmd, struct sdio_response_r5 *r5, struct sdio_card *sdio_card){ u8 *buf = cmd->response; sdio_card->errno = SDIO_ERROR_NONE; r5->cmd = unstuff_bits(buf, 40, 8, 6); r5->status = unstuff_bits(buf, 16, 8, 6); r5->data = unstuff_bits(buf, 8, 8, 6); dbg("cmd=%d status=%02x,data:%02x", r5->cmd, r5->status, r5->data); if (r5->status) { if (r5->status & R5_OUT_OF_RANGE) return SDIO_ERROR_OUT_OF_RANGE; if (r5->status & R5_COM_CRC_ERROR) return SDIO_ERROR_COM_CRC; if (r5->status & R5_ILLEGAL_COMMAND) return SDIO_ERROR_ILLEGAL_COMMAND; if (r5->status & R5_ERROR) return SDIO_ERROR_GENERAL; if (r5->status & R5_FUNCTION_NUMBER) return SDIO_ERROR_FUNC_NUM; } if (r5->cmd != cmd->opcode) { return SDIO_ERROR_HEADER_MISMATCH; } return 0;}static u16 sdio_unpack_r6(struct mss_cmd *cmd, struct sdio_response_r6 *r6, struct sdio_card *sdio_card){ u8 *buf = cmd->response; int errno = SDIO_ERROR_NONE; r6->cmd = unstuff_bits(buf, 40, 8, 6); r6->rca = unstuff_bits(buf, 24, 16, 6); r6->status = unstuff_bits(buf, 8, 16, 6); if (R6_STATUS(r6->status)) { if (r6->status & R6_COM_CRC_ERROR) errno = SDIO_ERROR_COM_CRC; if (r6->status & R6_ILLEGAL_COMMAND) errno = SDIO_ERROR_ILLEGAL_COMMAND; if (r6->status & R6_ERROR) errno = SDIO_ERROR_GENERAL; } if (r6->cmd != cmd->opcode) errno = SDIO_ERROR_HEADER_MISMATCH; sdio_card->errno = errno; if (errno) return MSS_ERROR_RESP_UNPACK; return 0 ; }/***************************************************************************** * * internal functions * ****************************************************************************//* sdio related function */static u32 sdio_make_cmd52_arg(int rw, int fun_num, int raw, int address, int write_data){ u32 ret; dbg("rw:%d,fun:%d,raw:%d,address:%d,write_data:%d\n", rw, fun_num, raw, address, write_data); ret = (rw << 31) | (fun_num << 28) | (raw << 27) | (address << 9) | write_data; return ret;}static u32 sdio_make_cmd53_arg(int rw, int fun_num, int block_mode, int op_code, int address, int count){ u32 ret; dbg("rw:%d,fun:%d,block_mode:%d,op_code:%d,address:%d,count:%d\n", rw, fun_num, block_mode, op_code, address, count); ret = (rw << 31) | (fun_num << 28) | (block_mode << 27) | (op_code << 26) | (address << 9) | count; return ret;}#if 0static int sdio_function_abort(struct mss_card_device *dev, u8 fun_id){ struct sdio_response_r5 r5; int retval,arg; u8 *buffer; //buffer = dev->io_request->buffer; buffer = NULL; arg = sdio_make_cmd52_arg(SDIO_WRITE_REG, 0, 0, IO_ABORT, fun_id); mss_simple_cmd( dev, IO_RW_DIRECT, arg, RESPONSE_R5, buffer ); if ( (retval = sdio_unpack_r5(dev->io_request, &r5)) ) { DEBUG("error=%d (%s)\n",retval, sdio_result_to_string(retval) ); return retval; } return 0;}#endif #define SDIO_FN0_READ_REG(addr) \ do { \ arg = sdio_make_cmd52_arg(SDIO_R, 0, 0, addr, 0); \ ret = mss_send_simple_ll_req(host, llreq, cmd, \ IO_RW_DIRECT, arg, MSS_RESPONSE_R5, \ MSS_CMD_SDIO_EN); \ if (ret) \ return ret; \ ret = sdio_unpack_r5(cmd, &r5, sdio_card); \ if (ret) \ return ret; \ } while(0) #define SDIO_FN0_WRITE_REG(addr, val) \ do { \ arg = sdio_make_cmd52_arg(SDIO_W, 0, 0, addr, val); \ ret = mss_send_simple_ll_req(host, llreq, cmd, \ IO_RW_DIRECT, arg, MSS_RESPONSE_R5, \ MSS_CMD_SDIO_EN); \ if (ret) \ return ret; \ ret = sdio_unpack_r5(cmd, &r5, sdio_card); \ if (ret) \ return ret; \ } while(0) static int sdio_reset(struct mss_card *card){ struct mss_host *host = card->slot->host; struct sdio_card *sdio_card = card->prot_card; struct mss_cmd *cmd = &sdio_card->cmd; struct mss_ll_request *llreq = &sdio_card->llreq; struct sdio_response_r5 r5; int ret,arg; SDIO_FN0_WRITE_REG(IO_ABORT, 0x8); return 0;}static int sdio_set_bus_width(struct mss_card *card, u8 buswidth){ struct mss_host *host = card->slot->host; struct sdio_card *sdio_card = card->prot_card; struct mss_cmd *cmd = &sdio_card->cmd; struct mss_ll_request *llreq = &sdio_card->llreq; struct sdio_response_r5 r5; int ret,arg; SDIO_FN0_WRITE_REG(BUS_IF_CTRL, buswidth); card->bus_width = MSS_BUSWIDTH_4BIT; return 0;}static int sdio_set_block_size(struct mss_card *card, u16 size, int func){ struct mss_host *host = card->slot->host; struct sdio_card *sdio_card = card->prot_card; struct mss_cmd *cmd = &sdio_card->cmd; struct mss_ll_request *llreq = &sdio_card->llreq; struct sdio_response_r5 r5; int ret,arg; u8 tmp; if (func == 0) { tmp = size & 0xff; SDIO_FN0_WRITE_REG(FN0_BLKSZ_1, tmp); tmp = (size & 0xff00) >> 8; SDIO_FN0_WRITE_REG(FN0_BLKSZ_2, tmp); sdio_card->cccr.fn0_blksz = size; } else { tmp = size & 0xff; SDIO_FN0_WRITE_REG(FNn_BLKSZ_1(func), tmp); tmp = (size & 0xff00) >> 8; SDIO_FN0_WRITE_REG(FNn_BLKSZ_2(func), tmp); sdio_card->fbr[func].fn_blksz = size; } return 0;}static int sdio_io_enable(struct mss_card *card, u8 set_mask){ struct mss_host *host = card->slot->host; struct sdio_card *sdio_card = card->prot_card; struct mss_cmd *cmd = &sdio_card->cmd; struct mss_ll_request *llreq = &sdio_card->llreq; struct sdio_response_r5 r5; int ret, arg; SDIO_FN0_WRITE_REG(IO_ENABLE, set_mask); return 0;}static int sdio_interrupt_enable(struct mss_card *card, u8 set_mask){ struct mss_host *host = card->slot->host; struct sdio_card *sdio_card = card->prot_card; struct mss_cmd *cmd = &sdio_card->cmd; struct mss_ll_request *llreq = &sdio_card->llreq; struct sdio_response_r5 r5; int ret, arg; SDIO_FN0_WRITE_REG(INT_ENABLE, set_mask); return 0;}static int sdio_csa_enable(struct mss_card *card, int func){ struct mss_host *host = card->slot->host; struct sdio_card *sdio_card = card->prot_card; struct mss_cmd *cmd = &sdio_card->cmd; struct mss_ll_request *llreq = &sdio_card->llreq; struct sdio_response_r5 r5; int arg; int ret = 0; if(sdio_card->fbr[func].fun_support_csa == 0) return ret; SDIO_FN0_WRITE_REG(FNn_IF_CODE(func), 0x80); return 0;}static int get_sdio_fbr_info(struct mss_card *card, int func){ struct mss_host *host = card->slot->host; struct sdio_card *sdio_card = card->prot_card; struct mss_cmd *cmd = &sdio_card->cmd; struct mss_ll_request *llreq = &sdio_card->llreq; struct sdio_response_r5 r5; int ret,arg; u32 tmp; SDIO_FN0_READ_REG(FNn_IF_CODE(func)); sdio_card->fbr[func].fun_if_code = r5.data & 0xF; sdio_card->fbr[func].fun_support_csa = (r5.data >> 6) & 0x1; sdio_card->fbr[func].fun_csa_enable = (r5.data >> 7) & 0x1; SDIO_FN0_READ_REG(FNn_EXT_IF_CODE(func));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -