You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/03/03 14:53:06 UTC

[incubator-nuttx] branch pr423 updated: NXP Freedom K28F Board SD-Card support (#423)

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch pr423
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/pr423 by this push:
     new e9b3fcd  NXP Freedom K28F Board SD-Card support (#423)
e9b3fcd is described below

commit e9b3fcdde2a77f884293bba98ba2097c58d37952
Author: johannes-nivus <jo...@nivus.com>
AuthorDate: Tue Mar 3 15:52:55 2020 +0100

    NXP Freedom K28F Board SD-Card support (#423)
    
    * Adds SDHC support for NXP Freedom-K28F
---
 arch/arm/src/kinetis/kinetis_sdhc.c                |  44 +++
 boards/arm/kinetis/freedom-k28f/Kconfig            |  30 +-
 boards/arm/kinetis/freedom-k28f/include/board.h    |  11 +
 boards/arm/kinetis/freedom-k28f/src/Makefile       |   7 +
 boards/arm/kinetis/freedom-k28f/src/freedom-k28f.h | 171 ++++++++++++
 .../arm/kinetis/freedom-k28f/src/k28_automount.c   | 310 +++++++++++++++++++++
 boards/arm/kinetis/freedom-k28f/src/k28_bringup.c  |  37 +++
 boards/arm/kinetis/freedom-k28f/src/k28_sdhc.c     | 240 ++++++++++++++++
 8 files changed, 849 insertions(+), 1 deletion(-)

diff --git a/arch/arm/src/kinetis/kinetis_sdhc.c b/arch/arm/src/kinetis/kinetis_sdhc.c
index 81be303..f6c6f7c 100644
--- a/arch/arm/src/kinetis/kinetis_sdhc.c
+++ b/arch/arm/src/kinetis/kinetis_sdhc.c
@@ -307,12 +307,19 @@ static int  kinetis_attach(FAR struct sdio_dev_s *dev);
 
 static int  kinetis_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
               uint32_t arg);
+
+#ifdef CONFIG_SDIO_BLOCKSETUP
+static void  kinetis_blocksetup(FAR struct sdio_dev_s *dev,
+              unsigned int blocksize, unsigned int nblocks);
+#endif
+
 #ifndef CONFIG_KINETIS_SDHC_DMA
 static int  kinetis_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
               size_t nbytes);
 static int  kinetis_sendsetup(FAR struct sdio_dev_s *dev,
               FAR const uint8_t *buffer, uint32_t nbytes);
 #endif
+
 static int  kinetis_cancel(FAR struct sdio_dev_s *dev);
 
 static int  kinetis_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd);
@@ -367,6 +374,9 @@ struct kinetis_dev_s g_sdhcdev =
     .clock            = kinetis_clock,
     .attach           = kinetis_attach,
     .sendcmd          = kinetis_sendcmd,
+#ifdef CONFIG_SDIO_BLOCKSETUP
+    .blocksetup       = kinetis_blocksetup,
+#endif
 #ifndef CONFIG_KINETIS_SDHC_DMA
     .recvsetup        = kinetis_recvsetup,
     .sendsetup        = kinetis_sendsetup,
