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

Commit be122abe authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6

Pull SPI changes from Grant Likely:
 "Bug fixes and new features for SPI device drivers.  Also move device
  tree support code out of drivers/of and into drivers/spi/spi.c where
  it makes more sense."

* tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6:
  spi: By default setup spi_masters with 1 chipselect and dynamics bus number
  SPI: PRIMA2: use the newest APIs of PINCTRL to fix compiling errors
  spi/spi-fsl-spi: reference correct pdata in fsl_spi_cs_control
  spi: refactor spi-coldfire-qspi to use SPI queue framework.
  spi/omap2-mcspi: convert to the pump message infrastructure
  spi/rspi: add dmaengine support
  spi/topcliff: use correct __devexit_p annotation
  spi: Dont call prepare/unprepare transfer if not populated
  spi/ep93xx: clean probe/remove routines
  spi/devicetree: Move devicetree support code into spi directory
  spi: use module_pci_driver
  spi/omap2-mcspi: Trivial optimisation
  spi: omap2-mcspi: add support for pm_runtime autosuspend
  spi/omap: Remove bus_num usage for instance index
  OMAP : SPI : use devm_* functions
  spi: omap2-mcspi: convert to module_platform_driver
  spi: omap2-mcspi: make it behave as a module
parents b343c8be 1e8a52e1
Loading
Loading
Loading
Loading
+0 −6
Original line number Original line Diff line number Diff line
@@ -67,12 +67,6 @@ config OF_NET
	depends on NETDEVICES
	depends on NETDEVICES
	def_bool y
	def_bool y


config OF_SPI
	def_tristate SPI
	depends on SPI && !SPARC
	help
	  OpenFirmware SPI accessors

config OF_MDIO
config OF_MDIO
	def_tristate PHYLIB
	def_tristate PHYLIB
	depends on PHYLIB
	depends on PHYLIB
+0 −1
Original line number Original line Diff line number Diff line
@@ -7,7 +7,6 @@ obj-$(CONFIG_OF_DEVICE) += device.o platform.o
obj-$(CONFIG_OF_GPIO)   += gpio.o
obj-$(CONFIG_OF_GPIO)   += gpio.o
obj-$(CONFIG_OF_I2C)	+= of_i2c.o
obj-$(CONFIG_OF_I2C)	+= of_i2c.o
obj-$(CONFIG_OF_NET)	+= of_net.o
obj-$(CONFIG_OF_NET)	+= of_net.o
obj-$(CONFIG_OF_SPI)	+= of_spi.o
obj-$(CONFIG_OF_SELFTEST) += selftest.o
obj-$(CONFIG_OF_SELFTEST) += selftest.o
obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
obj-$(CONFIG_OF_PCI)	+= of_pci.o
obj-$(CONFIG_OF_PCI)	+= of_pci.o

drivers/of/of_spi.c

deleted100644 → 0
+0 −99
Original line number Original line Diff line number Diff line
/*
 * SPI OF support routines
 * Copyright (C) 2008 Secret Lab Technologies Ltd.
 *
 * Support routines for deriving SPI device attachments from the device
 * tree.
 */

#include <linux/module.h>
#include <linux/of.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/of_irq.h>
#include <linux/of_spi.h>

/**
 * of_register_spi_devices - Register child devices onto the SPI bus
 * @master:	Pointer to spi_master device
 *
 * Registers an spi_device for each child node of master node which has a 'reg'
 * property.
 */
