/*
 * This file is part of the libopencm3 project.
 *
 * Copyright (C) 2012 Felix Held <felix-libopencm3@felixheld.de>
 *
 * This library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This library 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef LIBOPENCM3_SDIO_H
#define LIBOPENCM3_SDIO_H

#include <libopencm3/cm3/common.h>
#include <libopencm3/stm32/memorymap.h>

/* --- SDIO registers ------------------------------------------------------ */

/* SDIO power control register (SDIO_POWER) */
#define SDIO_POWER			MMIO32(SDIO_BASE + 0x00)

/* SDI clock control register (SDIO_CLKCR) */
#define SDIO_CLKCR			MMIO32(SDIO_BASE + 0x04)

/* SDIO argument register (SDIO_ARG) */
#define SDIO_ARG			MMIO32(SDIO_BASE + 0x08)

/* SDIO command register (SDIO_CMD) */
#define SDIO_CMD			MMIO32(SDIO_BASE + 0x0C)

/* SDIO command response register (SDIO_RESPCMD) */
#define SDIO_RESPCMD			MMIO32(SDIO_BASE + 0x10)

/* SDIO response 1..4 register (SDIO_RESPx) */
#define SDIO_RESP1			MMIO32(SDIO_BASE + 0x14)
#define SDIO_RESP2			MMIO32(SDIO_BASE + 0x18)
#define SDIO_RESP3			MMIO32(SDIO_BASE + 0x1C)
#define SDIO_RESP4			MMIO32(SDIO_BASE + 0x20)

/* SDIO data timer register (SDIO_DTIMER) */
#define SDIO_DTIMER			MMIO32(SDIO_BASE + 0x24)

/* SDIO data length register (SDIO_DLEN) */
#define SDIO_DLEN			MMIO32(SDIO_BASE + 0x28)

/* SDIO data control register (SDIO_DCTRL) */
#define SDIO_DCTRL			MMIO32(SDIO_BASE + 0x2C)

/* SDIO data counter register (SDIO_DCOUNT) */
/* read only, write has no effect */
#define SDIO_DCOUNT			MMIO32(SDIO_BASE + 0x30)

/* SDIO status register (SDIO_STA) */
#define SDIO_STA			MMIO32(SDIO_BASE + 0x34)

/* SDIO interrupt clear register (SDIO_ICR) */
#define SDIO_ICR			MMIO32(SDIO_BASE + 0x38)

/* SDIO mask register (SDIO_MASK) */
#define SDIO_MASK			MMIO32(SDIO_BASE + 0x3C)

/* SDIO FIFO counter register (SDIO_FIFOCNT) */
#define SDIO_FIFOCNT			MMIO32(SDIO_BASE + 0x48)

/* SDIO data FIFO register (SDIO_FIFO) */
/* the SDIO data FIFO is 32 32bit words long, beginning at this address */
#define SDIO_FIFO			MMIO32(SDIO_BASE + 0x80)


/* --- SDIO_POWER values --------------------------------------------------- */

#define SDIO_POWER_PWRCTRL_SHIFT	0
#define SDIO_POWER_PWRCTRL_MASK		0x3
#define SDIO_POWER_PWRCTRL_PWROFF	(0x0 << SDIO_POWER_PWRCTRL_SHIFT)
/* what does "10: Reserved power-up" mean? */
#define SDIO_POWER_PWRCTRL_RSVPWRUP	(0x2 << SDIO_POWER_PWRCTRL_SHIFT)
#define SDIO_POWER_PWRCTRL_PWRON	(0x3 << SDIO_POWER_PWRCTRL_SHIFT)


/* --- SDIO_CLKCR values --------------------------------------------------- */

/* HWFC_EN: HW Flow Control enable */
#define SDIO_CLKCR_HWFC_EN		(1 << 14)

/* NEGEDGE: SDIO_CK dephasing selection bit */
#define SDIO_CLKCR_NEGEDGE		(1 << 13)

/* WIDBUS: Wide bus mode enable bit */
/* set the width of the data bus */
#define SDIO_CLKCR_WIDBUS_SHIFT		11
#define SDIO_CLKCR_WIDBUS_MASK	0x3
#define SDIO_CLKCR_WIDBUS_1		(0x0 << SDIO_CLKCR_WIDBUS_SHIFT)
#define SDIO_CLKCR_WIDBUS_4		(0x1 << SDIO_CLKCR_WIDBUS_SHIFT)
#define SDIO_CLKCR_WIDBUS_8		(0x2 << SDIO_CLKCR_WIDBUS_SHIFT)

/* BYPASS: Clock divider bypass enable bit */
#define SDIO_CLKCR_BYPASS		(1 << 10)

