diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig index 2da3ae25849..c3144dfe1bd 100644 --- a/arch/arm/src/samv7/Kconfig +++ b/arch/arm/src/samv7/Kconfig @@ -2490,6 +2490,21 @@ endmenu # DAC device driver configuration menu "HSMCI device driver options" depends on SAMV7_HSMCI +config SAMV7_HSMCI_SW_CARDDETECT + bool "MMC/SD card detect is SW on CD/DAT3" + depends on MMCSD_HAVE_CARDDETECT + default n + ---help--- + Some SD card connectors do not have separate card detection pin. In that + case card detection has to be done on CD/DAT3 data line. This means software + (i.e. architecture level driver) has to take care of pin configuration switching + (pin has to be set as data pin in case of transfer and as interrupt card detection + pin when there is no action on data line). SAMv7 HSMCI driver offers this method + of SD card detection. Following macros have to be defined in include/board.h: + + GPIO_HSMCI0_CD - detection pin (same as CD/DAT3 but with IRQ) + IRQ_HSMCI0_CD - IRQ number for the pin + config SAMV7_HSMCI_DMA bool "Support DMA data transfers" default y diff --git a/arch/arm/src/samv7/sam_hsmci.c b/arch/arm/src/samv7/sam_hsmci.c index e11d75c992c..459a15ec08e 100644 --- a/arch/arm/src/samv7/sam_hsmci.c +++ b/arch/arm/src/samv7/sam_hsmci.c @@ -368,6 +368,11 @@ struct sam_dev_s int ntimes; /* Number of times */ #endif +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + uint32_t cdgpio; + uint32_t cdirq; +#endif + /* Register logging support */ #if defined(CONFIG_SAMV7_HSMCI_CMDDEBUG) && defined(CONFIG_SAMV7_HSMCI_XFRDEBUG) @@ -389,6 +394,13 @@ struct sam_dev_s /* Low-level helpers ********************************************************/ +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT +static int sam_carddetect_enable(struct sam_dev_s *priv); +static int sam_carddetect_disable(struct sam_dev_s *priv); +static int sam_carddetect_handler(int irq, void *context, + void *arg); +#endif + #ifdef CONFIG_SAMV7_HSMCI_REGDEBUG static bool sam_checkreg(struct sam_dev_s *priv, bool wr, uint32_t value, uint32_t address); @@ -574,6 +586,10 @@ static struct sam_dev_s g_hsmci0 = .waitsem = SEM_INITIALIZER(0), .base = SAM_HSMCI0_BASE, .hsmci = 0, +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + .cdgpio = GPIO_HSMCI0_CD, + .cdirq = IRQ_HSMCI0_CD, +#endif }; #endif @@ -581,6 +597,73 @@ static struct sam_dev_s g_hsmci0 = * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: sam_carddetect_enable + * + * Description: + * Enables card detection (switch CD/DAT3 to interrupt mode and enables it) + * + * Input Parameters: + * priv - A reference to the HSMCI device state structure + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT +static int sam_carddetect_enable(struct sam_dev_s *priv) +{ + sam_configgpio(priv->cdgpio); + sam_gpioirq(priv->cdgpio); + irq_attach(priv->cdirq, sam_carddetect_handler, (void *)priv); + sam_gpioirqenable(priv->cdirq); + + return OK; +} + +/**************************************************************************** + * Name: sam_carddetect_disable + * + * Description: + * Disables card detection (switch CD/DAT3 to data mode) + * + * Input Parameters: + * priv - A reference to the HSMCI device state structure + * + ****************************************************************************/ + +static int sam_carddetect_disable(struct sam_dev_s *priv) +{ + sam_gpioirqdisable(priv->cdirq); + irq_detach(priv->cdirq); + + sam_configgpio(GPIO_MCI0_DA3); + + return OK; +} + +/**************************************************************************** + * Name: sam_carddetect_handler + * + * Description: + * Standard interrupt handler for CD/DAT3 pin. Calls sdio_mediachange + * with current value of CD pin. + * + ****************************************************************************/ + +static int sam_carddetect_handler(int irq, void *context, + void *arg) +{ + struct sam_dev_s *priv = (struct sam_dev_s *)arg; + bool inserted; + + inserted = sam_gpioread(priv->cdgpio); + mcinfo("Inserted: %s\n", inserted ? "YES" : "NO"); + + sdio_mediachange(&priv->dev, inserted); + + return OK; +} +#endif + /**************************************************************************** * Name: sam_checkreg * @@ -1390,6 +1473,14 @@ static void sam_notransfer(struct sam_dev_s *priv) priv->xfrbusy = false; priv->txbusy = false; + +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* Transfer ended so switch CD/DAT3 do CD mode to detect card inserion + * or remove. + */ + + sam_carddetect_enable(priv); +#endif } /**************************************************************************** @@ -1944,6 +2035,12 @@ static int sam_sendcmd(struct sdio_dev_s *dev, uint32_t regval; uint32_t cmdidx; +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* Switch CD/DAT3 pin do data mode */ + + sam_carddetect_disable(priv); +#endif + sam_cmdsampleinit(priv); /* Set the HSMCI Argument value */ @@ -2122,6 +2219,12 @@ static int sam_recvsetup(struct sdio_dev_s *dev, uint8_t *buffer, DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* Switch CD/DAT3 pin do data mode */ + + sam_carddetect_disable(priv); +#endif + #ifndef CONFIG_SAMV7_HSMCI_UNALIGNED /* Default behavior is to transfer 32-bit values only */ @@ -2192,6 +2295,12 @@ static int sam_sendsetup(struct sdio_dev_s *dev, DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* Switch CD/DAT3 pin do data mode */ + + sam_carddetect_disable(priv); +#endif + #ifndef CONFIG_SAMV7_HSMCI_UNALIGNED /* Default behavior is to transfer 32-bit values only */ @@ -2381,6 +2490,12 @@ static int sam_waitresponse(struct sdio_dev_s *dev, uint32_t cmd) clock_t watchtime; int32_t timeout; +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* Switch CD/DAT3 pin do data mode */ + + sam_carddetect_disable(priv); +#endif + switch (cmd & MMCSD_RESPONSE_MASK) { case MMCSD_R1_RESPONSE: @@ -2496,6 +2611,12 @@ static int sam_recvshort(struct sdio_dev_s *dev, struct sam_dev_s *priv = (struct sam_dev_s *)dev; int ret = OK; +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* Switch CD/DAT3 pin do data mode */ + + sam_carddetect_disable(priv); +#endif + /* These responses could have CRC errors: * * R1 Command response (48-bit) @@ -2583,6 +2704,12 @@ static int sam_recvlong(struct sdio_dev_s *dev, uint32_t cmd, struct sam_dev_s *priv = (struct sam_dev_s *)dev; int ret = OK; +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* Switch CD/DAT3 pin do data mode */ + + sam_carddetect_disable(priv); +#endif + /* R2 CID, CSD register (136-bit) * 135 0 Start bit * 134 0 Transmission bit (0=from card) @@ -2861,6 +2988,15 @@ static void sam_callbackenable(struct sdio_dev_s *dev, mcinfo("eventset: %02x\n", eventset); DEBUGASSERT(priv != NULL); +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* Calling callbackenable means that we expect the card to be inserted + * or removed, therefore we have to switch CD/DAT3 pin to detection + * mode. + */ + + sam_carddetect_enable(priv); +#endif + priv->cbevents = eventset; sam_callback(priv); } @@ -2937,6 +3073,12 @@ static int sam_dmarecvsetup(struct sdio_dev_s *dev, uint8_t *buffer, DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* Switch CD/DAT3 pin do data mode */ + + sam_carddetect_disable(priv); +#endif + /* 32-bit buffer alignment is required for DMA transfers */ if (((uintptr_t)buffer & 3) != 0 || (buflen & 3) != 0) @@ -3052,6 +3194,12 @@ static int sam_dmasendsetup(struct sdio_dev_s *dev, DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* Switch CD/DAT3 pin do data mode */ + + sam_carddetect_disable(priv); +#endif + /* 32-bit buffer alignment is required for DMA transfers */ if (((uintptr_t)buffer & 3) != 0 || (buflen & 3) != 0) @@ -3278,7 +3426,9 @@ struct sdio_dev_s *sdio_initialize(int slotno) sam_configgpio(GPIO_MCI0_DA0); /* Data 0 of Slot A */ sam_configgpio(GPIO_MCI0_DA1); /* Data 1 of Slot A */ sam_configgpio(GPIO_MCI0_DA2); /* Data 2 of Slot A */ +#ifndef CONFIG_SAMV7_HSMCI_SW_CARDDETECT sam_configgpio(GPIO_MCI0_DA3); /* Data 3 of Slot A */ +#endif sam_configgpio(GPIO_MCI0_CK); /* Common SD clock */ sam_configgpio(GPIO_MCI0_CDA); /* Command/Response of Slot A */ @@ -3302,6 +3452,19 @@ struct sdio_dev_s *sdio_initialize(int slotno) mcinfo("priv: %p base: %08" PRIx32 " hsmci: %d pid: %" PRId32 "\n", priv, priv->base, priv->hsmci, pid); +#ifdef CONFIG_SAMV7_HSMCI_SW_CARDDETECT + /* We do not have separare card detect pin on SD card slot. This means + * card detection has to be done on CD/DAT3 pin. Generally we have to + * switch between configuration of the pin (once as a simple interrupt + * GPIO and then as data pin for SDIO driver). + * + * Lets start with CD pin configuration. + */ + + sam_carddetect_enable(priv); + sdio_mediachange(&priv->dev, sam_gpioread(priv->cdgpio)); +#endif + /* Allocate a DMA channel */ priv->dma = sam_dmachannel(0, DMA_FLAGS(pid)); diff --git a/boards/arm/samv7/common/src/sam_hsmci.c b/boards/arm/samv7/common/src/sam_hsmci.c index 576bce08944..2799698f950 100644 --- a/boards/arm/samv7/common/src/sam_hsmci.c +++ b/boards/arm/samv7/common/src/sam_hsmci.c @@ -96,14 +96,15 @@ static bool sam_cardinserted_internal(struct sam_hsmci_state_s *state) } /**************************************************************************** - * Name: sam_hsmci_cardetect and sam_hsmci_cardetect_handler + * Name: sam_hsmci_carddetect and sam_hsmci_carddetect_handler * * Description: * Card detect interrupt handlers * ****************************************************************************/ -static int sam_hsmci_cardetect(struct sam_hsmci_state_s *state) +#ifndef CONFIG_SAMV7_HSMCI_SW_CARDDETECT +static int sam_hsmci_carddetect(struct sam_hsmci_state_s *state) { /* Get the current card insertion state */ @@ -125,7 +126,7 @@ static int sam_hsmci_cardetect(struct sam_hsmci_state_s *state) return OK; } -static int sam_hsmci_cardetect_handler(int irq, void *context, +static int sam_hsmci_carddetect_handler(int irq, void *context, void *arg) { struct sam_hsmci_state_s *state = (struct sam_hsmci_state_s *)arg; @@ -136,7 +137,7 @@ static int sam_hsmci_cardetect_handler(int irq, void *context, * device. */ - ret = sam_hsmci_cardetect(state); + ret = sam_hsmci_carddetect(state); #ifdef CONFIG_FS_AUTOMOUNTER /* Let the automounter know about the insertion event */ @@ -146,6 +147,7 @@ static int sam_hsmci_cardetect_handler(int irq, void *context, return ret; } +#endif /**************************************************************************** * Name: sam_hsmci_state @@ -200,10 +202,12 @@ int sam_hsmci_initialize(int slotno, int minor, gpio_pinset_t cdcfg, state->cdirq = cdirq; state->cdinvert = cdinvert; +#ifndef CONFIG_SAMV7_HSMCI_SW_CARDDETECT /* Initialize card-detect, write-protect, and power enable PIOs */ sam_configgpio(state->cdcfg); sam_dumpgpio(state->cdcfg, "HSMCI Card Detect"); +#endif /* Mount the SDIO-based MMC/SD block driver */ @@ -225,10 +229,11 @@ int sam_hsmci_initialize(int slotno, int minor, gpio_pinset_t cdcfg, return ret; } +#ifndef CONFIG_SAMV7_HSMCI_SW_CARDDETECT /* Configure card detect interrupts */ sam_gpioirq(state->cdcfg); - irq_attach(state->cdirq, sam_hsmci_cardetect_handler, (void *)state); + irq_attach(state->cdirq, sam_hsmci_carddetect_handler, (void *)state); /* Then inform the HSMCI driver if there is or is not a card in the slot. */ @@ -238,6 +243,7 @@ int sam_hsmci_initialize(int slotno, int minor, gpio_pinset_t cdcfg, /* Enable card detect interrupts */ sam_gpioirqenable(state->cdirq); +#endif return OK; }