nes-proj/platform/zoul/dev/mmc-arch.c
Benoît Thébaudeau 062a8535ec zoul: remote: Add support for SD/MMC
This change adds SD/MMC support at block level, by porting the SD/MMC
driver.

Signed-off-by: Benoît Thébaudeau <benoit@wsystem.com>
2016-11-27 22:50:43 +01:00

140 lines
4.4 KiB
C

/*
* Copyright (c) 2016, Benoît Thébaudeau <benoit@wsystem.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 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 of the copyright holder 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 HOLDER 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.
*/
/**
* \addtogroup mmc-arch
* @{
*
* \file
* Implementation of the SD/MMC device driver RE-Mote-specific definitions.
*/
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include "spi-arch.h"
#include "dev/ioc.h"
#include "dev/gpio.h"
#include "dev/spi.h"
#include "mmc-arch.h"
#define USD_SEL_PORT_BASE GPIO_PORT_TO_BASE(USD_SEL_PORT)
#define USD_SEL_PIN_MASK GPIO_PIN_MASK(USD_SEL_PIN)
/*----------------------------------------------------------------------------*/
static void
mmc_arch_init(void)
{
static uint8_t init_done;
if(init_done) {
return;
}
GPIO_SET_INPUT(USD_SEL_PORT_BASE, USD_SEL_PIN_MASK);
GPIO_SOFTWARE_CONTROL(USD_SEL_PORT_BASE, USD_SEL_PIN_MASK);
ioc_set_over(USD_SEL_PORT, USD_SEL_PIN, IOC_OVERRIDE_DIS);
spix_cs_init(USD_CSN_PORT, USD_CSN_PIN);
spix_init(USD_SPI_INSTANCE);
spix_set_mode(USD_SPI_INSTANCE, SSI_CR0_FRF_MOTOROLA, 0, 0, 8);
init_done = 1;
}
/*----------------------------------------------------------------------------*/
bool
mmc_arch_get_cd(uint8_t dev)
{
mmc_arch_init();
if(GPIO_IS_OUTPUT(USD_SEL_PORT_BASE, USD_SEL_PIN_MASK)) {
/* Card previously detected and powered */
return true;
} else if(GPIO_READ_PIN(USD_SEL_PORT_BASE, USD_SEL_PIN_MASK)) {
/* Card inserted -> power it */
GPIO_SET_OUTPUT(USD_SEL_PORT_BASE, USD_SEL_PIN_MASK);
GPIO_CLR_PIN(USD_SEL_PORT_BASE, USD_SEL_PIN_MASK);
return true;
} else {
/* No card detected */
return false;
}
}
/*----------------------------------------------------------------------------*/
bool
mmc_arch_get_wp(uint8_t dev)
{
return false;
}
/*----------------------------------------------------------------------------*/
void
mmc_arch_spi_select(uint8_t dev, bool sel)
{
if(sel) {
SPIX_CS_CLR(USD_CSN_PORT, USD_CSN_PIN);
} else {
SPIX_CS_SET(USD_CSN_PORT, USD_CSN_PIN);
}
}
/*----------------------------------------------------------------------------*/
void
mmc_arch_spi_set_clock_freq(uint8_t dev, uint32_t freq)
{
spix_set_clock_freq(USD_SPI_INSTANCE, freq);
}
/*----------------------------------------------------------------------------*/
void
mmc_arch_spi_xfer(uint8_t dev, const void *tx_buf, size_t tx_cnt,
void *rx_buf, size_t rx_cnt)
{
const uint8_t *tx_buf_u8 = tx_buf;
uint8_t *rx_buf_u8 = rx_buf;
while(tx_cnt || rx_cnt) {
SPIX_WAITFORTxREADY(USD_SPI_INSTANCE);
if(tx_cnt) {
SPIX_BUF(USD_SPI_INSTANCE) = *tx_buf_u8++;
tx_cnt--;
} else {
SPIX_BUF(USD_SPI_INSTANCE) = 0;
}
SPIX_WAITFOREOTx(USD_SPI_INSTANCE);
SPIX_WAITFOREORx(USD_SPI_INSTANCE);
if(rx_cnt) {
*rx_buf_u8++ = SPIX_BUF(USD_SPI_INSTANCE);
rx_cnt--;
} else {
SPIX_BUF(USD_SPI_INSTANCE);
}
}
}
/*----------------------------------------------------------------------------*/
/** @} */