/* PWRSAV: Power saving configuration bit */
#define SDIO_CLKCR_PWRSAV		(1 << 9)

/* CLKEN: Clock enable bit */
#define SDIO_CLKCR_CLKEN		(1 << 8)

/* CLKDIV: Clock divide factor */
#define SDIO_CLKCR_CLKDIV_SHIFT		0
#define SDIO_CLKCR_CLKDIV_MASK		0xFF


/* --- SDIO_CMD values ---------------------------------------------------- */

/* ATACMD: CE-ATA command */
#define SDIO_CMD_ATACMD			(1 << 14)

/* nIEN: not Interrupt Enable */
#define SDIO_CMD_NIEN			(1 << 13)

/* ENCMDcompl: Enable CMD completion */
#define SDIO_CMD_ENCMDCOMPL		(1 << 12)

/* SDIOSuspend: SD I/O suspend command */
#define SDIO_CMD_SDIOSUSPEND		(1 << 11)

/* CPSMEN: Command path state machine (CPSM) Enable bit */
#define SDIO_CMD_CPSMEN			(1 << 10)

/* WAITPEND: CPSM Waits for ends of data transfer (CmdPend internal signal) */
#define SDIO_CMD_WAITPEND		(1 << 9)

/* WAITINT: CPSM waits for interrupt request */
#define SDIO_CMD_WAITINT		(1 << 8)

/* WAITRESP: Wait for response bits */
#define SDIO_CMD_WAITRESP_SHIFT		6
#define SDIO_CMD_WAITRESP_MASK		0x3
/* 00: No response, expect CMDSENT flag */
#define SDIO_CMD_WAITRESP_NO_0		(0x0 << SDIO_CMD_WAITRESP_SHIFT)
/* 01: Short response, expect CMDREND or CCRCFAIL flag */
#define SDIO_CMD_WAITRESP_SHORT		(0x1 << SDIO_CMD_WAITRESP_SHIFT)
/* 10: No response, expect CMDSENT flag */
#define SDIO_CMD_WAITRESP_NO_2		(0x2 << SDIO_CMD_WAITRESP_SHIFT)
/* 11: Long response, expect CMDREND or CCRCFAIL flag */
#define SDIO_CMD_WAITRESP_LONG		(0x3 << SDIO_CMD_WAITRESP_SHIFT)

/* CMDINDEX: Command index */
#define SDIO_CMD_CMDINDEX_SHIFT		0
#define SDIO_CMD_CMDINDEX_MASK		0x3F


/* --- SDIO_RESPCMD values ------------------------------------------------ */

#define SDIO_RESPCMD_SHIFT		0
#define SDIO_RESPCMD_MASK		0x3F


/* --- SDIO_DLEN values --------------------------------------------------- */

/* DATALENGTH: Data length value */
#define SDIO_DLEN_DATALENGTH_SHIFT	0
#define SDIO_DLEN_DATALENGTH_MASK	0x1FFFFFF


/* --- SDIO_DCTRL values -------------------------------------------------- */

/* SDIOEN: SD I/O enable functions */
#define SDIO_DCTRL_SDIOEN		(1 << 11)

/* RWMOD: Read wait mode */
/* 0: Read Wait control stopping SDIO_D2
 * 1: Read Wait control using SDIO_CK
 */
#define SDIO_DCTRL_RWMOD		(1 << 10)

/* RWSTOP: Read wait stop */
/* 0: Read wait in progress if RWSTART bit is set
 * 1: Enable for read wait stop if RWSTART bit is set
 */
#define SDIO_DCTRL_RWSTOP		(1 << 9)

/* RWSTART: Read wait start */
#define SDIO_DCTRL_RWSTART		(1 << 8)

/* DBLOCKSIZE: Data block size */
/* SDIO_DCTRL_DBLOCKSIZE_n
 * block size is 2**n bytes with 0<=n<=14
 */
#define SDIO_DCTRL_DBLOCKSIZE_SHIFT	4
#define SDIO_DCTRL_DBLOCKSIZE_MASK	0xF
#define SDIO_DCTRL_DBLOCKSIZE_0		(0x0 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_1		(0x1 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_2		(0x2 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_3		(0x3 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_4		(0x4 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_5		(0x5 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_6		(0x6 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_7		(0x7 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_8		(0x8 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_9		(0x9 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_10	(0xA << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_11	(0xB << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_12	(0xC << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_13	(0xD << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_14	(0xE << SDIO_DCTRL_DBLOCKSIZE_SHIFT)

/* DMAEN: DMA enable bit */
#define SDIO_DCTRL_DMAEN		(1 << 3)