@@ -1871,6 +1881,40 @@ static int kinetis_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
 }
 
 /****************************************************************************
+ * Name: kinetis_blocksetup
+ *
+ * Description:
+ *   Configure block size and the number of blocks for next transfer
+ *
+ * Input Parameters:
+ *   dev       - An instance of the SDIO device interface
+ *   blocksize  - The selected block size.
+ *   nblocklen - The number of blocks to transfer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SDIO_BLOCKSETUP
+static void kinetis_blocksetup(FAR struct sdio_dev_s *dev,
+                             unsigned int blocksize,
+                             unsigned int nblocks)
+{
+  uint32_t regval;
+
+  mcinfo("blocksize=%ld, total transfer=%ld (%ld blocks)\n", blocksize,
+		  blocksize * nblocks, nblocks);
+
+  /* Configure block size for next transfer */
+
+  regval = blocksize << SDHC_BLKATTR_SIZE_SHIFT |
+           nblocks   << SDHC_BLKATTR_CNT_SHIFT;
+  putreg32(regval, KINETIS_SDHC_BLKATTR);
+}
+#endif
+
+/****************************************************************************
  * Name: kinetis_recvsetup
  *
  * Description:
diff --git a/boards/arm/kinetis/freedom-k28f/Kconfig b/boards/arm/kinetis/freedom-k28f/Kconfig
index 8a8ba84..928307b 100644
--- a/boards/arm/kinetis/freedom-k28f/Kconfig
+++ b/boards/arm/kinetis/freedom-k28f/Kconfig
@@ -5,4 +5,32 @@
 
 if ARCH_BOARD_FREEDOM_K28F
 
-endif
+config FRDMK28F_SDHC_AUTOMOUNT
+	bool "SDHC automounter"
+	default n
+	depends on FS_AUTOMOUNTER && KINETIS_SDHC
+
+if FRDMK28F_SDHC_AUTOMOUNT
+
+config FRDMK28F_SDHC_AUTOMOUNT_FSTYPE
+	string "SDHC file system type"
+	default "vfat"
+
+config FRDMK28F_SDHC_AUTOMOUNT_BLKDEV
+	string "SDHC block device"
+	default "/dev/mmcsd0"
+
+config FRDMK28F_SDHC_AUTOMOUNT_MOUNTPOINT
+	string "SDHC mount point"
+	default "/mnt/sdcard"
+
+config FRDMK28F_SDHC_AUTOMOUNT_DDELAY
+	int "SDHC debounce delay (milliseconds)"
+	default 1000
+
+config FRDMK28F_SDHC_AUTOMOUNT_UDELAY
+	int "SDHC unmount retry delay (milliseconds)"
+	default 2000
+
+endif # FRDMK28F_SDHC_AUTOMOUNT
+endif # ARCH_BOARD_FREEDOM_K28F
diff --git a/boards/arm/kinetis/freedom-k28f/include/board.h b/boards/arm/kinetis/freedom-k28f/include/board.h
index a17c39d..8dcee67 100644
--- a/boards/arm/kinetis/freedom-k28f/include/board.h
+++ b/boards/arm/kinetis/freedom-k28f/include/board.h
@@ -415,6 +415,17 @@
 #endif
 #endif
 
+/* SDHC */
+
+#ifdef CONFIG_KINETIS_SDHC
+#  define PIN_SDHC0_CMD     PIN_SDHC0_CMD_1
+#  define PIN_SDHC0_D0      PIN_SDHC0_D0_1
+#  define PIN_SDHC0_D1      PIN_SDHC0_D1_1
+#  define PIN_SDHC0_D2      PIN_SDHC0_D2_1
+#  define PIN_SDHC0_D3      PIN_SDHC0_D3_1
+#  define PIN_SDHC0_DCLK    PIN_SDHC0_DCLK_1
+#endif
+
 /* LED definitions **********************************************************/
 
 /* The Freedom K28F has a single RGB LED driven by the K28F as follows:
diff --git a/boards/arm/kinetis/freedom-k28f/src/Makefile b/boards/arm/kinetis/freedom-k28f/src/Makefile
index c2c6c0f..8b7b793 100644
--- a/boards/arm/kinetis/freedom-k28f/src/Makefile
+++ b/boards/arm/kinetis/freedom-k28f/src/Makefile
@@ -52,6 +52,13 @@ CSRCS += k28_userleds.c
 endif
 endif
 
+ifeq ($(CONFIG_KINETIS_SDHC),y)
+CSRCS += k28_sdhc.c
+ifeq ($(CONFIG_FS_AUTOMOUNTER),y)
+CSRCS += k28_automount.c
+endif
+endif
+
 ifeq ($(CONFIG_PWM),y)
 CSRCS += k28_pwm.c
 endif
diff --git a/boards/arm/kinetis/freedom-k28f/src/freedom-k28f.h b/boards/arm/kinetis/freedom-k28f/src/freedom-k28f.h
index 0554a43..d1a5856 100644
--- a/boards/arm/kinetis/freedom-k28f/src/freedom-k28f.h
+++ b/boards/arm/kinetis/freedom-k28f/src/freedom-k28f.h
@@ -47,8 +47,95 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+/* Application Configuration ************************************************/
+
+/* Assume we have everything */
+
+#define HAVE_MMCSD       1
+#define HAVE_AUTOMOUNTER 1
+
+
+/* SD card support */
+
+#define MMCSD_SLOTNO 0
+
+/* Can't support MMC/SD features if mountpoints are disabled or if SDHC
+ * support is not enabled.
+ */
+
+#if defined(CONFIG_DISABLE_MOUNTPOINT) || !defined(CONFIG_KINETIS_SDHC)
+#  undef HAVE_MMCSD
+#endif
+
+#ifdef HAVE_MMCSD
+#  if defined(CONFIG_NSH_MMCSDSLOTNO) && CONFIG_NSH_MMCSDSLOTNO != 0
+#    error Only one MMC/SD slot, slot 0
+#  endif
+
+#  ifdef CONFIG_NSH_MMCSDMINOR
+#    define MMSCD_MINOR CONFIG_NSH_MMCSDMINOR
+#  else
+#    define MMSCD_MINOR 0
+#  endif
+
+/* We expect to receive GPIO interrupts for card insertion events */
+
+#  ifndef CONFIG_KINETIS_GPIOIRQ
+#    error "CONFIG_KINETIS_GPIOIRQ required for card detect interrupt"
+#  endif
+
+#  ifndef CONFIG_KINETIS_PORTBINTS
+#    error "CONFIG_KINETIS_PORTBINTS required for card detect interrupt"
+#  endif
+
+#endif
+
+/* Automounter */
+
+#if !defined(CONFIG_FS_AUTOMOUNTER) || !defined(HAVE_MMCSD)
+#  undef HAVE_AUTOMOUNTER
+#  undef CONFIG_FRDMK28F_SDHC_AUTOMOUNT
+#endif
+
+#ifndef CONFIG_FRDMK28F_SDHC_AUTOMOUNT
+#  undef HAVE_AUTOMOUNTER
+#endif
+
+/* Automounter defaults */
+
+#ifdef HAVE_AUTOMOUNTER
+
+#  ifndef CONFIG_FRDMK28F_SDHC_AUTOMOUNT_FSTYPE
+#    define CONFIG_FRDMK28F_SDHC_AUTOMOUNT_FSTYPE "vfat"
+#  endif
+
+#  ifndef CONFIG_FRDMK28F_SDHC_AUTOMOUNT_BLKDEV
+#    define CONFIG_FRDMK28F_SDHC_AUTOMOUNT_BLKDEV "/dev/mmcds0"
+#  endif
+
+#  ifndef CONFIG_FRDMK28F_SDHC_AUTOMOUNT_MOUNTPOINT
+#    define CONFIG_FRDMK28F_SDHC_AUTOMOUNT_MOUNTPOINT "/mnt/sdcard"
+#  endif
+
+#  ifndef CONFIG_FRDMK28F_SDHC_AUTOMOUNT_DDELAY
+#    define CONFIG_FRDMK28F_SDHC_AUTOMOUNT_DDELAY 1000
+#  endif
+
+#  ifndef CONFIG_FRDMK28F_SDHC_AUTOMOUNT_UDELAY
+#    define CONFIG_FRDMK28F_SDHC_AUTOMOUNT_UDELAY 2000
+#  endif
+#endif /* HAVE_AUTOMOUNTER */
+
 /* Freedom-K28F GPIOs *******************************************************/
 
