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

Commit 34706500 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'spi/topic/dw', 'spi/topic/ep93xx',...

Merge remote-tracking branches 'spi/topic/dw', 'spi/topic/ep93xx', 'spi/topic/falcon' and 'spi/topic/fsl-lpspi' into spi-next
Loading
Loading
Loading
Loading

Documentation/spi/ep93xx_spi

deleted100644 → 0
+0 −105
Original line number Diff line number Diff line
Cirrus EP93xx SPI controller driver HOWTO
=========================================

ep93xx_spi driver brings SPI master support for EP93xx SPI controller.  Chip
selects are implemented with GPIO lines.

NOTE: If possible, don't use SFRMOUT (SFRM1) signal as a chip select. It will
not work correctly (it cannot be controlled by software). Use GPIO lines
instead.

Sample configuration
====================

Typically driver configuration is done in platform board files (the files under
arch/arm/mach-ep93xx/*.c). In this example we configure MMC over SPI through
this driver on TS-7260 board. You can adapt the code to suit your needs.

This example uses EGPIO9 as SD/MMC card chip select (this is wired in DIO1
header on the board).

You need to select CONFIG_MMC_SPI to use mmc_spi driver.

arch/arm/mach-ep93xx/ts72xx.c:

...
#include <linux/gpio.h>
#include <linux/spi/spi.h>

#include <linux/platform_data/spi-ep93xx.h>

/* this is our GPIO line used for chip select */
#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO9

static int ts72xx_mmc_spi_setup(struct spi_device *spi)
{
	int err;

	err = gpio_request(MMC_CHIP_SELECT_GPIO, spi->modalias);
	if (err)
		return err;

	gpio_direction_output(MMC_CHIP_SELECT_GPIO, 1);

	return 0;
}

static void ts72xx_mmc_spi_cleanup(struct spi_device *spi)
{
	gpio_set_value(MMC_CHIP_SELECT_GPIO, 1);
	gpio_direction_input(MMC_CHIP_SELECT_GPIO);
	gpio_free(MMC_CHIP_SELECT_GPIO);
}

static void ts72xx_mmc_spi_cs_control(struct spi_device *spi, int value)
{
	gpio_set_value(MMC_CHIP_SELECT_GPIO, value);
}

static struct ep93xx_spi_chip_ops ts72xx_mmc_spi_ops = {
	.setup		= ts72xx_mmc_spi_setup,
	.cleanup	= ts72xx_mmc_spi_cleanup,
	.cs_control	= ts72xx_mmc_spi_cs_control,
};

static struct spi_board_info ts72xx_spi_devices[] __initdata = {
	{
		.modalias		= "mmc_spi",
		.controller_data	= &ts72xx_mmc_spi_ops,
		/*
		 * We use 10 MHz even though the maximum is 7.4 MHz. The driver
		 * will limit it automatically to max. frequency.
		 */
		.max_speed_hz		= 10 * 1000 * 1000,
		.bus_num		= 0,
		.chip_select		= 0,
		.mode			= SPI_MODE_0,
	},
};

static struct ep93xx_spi_info ts72xx_spi_info = {
	.num_chipselect	= ARRAY_SIZE(ts72xx_spi_devices),
};

static void __init ts72xx_init_machine(void)
{
	...
	ep93xx_register_spi(&ts72xx_spi_info, ts72xx_spi_devices,
			    ARRAY_SIZE(ts72xx_spi_devices));
}

The driver can use DMA for the transfers also. In this case ts72xx_spi_info
becomes:

static struct ep93xx_spi_info ts72xx_spi_info = {
	.num_chipselect	= ARRAY_SIZE(ts72xx_spi_devices),
	.use_dma	= true;
};

Note that CONFIG_EP93XX_DMA should be enabled as well.

Thanks to
=========
Martin Guy, H. Hartley Sweeten and others who helped me during development of
the driver. Simplemachines.it donated me a Sim.One board which I used testing
the driver on EP9307.
+6 −25
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
#include <linux/spi/spi.h>
@@ -106,33 +105,10 @@ static struct cs4271_platform_data edb93xx_cs4271_data = {
	.gpio_nreset	= -EINVAL,	/* filled in later */
};

static int edb93xx_cs4271_hw_setup(struct spi_device *spi)
{
	return gpio_request_one(EP93XX_GPIO_LINE_EGPIO6,
				GPIOF_OUT_INIT_HIGH, spi->modalias);
}

static void edb93xx_cs4271_hw_cleanup(struct spi_device *spi)
{
	gpio_free(EP93XX_GPIO_LINE_EGPIO6);
}

static void edb93xx_cs4271_hw_cs_control(struct spi_device *spi, int value)
{
	gpio_set_value(EP93XX_GPIO_LINE_EGPIO6, value);
}

static struct ep93xx_spi_chip_ops edb93xx_cs4271_hw = {
	.setup		= edb93xx_cs4271_hw_setup,
	.cleanup	= edb93xx_cs4271_hw_cleanup,
	.cs_control	= edb93xx_cs4271_hw_cs_control,
};

static struct spi_board_info edb93xx_spi_board_info[] __initdata = {
	{
		.modalias		= "cs4271",
		.platform_data		= &edb93xx_cs4271_data,
		.controller_data	= &edb93xx_cs4271_hw,
		.max_speed_hz		= 6000000,
		.bus_num		= 0,
		.chip_select		= 0,
@@ -140,8 +116,13 @@ static struct spi_board_info edb93xx_spi_board_info[] __initdata = {
	},
};

static int edb93xx_spi_chipselects[] __initdata = {
	EP93XX_GPIO_LINE_EGPIO6,
};

static struct ep93xx_spi_info edb93xx_spi_info __initdata = {
	.num_chipselect	= ARRAY_SIZE(edb93xx_spi_board_info),
	.chipselect	= edb93xx_spi_chipselects,
	.num_chipselect	= ARRAY_SIZE(edb93xx_spi_chipselects),
};

static void __init edb93xx_register_spi(void)
+11 −52
Original line number Diff line number Diff line
@@ -48,56 +48,6 @@ static struct ep93xxfb_mach_info __initdata simone_fb_info = {
 */
#define MMC_CARD_DETECT_GPIO EP93XX_GPIO_LINE_EGPIO0

/*
 * Up to v1.3, the Sim.One used SFRMOUT as SD card chip select, but this goes
 * low between multi-message command blocks. From v1.4, it uses a GPIO instead.
 * v1.3 parts will still work, since the signal on SFRMOUT is automatic.
 */
#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO1

/*
 * MMC SPI chip select GPIO handling. If you are using SFRMOUT (SFRM1) signal,
 * you can leave these empty and pass NULL as .controller_data.
 */

static int simone_mmc_spi_setup(struct spi_device *spi)
{
	unsigned int gpio = MMC_CHIP_SELECT_GPIO;
	int err;

	err = gpio_request(gpio, spi->modalias);
	if (err)
		return err;

	err = gpio_direction_output(gpio, 1);
	if (err) {
		gpio_free(gpio);
		return err;
	}

	return 0;
}

static void simone_mmc_spi_cleanup(struct spi_device *spi)
{
	unsigned int gpio = MMC_CHIP_SELECT_GPIO;

	gpio_set_value(gpio, 1);
	gpio_direction_input(gpio);
	gpio_free(gpio);
}

static void simone_mmc_spi_cs_control(struct spi_device *spi, int value)
{
	gpio_set_value(MMC_CHIP_SELECT_GPIO, value);
}

static struct ep93xx_spi_chip_ops simone_mmc_spi_ops = {
	.setup		= simone_mmc_spi_setup,
	.cleanup	= simone_mmc_spi_cleanup,
	.cs_control	= simone_mmc_spi_cs_control,
};

/*
 * MMC card detection GPIO setup.
 */
@@ -152,7 +102,6 @@ static struct mmc_spi_platform_data simone_mmc_spi_data = {
static struct spi_board_info simone_spi_devices[] __initdata = {
	{
		.modalias		= "mmc_spi",
		.controller_data	= &simone_mmc_spi_ops,
		.platform_data		= &simone_mmc_spi_data,
		/*
		 * We use 10 MHz even though the maximum is 3.7 MHz. The driver
@@ -165,8 +114,18 @@ static struct spi_board_info simone_spi_devices[] __initdata = {
	},
};

/*
 * Up to v1.3, the Sim.One used SFRMOUT as SD card chip select, but this goes
 * low between multi-message command blocks. From v1.4, it uses a GPIO instead.
 * v1.3 parts will still work, since the signal on SFRMOUT is automatic.
 */
static int simone_spi_chipselects[] __initdata = {
	EP93XX_GPIO_LINE_EGPIO1,
};

static struct ep93xx_spi_info simone_spi_info __initdata = {
	.num_chipselect	= ARRAY_SIZE(simone_spi_devices),
	.chipselect	= simone_spi_chipselects,
	.num_chipselect	= ARRAY_SIZE(simone_spi_chipselects),
	.use_dma = 1,
};

+10 −78
Original line number Diff line number Diff line
@@ -175,33 +175,9 @@ static struct cs4271_platform_data vision_cs4271_data = {
	.gpio_nreset	= EP93XX_GPIO_LINE_H(2),
};

static int vision_cs4271_hw_setup(struct spi_device *spi)
{
	return gpio_request_one(EP93XX_GPIO_LINE_EGPIO6,
				GPIOF_OUT_INIT_HIGH, spi->modalias);
}

static void vision_cs4271_hw_cleanup(struct spi_device *spi)
{
	gpio_free(EP93XX_GPIO_LINE_EGPIO6);
}

static void vision_cs4271_hw_cs_control(struct spi_device *spi, int value)
{
	gpio_set_value(EP93XX_GPIO_LINE_EGPIO6, value);
}

static struct ep93xx_spi_chip_ops vision_cs4271_hw = {
	.setup		= vision_cs4271_hw_setup,
	.cleanup	= vision_cs4271_hw_cleanup,
	.cs_control	= vision_cs4271_hw_cs_control,
};

/*************************************************************************
 * SPI Flash
 *************************************************************************/
#define VISION_SPI_FLASH_CS	EP93XX_GPIO_LINE_EGPIO7

static struct mtd_partition vision_spi_flash_partitions[] = {
	{
		.name	= "SPI bootstrap",
@@ -224,68 +200,20 @@ static struct flash_platform_data vision_spi_flash_data = {
	.nr_parts	= ARRAY_SIZE(vision_spi_flash_partitions),
};

static int vision_spi_flash_hw_setup(struct spi_device *spi)
{
	return gpio_request_one(VISION_SPI_FLASH_CS, GPIOF_INIT_HIGH,
				spi->modalias);
}

static void vision_spi_flash_hw_cleanup(struct spi_device *spi)
{
	gpio_free(VISION_SPI_FLASH_CS);
}

static void vision_spi_flash_hw_cs_control(struct spi_device *spi, int value)
{
	gpio_set_value(VISION_SPI_FLASH_CS, value);
}

static struct ep93xx_spi_chip_ops vision_spi_flash_hw = {
	.setup		= vision_spi_flash_hw_setup,
	.cleanup	= vision_spi_flash_hw_cleanup,
	.cs_control	= vision_spi_flash_hw_cs_control,
};

/*************************************************************************
 * SPI SD/MMC host
 *************************************************************************/
#define VISION_SPI_MMC_CS	EP93XX_GPIO_LINE_G(2)
#define VISION_SPI_MMC_WP	EP93XX_GPIO_LINE_F(0)
#define VISION_SPI_MMC_CD	EP93XX_GPIO_LINE_EGPIO15

static struct mmc_spi_platform_data vision_spi_mmc_data = {
	.detect_delay	= 100,
	.powerup_msecs	= 100,
	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
	.flags		= MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO,
	.cd_gpio	= VISION_SPI_MMC_CD,
	.cd_gpio	= EP93XX_GPIO_LINE_EGPIO15,
	.cd_debounce	= 1,
	.ro_gpio	= VISION_SPI_MMC_WP,
	.ro_gpio	= EP93XX_GPIO_LINE_F(0),
	.caps2		= MMC_CAP2_RO_ACTIVE_HIGH,
};

static int vision_spi_mmc_hw_setup(struct spi_device *spi)
{
	return gpio_request_one(VISION_SPI_MMC_CS, GPIOF_INIT_HIGH,
				spi->modalias);
}

static void vision_spi_mmc_hw_cleanup(struct spi_device *spi)
{
	gpio_free(VISION_SPI_MMC_CS);
}

static void vision_spi_mmc_hw_cs_control(struct spi_device *spi, int value)
{
	gpio_set_value(VISION_SPI_MMC_CS, value);
}

static struct ep93xx_spi_chip_ops vision_spi_mmc_hw = {
	.setup		= vision_spi_mmc_hw_setup,
	.cleanup	= vision_spi_mmc_hw_cleanup,
	.cs_control	= vision_spi_mmc_hw_cs_control,
};

/*************************************************************************
 * SPI Bus
 *************************************************************************/
@@ -293,7 +221,6 @@ static struct spi_board_info vision_spi_board_info[] __initdata = {
	{
		.modalias		= "cs4271",
		.platform_data		= &vision_cs4271_data,
		.controller_data	= &vision_cs4271_hw,
		.max_speed_hz		= 6000000,
		.bus_num		= 0,
		.chip_select		= 0,
@@ -301,7 +228,6 @@ static struct spi_board_info vision_spi_board_info[] __initdata = {
	}, {
		.modalias		= "sst25l",
		.platform_data		= &vision_spi_flash_data,
		.controller_data	= &vision_spi_flash_hw,
		.max_speed_hz		= 20000000,
		.bus_num		= 0,
		.chip_select		= 1,
@@ -309,7 +235,6 @@ static struct spi_board_info vision_spi_board_info[] __initdata = {
	}, {
		.modalias		= "mmc_spi",
		.platform_data		= &vision_spi_mmc_data,
		.controller_data	= &vision_spi_mmc_hw,
		.max_speed_hz		= 20000000,
		.bus_num		= 0,
		.chip_select		= 2,
@@ -317,8 +242,15 @@ static struct spi_board_info vision_spi_board_info[] __initdata = {
	},
};

static int vision_spi_chipselects[] __initdata = {
	EP93XX_GPIO_LINE_EGPIO6,
	EP93XX_GPIO_LINE_EGPIO7,
	EP93XX_GPIO_LINE_G(2),
};

static struct ep93xx_spi_info vision_spi_master __initdata = {
	.num_chipselect	= ARRAY_SIZE(vision_spi_board_info),
	.chipselect	= vision_spi_chipselects,
	.num_chipselect	= ARRAY_SIZE(vision_spi_chipselects),
	.use_dma	= 1,
};

+1 −1
Original line number Diff line number Diff line
@@ -264,7 +264,7 @@ config SPI_EP93XX
	  mode.

config SPI_FALCON
	tristate "Falcon SPI controller support"
	bool "Falcon SPI controller support"
	depends on SOC_FALCON
	help
	  The external bus unit (EBU) found on the FALC-ON SoC has SPI
Loading