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

Commit 702c0b04 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'next-spi' of git://git.secretlab.ca/git/linux-2.6

* 'next-spi' of git://git.secretlab.ca/git/linux-2.6:
  spi/xilinx: Fix compile error
  spi/davinci: Fix clock prescale factor computation
  spi: move bitbang txrx utility functions to private header
  spi/mpc5121: Add SPI master driver for MPC5121 PSC
  powerpc/mpc5121: move PSC FIFO memory init to platform code
  spi/ep93xx: implemented driver for Cirrus EP93xx SPI controller
  Documentation/spi/* compile warning fix
  spi/omap2_mcspi: Check params before dereference or use
  spi/omap2_mcspi: add turbo mode support
  spi/omap2_mcspi: change default DMA_MIN_BYTES value to 160
  spi/pl022: fix stop queue procedure
  spi/pl022: add support for the PL023 derivate
  spi/pl022: fix up differences between ARM and ST versions
  spi/spi_mpc8xxx: Do not use map_tx_dma to unmap rx_dma
  spi/spi_mpc8xxx: Fix QE mode Litte Endian
  spi/spi_mpc8xxx: fix potential memory corruption.
parents c19eb8f0 bf6a67ee
Loading
Loading
Loading
Loading
+95 −0
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 <mach/ep93xx_spi.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));
}

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.
+2 −2
Original line number Diff line number Diff line
@@ -58,10 +58,10 @@ static void do_msg(int fd, int len)
		len = sizeof buf;

	buf[0] = 0xaa;
	xfer[0].tx_buf = (__u64) buf;
	xfer[0].tx_buf = (unsigned long)buf;
	xfer[0].len = 1;

	xfer[1].rx_buf = (__u64) buf;
	xfer[1].rx_buf = (unsigned long) buf;
	xfer[1].len = len;

	status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
+27 −0
Original line number Diff line number Diff line
#ifndef __ASM_MACH_EP93XX_SPI_H
#define __ASM_MACH_EP93XX_SPI_H

struct spi_device;

/**
 * struct ep93xx_spi_info - EP93xx specific SPI descriptor
 * @num_chipselect: number of chip selects on this board, must be
 *                  at least one
 */
struct ep93xx_spi_info {
	int	num_chipselect;
};

/**
 * struct ep93xx_spi_chip_ops - operation callbacks for SPI slave device
 * @setup: setup the chip select mechanism
 * @cleanup: cleanup the chip select mechanism
 * @cs_control: control the device chip select
 */
struct ep93xx_spi_chip_ops {
	int	(*setup)(struct spi_device *spi);
	void	(*cleanup)(struct spi_device *spi);
	void	(*cs_control)(struct spi_device *spi, int value);
};

#endif /* __ASM_MACH_EP93XX_SPI_H */
+1 −0
Original line number Diff line number Diff line
@@ -248,6 +248,7 @@ struct mpc52xx_psc_fifo {
	u16		tflwfptr;	/* PSC + 0x9e */
};

#define MPC512x_PSC_FIFO_EOF		0x100
#define MPC512x_PSC_FIFO_RESET_SLICE	0x80
#define MPC512x_PSC_FIFO_ENABLE_SLICE	0x01
#define MPC512x_PSC_FIFO_ENABLE_DMA	0x04
+78 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <asm/prom.h>
#include <asm/time.h>
#include <asm/mpc5121.h>
#include <asm/mpc52xx_psc.h>

#include "mpc512x.h"

@@ -95,9 +96,86 @@ void __init mpc512x_declare_of_platform_devices(void)
	}
}

#define DEFAULT_FIFO_SIZE 16

static unsigned int __init get_fifo_size(struct device_node *np,
					 char *prop_name)
{
	const unsigned int *fp;

	fp = of_get_property(np, prop_name, NULL);
	if (fp)
		return *fp;

	pr_warning("no %s property in %s node, defaulting to %d\n",
		   prop_name, np->full_name, DEFAULT_FIFO_SIZE);

	return DEFAULT_FIFO_SIZE;
}

#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
		    ((u32)(_base) + sizeof(struct mpc52xx_psc)))

/* Init PSC FIFO space for TX and RX slices */
void __init mpc512x_psc_fifo_init(void)
{
	struct device_node *np;
	void __iomem *psc;
	unsigned int tx_fifo_size;
	unsigned int rx_fifo_size;
	int fifobase = 0; /* current fifo address in 32 bit words */

	for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") {
		tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
		rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");

		/* size in register is in 4 byte units */
		tx_fifo_size /= 4;
		rx_fifo_size /= 4;
		if (!tx_fifo_size)
			tx_fifo_size = 1;
		if (!rx_fifo_size)
			rx_fifo_size = 1;

		psc = of_iomap(np, 0);
		if (!psc) {
			pr_err("%s: Can't map %s device\n",
				__func__, np->full_name);
			continue;
		}

		/* FIFO space is 4KiB, check if requested size is available */
		if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
			pr_err("%s: no fifo space available for %s\n",
				__func__, np->full_name);
			iounmap(psc);
			/*
			 * chances are that another device requests less
			 * fifo space, so we continue.
			 */
			continue;
		}

		/* set tx and rx fifo size registers */
		out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
		fifobase += tx_fifo_size;
		out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
		fifobase += rx_fifo_size;

		/* reset and enable the slices */
		out_be32(&FIFOC(psc)->txcmd, 0x80);
		out_be32(&FIFOC(psc)->txcmd, 0x01);
		out_be32(&FIFOC(psc)->rxcmd, 0x80);
		out_be32(&FIFOC(psc)->rxcmd, 0x01);

		iounmap(psc);
	}
}

void __init mpc512x_init(void)
{
	mpc512x_declare_of_platform_devices();
	mpc5121_clk_init();
	mpc512x_restart_init();
	mpc512x_psc_fifo_init();
}
Loading