11c6a0718SPierre Ossman /* 270f10482SPierre Ossman * linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver 31c6a0718SPierre Ossman * 4b69c9058SPierre Ossman * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. 51c6a0718SPierre Ossman * 61c6a0718SPierre Ossman * This program is free software; you can redistribute it and/or modify 71c6a0718SPierre Ossman * it under the terms of the GNU General Public License as published by 81c6a0718SPierre Ossman * the Free Software Foundation; either version 2 of the License, or (at 91c6a0718SPierre Ossman * your option) any later version. 101c6a0718SPierre Ossman */ 111c6a0718SPierre Ossman 120c7ad106SAndrew Morton #include <linux/scatterlist.h> 130c7ad106SAndrew Morton 141c6a0718SPierre Ossman /* 151c6a0718SPierre Ossman * Controller registers 161c6a0718SPierre Ossman */ 171c6a0718SPierre Ossman 181c6a0718SPierre Ossman #define SDHCI_DMA_ADDRESS 0x00 191c6a0718SPierre Ossman 201c6a0718SPierre Ossman #define SDHCI_BLOCK_SIZE 0x04 211c6a0718SPierre Ossman #define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) 221c6a0718SPierre Ossman 231c6a0718SPierre Ossman #define SDHCI_BLOCK_COUNT 0x06 241c6a0718SPierre Ossman 251c6a0718SPierre Ossman #define SDHCI_ARGUMENT 0x08 261c6a0718SPierre Ossman 271c6a0718SPierre Ossman #define SDHCI_TRANSFER_MODE 0x0C 281c6a0718SPierre Ossman #define SDHCI_TRNS_DMA 0x01 291c6a0718SPierre Ossman #define SDHCI_TRNS_BLK_CNT_EN 0x02 301c6a0718SPierre Ossman #define SDHCI_TRNS_ACMD12 0x04 311c6a0718SPierre Ossman #define SDHCI_TRNS_READ 0x10 321c6a0718SPierre Ossman #define SDHCI_TRNS_MULTI 0x20 331c6a0718SPierre Ossman 341c6a0718SPierre Ossman #define SDHCI_COMMAND 0x0E 351c6a0718SPierre Ossman #define SDHCI_CMD_RESP_MASK 0x03 361c6a0718SPierre Ossman #define SDHCI_CMD_CRC 0x08 371c6a0718SPierre Ossman #define SDHCI_CMD_INDEX 0x10 381c6a0718SPierre Ossman #define SDHCI_CMD_DATA 0x20 391c6a0718SPierre Ossman 401c6a0718SPierre Ossman #define SDHCI_CMD_RESP_NONE 0x00 411c6a0718SPierre Ossman #define SDHCI_CMD_RESP_LONG 0x01 421c6a0718SPierre Ossman #define SDHCI_CMD_RESP_SHORT 0x02 431c6a0718SPierre Ossman #define SDHCI_CMD_RESP_SHORT_BUSY 0x03 441c6a0718SPierre Ossman 451c6a0718SPierre Ossman #define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) 461c6a0718SPierre Ossman 471c6a0718SPierre Ossman #define SDHCI_RESPONSE 0x10 481c6a0718SPierre Ossman 491c6a0718SPierre Ossman #define SDHCI_BUFFER 0x20 501c6a0718SPierre Ossman 511c6a0718SPierre Ossman #define SDHCI_PRESENT_STATE 0x24 521c6a0718SPierre Ossman #define SDHCI_CMD_INHIBIT 0x00000001 531c6a0718SPierre Ossman #define SDHCI_DATA_INHIBIT 0x00000002 541c6a0718SPierre Ossman #define SDHCI_DOING_WRITE 0x00000100 551c6a0718SPierre Ossman #define SDHCI_DOING_READ 0x00000200 561c6a0718SPierre Ossman #define SDHCI_SPACE_AVAILABLE 0x00000400 571c6a0718SPierre Ossman #define SDHCI_DATA_AVAILABLE 0x00000800 581c6a0718SPierre Ossman #define SDHCI_CARD_PRESENT 0x00010000 591c6a0718SPierre Ossman #define SDHCI_WRITE_PROTECT 0x00080000 601c6a0718SPierre Ossman 611c6a0718SPierre Ossman #define SDHCI_HOST_CONTROL 0x28 621c6a0718SPierre Ossman #define SDHCI_CTRL_LED 0x01 631c6a0718SPierre Ossman #define SDHCI_CTRL_4BITBUS 0x02 641c6a0718SPierre Ossman #define SDHCI_CTRL_HISPD 0x04 652134a922SPierre Ossman #define SDHCI_CTRL_DMA_MASK 0x18 662134a922SPierre Ossman #define SDHCI_CTRL_SDMA 0x00 672134a922SPierre Ossman #define SDHCI_CTRL_ADMA1 0x08 682134a922SPierre Ossman #define SDHCI_CTRL_ADMA32 0x10 692134a922SPierre Ossman #define SDHCI_CTRL_ADMA64 0x18 701c6a0718SPierre Ossman 711c6a0718SPierre Ossman #define SDHCI_POWER_CONTROL 0x29 721c6a0718SPierre Ossman #define SDHCI_POWER_ON 0x01 731c6a0718SPierre Ossman #define SDHCI_POWER_180 0x0A 741c6a0718SPierre Ossman #define SDHCI_POWER_300 0x0C 751c6a0718SPierre Ossman #define SDHCI_POWER_330 0x0E 761c6a0718SPierre Ossman 771c6a0718SPierre Ossman #define SDHCI_BLOCK_GAP_CONTROL 0x2A 781c6a0718SPierre Ossman 792df3b71bSNicolas Pitre #define SDHCI_WAKE_UP_CONTROL 0x2B 801c6a0718SPierre Ossman 811c6a0718SPierre Ossman #define SDHCI_CLOCK_CONTROL 0x2C 821c6a0718SPierre Ossman #define SDHCI_DIVIDER_SHIFT 8 831c6a0718SPierre Ossman #define SDHCI_CLOCK_CARD_EN 0x0004 841c6a0718SPierre Ossman #define SDHCI_CLOCK_INT_STABLE 0x0002 851c6a0718SPierre Ossman #define SDHCI_CLOCK_INT_EN 0x0001 861c6a0718SPierre Ossman 871c6a0718SPierre Ossman #define SDHCI_TIMEOUT_CONTROL 0x2E 881c6a0718SPierre Ossman 891c6a0718SPierre Ossman #define SDHCI_SOFTWARE_RESET 0x2F 901c6a0718SPierre Ossman #define SDHCI_RESET_ALL 0x01 911c6a0718SPierre Ossman #define SDHCI_RESET_CMD 0x02 921c6a0718SPierre Ossman #define SDHCI_RESET_DATA 0x04 931c6a0718SPierre Ossman 941c6a0718SPierre Ossman #define SDHCI_INT_STATUS 0x30 951c6a0718SPierre Ossman #define SDHCI_INT_ENABLE 0x34 961c6a0718SPierre Ossman #define SDHCI_SIGNAL_ENABLE 0x38 971c6a0718SPierre Ossman #define SDHCI_INT_RESPONSE 0x00000001 981c6a0718SPierre Ossman #define SDHCI_INT_DATA_END 0x00000002 991c6a0718SPierre Ossman #define SDHCI_INT_DMA_END 0x00000008 1001c6a0718SPierre Ossman #define SDHCI_INT_SPACE_AVAIL 0x00000010 1011c6a0718SPierre Ossman #define SDHCI_INT_DATA_AVAIL 0x00000020 1021c6a0718SPierre Ossman #define SDHCI_INT_CARD_INSERT 0x00000040 1031c6a0718SPierre Ossman #define SDHCI_INT_CARD_REMOVE 0x00000080 1041c6a0718SPierre Ossman #define SDHCI_INT_CARD_INT 0x00000100 105964f9ce2SPierre Ossman #define SDHCI_INT_ERROR 0x00008000 1061c6a0718SPierre Ossman #define SDHCI_INT_TIMEOUT 0x00010000 1071c6a0718SPierre Ossman #define SDHCI_INT_CRC 0x00020000 1081c6a0718SPierre Ossman #define SDHCI_INT_END_BIT 0x00040000 1091c6a0718SPierre Ossman #define SDHCI_INT_INDEX 0x00080000 1101c6a0718SPierre Ossman #define SDHCI_INT_DATA_TIMEOUT 0x00100000 1111c6a0718SPierre Ossman #define SDHCI_INT_DATA_CRC 0x00200000 1121c6a0718SPierre Ossman #define SDHCI_INT_DATA_END_BIT 0x00400000 1131c6a0718SPierre Ossman #define SDHCI_INT_BUS_POWER 0x00800000 1141c6a0718SPierre Ossman #define SDHCI_INT_ACMD12ERR 0x01000000 1152134a922SPierre Ossman #define SDHCI_INT_ADMA_ERROR 0x02000000 1161c6a0718SPierre Ossman 1171c6a0718SPierre Ossman #define SDHCI_INT_NORMAL_MASK 0x00007FFF 1181c6a0718SPierre Ossman #define SDHCI_INT_ERROR_MASK 0xFFFF8000 1191c6a0718SPierre Ossman 1201c6a0718SPierre Ossman #define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \ 1211c6a0718SPierre Ossman SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX) 1221c6a0718SPierre Ossman #define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ 1231c6a0718SPierre Ossman SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ 1241c6a0718SPierre Ossman SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ 1251c6a0718SPierre Ossman SDHCI_INT_DATA_END_BIT) 1261c6a0718SPierre Ossman 1271c6a0718SPierre Ossman #define SDHCI_ACMD12_ERR 0x3C 1281c6a0718SPierre Ossman 1291c6a0718SPierre Ossman /* 3E-3F reserved */ 1301c6a0718SPierre Ossman 1311c6a0718SPierre Ossman #define SDHCI_CAPABILITIES 0x40 1321c6a0718SPierre Ossman #define SDHCI_TIMEOUT_CLK_MASK 0x0000003F 1331c6a0718SPierre Ossman #define SDHCI_TIMEOUT_CLK_SHIFT 0 1341c6a0718SPierre Ossman #define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 1351c6a0718SPierre Ossman #define SDHCI_CLOCK_BASE_MASK 0x00003F00 1361c6a0718SPierre Ossman #define SDHCI_CLOCK_BASE_SHIFT 8 1371c6a0718SPierre Ossman #define SDHCI_MAX_BLOCK_MASK 0x00030000 1381c6a0718SPierre Ossman #define SDHCI_MAX_BLOCK_SHIFT 16 1392134a922SPierre Ossman #define SDHCI_CAN_DO_ADMA2 0x00080000 1402134a922SPierre Ossman #define SDHCI_CAN_DO_ADMA1 0x00100000 1411c6a0718SPierre Ossman #define SDHCI_CAN_DO_HISPD 0x00200000 1421c6a0718SPierre Ossman #define SDHCI_CAN_DO_DMA 0x00400000 1431c6a0718SPierre Ossman #define SDHCI_CAN_VDD_330 0x01000000 1441c6a0718SPierre Ossman #define SDHCI_CAN_VDD_300 0x02000000 1451c6a0718SPierre Ossman #define SDHCI_CAN_VDD_180 0x04000000 1462134a922SPierre Ossman #define SDHCI_CAN_64BIT 0x10000000 1471c6a0718SPierre Ossman 1481c6a0718SPierre Ossman /* 44-47 reserved for more caps */ 1491c6a0718SPierre Ossman 1501c6a0718SPierre Ossman #define SDHCI_MAX_CURRENT 0x48 1511c6a0718SPierre Ossman 1521c6a0718SPierre Ossman /* 4C-4F reserved for more max current */ 1531c6a0718SPierre Ossman 1542134a922SPierre Ossman #define SDHCI_SET_ACMD12_ERROR 0x50 1552134a922SPierre Ossman #define SDHCI_SET_INT_ERROR 0x52 1562134a922SPierre Ossman 1572134a922SPierre Ossman #define SDHCI_ADMA_ERROR 0x54 1582134a922SPierre Ossman 1592134a922SPierre Ossman /* 55-57 reserved */ 1602134a922SPierre Ossman 1612134a922SPierre Ossman #define SDHCI_ADMA_ADDRESS 0x58 1622134a922SPierre Ossman 1632134a922SPierre Ossman /* 60-FB reserved */ 1641c6a0718SPierre Ossman 1651c6a0718SPierre Ossman #define SDHCI_SLOT_INT_STATUS 0xFC 1661c6a0718SPierre Ossman 1671c6a0718SPierre Ossman #define SDHCI_HOST_VERSION 0xFE 1681c6a0718SPierre Ossman #define SDHCI_VENDOR_VER_MASK 0xFF00 1691c6a0718SPierre Ossman #define SDHCI_VENDOR_VER_SHIFT 8 1701c6a0718SPierre Ossman #define SDHCI_SPEC_VER_MASK 0x00FF 1711c6a0718SPierre Ossman #define SDHCI_SPEC_VER_SHIFT 0 1722134a922SPierre Ossman #define SDHCI_SPEC_100 0 1732134a922SPierre Ossman #define SDHCI_SPEC_200 1 1741c6a0718SPierre Ossman 175b8c86fc5SPierre Ossman struct sdhci_ops; 1761c6a0718SPierre Ossman 1771c6a0718SPierre Ossman struct sdhci_host { 178b8c86fc5SPierre Ossman /* Data set by hardware interface driver */ 179b8c86fc5SPierre Ossman const char *hw_name; /* Hardware bus name */ 180b8c86fc5SPierre Ossman 181b8c86fc5SPierre Ossman unsigned int quirks; /* Deviations from spec. */ 182b8c86fc5SPierre Ossman 183b8c86fc5SPierre Ossman /* Controller doesn't honor resets unless we touch the clock register */ 184b8c86fc5SPierre Ossman #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) 185b8c86fc5SPierre Ossman /* Controller has bad caps bits, but really supports DMA */ 186b8c86fc5SPierre Ossman #define SDHCI_QUIRK_FORCE_DMA (1<<1) 187b8c86fc5SPierre Ossman /* Controller doesn't like to be reset when there is no card inserted. */ 188b8c86fc5SPierre Ossman #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) 189b8c86fc5SPierre Ossman /* Controller doesn't like clearing the power reg before a change */ 190b8c86fc5SPierre Ossman #define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) 191b8c86fc5SPierre Ossman /* Controller has flaky internal state so reset it on each ios change */ 192b8c86fc5SPierre Ossman #define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) 193b8c86fc5SPierre Ossman /* Controller has an unusable DMA engine */ 194b8c86fc5SPierre Ossman #define SDHCI_QUIRK_BROKEN_DMA (1<<5) 1952134a922SPierre Ossman /* Controller has an unusable ADMA engine */ 1962134a922SPierre Ossman #define SDHCI_QUIRK_BROKEN_ADMA (1<<6) 197b8c86fc5SPierre Ossman /* Controller can only DMA from 32-bit aligned addresses */ 1982134a922SPierre Ossman #define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<7) 199b8c86fc5SPierre Ossman /* Controller can only DMA chunk sizes that are a multiple of 32 bits */ 2002134a922SPierre Ossman #define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<8) 2012134a922SPierre Ossman /* Controller can only ADMA chunks that are a multiple of 32 bits */ 2022134a922SPierre Ossman #define SDHCI_QUIRK_32BIT_ADMA_SIZE (1<<9) 203b8c86fc5SPierre Ossman /* Controller needs to be reset after each request to stay stable */ 2042134a922SPierre Ossman #define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<10) 205b8c86fc5SPierre Ossman /* Controller needs voltage and power writes to happen separately */ 2062134a922SPierre Ossman #define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11) 207ee53ab5dSPierre Ossman /* Controller provides an incorrect timeout value for transfers */ 2082134a922SPierre Ossman #define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12) 209b8c86fc5SPierre Ossman 210b8c86fc5SPierre Ossman int irq; /* Device IRQ */ 211b8c86fc5SPierre Ossman void __iomem * ioaddr; /* Mapped address */ 212b8c86fc5SPierre Ossman 213b8c86fc5SPierre Ossman const struct sdhci_ops *ops; /* Low level hw interface */ 214b8c86fc5SPierre Ossman 215b8c86fc5SPierre Ossman /* Internal data */ 2161c6a0718SPierre Ossman struct mmc_host *mmc; /* MMC structure */ 2177659150cSPierre Ossman u64 dma_mask; /* custom DMA mask */ 2181c6a0718SPierre Ossman 2192f730fecSPierre Ossman #ifdef CONFIG_LEDS_CLASS 2202f730fecSPierre Ossman struct led_classdev led; /* LED control */ 2212f730fecSPierre Ossman #endif 2222f730fecSPierre Ossman 2231c6a0718SPierre Ossman spinlock_t lock; /* Mutex */ 2241c6a0718SPierre Ossman 2251c6a0718SPierre Ossman int flags; /* Host attributes */ 226c9fddbc4SPierre Ossman #define SDHCI_USE_DMA (1<<0) /* Host is DMA capable */ 2272134a922SPierre Ossman #define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */ 2282134a922SPierre Ossman #define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ 2292134a922SPierre Ossman #define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ 2302134a922SPierre Ossman 2312134a922SPierre Ossman unsigned int version; /* SDHCI spec. version */ 2321c6a0718SPierre Ossman 2331c6a0718SPierre Ossman unsigned int max_clk; /* Max possible freq (MHz) */ 2341c6a0718SPierre Ossman unsigned int timeout_clk; /* Timeout freq (KHz) */ 2351c6a0718SPierre Ossman 2361c6a0718SPierre Ossman unsigned int clock; /* Current clock (MHz) */ 2371c6a0718SPierre Ossman unsigned short power; /* Current voltage */ 2381c6a0718SPierre Ossman 2391c6a0718SPierre Ossman struct mmc_request *mrq; /* Current request */ 2401c6a0718SPierre Ossman struct mmc_command *cmd; /* Current command */ 2411c6a0718SPierre Ossman struct mmc_data *data; /* Current data request */ 24255654be9SHarvey Harrison unsigned int data_early:1; /* Data finished before cmd */ 2431c6a0718SPierre Ossman 2447659150cSPierre Ossman struct sg_mapping_iter sg_miter; /* SG state for PIO */ 2457659150cSPierre Ossman unsigned int blocks; /* remaining PIO blocks */ 2461c6a0718SPierre Ossman 2472134a922SPierre Ossman int sg_count; /* Mapped sg entries */ 2482134a922SPierre Ossman 2492134a922SPierre Ossman u8 *adma_desc; /* ADMA descriptor table */ 2502134a922SPierre Ossman u8 *align_buffer; /* Bounce buffer */ 2512134a922SPierre Ossman 2522134a922SPierre Ossman dma_addr_t adma_addr; /* Mapped ADMA descr. table */ 2532134a922SPierre Ossman dma_addr_t align_addr; /* Mapped bounce buffer */ 2542134a922SPierre Ossman 2551c6a0718SPierre Ossman struct tasklet_struct card_tasklet; /* Tasklet structures */ 2561c6a0718SPierre Ossman struct tasklet_struct finish_tasklet; 2571c6a0718SPierre Ossman 2581c6a0718SPierre Ossman struct timer_list timer; /* Timer for timeouts */ 259b8c86fc5SPierre Ossman 260b8c86fc5SPierre Ossman unsigned long private[0] ____cacheline_aligned; 2611c6a0718SPierre Ossman }; 2621c6a0718SPierre Ossman 2631c6a0718SPierre Ossman 264b8c86fc5SPierre Ossman struct sdhci_ops { 265b8c86fc5SPierre Ossman int (*enable_dma)(struct sdhci_host *host); 2661c6a0718SPierre Ossman }; 267b8c86fc5SPierre Ossman 268b8c86fc5SPierre Ossman 269b8c86fc5SPierre Ossman extern struct sdhci_host *sdhci_alloc_host(struct device *dev, 270b8c86fc5SPierre Ossman size_t priv_size); 271b8c86fc5SPierre Ossman extern void sdhci_free_host(struct sdhci_host *host); 272b8c86fc5SPierre Ossman 273b8c86fc5SPierre Ossman static inline void *sdhci_priv(struct sdhci_host *host) 274b8c86fc5SPierre Ossman { 275b8c86fc5SPierre Ossman return (void *)host->private; 276b8c86fc5SPierre Ossman } 277b8c86fc5SPierre Ossman 278b8c86fc5SPierre Ossman extern int sdhci_add_host(struct sdhci_host *host); 2791e72859eSPierre Ossman extern void sdhci_remove_host(struct sdhci_host *host, int dead); 280b8c86fc5SPierre Ossman 281b8c86fc5SPierre Ossman #ifdef CONFIG_PM 282b8c86fc5SPierre Ossman extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state); 283b8c86fc5SPierre Ossman extern int sdhci_resume_host(struct sdhci_host *host); 284b8c86fc5SPierre Ossman #endif 285