Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf287a90 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Chris Ball
Browse files

mmc: mmc_spi: Support CD/RO GPIOs



Add support for passing CD/RO GPIO numbers directly to the mmc_spi
driver instead of relying solely on board code callbacks to retrieve the
CD/RO signals values. The driver will enable debouncing on the card
detect GPIO if the cd_debounce field is set to a non-zero value.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 214fc309
Loading
Loading
Loading
Loading
+24 −9
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@

#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>		/* for R1_SPI_* bit values */
#include <linux/mmc/slot-gpio.h>

#include <linux/spi/spi.h>
#include <linux/spi/mmc_spi.h>
@@ -1278,11 +1279,8 @@ static int mmc_spi_get_ro(struct mmc_host *mmc)

	if (host->pdata && host->pdata->get_ro)
		return !!host->pdata->get_ro(mmc->parent);
	/*
	 * Board doesn't support read only detection; let the mmc core
	 * decide what to do.
	 */
	return -ENOSYS;
	else
		return mmc_gpio_get_ro(mmc);
}

static int mmc_spi_get_cd(struct mmc_host *mmc)
@@ -1291,7 +1289,8 @@ static int mmc_spi_get_cd(struct mmc_host *mmc)

	if (host->pdata && host->pdata->get_cd)
		return !!host->pdata->get_cd(mmc->parent);
	return -ENOSYS;
	else
		return mmc_gpio_get_cd(mmc);
}

static const struct mmc_host_ops mmc_spi_ops = {
@@ -1324,6 +1323,7 @@ static int mmc_spi_probe(struct spi_device *spi)
	struct mmc_host		*mmc;
	struct mmc_spi_host	*host;
	int			status;
	bool			has_ro = false;

	/* We rely on full duplex transfers, mostly to reduce
	 * per-transfer overheads (by making fewer transfers).
@@ -1448,18 +1448,33 @@ static int mmc_spi_probe(struct spi_device *spi)
	}

	/* pass platform capabilities, if any */
	if (host->pdata)
	if (host->pdata) {
		mmc->caps |= host->pdata->caps;
		mmc->caps2 |= host->pdata->caps2;
	}

	status = mmc_add_host(mmc);
	if (status != 0)
		goto fail_add_host;

	if (host->pdata && host->pdata->flags & MMC_SPI_USE_CD_GPIO) {
		status = mmc_gpio_request_cd(mmc, host->pdata->cd_gpio,
					     host->pdata->cd_debounce);
		if (status != 0)
			goto fail_add_host;
	}

	if (host->pdata && host->pdata->flags & MMC_SPI_USE_RO_GPIO) {
		has_ro = true;
		status = mmc_gpio_request_ro(mmc, host->pdata->ro_gpio);
		if (status != 0)
			goto fail_add_host;
	}

	dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n",
			dev_name(&mmc->class_dev),
			host->dma_dev ? "" : ", no DMA",
			(host->pdata && host->pdata->get_ro)
				? "" : ", no WP",
			has_ro ? "" : ", no WP",
			(host->pdata && host->pdata->setpower)
				? "" : ", no poweroff",
			(mmc->caps & MMC_CAP_NEEDS_POLL)
+12 −34
Original line number Diff line number Diff line
@@ -50,25 +50,6 @@ static struct of_mmc_spi *to_of_mmc_spi(struct device *dev)
	return container_of(dev->platform_data, struct of_mmc_spi, pdata);
}

static int of_mmc_spi_read_gpio(struct device *dev, int gpio_num)
{
	struct of_mmc_spi *oms = to_of_mmc_spi(dev);
	bool active_low = oms->alow_gpios[gpio_num];
	bool value = gpio_get_value(oms->gpios[gpio_num]);

	return active_low ^ value;
}

static int of_mmc_spi_get_cd(struct device *dev)
{
	return of_mmc_spi_read_gpio(dev, CD_GPIO);
}

static int of_mmc_spi_get_ro(struct device *dev)
{
	return of_mmc_spi_read_gpio(dev, WP_GPIO);
}

static int of_mmc_spi_init(struct device *dev,
			   irqreturn_t (*irqhandler)(int, void *), void *mmc)
{
@@ -130,20 +111,22 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
		if (!gpio_is_valid(oms->gpios[i]))
			continue;

		ret = gpio_request(oms->gpios[i], dev_name(dev));
		if (ret < 0) {
			oms->gpios[i] = -EINVAL;
			continue;
		}

		if (gpio_flags & OF_GPIO_ACTIVE_LOW)
			oms->alow_gpios[i] = true;
	}

	if (gpio_is_valid(oms->gpios[CD_GPIO]))
		oms->pdata.get_cd = of_mmc_spi_get_cd;
	if (gpio_is_valid(oms->gpios[WP_GPIO]))
		oms->pdata.get_ro = of_mmc_spi_get_ro;
	if (gpio_is_valid(oms->gpios[CD_GPIO])) {
		oms->pdata.cd_gpio = oms->gpios[CD_GPIO];
		oms->pdata.flags |= MMC_SPI_USE_CD_GPIO;
		if (!oms->alow_gpios[CD_GPIO])
			oms->pdata.caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
	}
	if (gpio_is_valid(oms->gpios[WP_GPIO])) {
		oms->pdata.ro_gpio = oms->gpios[WP_GPIO];
		oms->pdata.flags |= MMC_SPI_USE_RO_GPIO;
		if (!oms->alow_gpios[WP_GPIO])
			oms->pdata.caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
	}

	oms->detect_irq = irq_of_parse_and_map(np, 0);
	if (oms->detect_irq != 0) {
@@ -166,15 +149,10 @@ void mmc_spi_put_pdata(struct spi_device *spi)
	struct device *dev = &spi->dev;
	struct device_node *np = dev->of_node;
	struct of_mmc_spi *oms = to_of_mmc_spi(dev);
	int i;

	if (!dev->platform_data || !np)
		return;

	for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) {
		if (gpio_is_valid(oms->gpios[i]))
			gpio_free(oms->gpios[i]);
	}
	kfree(oms);
	dev->platform_data = NULL;
}
+16 −0
Original line number Diff line number Diff line
@@ -7,6 +7,11 @@
struct device;
struct mmc_host;

#define MMC_SPI_USE_CD_GPIO			(1 << 0)
#define MMC_SPI_USE_RO_GPIO			(1 << 1)
#define MMC_SPI_CD_GPIO_ACTIVE_LOW		(1 << 2)
#define MMC_SPI_RO_GPIO_ACTIVE_LOW		(1 << 3)

/* Put this in platform_data of a device being used to manage an MMC/SD
 * card slot.  (Modeled after PXA mmc glue; see that for usage examples.)
 *
@@ -30,8 +35,19 @@ struct mmc_spi_platform_data {
	 */
	int (*get_cd)(struct device *);

	/*
	 * Card Detect and Read Only GPIOs. To enable debouncing on the card
	 * detect GPIO, set the cd_debounce to the debounce time in
	 * microseconds.
	 */
	unsigned int flags;
	unsigned int cd_gpio;
	unsigned int cd_debounce;
	unsigned int ro_gpio;

	/* Capabilities to pass into mmc core (e.g. MMC_CAP_NEEDS_POLL). */
	unsigned long caps;
	unsigned long caps2;

	/* how long to debounce card detect, in msecs */
	u16 detect_delay;