void of_register_spi_devices(struct spi_master *master)
{
	struct spi_device *spi;
	struct device_node *nc;
	const __be32 *prop;
	int rc;
	int len;

	if (!master->dev.of_node)
		return;

	for_each_child_of_node(master->dev.of_node, nc) {
		/* Alloc an spi_device */
		spi = spi_alloc_device(master);
		if (!spi) {
			dev_err(&master->dev, "spi_device alloc error for %s\n",
				nc->full_name);
			spi_dev_put(spi);
			continue;
		}

		/* Select device driver */
		if (of_modalias_node(nc, spi->modalias,
				     sizeof(spi->modalias)) < 0) {
			dev_err(&master->dev, "cannot find modalias for %s\n",
				nc->full_name);
			spi_dev_put(spi);
			continue;
		}

		/* Device address */
		prop = of_get_property(nc, "reg", &len);
		if (!prop || len < sizeof(*prop)) {
			dev_err(&master->dev, "%s has no 'reg' property\n",
				nc->full_name);
			spi_dev_put(spi);
			continue;
		}
		spi->chip_select = be32_to_cpup(prop);

		/* Mode (clock phase/polarity/etc.) */
		if (of_find_property(nc, "spi-cpha", NULL))
			spi->mode |= SPI_CPHA;
		if (of_find_property(nc, "spi-cpol", NULL))
			spi->mode |= SPI_CPOL;
		if (of_find_property(nc, "spi-cs-high", NULL))
			spi->mode |= SPI_CS_HIGH;

		/* Device speed */
		prop = of_get_property(nc, "spi-max-frequency", &len);
		if (!prop || len < sizeof(*prop)) {
			dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n",
				nc->full_name);
			spi_dev_put(spi);
			continue;
		}
		spi->max_speed_hz = be32_to_cpup(prop);

		/* IRQ */
		spi->irq = irq_of_parse_and_map(nc, 0);

		/* Store a pointer to the node in the device structure */
		of_node_get(nc);
		spi->dev.of_node = nc;

		/* Register the new device */
		request_module(spi->modalias);
		rc = spi_add_device(spi);
		if (rc) {
			dev_err(&master->dev, "spi_device register error %s\n",
				nc->full_name);
			spi_dev_put(spi);
		}

	}
}
EXPORT_SYMBOL(of_register_spi_devices);
+0 −3
Original line number Original line Diff line number Diff line
@@ -216,9 +216,6 @@ static __devinit int ath79_spi_probe(struct platform_device *pdev)
	if (pdata) {
	if (pdata) {
		master->bus_num = pdata->bus_num;
		master->bus_num = pdata->bus_num;
		master->num_chipselect = pdata->num_chipselect;
		master->num_chipselect = pdata->num_chipselect;
	} else {
		master->bus_num = -1;
		master->num_chipselect = 1;
	}
	}


	sp->bitbang.master = spi_master_get(master);
	sp->bitbang.master = spi_master_get(master);
+114 −141
Original line number Original line Diff line number Diff line
@@ -25,12 +25,12 @@
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi.h>
#include <linux/pm_runtime.h>


#include <asm/coldfire.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#include <asm/mcfsim.h>
@@ -78,10 +78,7 @@ struct mcfqspi {


	wait_queue_head_t waitq;
	wait_queue_head_t waitq;


	struct work_struct work;
	struct device *dev;
	struct workqueue_struct *workq;
	spinlock_t lock;
	struct list_head msgq;
};
};


static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
@@ -303,40 +300,28 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
	}
	}
}
}