/* DTMODE: Data transfer mode selection 1: Stream or SDIO multi byte transfer */
#define SDIO_DCTRL_DTMODE		(1 << 2)

/* DTDIR: Data transfer direction selection */
/* 0: From controller to card.
 * 1: From card to controller.
 */
#define SDIO_DCTRL_DTDIR		(1 << 1)

/* DTEN: Data transfer enabled bit */
#define SDIO_DCTRL_DTEN			(1 << 0)


/* --- SDIO_STA values ---------------------------------------------------- */

/* CEATAEND: CE-ATA command completion signal received for CMD61 */
#define SDIO_STA_CEATAEND		(1 << 23)

/* SDIOIT: SDIO interrupt received */
#define SDIO_STA_SDIOIT			(1 << 22)

/* RXDAVL: Data available in receive FIFO */
#define SDIO_STA_RXDAVL			(1 << 21)

/* TXDAVL: Data available in transmit FIFO */
#define SDIO_STA_TXDAVL			(1 << 20)

/* RXFIFOE: Receive FIFO empty */
#define SDIO_STA_RXFIFOE		(1 << 19)

/* TXFIFOE: Transmit FIFO empty */
/* HW Flow Control enabled -> TXFIFOE signals becomes activated when the FIFO
 * contains 2 words.
 */
#define SDIO_STA_TXFIFOE		(1 << 18)

/* RXFIFOF: Receive FIFO full */
/* HW Flow Control  enabled => RXFIFOF signals becomes activated 2 words before
 * the FIFO is full.
 */
#define SDIO_STA_RXFIFOF		(1 << 17)

/* TXFIFOF: Transmit FIFO full */
#define SDIO_STA_TXFIFOF		(1 << 16)

/* RXFIFOHF: Receive FIFO half full: there are at least 8 words in the FIFO */
#define SDIO_STA_RXFIFOHF		(1 << 15)

/* TXFIFOHE: Transmit FIFO half empty: at least 8 words can be written into
 * the FIFO
 */
#define SDIO_STA_TXFIFOHE		(1 << 14)

/* RXACT: Data receive in progress */
#define SDIO_STA_RXACT			(1 << 13)

/* TXACT: Data transmit in progress */
#define SDIO_STA_TXACT			(1 << 12)

/* CMDACT: Command transfer in progress */
#define SDIO_STA_CMDACT			(1 << 11)

/* DBCKEND: Data block sent/received (CRC check passed) */
#define SDIO_STA_DBCKEND		(1 << 10)

/* STBITERR: Start bit not detected on all data signals in wide bus mode */
#define SDIO_STA_STBITERR		(1 << 9)

/* DATAEND: Data end (data counter, SDIDCOUNT, is zero) */
#define SDIO_STA_DATAEND		(1 << 8)

/* CMDSENT: Command sent (no response required) */
#define SDIO_STA_CMDSENT		(1 << 7)

/* CMDREND: Command response received (CRC check passed) */
#define SDIO_STA_CMDREND		(1 << 6)

/* RXOVERR: Received FIFO overrun error */
#define SDIO_STA_RXOVERR		(1 << 5)

/* TXUNDERR: Transmit FIFO underrun error */
#define SDIO_STA_TXUNDERR		(1 << 4)

/* DTIMEOUT: Data timeout */
#define SDIO_STA_DTIMEOUT		(1 << 3)

/* CTIMEOUT: Command response timeout */
#define SDIO_STA_CTIMEOUT		(1 << 2)

/* DCRCFAIL: Data block sent/received (CRC check failed) */
#define SDIO_STA_DCRCFAIL		(1 << 1)

/* CCRCFAIL: Command response received (CRC check failed) */
#define SDIO_STA_CCRCFAIL		(1 << 0)


/* --- SDIO_ICR values ---------------------------------------------------- */

/* CEATAENDC: CEATAEND flag clear bit */
#define SDIO_ICR_CEATAENDC		(1 << 23)

/* SDIOITC: SDIOIT flag clear bit */
#define SDIO_ICR_SDIOITC		(1 << 22)

/* DBCKENDC: DBCKEND flag clear bit */
#define SDIO_ICR_DBCKENDC		(1 << 10)

/* STBITERRC: STBITERR flag clear bit */
#define SDIO_ICR_STBITERRC		(1 << 9)

/* DATAENDC: DATAEND flag clear bit */
#define SDIO_ICR_DATAENDC		(1 << 8)

/* CMDSENTC: CMDSENT flag clear bit */
#define SDIO_ICR_CMDSENTC		(1 << 7)

/* CMDRENDC: CMDREND flag clear bit */
#define SDIO_ICR_CMDRENDC		(1 << 6)

