disk: sdhc: spi: leave SPI CS GPIO handling to the SPI controller driver

Leave the SPI CS GPIO handling to the SPI controller driver and make SPI
CS GPIO optional for SDHC disk access via SPI.

The SPI SDHC implementation relies on SPI_HOLD_ON_CS so we need to
explicitly release the SPI controller driver after ending transmissions
to force the CS line to be de-asserted.

Fixes #27444.

Signed-off-by: Henrik Brix Andersen <henrik@brixandersen.dk>
This commit is contained in:
Henrik Brix Andersen 2020-08-19 20:51:22 +02:00 committed by Ioannis Glaropoulos
commit c64e0ce923

View file

@ -20,16 +20,17 @@ LOG_MODULE_REGISTER(sdhc_spi, CONFIG_DISK_LOG_LEVEL);
/* Clock speed used after initialisation */
#define SDHC_SPI_SPEED 4000000
#if !DT_NODE_HAS_STATUS(DT_INST(0, zephyr_mmc_spi_slot), okay)
#define SPI_SDHC_NODE DT_INST(0, zephyr_mmc_spi_slot)
#if !DT_NODE_HAS_STATUS(SPI_SDHC_NODE, okay)
#warning NO SDHC slot specified on board
#else
struct sdhc_spi_data {
struct device *spi;
struct spi_config cfg;
struct device *cs;
uint32_t pin;
gpio_dt_flags_t flags;
#if DT_SPI_DEV_HAS_CS_GPIOS(SPI_SDHC_NODE)
struct spi_cs_control cs;
#endif
bool high_capacity;
uint32_t sector_count;
uint8_t status;
@ -69,12 +70,6 @@ static int sdhc_spi_trace(struct sdhc_spi_data *data, int dir, int err,
return err;
}
/* Asserts or deasserts chip select */
static void sdhc_spi_set_cs(struct sdhc_spi_data *data, int value)
{
gpio_pin_set(data->cs, data->pin, value);
}
/* Receives a fixed number of bytes */
static int sdhc_spi_rx_bytes(struct sdhc_spi_data *data, uint8_t *buf, int len)
{
@ -460,12 +455,9 @@ static int sdhc_spi_recover(struct sdhc_spi_data *data)
/* Attempts to return the card to idle mode */
static int sdhc_spi_go_idle(struct sdhc_spi_data *data)
{
sdhc_spi_set_cs(data, 1);
/* Write the initial >= 74 clocks */
sdhc_spi_tx(data, sdhc_ones, 10);
sdhc_spi_set_cs(data, 0);
spi_release(data->spi, &data->cfg);
return sdhc_spi_cmd_r1_idle(data, SDHC_GO_IDLE_STATE, 0);
}
@ -673,8 +665,6 @@ static int sdhc_spi_read(struct sdhc_spi_data *data,
addr = sector * SDMMC_DEFAULT_BLOCK_SIZE;
}
sdhc_spi_set_cs(data, 0);
/* Send the start read command */
err = sdhc_spi_cmd_r1(data, SDHC_READ_MULTIPLE_BLOCK, addr);
if (err != 0) {
@ -698,7 +688,7 @@ static int sdhc_spi_read(struct sdhc_spi_data *data,
err = sdhc_spi_skip_until_ready(data);
error:
sdhc_spi_set_cs(data, 1);
spi_release(data->spi, &data->cfg);
return err;
}
@ -714,8 +704,6 @@ static int sdhc_spi_write(struct sdhc_spi_data *data,
return err;
}
sdhc_spi_set_cs(data, 0);
/* Write the blocks one-by-one */
for (; count != 0U; count--) {
/* Translate sector number to data address.
@ -755,7 +743,7 @@ static int sdhc_spi_write(struct sdhc_spi_data *data,
err = 0;
error:
sdhc_spi_set_cs(data, 1);
spi_release(data->spi, &data->cfg);
return err;
}
@ -766,22 +754,25 @@ static int sdhc_spi_init(struct device *dev)
{
struct sdhc_spi_data *data = dev->data;
data->spi = device_get_binding(DT_BUS_LABEL(DT_INST(0, zephyr_mmc_spi_slot)));
data->spi = device_get_binding(DT_BUS_LABEL(SPI_SDHC_NODE));
data->cfg.frequency = SDHC_SPI_INITIAL_SPEED;
data->cfg.operation = SPI_WORD_SET(8) | SPI_HOLD_ON_CS;
data->cfg.slave = DT_REG_ADDR(DT_INST(0, zephyr_mmc_spi_slot));
data->cs = device_get_binding(
DT_SPI_DEV_CS_GPIOS_LABEL(DT_INST(0, zephyr_mmc_spi_slot)));
__ASSERT_NO_MSG(data->cs != NULL);
data->cfg.slave = DT_REG_ADDR(SPI_SDHC_NODE);
data->pin = DT_SPI_DEV_CS_GPIOS_PIN(DT_INST(0, zephyr_mmc_spi_slot));
data->flags = DT_SPI_DEV_CS_GPIOS_FLAGS(DT_INST(0, zephyr_mmc_spi_slot));
#if DT_SPI_DEV_HAS_CS_GPIOS(SPI_SDHC_NODE)
data->cs.gpio_dev =
device_get_binding(DT_SPI_DEV_CS_GPIOS_LABEL(SPI_SDHC_NODE));
__ASSERT_NO_MSG(data->cs.gpio_dev != NULL);
data->cs.gpio_pin = DT_SPI_DEV_CS_GPIOS_PIN(SPI_SDHC_NODE);
data->cs.gpio_dt_flags = DT_SPI_DEV_CS_GPIOS_FLAGS(SPI_SDHC_NODE);
data->cfg.cs = &data->cs;
#endif
disk_spi_sdhc_init(dev);
return gpio_pin_configure(data->cs, data->pin,
GPIO_OUTPUT_INACTIVE | data->flags);
return 0;
}
static int disk_spi_sdhc_access_status(struct disk_info *disk)
@ -866,7 +857,7 @@ static int disk_spi_sdhc_access_init(struct disk_info *disk)
int err;
err = sdhc_spi_detect(data);
sdhc_spi_set_cs(data, 1);
spi_release(data->spi, &data->cfg);
return err;
}
@ -898,7 +889,7 @@ static int disk_spi_sdhc_init(struct device *dev)
static struct sdhc_spi_data sdhc_spi_data_0;
DEVICE_AND_API_INIT(sdhc_spi_0,
DT_LABEL(DT_INST(0, zephyr_mmc_spi_slot)),
DT_LABEL(SPI_SDHC_NODE),
sdhc_spi_init, &sdhc_spi_data_0, NULL,
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL);
#endif