static void mcfqspi_work(struct work_struct *work)
static int mcfqspi_transfer_one_message(struct spi_master *master,
					 struct spi_message *msg)
{
{
	struct mcfqspi *mcfqspi = container_of(work, struct mcfqspi, work);
	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
	unsigned long flags;
	struct spi_device *spi = msg->spi;

	struct spi_transfer *t;
	spin_lock_irqsave(&mcfqspi->lock, flags);
	while (!list_empty(&mcfqspi->msgq)) {
		struct spi_message *msg;
		struct spi_device *spi;
		struct spi_transfer *xfer;
	int status = 0;
	int status = 0;


		msg = container_of(mcfqspi->msgq.next, struct spi_message,
	list_for_each_entry(t, &msg->transfers, transfer_list) {
				   queue);

		list_del_init(&msg->queue);
		spin_unlock_irqrestore(&mcfqspi->lock, flags);

		spi = msg->spi;

		list_for_each_entry(xfer, &msg->transfers, transfer_list) {
		bool cs_high = spi->mode & SPI_CS_HIGH;
		bool cs_high = spi->mode & SPI_CS_HIGH;
		u16 qmr = MCFQSPI_QMR_MSTR;
		u16 qmr = MCFQSPI_QMR_MSTR;


			if (xfer->bits_per_word)
		if (t->bits_per_word)
				qmr |= xfer->bits_per_word << 10;
			qmr |= t->bits_per_word << 10;
		else
		else
			qmr |= spi->bits_per_word << 10;
			qmr |= spi->bits_per_word << 10;
		if (spi->mode & SPI_CPHA)
		if (spi->mode & SPI_CPHA)
			qmr |= MCFQSPI_QMR_CPHA;
			qmr |= MCFQSPI_QMR_CPHA;
		if (spi->mode & SPI_CPOL)
		if (spi->mode & SPI_CPOL)
			qmr |= MCFQSPI_QMR_CPOL;
			qmr |= MCFQSPI_QMR_CPOL;
			if (xfer->speed_hz)
		if (t->speed_hz)
				qmr |= mcfqspi_qmr_baud(xfer->speed_hz);
			qmr |= mcfqspi_qmr_baud(t->speed_hz);
		else
		else
			qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
			qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
		mcfqspi_wr_qmr(mcfqspi, qmr);
		mcfqspi_wr_qmr(mcfqspi, qmr);
@@ -344,79 +329,51 @@ static void mcfqspi_work(struct work_struct *work)
		mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
		mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);


		mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
		mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
			if ((xfer->bits_per_word ? xfer->bits_per_word :
		if ((t->bits_per_word ? t->bits_per_word :
					spi->bits_per_word) == 8)
					spi->bits_per_word) == 8)
				mcfqspi_transfer_msg8(mcfqspi, xfer->len,
			mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
						      xfer->tx_buf,
					t->rx_buf);
						      xfer->rx_buf);
		else
		else
				mcfqspi_transfer_msg16(mcfqspi, xfer->len / 2,
			mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
						       xfer->tx_buf,
					t->rx_buf);
						       xfer->rx_buf);
		mcfqspi_wr_qir(mcfqspi, 0);
		mcfqspi_wr_qir(mcfqspi, 0);


			if (xfer->delay_usecs)
		if (t->delay_usecs)
				udelay(xfer->delay_usecs);
			udelay(t->delay_usecs);
			if (xfer->cs_change) {
		if (t->cs_change) {
				if (!list_is_last(&xfer->transfer_list,
			if (!list_is_last(&t->transfer_list, &msg->transfers))
						  &msg->transfers))
				mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
					mcfqspi_cs_deselect(mcfqspi,
							    spi->chip_select,
						cs_high);
						cs_high);
		} else {
		} else {
				if (list_is_last(&xfer->transfer_list,
			if (list_is_last(&t->transfer_list, &msg->transfers))
						 &msg->transfers))
				mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
					mcfqspi_cs_deselect(mcfqspi,
							    spi->chip_select,
						cs_high);
						cs_high);
		}
		}
			msg->actual_length += xfer->len;
		msg->actual_length += t->len;
	}
	}
	msg->status = status;
	msg->status = status;
		msg->complete(msg->context);
	spi_finalize_current_message(master);

	return status;


		spin_lock_irqsave(&mcfqspi->lock, flags);
	}
	spin_unlock_irqrestore(&mcfqspi->lock, flags);
}
}


