1da7fbe58SPierre Ossman /* 270f10482SPierre Ossman * linux/drivers/mmc/core/mmc_ops.h 3da7fbe58SPierre Ossman * 4da7fbe58SPierre Ossman * Copyright 2006-2007 Pierre Ossman 5da7fbe58SPierre Ossman * 6da7fbe58SPierre Ossman * This program is free software; you can redistribute it and/or modify 7da7fbe58SPierre Ossman * it under the terms of the GNU General Public License as published by 8da7fbe58SPierre Ossman * the Free Software Foundation; either version 2 of the License, or (at 9da7fbe58SPierre Ossman * your option) any later version. 10da7fbe58SPierre Ossman */ 11da7fbe58SPierre Ossman 12da7fbe58SPierre Ossman #include <linux/types.h> 13da7fbe58SPierre Ossman #include <asm/scatterlist.h> 14da7fbe58SPierre Ossman #include <linux/scatterlist.h> 15da7fbe58SPierre Ossman 16da7fbe58SPierre Ossman #include <linux/mmc/host.h> 17da7fbe58SPierre Ossman #include <linux/mmc/card.h> 18da7fbe58SPierre Ossman #include <linux/mmc/mmc.h> 19da7fbe58SPierre Ossman 20da7fbe58SPierre Ossman #include "core.h" 21da7fbe58SPierre Ossman #include "mmc_ops.h" 22da7fbe58SPierre Ossman 23da7fbe58SPierre Ossman static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) 24da7fbe58SPierre Ossman { 25da7fbe58SPierre Ossman int err; 26da7fbe58SPierre Ossman struct mmc_command cmd; 27da7fbe58SPierre Ossman 28da7fbe58SPierre Ossman BUG_ON(!host); 29da7fbe58SPierre Ossman 30da7fbe58SPierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 31da7fbe58SPierre Ossman 32da7fbe58SPierre Ossman cmd.opcode = MMC_SELECT_CARD; 33da7fbe58SPierre Ossman 34da7fbe58SPierre Ossman if (card) { 35da7fbe58SPierre Ossman cmd.arg = card->rca << 16; 36da7fbe58SPierre Ossman cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 37da7fbe58SPierre Ossman } else { 38da7fbe58SPierre Ossman cmd.arg = 0; 39da7fbe58SPierre Ossman cmd.flags = MMC_RSP_NONE | MMC_CMD_AC; 40da7fbe58SPierre Ossman } 41da7fbe58SPierre Ossman 42da7fbe58SPierre Ossman err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); 43da7fbe58SPierre Ossman if (err != MMC_ERR_NONE) 44da7fbe58SPierre Ossman return err; 45da7fbe58SPierre Ossman 46da7fbe58SPierre Ossman return MMC_ERR_NONE; 47da7fbe58SPierre Ossman } 48da7fbe58SPierre Ossman 49da7fbe58SPierre Ossman int mmc_select_card(struct mmc_card *card) 50da7fbe58SPierre Ossman { 51da7fbe58SPierre Ossman BUG_ON(!card); 52da7fbe58SPierre Ossman 53da7fbe58SPierre Ossman return _mmc_select_card(card->host, card); 54da7fbe58SPierre Ossman } 55da7fbe58SPierre Ossman 56da7fbe58SPierre Ossman int mmc_deselect_cards(struct mmc_host *host) 57da7fbe58SPierre Ossman { 58da7fbe58SPierre Ossman return _mmc_select_card(host, NULL); 59da7fbe58SPierre Ossman } 60da7fbe58SPierre Ossman 61da7fbe58SPierre Ossman int mmc_go_idle(struct mmc_host *host) 62da7fbe58SPierre Ossman { 63da7fbe58SPierre Ossman int err; 64da7fbe58SPierre Ossman struct mmc_command cmd; 65da7fbe58SPierre Ossman 66da7fbe58SPierre Ossman mmc_set_chip_select(host, MMC_CS_HIGH); 67da7fbe58SPierre Ossman 68da7fbe58SPierre Ossman mmc_delay(1); 69da7fbe58SPierre Ossman 70da7fbe58SPierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 71da7fbe58SPierre Ossman 72da7fbe58SPierre Ossman cmd.opcode = MMC_GO_IDLE_STATE; 73da7fbe58SPierre Ossman cmd.arg = 0; 74da7fbe58SPierre Ossman cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; 75da7fbe58SPierre Ossman 76da7fbe58SPierre Ossman err = mmc_wait_for_cmd(host, &cmd, 0); 77da7fbe58SPierre Ossman 78da7fbe58SPierre Ossman mmc_delay(1); 79da7fbe58SPierre Ossman 80da7fbe58SPierre Ossman mmc_set_chip_select(host, MMC_CS_DONTCARE); 81da7fbe58SPierre Ossman 82da7fbe58SPierre Ossman mmc_delay(1); 83da7fbe58SPierre Ossman 84da7fbe58SPierre Ossman return err; 85da7fbe58SPierre Ossman } 86da7fbe58SPierre Ossman 87da7fbe58SPierre Ossman int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) 88da7fbe58SPierre Ossman { 89da7fbe58SPierre Ossman struct mmc_command cmd; 90da7fbe58SPierre Ossman int i, err = 0; 91da7fbe58SPierre Ossman 92da7fbe58SPierre Ossman BUG_ON(!host); 93da7fbe58SPierre Ossman 94da7fbe58SPierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 95da7fbe58SPierre Ossman 96da7fbe58SPierre Ossman cmd.opcode = MMC_SEND_OP_COND; 97da7fbe58SPierre Ossman cmd.arg = ocr; 98da7fbe58SPierre Ossman cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; 99da7fbe58SPierre Ossman 100da7fbe58SPierre Ossman for (i = 100; i; i--) { 101da7fbe58SPierre Ossman err = mmc_wait_for_cmd(host, &cmd, 0); 102da7fbe58SPierre Ossman if (err != MMC_ERR_NONE) 103da7fbe58SPierre Ossman break; 104da7fbe58SPierre Ossman 105da7fbe58SPierre Ossman if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) 106da7fbe58SPierre Ossman break; 107da7fbe58SPierre Ossman 108da7fbe58SPierre Ossman err = MMC_ERR_TIMEOUT; 109da7fbe58SPierre Ossman 110da7fbe58SPierre Ossman mmc_delay(10); 111da7fbe58SPierre Ossman } 112da7fbe58SPierre Ossman 113da7fbe58SPierre Ossman if (rocr) 114da7fbe58SPierre Ossman *rocr = cmd.resp[0]; 115da7fbe58SPierre Ossman 116da7fbe58SPierre Ossman return err; 117da7fbe58SPierre Ossman } 118da7fbe58SPierre Ossman 119da7fbe58SPierre Ossman int mmc_all_send_cid(struct mmc_host *host, u32 *cid) 120da7fbe58SPierre Ossman { 121da7fbe58SPierre Ossman int err; 122da7fbe58SPierre Ossman struct mmc_command cmd; 123da7fbe58SPierre Ossman 124da7fbe58SPierre Ossman BUG_ON(!host); 125da7fbe58SPierre Ossman BUG_ON(!cid); 126da7fbe58SPierre Ossman 127da7fbe58SPierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 128da7fbe58SPierre Ossman 129da7fbe58SPierre Ossman cmd.opcode = MMC_ALL_SEND_CID; 130da7fbe58SPierre Ossman cmd.arg = 0; 131da7fbe58SPierre Ossman cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; 132da7fbe58SPierre Ossman 133da7fbe58SPierre Ossman err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); 134da7fbe58SPierre Ossman if (err != MMC_ERR_NONE) 135da7fbe58SPierre Ossman return err; 136da7fbe58SPierre Ossman 137da7fbe58SPierre Ossman memcpy(cid, cmd.resp, sizeof(u32) * 4); 138da7fbe58SPierre Ossman 139da7fbe58SPierre Ossman return MMC_ERR_NONE; 140da7fbe58SPierre Ossman } 141da7fbe58SPierre Ossman 142da7fbe58SPierre Ossman int mmc_set_relative_addr(struct mmc_card *card) 143da7fbe58SPierre Ossman { 144da7fbe58SPierre Ossman int err; 145da7fbe58SPierre Ossman struct mmc_command cmd; 146da7fbe58SPierre Ossman 147da7fbe58SPierre Ossman BUG_ON(!card); 148da7fbe58SPierre Ossman BUG_ON(!card->host); 149da7fbe58SPierre Ossman 150da7fbe58SPierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 151da7fbe58SPierre Ossman 152da7fbe58SPierre Ossman cmd.opcode = MMC_SET_RELATIVE_ADDR; 153da7fbe58SPierre Ossman cmd.arg = card->rca << 16; 154da7fbe58SPierre Ossman cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 155da7fbe58SPierre Ossman 156da7fbe58SPierre Ossman err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); 157da7fbe58SPierre Ossman if (err != MMC_ERR_NONE) 158da7fbe58SPierre Ossman return err; 159da7fbe58SPierre Ossman 160da7fbe58SPierre Ossman return MMC_ERR_NONE; 161da7fbe58SPierre Ossman } 162da7fbe58SPierre Ossman 163da7fbe58SPierre Ossman int mmc_send_csd(struct mmc_card *card, u32 *csd) 164da7fbe58SPierre Ossman { 165da7fbe58SPierre Ossman int err; 166da7fbe58SPierre Ossman struct mmc_command cmd; 167da7fbe58SPierre Ossman 168da7fbe58SPierre Ossman BUG_ON(!card); 169da7fbe58SPierre Ossman BUG_ON(!card->host); 170da7fbe58SPierre Ossman BUG_ON(!csd); 171da7fbe58SPierre Ossman 172da7fbe58SPierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 173da7fbe58SPierre Ossman 174da7fbe58SPierre Ossman cmd.opcode = MMC_SEND_CSD; 175da7fbe58SPierre Ossman cmd.arg = card->rca << 16; 176da7fbe58SPierre Ossman cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; 177da7fbe58SPierre Ossman 178da7fbe58SPierre Ossman err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); 179da7fbe58SPierre Ossman if (err != MMC_ERR_NONE) 180da7fbe58SPierre Ossman return err; 181da7fbe58SPierre Ossman 182da7fbe58SPierre Ossman memcpy(csd, cmd.resp, sizeof(u32) * 4); 183da7fbe58SPierre Ossman 184da7fbe58SPierre Ossman return MMC_ERR_NONE; 185da7fbe58SPierre Ossman } 186da7fbe58SPierre Ossman 187da7fbe58SPierre Ossman int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) 188da7fbe58SPierre Ossman { 189da7fbe58SPierre Ossman struct mmc_request mrq; 190da7fbe58SPierre Ossman struct mmc_command cmd; 191da7fbe58SPierre Ossman struct mmc_data data; 192da7fbe58SPierre Ossman struct scatterlist sg; 193da7fbe58SPierre Ossman 194da7fbe58SPierre Ossman BUG_ON(!card); 195da7fbe58SPierre Ossman BUG_ON(!card->host); 196da7fbe58SPierre Ossman BUG_ON(!ext_csd); 197da7fbe58SPierre Ossman 198da7fbe58SPierre Ossman memset(&mrq, 0, sizeof(struct mmc_request)); 199da7fbe58SPierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 200da7fbe58SPierre Ossman memset(&data, 0, sizeof(struct mmc_data)); 201da7fbe58SPierre Ossman 202da7fbe58SPierre Ossman mrq.cmd = &cmd; 203da7fbe58SPierre Ossman mrq.data = &data; 204da7fbe58SPierre Ossman 205da7fbe58SPierre Ossman cmd.opcode = MMC_SEND_EXT_CSD; 206da7fbe58SPierre Ossman cmd.arg = 0; 207da7fbe58SPierre Ossman cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; 208da7fbe58SPierre Ossman 209da7fbe58SPierre Ossman data.blksz = 512; 210da7fbe58SPierre Ossman data.blocks = 1; 211da7fbe58SPierre Ossman data.flags = MMC_DATA_READ; 212da7fbe58SPierre Ossman data.sg = &sg; 213da7fbe58SPierre Ossman data.sg_len = 1; 214da7fbe58SPierre Ossman 215da7fbe58SPierre Ossman sg_init_one(&sg, ext_csd, 512); 216da7fbe58SPierre Ossman 217da7fbe58SPierre Ossman mmc_set_data_timeout(&data, card, 0); 218da7fbe58SPierre Ossman 219da7fbe58SPierre Ossman mmc_wait_for_req(card->host, &mrq); 220da7fbe58SPierre Ossman 221da7fbe58SPierre Ossman if (cmd.error != MMC_ERR_NONE) 222da7fbe58SPierre Ossman return cmd.error; 223da7fbe58SPierre Ossman if (data.error != MMC_ERR_NONE) 224da7fbe58SPierre Ossman return data.error; 225da7fbe58SPierre Ossman 226da7fbe58SPierre Ossman return MMC_ERR_NONE; 227da7fbe58SPierre Ossman } 228da7fbe58SPierre Ossman 229da7fbe58SPierre Ossman int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) 230da7fbe58SPierre Ossman { 231da7fbe58SPierre Ossman int err; 232da7fbe58SPierre Ossman struct mmc_command cmd; 233da7fbe58SPierre Ossman 234da7fbe58SPierre Ossman BUG_ON(!card); 235da7fbe58SPierre Ossman BUG_ON(!card->host); 236da7fbe58SPierre Ossman 237da7fbe58SPierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 238da7fbe58SPierre Ossman 239da7fbe58SPierre Ossman cmd.opcode = MMC_SWITCH; 240da7fbe58SPierre Ossman cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 241da7fbe58SPierre Ossman (index << 16) | 242da7fbe58SPierre Ossman (value << 8) | 243da7fbe58SPierre Ossman set; 244da7fbe58SPierre Ossman cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; 245da7fbe58SPierre Ossman 246da7fbe58SPierre Ossman err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); 247da7fbe58SPierre Ossman if (err != MMC_ERR_NONE) 248da7fbe58SPierre Ossman return err; 249da7fbe58SPierre Ossman 250da7fbe58SPierre Ossman return MMC_ERR_NONE; 251da7fbe58SPierre Ossman } 252da7fbe58SPierre Ossman 253da7fbe58SPierre Ossman int mmc_send_status(struct mmc_card *card, u32 *status) 254da7fbe58SPierre Ossman { 255da7fbe58SPierre Ossman int err; 256da7fbe58SPierre Ossman struct mmc_command cmd; 257da7fbe58SPierre Ossman 258da7fbe58SPierre Ossman BUG_ON(!card); 259da7fbe58SPierre Ossman BUG_ON(!card->host); 260da7fbe58SPierre Ossman 261da7fbe58SPierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 262da7fbe58SPierre Ossman 263da7fbe58SPierre Ossman cmd.opcode = MMC_SEND_STATUS; 264da7fbe58SPierre Ossman cmd.arg = card->rca << 16; 265da7fbe58SPierre Ossman cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 266da7fbe58SPierre Ossman 267da7fbe58SPierre Ossman err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); 268da7fbe58SPierre Ossman if (err != MMC_ERR_NONE) 269da7fbe58SPierre Ossman return err; 270da7fbe58SPierre Ossman 271da7fbe58SPierre Ossman if (status) 272da7fbe58SPierre Ossman *status = cmd.resp[0]; 273da7fbe58SPierre Ossman 274da7fbe58SPierre Ossman return MMC_ERR_NONE; 275da7fbe58SPierre Ossman } 276da7fbe58SPierre Ossman 277