+/* A micro Secure Digital (SD) card slot is available on the FRDM-K28F
+ * connected to the SD Host Controller (SDHC) signals of the MCU.
+ * This slot will accept micro format SD memory cards.
+ * The SD card detect pin (PTB5) is an open switch that shorts with VDD when
+ * card is inserted.
+ */
+#define GPIO_SD_CARDDETECT (GPIO_INPUT | PIN_INT_BOTH | PIN_PORTB | PIN5)
+
 /* An RGB LED is connected through GPIO as shown below:
  *
  *   LED    K28
@@ -148,6 +235,90 @@ void k28_i2cdev_initialize(void);
 extern void weak_function k28_usbdev_initialize(void);
 
 /****************************************************************************
+ * Name: k28_sdhc_initialize
+ *
+ * Description:
+ *   Inititialize the SDHC SD card slot
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_MMCSD
+int k28_sdhc_initialize(void);
+#else
+#  define k28_sdhc_initialize() (OK)
+#endif
+
+/****************************************************************************
+ * Name: k28_cardinserted
+ *
+ * Description:
+ *   Check if a card is inserted into the SDHC slot
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_AUTOMOUNTER
+bool k28_cardinserted(void);
+#else
+#  define k28_cardinserted() (false)
+#endif
+
+/****************************************************************************
+ * Name: k28_writeprotected
+ *
+ * Description:
+ *   Check if the card in the MMC/SD slot is write protected
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_AUTOMOUNTER
+bool k28_writeprotected(void);
+#else
+#  define k28_writeprotected() (false)
+#endif
+
+/****************************************************************************
+ * Name:  k28_automount_initialize
+ *
+ * Description:
+ *   Configure auto-mounter for the configured SDHC slot
+ *
+ * Input Parameters:
+ *   None
+ *
+ *  Returned Value:
+ *    None
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_AUTOMOUNTER
+void k28_automount_initialize(void);
+#endif
+
+/****************************************************************************
+ * Name:  k28_automount_event
+ *
+ * Description:
+ *   The SDHC card detection logic has detected an insertion or removal event.
+ *   It has already scheduled the MMC/SD block driver operations.
+ *   Now we need to schedule the auto-mount event which will occur with a
+ *   substantial delay to make sure that everything has settle down.
+ *
+ * Input Parameters:
+ *   inserted - True if the card is inserted in the slot.  False otherwise.
+ *
+ *  Returned Value:
+ *    None
+ *
+ *  Assumptions:
+ *    Interrupts are disabled.
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_AUTOMOUNTER
+void k28_automount_event(bool inserted);
+#endif
+
+/****************************************************************************
  * Name: k28_pwm_setup
  *
  * Description:
diff --git a/boards/arm/kinetis/freedom-k28f/src/k28_automount.c b/boards/arm/kinetis/freedom-k28f/src/k28_automount.c
new file mode 100644
index 0000000..cf996a5
--- /dev/null
+++ b/boards/arm/kinetis/freedom-k28f/src/k28_automount.c
@@ -0,0 +1,310 @@
+/****************************************************************************
+ * boards/arm/kinetis/freedom-k28f/src/k28_automount.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>
+
+#if defined(CONFIG_FS_AUTOMOUNTER_DEBUG) && !defined(CONFIG_DEBUG_FS)
+#  define CONFIG_DEBUG_FS 1
+#endif
+
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/fs/automount.h>
+
+#include "freedom-k28f.h"
+
+#ifdef HAVE_AUTOMOUNTER
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef NULL
+#  define NULL (FAR void *)0
+#endif
+
+#ifndef OK
+#  define OK 0
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure represents the changeable state of the automounter */
+
+struct k28_automount_state_s
+{
+  volatile automount_handler_t handler;    /* Upper half handler */
+  FAR void *arg;                           /* Handler argument */
+  bool enable;                             /* Fake interrupt enable */
+  bool pending;                            /* Set if there an event while disabled */
+};
+
+/* This structure represents the static configuration of an automounter */
+
+struct k28_automount_config_s
+{
+  /* This must be first thing in structure so that we can simply cast from
+   * struct automount_lower_s to struct k28_automount_config_s
+   */
+
+  struct automount_lower_s lower;          /* Publicly visible part */
+  FAR struct k28_automount_state_s *state; /* Changeable state */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int  k28_attach(FAR const struct automount_lower_s *lower,
+                       automount_handler_t isr, FAR void *arg);
+static void k28_enable(FAR const struct automount_lower_s *lower,
+                       bool enable);
+static bool k28_inserted(FAR const struct automount_lower_s *lower);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct k28_automount_state_s g_sdhc_state;
+static const struct k28_automount_config_s g_sdhc_config =
+{
+  .lower        =
+  {
+    .fstype     = CONFIG_FRDMK28F_SDHC_AUTOMOUNT_FSTYPE,
+    .blockdev   = CONFIG_FRDMK28F_SDHC_AUTOMOUNT_BLKDEV,
+    .mountpoint = CONFIG_FRDMK28F_SDHC_AUTOMOUNT_MOUNTPOINT,
+    .ddelay     = MSEC2TICK(CONFIG_FRDMK28F_SDHC_AUTOMOUNT_DDELAY),
+    .udelay     = MSEC2TICK(CONFIG_FRDMK28F_SDHC_AUTOMOUNT_UDELAY),
+    .attach     = k28_attach,
+    .enable     = k28_enable,
+    .inserted   = k28_inserted
+  },
+  .state        = &g_sdhc_state
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name:  k28_attach
+ *
+ * Description:
+ *   Attach a new SDHC event handler
+ *
+ * Input Parameters:
+ *   lower - An instance of the auto-mounter lower half state structure
+ *   isr   - The new event handler to be attach
+ *   arg   - Client data to be provided when the event handler is invoked.
+ *
+ *  Returned Value:
+ *    Always returns OK
+ *
+ ****************************************************************************/
+
+static int k28_attach(FAR const struct automount_lower_s *lower,
+                      automount_handler_t isr, FAR void *arg)
+{
+  FAR const struct k28_automount_config_s *config;
+  FAR struct k28_automount_state_s *state;
+
+  /* Recover references to our structure */
+
+  config = (FAR struct k28_automount_config_s *)lower;
+  DEBUGASSERT(config != NULL && config->state != NULL);
+
+  state = config->state;
+
+  /* Save the new handler info (clearing the handler first to eliminate race
+   * conditions).
+   */
+
+  state->handler = NULL;
+  state->pending = false;
+  state->arg     = arg;
+  state->handler = isr;
+  return OK;
+}
+
+/****************************************************************************
+ * Name:  k28_enable
+ *
+ * Description:
+ *   Enable card insertion/removal event detection
+ *
+ * Input Parameters:
+ *   lower - An instance of the auto-mounter lower half state structure
+ *   enable - True: enable event detection; False: disable
+ *
+ *  Returned Value:
+ *    None
+ *
+ ****************************************************************************/
+
+static void k28_enable(FAR const struct automount_lower_s *lower,
+                       bool enable)
+{
+  FAR const struct k28_automount_config_s *config;
+  FAR struct k28_automount_state_s *state;
+  irqstate_t flags;
+
+  /* Recover references to our structure */
+
+  config = (FAR struct k28_automount_config_s *)lower;
+  DEBUGASSERT(config != NULL && config->state != NULL);
+
+  state = config->state;
+
+  /* Save the fake enable setting */
+
+  flags = enter_critical_section();
+  state->enable = enable;
+
+  /* Did an interrupt occur while interrupts were disabled? */
+
+  if (enable && state->pending)
+    {
+      /* Yes.. perform the fake interrupt if the interrutp is attached */
+
+      if (state->handler)
+        {
+          bool inserted = k28_cardinserted();
+          state->handler(&config->lower, state->arg, inserted);
+        }
+
+      state->pending = false;
+    }
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: k28_inserted
+ *
+ * Description:
+ *   Check if a card is inserted into the slot.
+ *
+ * Input Parameters:
+ *   lower - An instance of the auto-mounter lower half state structure
+ *
+ *  Returned Value:
+ *    True if the card is inserted; False otherwise
+ *
+ ****************************************************************************/
+
+static bool k28_inserted(FAR const struct automount_lower_s *lower)
+{
+  return k28_cardinserted();
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name:  k28_automount_initialize
+ *
+ * Description:
+ *   Configure auto-mounters for each enable and so configured SDHC
+ *
+ * Input Parameters:
+ *   None
+ *
+ *  Returned Value:
+ *    None
+ *
+ ****************************************************************************/
+
+void k28_automount_initialize(void)
+{
+  FAR void *handle;
+
+  finfo("Initializing automounter(s)\n");
+
+  /* Initialize the SDHC0 auto-mounter */
+
+  handle = automount_initialize(&g_sdhc_config.lower);
+  if (!handle)
+    {
+      ferr("ERROR: Failed to initialize auto-mounter for SDHC0\n");
+    }
+}
+
+/****************************************************************************
+ * Name:  k28_automount_event
+ *
+ * Description:
+ *   The SDHC card detection logic has detected an insertion or removal event.
+ *   It has already scheduled the MMC/SD block driver operations.
+ *   Now we need to schedule the auto-mount event which will occur with a
+ *   substantial delay to make sure that everything has settle down.
+ *
+ * Input Parameters:
+ *   slotno - Identifies the SDHC0 slot: SDHC0_SLOTNO or SDHC1_SLOTNO.
+ *      There is a terminology problem here:  Each SDHC supports two slots,
+ *      slot A and slot B. Only slot A is used.
+ *      So this is not a really a slot, but an HSCMI peripheral number.
+ *   inserted - True if the card is inserted in the slot.  False otherwise.
+ *
+ *  Returned Value:
+ *    None
+ *
+ *  Assumptions:
+ *    Interrupts are disabled.
+ *
+ ****************************************************************************/
+
+void k28_automount_event(bool inserted)
+{
+  FAR const struct k28_automount_config_s *config = &g_sdhc_config;
+  FAR struct k28_automount_state_s *state = &g_sdhc_state;
+
+  /* Is the auto-mounter interrupt attached? */
+
+  if (state->handler)
+    {
+      /* Yes.. Have we been asked to hold off interrupts? */
+
+      if (!state->enable)
+        {
+          /* Yes.. just remember that there is a pending interrupt. We will
+           * deliver the interrupt when interrupts are "re-enabled."
+           */
+
+          state->pending = true;
+        }
+      else
+        {
+          /* No.. forward the event to the handler */
+
+          state->handler(&config->lower, state->arg, inserted);
+        }
+    }
+}
+
+#endif /* HAVE_AUTOMOUNTER */
diff --git a/boards/arm/kinetis/freedom-k28f/src/k28_bringup.c b/boards/arm/kinetis/freedom-k28f/src/k28_bringup.c
index 108e6b0..d7d9f65 100644
--- a/boards/arm/kinetis/freedom-k28f/src/k28_bringup.c
+++ b/boards/arm/kinetis/freedom-k28f/src/k28_bringup.c
@@ -45,6 +45,8 @@
 #include <debug.h>
 #include <errno.h>
 
+#include "freedom-k28f.h"
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -93,6 +95,41 @@ int k28_bringup(void)
   k28_i2cdev_initialize();
 #endif
 
+#ifdef HAVE_MMCSD
+  /* Initialize the SDHC driver */
+
+  ret = k28_sdhc_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: k28_sdhc_initialize() failed: %d\n", ret);
+    }
+
+#ifdef CONFIG_FRDMK28F_SDHC_MOUNT
+  else
+    {
+      /* Mount the volume on HSMCI0 */
+
+      ret = mount(CONFIG_FRDMK28F_SDHC_MOUNT_BLKDEV,
+                  CONFIG_FRDMK28F_SDHC_MOUNT_MOUNTPOINT,
+                  CONFIG_FRDMK28F_SDHC_MOUNT_FSTYPE,
+                  0, NULL);
+
+      if (ret < 0)
+        {
+          syslog(LOG_ERR,"ERROR: Failed to mount %s: %d\n",
+                 CONFIG_FRDMK28F_SDHC_MOUNT_MOUNTPOINT, errno);
+        }
+    }
+
+#endif /* CONFIG_FRDMK28F_SDHC_MOUNT */
+#endif /* HAVE_MMCSD */
+
+#ifdef HAVE_AUTOMOUNTER
+  /* Initialize the auto-mounter */
+
+  k28_automount_initialize();
+#endif
+
   UNUSED(ret);
   return OK;
 }
diff --git a/boards/arm/kinetis/freedom-k28f/src/k28_sdhc.c b/boards/arm/kinetis/freedom-k28f/src/k28_sdhc.c
new file mode 100644
index 0000000..356c912
--- /dev/null
+++ b/boards/arm/kinetis/freedom-k28f/src/k28_sdhc.c
@@ -0,0 +1,240 @@
+/****************************************************************************
+ * boards/arm/kinetis/freedom-k28f/src/k28_sdhc.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.
+ *
+ ****************************************************************************/
+
+/* A micro Secure Digital (SD) card slot is available on the FRDM-K64F
+ * connected to the SD Host Controller (SDHC) signals of the MCU.
+ * This slot will accept micro format SD memory cards.
+ * The SD card detect pin (PTB5) is an open switch that shorts with VDD when
+ * card is inserted.
+ *
+ *   ------------ ------------- --------
+ *    SD Card Slot Board Signal  K64F Pin
+ *    ------------ ------------- --------
+ *    DAT0         SDHC0_D0      PTA25
+ *    DAT1         SDHC0_D1      PTA24
+ *    DAT2         SDHC0_D2      PTA29
+ *    CD/DAT3      SDHC0_D3      PTA28
+ *    CMD          SDHC0_CMD     PTA27
+ *    CLK          SDHC0_DCLK    PTA26
+ *    SWITCH       D_CARD_DETECT PTB5
+ *    ------------ ------------- --------
+ *
+ * There is no Write Protect pin available to the K28F.
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <debug.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/sdio.h>
+#include <nuttx/mmcsd.h>
+
+#include "kinetis.h"
+
+#include "freedom-k28f.h"
+
+#ifdef HAVE_MMCSD
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure holds static information unique to one SDHC peripheral */
+
+struct k28_sdhc_state_s
+{
+  struct sdio_dev_s *sdhc;    /* R/W device handle */
+  bool inserted;              /* TRUE: card is inserted */
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* HSCMI device state */
+
+static struct k28_sdhc_state_s g_sdhc;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: k28_mediachange
+ ****************************************************************************/
+
+static void k28_mediachange(void)
+{
+  bool inserted;
+
+  /* Get the current value of the card detect pin.  This pin is pulled up on
+   * board.  So low means that a card is present.
+   */
+
+  inserted = kinetis_gpioread(GPIO_SD_CARDDETECT);
+  mcinfo("inserted: %s\n", inserted ? "Yes" : "No");
+
+  /* Has the pin changed state? */
+
+  if (inserted != g_sdhc.inserted)
+    {
+      mcinfo("Media change: %d->%d\n",  g_sdhc.inserted, inserted);
+
+      /* Yes.. perform the appropriate action (this might need some debounce). */
+
+      g_sdhc.inserted = inserted;
+      sdhc_mediachange(g_sdhc.sdhc, inserted);
+
+#ifdef CONFIG_FRDMK28F_SDHC_AUTOMOUNT
+      /* Let the automounter know about the insertion event */
+
+      k28_automount_event(k28_cardinserted());
+#endif
+    }
+}
+
+/****************************************************************************
+ * Name: k28_cdinterrupt
+ ****************************************************************************/
+
+static int k28_cdinterrupt(int irq, FAR void *context, FAR void *arg)
+{
+  /* All of the work is done by k28_mediachange() */
+
+  k28_mediachange();
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: k28_sdhc_initialize
+ *
+ * Description:
+ *   Inititialize the SDHC SD card slot
+ *
+ ****************************************************************************/
+
+int k28_sdhc_initialize(void)
+{
+  int ret;
+
+  /* Configure GPIO pins */
+
+  kinetis_pinconfig(GPIO_SD_CARDDETECT);
+
+  /* Attached the card detect interrupt (but don't enable it yet) */
+
+  kinetis_pinirqattach(GPIO_SD_CARDDETECT, k28_cdinterrupt, NULL);
+
+  /* Configure the write protect GPIO -- None */
+
+  /* Mount the SDHC-based MMC/SD block driver */
+
+  /* First, get an instance of the SDHC interface */
+
+  mcinfo("Initializing SDHC slot %d\n", MMCSD_SLOTNO);
+
+  g_sdhc.sdhc = sdhc_initialize(MMCSD_SLOTNO);
+  if (!g_sdhc.sdhc)
+    {
+      mcerr("ERROR: Failed to initialize SDHC slot %d\n", MMCSD_SLOTNO);
+      return -ENODEV;
+    }
+
+  /* Now bind the SDHC interface to the MMC/SD driver */
+
+  mcinfo("Bind SDHC to the MMC/SD driver, minor=%d\n", MMSCD_MINOR);
+
+  ret = mmcsd_slotinitialize(MMSCD_MINOR, g_sdhc.sdhc);
+  if (ret != OK)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to bind SDHC to the MMC/SD driver: %d\n",
+             ret);
+      return ret;
+    }
+
+  syslog(LOG_INFO, "Successfully bound SDHC to the MMC/SD driver\n");
+
+  /* Handle the initial card state */
+
+  k28_mediachange();
+
+  /* Enable CD interrupts to handle subsequent media changes */
+
+  kinetis_pinirqenable(GPIO_SD_CARDDETECT);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: k28_cardinserted
+ *
+ * Description:
+ *   Check if a card is inserted into the SDHC slot
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_AUTOMOUNTER
+bool k28_cardinserted(void)
+{
+  bool inserted;
+
+  /* Get the current value of the card detect pin.  This pin is pulled up on
+   * board.  So low means that a card is present.
+   */
+
+  inserted = kinetis_gpioread(GPIO_SD_CARDDETECT);
+  mcinfo("inserted: %s\n", inserted ? "Yes" : "No");
+  return inserted;
+}
+#endif
+
+/****************************************************************************
+ * Name: k28_writeprotected
+ *
+ * Description:
+ *   Check if a card is inserted into the SDHC slot
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_AUTOMOUNTER
+bool k28_writeprotected(void)
+{
+  /* There are no write protect pins */
+
+  return false;
+}
+#endif
+
+#endif /* HAVE_MMCSD */