static int mcfqspi_transfer(struct spi_device *spi, struct spi_message *msg)
static int mcfqspi_prepare_transfer_hw(struct spi_master *master)
{
{
	struct mcfqspi *mcfqspi;
	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
	struct spi_transfer *xfer;
	unsigned long flags;


	mcfqspi = spi_master_get_devdata(spi->master);
	pm_runtime_get_sync(mcfqspi->dev);


	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
	return 0;
		if (xfer->bits_per_word && ((xfer->bits_per_word < 8)
					|| (xfer->bits_per_word > 16))) {
			dev_dbg(&spi->dev,
				"%d bits per word is not supported\n",
				xfer->bits_per_word);
			goto fail;
		}
		if (xfer->speed_hz) {
			u32 real_speed = MCFQSPI_BUSCLK /
				mcfqspi_qmr_baud(xfer->speed_hz);
			if (real_speed != xfer->speed_hz)
				dev_dbg(&spi->dev,
					"using speed %d instead of %d\n",
					real_speed, xfer->speed_hz);
		}
}
}
	msg->status = -EINPROGRESS;
	msg->actual_length = 0;


	spin_lock_irqsave(&mcfqspi->lock, flags);
static int mcfqspi_unprepare_transfer_hw(struct spi_master *master)
	list_add_tail(&msg->queue, &mcfqspi->msgq);
{
	queue_work(mcfqspi->workq, &mcfqspi->work);
	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
	spin_unlock_irqrestore(&mcfqspi->lock, flags);

	pm_runtime_put_sync(mcfqspi->dev);


	return 0;
	return 0;
fail:
	msg->status = -EINVAL;
	return -EINVAL;
}
}


static int mcfqspi_setup(struct spi_device *spi)
static int mcfqspi_setup(struct spi_device *spi)
@@ -502,21 +459,10 @@ static int __devinit mcfqspi_probe(struct platform_device *pdev)
	}
	}
	clk_enable(mcfqspi->clk);
	clk_enable(mcfqspi->clk);


	mcfqspi->workq = create_singlethread_workqueue(dev_name(master->dev.parent));
	if (!mcfqspi->workq) {
		dev_dbg(&pdev->dev, "create_workqueue failed\n");
		status = -ENOMEM;
		goto fail4;
	}
	INIT_WORK(&mcfqspi->work, mcfqspi_work);
	spin_lock_init(&mcfqspi->lock);
	INIT_LIST_HEAD(&mcfqspi->msgq);
	init_waitqueue_head(&mcfqspi->waitq);

	pdata = pdev->dev.platform_data;
	pdata = pdev->dev.platform_data;
	if (!pdata) {
	if (!pdata) {
		dev_dbg(&pdev->dev, "platform data is missing\n");
		dev_dbg(&pdev->dev, "platform data is missing\n");
		goto fail5;
		goto fail4;
	}
	}
	master->bus_num = pdata->bus_num;
	master->bus_num = pdata->bus_num;
	master->num_chipselect = pdata->num_chipselect;
	master->num_chipselect = pdata->num_chipselect;
@@ -525,28 +471,33 @@ static int __devinit mcfqspi_probe(struct platform_device *pdev)
	status = mcfqspi_cs_setup(mcfqspi);
	status = mcfqspi_cs_setup(mcfqspi);
	if (status) {
	if (status) {
		dev_dbg(&pdev->dev, "error initializing cs_control\n");
		dev_dbg(&pdev->dev, "error initializing cs_control\n");
		goto fail5;
		goto fail4;
	}
	}


	init_waitqueue_head(&mcfqspi->waitq);
	mcfqspi->dev = &pdev->dev;

	master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
	master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
	master->setup = mcfqspi_setup;
	master->setup = mcfqspi_setup;
	master->transfer = mcfqspi_transfer;
	master->transfer_one_message = mcfqspi_transfer_one_message;
	master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw;
	master->unprepare_transfer_hardware = mcfqspi_unprepare_transfer_hw;


	platform_set_drvdata(pdev, master);
	platform_set_drvdata(pdev, master);


	status = spi_register_master(master);
	status = spi_register_master(master);
	if (status) {
	if (status) {
		dev_dbg(&pdev->dev, "spi_register_master failed\n");
		dev_dbg(&pdev->dev, "spi_register_master failed\n");
		goto fail6;
		goto fail5;
	}
	}
	pm_runtime_enable(mcfqspi->dev);

	dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
	dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");


	return 0;
	return 0;