/* RXOVERRC: RXOVERR flag clear bit */
#define SDIO_ICR_RXOVERRC		(1 << 5)

/* TXUNDERRC: TXUNDERR flag clear bit */
#define SDIO_ICR_TXUNDERRC		(1 << 4)

/* DTIMEOUTC: DTIMEOUT flag clear bit */
#define SDIO_ICR_DTIMEOUTC		(1 << 3)

/* CTIMEOUTC: CTIMEOUT flag clear bit */
#define SDIO_ICR_CTIMEOUTC		(1 << 2)

/* DCRCFAILC: DCRCFAIL flag clear bit */
#define SDIO_ICR_DCRCFAILC		(1 << 1)

/* CCRCFAILC: CCRCFAIL flag clear bit */
#define SDIO_ICR_CCRCFAILC		(1 << 0)


/* --- SDIO_MASK values --------------------------------------------------- */

/* CEATAENDIE: CE-ATA command completion signal received interrupt enable */
#define SDIO_MASK_CEATAENDIE		(1 << 23)

/* SDIOITIE: SDIO mode interrupt received interrupt enable */
#define SDIO_MASK_SDIOITIE		(1 << 22)

/* RXDAVLIE: Data available in Rx FIFO interrupt enable */
#define SDIO_MASK_RXDAVLIE		(1 << 21)

/* TXDAVLIE: Data available in Tx FIFO interrupt enable */
#define SDIO_MASK_TXDAVLIE		(1 << 20)

/* RXFIFOEIE: Rx FIFO empty interrupt enable */
#define SDIO_MASK_RXFIFOEIE		(1 << 19)

/* TXFIFOEIE: Tx FIFO empty interrupt enable */
#define SDIO_MASK_TXFIFOEIE		(1 << 18)

/* RXFIFOFIE: Rx FIFO full interrupt enable */
#define SDIO_MASK_RXFIFOFIE		(1 << 17)

/* TXFIFOFIE: Tx FIFO full interrupt enable */
#define SDIO_MASK_TXFIFOFIE		(1 << 16)

/* RXFIFOHFIE: Rx FIFO half full interrupt enable */
#define SDIO_MASK_RXFIFOHFIE		(1 << 15)

/* TXFIFOHEIE: Tx FIFO half empty interrupt enable */
#define SDIO_MASK_TXFIFOHEIE		(1 << 14)

/* RXACTIE: Data receive acting interrupt enable */
#define SDIO_MASK_RXACTIE		(1 << 13)

/* TXACTIE: Data transmit acting interrupt enable */
#define SDIO_MASK_TXACTIE		(1 << 12)

/* CMDACTIE: Command acting interrupt enable */
#define SDIO_MASK_CMDACTIE		(1 << 11)

/* DBCKENDIE: Data block end interrupt enable */
#define SDIO_MASK_DBCKENDIE		(1 << 10)

/* STBITERRIE: Start bit error interrupt enable */
#define SDIO_MASK_STBITERRIE		(1 << 9)

/* DATAENDIE: Data end interrupt enable */
#define SDIO_MASK_DATAENDIE		(1 << 8)

/* CMDSENTIE: Command sent interrupt enable */
#define SDIO_MASK_CMDSENTIE		(1 << 7)

/* CMDRENDIE: Command response received interrupt enable */
#define SDIO_MASK_CMDRENDIE		(1 << 6)

/* RXOVERRIE: Rx FIFO overrun error interrupt enable */
#define SDIO_MASK_RXOVERRIE		(1 << 5)

/* TXUNDERRIE: Tx FIFO underrun error interrupt enable */
#define SDIO_MASK_TXUNDERRIE		(1 << 4)

/* DTIMEOUTIE: Data timeout interrupt enable */
#define SDIO_MASK_DTIMEOUTIE		(1 << 3)

/* CTIMEOUTIE: Command timeout interrupt enable */
#define SDIO_MASK_CTIMEOUTIE		(1 << 2)

/* DCRCFAILIE: Data CRC fail interrupt enable */
#define SDIO_MASK_DCRCFAILIE		(1 << 1)

/* CCRCFAILIE: Command CRC fail interrupt enable */
#define SDIO_MASK_CCRCFAILIE		(1 << 0)


/* --- SDIO_FIFOCNT values ------------------------------------------------- */

/* FIFOCOUNT: Remaining number of words to be written to or read from the
 * FIFO
 */
#define SDIO_FIFOCNT_FIFOCOUNT_SHIFT	0
#define SDIO_FIFOCNT_FIFOCOUNT_MASK	0xFFFFFF


/* --- Function prototypes ------------------------------------------------- */


/* TODO */


#endif
