blob: cab97d9b1ae5a8c491bb339978750728c3ab59af [file] [log] [blame]
/* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright 2020 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <zephyr.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>
#include <logging/log.h>
#include <shell/shell.h>
#include <sys/__assert.h>
#include "io.h"
#include "sd.h"
LOG_MODULE_REGISTER(sd);
enum sd_state mux_state; /**< Currently selected state */
int sd_mux_set(enum sd_state state)
{
/* To enable the FPGA to access the SD card:
* SD_MUX_EN_L := 0
* SD_MUX_SEL := 0
* USD_PWR_EN := 1
* USD_PWR_SEL := 1
* To enable the USB port to access the SD card:
* SD_MUX_EN_L := 0
* SD_MUX_SEL := 1
* USD_PWR_EN := 1
* USD_PWR_SEL := 0
* To disconnect the SD card from either:
* SD_MUX_EN_L := 1
* SD_MUX_SEL := don't care
* USD_PWR_EN := 0
* USD_PWR_SEL := don't care
*/
int ret;
int mux_en = (state == SD_MUX_OFF) ? 1 : 0;
int mux_sel = (state == SD_MUX_USB) ? 1 : 0;
int pwr_en = (state != SD_MUX_OFF) ? 1 : 0;
int pwr_sel = (state == SD_MUX_FPGA) ? 1 : 0;
mux_state = state;
ret = gpio_set_level(sd_mux_sel, mux_sel);
if (ret < 0) {
LOG_ERR("gpio_set_level(sd_mux_sel) failed, ret = %d\n", ret);
return ret;
}
ret = gpio_set_level(sd_mux_en_l, mux_en);
if (ret < 0) {
LOG_ERR("gpio_set_level(sd_mux_en+l) failed, ret = %d\n", ret);
return ret;
}
ret = gpio_set_level(usd_pwr_sel, pwr_sel);
if (ret < 0) {
LOG_ERR("gpio_set_level(usd_pwr_sel) failed, ret = %d\n", ret);
return ret;
}
ret = gpio_set_level(usd_pwr_en, pwr_en);
if (ret < 0) {
LOG_ERR("gpio_set_level(usd_pwr_en) failed, ret = %d\n", ret);
return ret;
}
return 0;
}
enum sd_state sd_mux_get(void)
{
return mux_state;
}
int sd_get_cd_det(void)
{
return gpio_get_level(usd_cd_det);
}
/**
* @brief Initialize the SD mux GPIOs to a disconnected state
*
* The SD mux controls whether the SD card signals are connected, and
* if they are connected, whether to the FPGA or the USB controller.
* Set up the GPIOs and then set the mux to disconnected.
*/
static int sd_mux_init(const struct device *ptr)
{
ARG_UNUSED(ptr);
return sd_mux_set(SD_MUX_OFF);
}
SYS_INIT(sd_mux_init, APPLICATION, 90);
/**
* @brief Handle the "sd off" shell command.
*/
static int cmd_sd_off(const struct shell *shell, size_t argc, char **argv)
{
ARG_UNUSED(shell);
ARG_UNUSED(argc);
ARG_UNUSED(argv);
return sd_mux_set(SD_MUX_OFF);
}
/**
* @brief Handle the "sd fpga" shell command.
*/
static int cmd_sd_fpga(const struct shell *shell, size_t argc, char **argv)
{
ARG_UNUSED(shell);
ARG_UNUSED(argc);
ARG_UNUSED(argv);
return sd_mux_set(SD_MUX_FPGA);
}
/**
* @brief Handle the "sd usb" shell command.
*/
static int cmd_sd_usb(const struct shell *shell, size_t argc, char **argv)
{
ARG_UNUSED(shell);
ARG_UNUSED(argc);
ARG_UNUSED(argv);
return sd_mux_set(SD_MUX_USB);
}
/**
* @brief Handle the "sd status" shell command.
*/
static int cmd_sd_status(const struct shell *shell, size_t argc, char **argv)
{
ARG_UNUSED(argc);
ARG_UNUSED(argv);
shell_fprintf(shell, SHELL_NORMAL, "The SD mux is set to ");
switch (sd_mux_get()) {
case SD_MUX_OFF:
shell_fprintf(shell, SHELL_NORMAL, "disconnected\n");
break;
case SD_MUX_FPGA:
shell_fprintf(shell, SHELL_NORMAL, "FPGA\n");
break;
case SD_MUX_USB:
shell_fprintf(shell, SHELL_NORMAL, "USB\n");
break;
default:
shell_fprintf(shell, SHELL_NORMAL, "invalid value, %d\n",
(int)mux_state);
}
shell_fprintf(shell, SHELL_NORMAL, "CD_DET = %d\n", sd_get_cd_det());
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(
sd_cmds, SHELL_CMD(off, NULL, "disconnect the SD mux", cmd_sd_off),
SHELL_CMD(fpga, NULL, "connect the SD mux to the FPGA", cmd_sd_fpga),
SHELL_CMD(usb, NULL, "connect the SD mux to the USB", cmd_sd_usb),
SHELL_CMD(status, NULL, "get SD mux status", cmd_sd_status),
SHELL_SUBCMD_SET_END /* Array terminated. */
);
SHELL_CMD_REGISTER(sd, &sd_cmds, "SD mux commands", NULL);