c2bc3dfb12
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). This commit adds CD/DAT3 line card detection support for SAMv7 MCU. Signed-off-by: Michal Lenc <michallenc@seznam.cz>
290 lines
8.0 KiB
C
290 lines
8.0 KiB
C
/****************************************************************************
|
|
* boards/arm/samv7/common/src/sam_hsmci.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <debug.h>
|
|
#include <errno.h>
|
|
|
|
#include <nuttx/sdio.h>
|
|
#include <nuttx/mmcsd.h>
|
|
|
|
#include "sam_hsmci.h"
|
|
#include "board_hsmci.h"
|
|
|
|
#ifdef CONFIG_FS_AUTOMOUNTER
|
|
# include "sam_automount.h"
|
|
#endif /* CONFIG_FS_AUTOMOUNTER */
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
/* This structure holds static information unique to one HSMCI peripheral */
|
|
|
|
struct sam_hsmci_state_s
|
|
{
|
|
struct sdio_dev_s *hsmci; /* R/W device handle */
|
|
gpio_pinset_t cdcfg; /* Card detect PIO pin configuration */
|
|
int cdirq; /* Interrupt number (same as pid) */
|
|
uint8_t slotno; /* Slot number */
|
|
bool cd; /* TRUE: card is inserted */
|
|
bool cdinvert; /* Invert card detection to 0 signaling card */
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/* HSCMI device state */
|
|
|
|
#ifdef CONFIG_SAMV7_HSMCI0
|
|
static struct sam_hsmci_state_s g_hsmci0 =
|
|
{
|
|
.slotno = 0
|
|
};
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: sam_cardinserted_internal
|
|
*
|
|
* Description:
|
|
* Check if a card is inserted into the selected HSMCI slot
|
|
*
|
|
****************************************************************************/
|
|
|
|
static bool sam_cardinserted_internal(struct sam_hsmci_state_s *state)
|
|
{
|
|
bool inserted;
|
|
|
|
/* Get the state of the PIO pin */
|
|
|
|
inserted = sam_gpioread(state->cdcfg) != state->cdinvert;
|
|
finfo("Slot %d inserted: %s\n", state->slotno, inserted ? "YES" : "NO");
|
|
return inserted;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: sam_hsmci_carddetect and sam_hsmci_carddetect_handler
|
|
*
|
|
* Description:
|
|
* Card detect interrupt handlers
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef CONFIG_SAMV7_HSMCI_SW_CARDDETECT
|
|
static int sam_hsmci_carddetect(struct sam_hsmci_state_s *state)
|
|
{
|
|
/* Get the current card insertion state */
|
|
|
|
bool cd = sam_cardinserted_internal(state);
|
|
|
|
/* Has the card detect state changed? */
|
|
|
|
if (cd != state->cd)
|
|
{
|
|
/* Yes... remember that new state and inform the HSMCI driver */
|
|
|
|
state->cd = cd;
|
|
|
|
/* Report the new state to the SDIO driver */
|
|
|
|
sdio_mediachange(state->hsmci, cd);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int sam_hsmci_carddetect_handler(int irq, void *context,
|
|
void *arg)
|
|
{
|
|
struct sam_hsmci_state_s *state = (struct sam_hsmci_state_s *)arg;
|
|
int ret;
|
|
|
|
/* Handle the card detect interrupt. The interrupt level logic will
|
|
* kick of the driver-level operations to initialize the MMC/SD block
|
|
* device.
|
|
*/
|
|
|
|
ret = sam_hsmci_carddetect(state);
|
|
|
|
#ifdef CONFIG_FS_AUTOMOUNTER
|
|
/* Let the automounter know about the insertion event */
|
|
|
|
sam_automount_event(state->slotno, sam_cardinserted(state->slotno));
|
|
#endif /* CONFIG_FS_AUTOMOUNTER */
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: sam_hsmci_state
|
|
*
|
|
* Description:
|
|
* Initialize HSMCI PIOs.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline struct sam_hsmci_state_s *sam_hsmci_state(int slotno)
|
|
{
|
|
struct sam_hsmci_state_s *state = NULL;
|
|
|
|
#ifdef CONFIG_SAMV7_HSMCI0
|
|
if (g_hsmci0.slotno == slotno)
|
|
{
|
|
state = &g_hsmci0;
|
|
}
|
|
#endif
|
|
|
|
return state;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: sam_hsmci_initialize
|
|
*
|
|
* Description:
|
|
* Perform architecture specific initialization
|
|
*
|
|
****************************************************************************/
|
|
|
|
int sam_hsmci_initialize(int slotno, int minor, gpio_pinset_t cdcfg,
|
|
int cdirq, bool cdinvert)
|
|
{
|
|
struct sam_hsmci_state_s *state;
|
|
int ret;
|
|
|
|
/* Get the static HSMI description */
|
|
|
|
state = sam_hsmci_state(slotno);
|
|
if (state == NULL)
|
|
{
|
|
ferr("ERROR: No state for slotno %d\n", slotno);
|
|
return -EINVAL;
|
|
}
|
|
|
|
state->cdcfg = 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 */
|
|
|
|
/* First, get an instance of the SDIO interface */
|
|
|
|
state->hsmci = sdio_initialize(slotno);
|
|
if (state->hsmci == NULL)
|
|
{
|
|
ferr("ERROR: Failed to initialize SDIO slot %d\n", slotno);
|
|
return -ENODEV;
|
|
}
|
|
|
|
/* Now bind the SDIO interface to the MMC/SD driver */
|
|
|
|
ret = mmcsd_slotinitialize(minor, state->hsmci);
|
|
if (ret != OK)
|
|
{
|
|
ferr("ERROR: Failed to bind SDIO to the MMC/SD driver: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
#ifndef CONFIG_SAMV7_HSMCI_SW_CARDDETECT
|
|
/* Configure card detect interrupts */
|
|
|
|
sam_gpioirq(state->cdcfg);
|
|
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. */
|
|
|
|
state->cd = sam_cardinserted_internal(state);
|
|
sdio_mediachange(state->hsmci, state->cd);
|
|
|
|
/* Enable card detect interrupts */
|
|
|
|
sam_gpioirqenable(state->cdirq);
|
|
#endif
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: sam_cardinserted
|
|
*
|
|
* Description:
|
|
* Check if a card is inserted into the selected HSMCI slot
|
|
*
|
|
****************************************************************************/
|
|
|
|
bool sam_cardinserted(int slotno)
|
|
{
|
|
struct sam_hsmci_state_s *state;
|
|
|
|
/* Get the HSMI description */
|
|
|
|
state = sam_hsmci_state(slotno);
|
|
if (state == NULL)
|
|
{
|
|
ferr("ERROR: No state for slotno %d\n", slotno);
|
|
return false;
|
|
}
|
|
|
|
/* Return the state of the PIO pin */
|
|
|
|
return sam_cardinserted_internal(state);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: sam_writeprotected
|
|
*
|
|
* Description:
|
|
* Check if a card is inserted into the selected HSMCI slot
|
|
*
|
|
****************************************************************************/
|
|
|
|
bool sam_writeprotected(int slotno)
|
|
{
|
|
/* There are no write protect pins */
|
|
|
|
return false;
|
|
}
|