fail6:
	mcfqspi_cs_teardown(mcfqspi);
fail5:
fail5:
	destroy_workqueue(mcfqspi->workq);
	mcfqspi_cs_teardown(mcfqspi);
fail4:
fail4:
	clk_disable(mcfqspi->clk);
	clk_disable(mcfqspi->clk);
	clk_put(mcfqspi->clk);
	clk_put(mcfqspi->clk);
@@ -570,12 +521,12 @@ static int __devexit mcfqspi_remove(struct platform_device *pdev)
	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);


	pm_runtime_disable(mcfqspi->dev);
	/* disable the hardware (set the baud rate to 0) */
	/* disable the hardware (set the baud rate to 0) */
	mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
	mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);


	platform_set_drvdata(pdev, NULL);
	platform_set_drvdata(pdev, NULL);
	mcfqspi_cs_teardown(mcfqspi);
	mcfqspi_cs_teardown(mcfqspi);
	destroy_workqueue(mcfqspi->workq);
	clk_disable(mcfqspi->clk);
	clk_disable(mcfqspi->clk);
	clk_put(mcfqspi->clk);
	clk_put(mcfqspi->clk);
	free_irq(mcfqspi->irq, mcfqspi);
	free_irq(mcfqspi->irq, mcfqspi);
@@ -587,11 +538,13 @@ static int __devexit mcfqspi_remove(struct platform_device *pdev)
	return 0;
	return 0;
}
}


#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP

static int mcfqspi_suspend(struct device *dev)
static int mcfqspi_suspend(struct device *dev)
{
{
	struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
	struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);

	spi_master_suspend(master);


	clk_disable(mcfqspi->clk);
	clk_disable(mcfqspi->clk);


@@ -600,27 +553,47 @@ static int mcfqspi_suspend(struct device *dev)


static int mcfqspi_resume(struct device *dev)
static int mcfqspi_resume(struct device *dev)
{
{
	struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
	struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);

	spi_master_resume(master);


	clk_enable(mcfqspi->clk);
	clk_enable(mcfqspi->clk);


	return 0;
	return 0;
}
}
#endif


static struct dev_pm_ops mcfqspi_dev_pm_ops = {
#ifdef CONFIG_PM_RUNTIME
	.suspend	= mcfqspi_suspend,
static int mcfqspi_runtime_suspend(struct device *dev)
	.resume		= mcfqspi_resume,
{
};
	struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));


#define	MCFQSPI_DEV_PM_OPS	(&mcfqspi_dev_pm_ops)
	clk_disable(mcfqspi->clk);
#else

#define	MCFQSPI_DEV_PM_OPS	NULL
	return 0;
}

static int mcfqspi_runtime_resume(struct device *dev)
{
	struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));

	clk_enable(mcfqspi->clk);

	return 0;
}
#endif
#endif


static const struct dev_pm_ops mcfqspi_pm = {
	SET_SYSTEM_SLEEP_PM_OPS(mcfqspi_suspend, mcfqspi_resume)
	SET_RUNTIME_PM_OPS(mcfqspi_runtime_suspend, mcfqspi_runtime_resume,
			NULL)
};

static struct platform_driver mcfqspi_driver = {
static struct platform_driver mcfqspi_driver = {
	.driver.name	= DRIVER_NAME,
	.driver.name	= DRIVER_NAME,
	.driver.owner	= THIS_MODULE,
	.driver.owner	= THIS_MODULE,
	.driver.pm	= MCFQSPI_DEV_PM_OPS,
	.driver.pm	= &mcfqspi_pm,
	.probe		= mcfqspi_probe,
	.probe		= mcfqspi_probe,
	.remove		= __devexit_p(mcfqspi_remove),
	.remove		= __devexit_p(mcfqspi_remove),
};
};
Loading