diff --git a/arch/arm/src/kinetis/kinetis_sdhc.c b/arch/arm/src/kinetis/kinetis_sdhc.c index 81be3038d4..58d912bc0e 100644 --- a/arch/arm/src/kinetis/kinetis_sdhc.c +++ b/arch/arm/src/kinetis/kinetis_sdhc.c @@ -1,35 +1,20 @@ /**************************************************************************** * arch/arm/src/kinetis/kinetis_sdhc.c * - * Copyright (C) 2011-2012, 2014, 2016-2018 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * 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 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * 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. * ****************************************************************************/ @@ -174,6 +159,7 @@ struct kinetis_dev_s struct sdio_dev_s dev; /* Standard, base SDIO interface */ /* Kinetis-specific extensions */ + /* Event support */ sem_t waitsem; /* Implements event waiting */ @@ -267,16 +253,18 @@ static void kinetis_showregs(struct kinetis_dev_s *priv, const char *msg); /* Data Transfer Helpers ****************************************************/ static void kinetis_dataconfig(struct kinetis_dev_s *priv, bool bwrite, - unsigned int blocksize, unsigned int nblocks, - unsigned int timeout); + unsigned int blocksize, unsigned int nblocks, + unsigned int timeout); static void kinetis_datadisable(void); #ifndef CONFIG_KINETIS_SDHC_DMA static void kinetis_transmit(struct kinetis_dev_s *priv); static void kinetis_receive(struct kinetis_dev_s *priv); #endif static void kinetis_eventtimeout(int argc, uint32_t arg); -static void kinetis_endwait(struct kinetis_dev_s *priv, sdio_eventset_t wkupevent); -static void kinetis_endtransfer(struct kinetis_dev_s *priv, sdio_eventset_t wkupevent); +static void kinetis_endwait(struct kinetis_dev_s *priv, + sdio_eventset_t wkupevent); +static void kinetis_endtransfer(struct kinetis_dev_s *priv, + sdio_eventset_t wkupevent); /* Interrupt Handling *******************************************************/ @@ -307,12 +295,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 +362,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, @@ -409,9 +407,6 @@ static struct kinetis_sdhcregs_s g_sampleregs[DEBUG_NSAMPLES]; * Private Functions ****************************************************************************/ -/**************************************************************************** - * Low-level Helpers - ****************************************************************************/ /**************************************************************************** * Name: kinetis_takesem * @@ -496,10 +491,6 @@ static void kinetis_configxfrints(struct kinetis_dev_s *priv, uint32_t xfrints) leave_critical_section(flags); } -/**************************************************************************** - * DMA Helpers - ****************************************************************************/ - /**************************************************************************** * Name: kinetis_sampleinit * @@ -615,9 +606,12 @@ static void kinetis_dumpsample(struct kinetis_dev_s *priv, #ifdef CONFIG_SDIO_XFRDEBUG static void kinetis_dumpsamples(struct kinetis_dev_s *priv) { - kinetis_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP], "Before setup"); - kinetis_dumpsample(priv, &g_sampleregs[SAMPLENDX_AFTER_SETUP], "After setup"); - kinetis_dumpsample(priv, &g_sampleregs[SAMPLENDX_END_TRANSFER], "End of transfer"); + kinetis_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP], + "Before setup"); + kinetis_dumpsample(priv, &g_sampleregs[SAMPLENDX_AFTER_SETUP], + "After setup"); + kinetis_dumpsample(priv, &g_sampleregs[SAMPLENDX_END_TRANSFER], + "End of transfer"); } #endif @@ -639,10 +633,6 @@ static void kinetis_showregs(struct kinetis_dev_s *priv, const char *msg) } #endif -/**************************************************************************** - * Data Transfer Helpers - ****************************************************************************/ - /**************************************************************************** * Name: kinetis_dataconfig * @@ -970,7 +960,8 @@ static void kinetis_eventtimeout(int argc, uint32_t arg) * ****************************************************************************/ -static void kinetis_endwait(struct kinetis_dev_s *priv, sdio_eventset_t wkupevent) +static void kinetis_endwait(struct kinetis_dev_s *priv, + sdio_eventset_t wkupevent) { /* Cancel the watchdog timeout */ @@ -1005,7 +996,8 @@ static void kinetis_endwait(struct kinetis_dev_s *priv, sdio_eventset_t wkupeven * ****************************************************************************/ -static void kinetis_endtransfer(struct kinetis_dev_s *priv, sdio_eventset_t wkupevent) +static void kinetis_endtransfer(struct kinetis_dev_s *priv, + sdio_eventset_t wkupevent) { #ifdef CONFIG_KINETIS_SDHC_DMA uint32_t regval; @@ -1053,10 +1045,6 @@ static void kinetis_endtransfer(struct kinetis_dev_s *priv, sdio_eventset_t wkup } } -/**************************************************************************** - * Interrupt Handling - ****************************************************************************/ - /**************************************************************************** * Name: kinetis_interrupt * @@ -1143,7 +1131,8 @@ static int kinetis_interrupt(int irq, void *context, FAR void *arg) { /* Terminate the transfer with an error */ - mcerr("ERROR: Data block CRC failure, remaining: %d\n", priv->remaining); + mcerr("ERROR: Data block CRC failure, remaining: %d\n", + priv->remaining); kinetis_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); } @@ -1191,16 +1180,12 @@ static int kinetis_interrupt(int irq, void *context, FAR void *arg) return OK; } -/**************************************************************************** - * SDIO Interface Methods - ****************************************************************************/ - /**************************************************************************** * Name: kinetis_lock * * Description: * Locks the bus. Function calls low-level multiplexed bus routines to - * resolve bus requests and acknowledgement issues. + * resolve bus requests and acknowledgment issues. * * Input Parameters: * dev - An instance of the SDIO device interface @@ -1379,6 +1364,7 @@ static void kinetis_widebus(FAR struct sdio_dev_s *dev, bool wide) { regval |= SDHC_PROCTL_DTW_1BIT; } + putreg32(regval, KINETIS_SDHC_PROCTL); } @@ -1690,7 +1676,6 @@ static int kinetis_attach(FAR struct sdio_dev_s *dev) ret = irq_attach(KINETIS_IRQ_SDHC, kinetis_interrupt, NULL); if (ret == OK) { - /* Disable all interrupts at the SDIO controller and clear all pending * interrupts. */ @@ -1870,6 +1855,40 @@ static int kinetis_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, return OK; } +/**************************************************************************** + * 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 * @@ -1943,8 +1962,8 @@ static int kinetis_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, ****************************************************************************/ #ifndef CONFIG_KINETIS_SDHC_DMA -static int kinetis_sendsetup(FAR struct sdio_dev_s *dev, FAR const uint8_t *buffer, - size_t nbytes) +static int kinetis_sendsetup(FAR struct sdio_dev_s *dev, + FAR const uint8_t *buffer, size_t nbytes) { struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev; @@ -2170,7 +2189,6 @@ static int kinetis_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, * 0 1 End bit */ - #ifdef CONFIG_DEBUG_FEATURES if (!rshort) { @@ -2331,7 +2349,8 @@ static int kinetis_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, /* MMC responses not supported */ -static int kinetis_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rnotimpl) +static int kinetis_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd, + uint32_t *rnotimpl) { /* Just return an error */ @@ -2684,9 +2703,6 @@ static int kinetis_dmasendsetup(FAR struct sdio_dev_s *dev, } #endif -/**************************************************************************** - * Initialization/uninitialization/reset - ****************************************************************************/ /**************************************************************************** * Name: kinetis_callback * @@ -2752,8 +2768,10 @@ static void kinetis_callback(void *arg) { /* Yes.. queue it */ - mcinfo("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg); - work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0); + mcinfo("Queuing callback to %p(%p)\n", + priv->callback, priv->cbarg); + work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, + priv->cbarg, 0); } else { @@ -2793,6 +2811,7 @@ FAR struct sdio_dev_s *sdhc_initialize(int slotno) DEBUGASSERT(slotno == 0); /* Initialize the SDHC slot structure data structure */ + /* Initialize semaphores */ nxsem_init(&priv->waitsem, 0, 0); @@ -2833,7 +2852,6 @@ FAR struct sdio_dev_s *sdhc_initialize(int slotno) putreg32(regval, KINETIS_SIM_SCGC3); mcinfo("SIM_SCGC3: %08x\n", regval); - /* Configure pins for 1 or 4-bit, wide-bus operation (the chip is capable * of 8-bit wide bus operation but D4-D7 are not configured). * diff --git a/boards/arm/kinetis/freedom-k28f/Kconfig b/boards/arm/kinetis/freedom-k28f/Kconfig index 8a8ba84561..928307b697 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 a17c39dd61..8dcee67bc3 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 c2c6c0f8ff..8b7b793b67 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 0554a43310..e1ef15ca07 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 @@ -90,14 +177,14 @@ struct i2c_master_s; /* Forward reference */ #ifdef CONFIG_KINETIS_I2C0 -extern FAR struct i2c_master_s* g_i2c0_dev; +extern FAR struct i2c_master_s *g_i2c0_dev; #endif #ifdef CONFIG_KINETIS_I2C1 -extern FAR struct i2c_master_s* g_i2c1_dev; +extern FAR struct i2c_master_s *g_i2c1_dev; #endif /**************************************************************************** - * Public Functions + * Public Function Prototypes ****************************************************************************/ /**************************************************************************** @@ -133,7 +220,7 @@ void weak_function k28_spidev_initialize(void); * Description: * Called to configure I2C * - *****************************************************************************/ + ****************************************************************************/ void k28_i2cdev_initialize(void); @@ -147,6 +234,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 * 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 0000000000..cf996a516d --- /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 + +#if defined(CONFIG_FS_AUTOMOUNTER_DEBUG) && !defined(CONFIG_DEBUG_FS) +# define CONFIG_DEBUG_FS 1 +#endif + +#include + +#include +#include +#include + +#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 108e6b0870..4bb36712a4 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 #include +#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 0000000000..356c91237e --- /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 + +#include +#include +#include +#include +#include + +#include +#include + +#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 */