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

Commit 95e40cc5 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'spi/topic/mpc512x' into spi-next

parents 11e91689 85085898
Loading
Loading
Loading
Loading
+186 −155
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@
#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
#include <linux/io.h>
#include <linux/delay.h>
@@ -33,24 +32,15 @@

struct mpc512x_psc_spi {
	void (*cs_control)(struct spi_device *spi, bool on);
	u32 sysclk;

	/* driver internal data */
	struct mpc52xx_psc __iomem *psc;
	struct mpc512x_psc_fifo __iomem *fifo;
	unsigned int irq;
	u8 bits_per_word;
	u8 busy;
	u32 mclk;
	u8 eofbyte;

	struct workqueue_struct *workqueue;
	struct work_struct work;

	struct list_head queue;
	spinlock_t lock;	/* Message queue lock */

	struct completion done;
	struct completion txisrdone;
};

/* controller state */
@@ -136,99 +126,149 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
					 struct spi_transfer *t)
{
	struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
	struct mpc52xx_psc __iomem *psc = mps->psc;
	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
	size_t len = t->len;
	size_t tx_len = t->len;
	size_t rx_len = t->len;
	u8 *tx_buf = (u8 *)t->tx_buf;
	u8 *rx_buf = (u8 *)t->rx_buf;

	if (!tx_buf && !rx_buf && t->len)
		return -EINVAL;

	/* Zero MR2 */
	in_8(&psc->mode);
	out_8(&psc->mode, 0x0);

	/* enable transmiter/receiver */
	out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);

	while (len) {
		int count;
		int i;
	while (rx_len || tx_len) {
		size_t txcount;
		u8 data;
		size_t fifosz;
		int rxcount;
		size_t rxcount;
		int rxtries;

		/*
		 * The number of bytes that can be sent at a time
		 * depends on the fifo size.
		 * send the TX bytes in as large a chunk as possible
		 * but neither exceed the TX nor the RX FIFOs
		 */
		fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz));
		count = min(fifosz, len);

		for (i = count; i > 0; i--) {
		txcount = min(fifosz, tx_len);
		fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->rxsz));
		fifosz -= in_be32(&fifo->rxcnt) + 1;
		txcount = min(fifosz, txcount);
		if (txcount) {

			/* fill the TX FIFO */
			while (txcount-- > 0) {
				data = tx_buf ? *tx_buf++ : 0;
			if (len == EOFBYTE && t->cs_change)
				setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF);
				if (tx_len == EOFBYTE && t->cs_change)
					setbits32(&fifo->txcmd,
						  MPC512x_PSC_FIFO_EOF);
				out_8(&fifo->txdata_8, data);
			len--;
				tx_len--;
			}

		INIT_COMPLETION(mps->done);

		/* interrupt on tx fifo empty */
			/* have the ISR trigger when the TX FIFO is empty */
			INIT_COMPLETION(mps->txisrdone);
			out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
			out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY);
			wait_for_completion(&mps->txisrdone);
		}

		wait_for_completion(&mps->done);
		/*
		 * consume as much RX data as the FIFO holds, while we
		 * iterate over the transfer's TX data length
		 *
		 * only insist in draining all the remaining RX bytes
		 * when the TX bytes were exhausted (that's at the very
		 * end of this transfer, not when still iterating over
		 * the transfer's chunks)
		 */
		rxtries = 50;
		do {

		mdelay(1);
			/*
			 * grab whatever was in the FIFO when we started
			 * looking, don't bother fetching what was added to
			 * the FIFO while we read from it -- we'll return
			 * here eventually and prefer sending out remaining
			 * TX data
			 */
			fifosz = in_be32(&fifo->rxcnt);
			rxcount = min(fifosz, rx_len);
			while (rxcount-- > 0) {
				data = in_8(&fifo->rxdata_8);
				if (rx_buf)
					*rx_buf++ = data;
				rx_len--;
			}

		/* rx fifo should have count bytes in it */
		rxcount = in_be32(&fifo->rxcnt);
		if (rxcount != count)
			mdelay(1);
			/*
			 * come back later if there still is TX data to send,
			 * bail out of the RX drain loop if all of the TX data
			 * was sent and all of the RX data was received (i.e.
			 * when the transmission has completed)
			 */
			if (tx_len)
				break;
			if (!rx_len)
				break;

			/*
			 * TX data transmission has completed while RX data
			 * is still pending -- that's a transient situation
			 * which depends on wire speed and specific
			 * hardware implementation details (buffering) yet
			 * should resolve very quickly
			 *
			 * just yield for a moment to not hog the CPU for
			 * too long when running SPI at low speed
			 *
			 * the timeout range is rather arbitrary and tries
			 * to balance throughput against system load; the
			 * chosen values result in a minimal timeout of 50
			 * times 10us and thus work at speeds as low as
			 * some 20kbps, while the maximum timeout at the
			 * transfer's end could be 5ms _if_ nothing else
			 * ticks in the system _and_ RX data still wasn't
			 * received, which only occurs in situations that
			 * are exceptional; removing the unpredictability
			 * of the timeout either decreases throughput
			 * (longer timeouts), or puts more load on the
			 * system (fixed short timeouts) or requires the
			 * use of a timeout API instead of a counter and an
			 * unknown inner delay
			 */
			usleep_range(10, 100);

		} while (--rxtries > 0);
		if (!tx_len && rx_len && !rxtries) {
			/*
			 * not enough RX bytes even after several retries
			 * and the resulting rather long timeout?
			 */
			rxcount = in_be32(&fifo->rxcnt);
		if (rxcount != count) {
			dev_warn(&spi->dev, "expected %d bytes in rx fifo "
				 "but got %d\n", count, rxcount);
			dev_warn(&spi->dev,
				 "short xfer, missing %zd RX bytes, FIFO level %zd\n",
				 rx_len, rxcount);
		}

		rxcount = min(rxcount, count);
		for (i = rxcount; i > 0; i--) {
			data = in_8(&fifo->rxdata_8);
			if (rx_buf)
				*rx_buf++ = data;
		}
		while (in_be32(&fifo->rxcnt)) {
		/*
		 * drain and drop RX data which "should not be there" in
		 * the first place, for undisturbed transmission this turns
		 * into a NOP (except for the FIFO level fetch)
		 */
		if (!tx_len && !rx_len) {
			while (in_be32(&fifo->rxcnt))
				in_8(&fifo->rxdata_8);
		}

	}
	/* disable transmiter/receiver and fifo interrupt */
	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
	out_be32(&fifo->tximr, 0);
	return 0;
}

static void mpc512x_psc_spi_work(struct work_struct *work)
static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
				    struct spi_message *m)
{
	struct mpc512x_psc_spi *mps = container_of(work,
						   struct mpc512x_psc_spi,
						   work);

	spin_lock_irq(&mps->lock);
	mps->busy = 1;
	while (!list_empty(&mps->queue)) {
		struct spi_message *m;
	struct spi_device *spi;
		struct spi_transfer *t = NULL;
	unsigned cs_change;
	int status;

		m = container_of(mps->queue.next, struct spi_message, queue);
		list_del_init(&m->queue);
		spin_unlock_irq(&mps->lock);
	struct spi_transfer *t;

	spi = m->spi;
	cs_change = 1;
@@ -264,17 +304,45 @@ static void mpc512x_psc_spi_work(struct work_struct *work)

	mpc512x_psc_spi_transfer_setup(spi, NULL);

		spin_lock_irq(&mps->lock);
	spi_finalize_current_message(master);
	return status;
}
	mps->busy = 0;
	spin_unlock_irq(&mps->lock);

static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
{
	struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
	struct mpc52xx_psc __iomem *psc = mps->psc;

	dev_dbg(&master->dev, "%s()\n", __func__);

	/* Zero MR2 */
	in_8(&psc->mode);
	out_8(&psc->mode, 0x0);

	/* enable transmitter/receiver */
	out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);

	return 0;
}

static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master)
{
	struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
	struct mpc52xx_psc __iomem *psc = mps->psc;
	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;

	dev_dbg(&master->dev, "%s()\n", __func__);

	/* disable transmitter/receiver and fifo interrupt */
	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
	out_be32(&fifo->tximr, 0);

	return 0;
}

static int mpc512x_psc_spi_setup(struct spi_device *spi)
{
	struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
	struct mpc512x_psc_spi_cs *cs = spi->controller_state;
	unsigned long flags;
	int ret;

	if (spi->bits_per_word % 8)
@@ -303,28 +371,6 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi)
	cs->bits_per_word = spi->bits_per_word;
	cs->speed_hz = spi->max_speed_hz;

	spin_lock_irqsave(&mps->lock, flags);
	if (!mps->busy)
		mpc512x_psc_spi_deactivate_cs(spi);
	spin_unlock_irqrestore(&mps->lock, flags);

	return 0;
}

static int mpc512x_psc_spi_transfer(struct spi_device *spi,
				    struct spi_message *m)
{
	struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
	unsigned long flags;

	m->actual_length = 0;
	m->status = -EINPROGRESS;

	spin_lock_irqsave(&mps->lock, flags);
	list_add_tail(&m->queue, &mps->queue);
	queue_work(mps->workqueue, &mps->work);
	spin_unlock_irqrestore(&mps->lock, flags);

	return 0;
}

@@ -407,12 +453,12 @@ static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
	struct mpc512x_psc_spi *mps = (struct mpc512x_psc_spi *)dev_id;
	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;

	/* clear interrupt and wake up the work queue */
	/* clear interrupt and wake up the rx/tx routine */
	if (in_be32(&fifo->txisr) &
	    in_be32(&fifo->tximr) & MPC512x_PSC_FIFO_EMPTY) {
		out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
		out_be32(&fifo->tximr, 0);
		complete(&mps->done);
		complete(&mps->txisrdone);
		return IRQ_HANDLED;
	}
	return IRQ_NONE;
@@ -444,18 +490,18 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,

	if (pdata == NULL) {
		mps->cs_control = mpc512x_spi_cs_control;
		mps->sysclk = 0;
		master->bus_num = bus_num;
	} else {
		mps->cs_control = pdata->cs_control;
		mps->sysclk = pdata->sysclk;
		master->bus_num = pdata->bus_num;
		master->num_chipselect = pdata->max_chipselect;
	}

	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
	master->setup = mpc512x_psc_spi_setup;
	master->transfer = mpc512x_psc_spi_transfer;
	master->prepare_transfer_hardware = mpc512x_psc_spi_prep_xfer_hw;
	master->transfer_one_message = mpc512x_psc_spi_msg_xfer;
	master->unprepare_transfer_hardware = mpc512x_psc_spi_unprep_xfer_hw;
	master->cleanup = mpc512x_psc_spi_cleanup;
	master->dev.of_node = dev->of_node;

@@ -473,31 +519,18 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
			  "mpc512x-psc-spi", mps);
	if (ret)
		goto free_master;
	init_completion(&mps->txisrdone);

	ret = mpc512x_psc_spi_port_config(master, mps);
	if (ret < 0)
		goto free_irq;

	spin_lock_init(&mps->lock);
	init_completion(&mps->done);
	INIT_WORK(&mps->work, mpc512x_psc_spi_work);
	INIT_LIST_HEAD(&mps->queue);

	mps->workqueue =
		create_singlethread_workqueue(dev_name(master->dev.parent));
	if (mps->workqueue == NULL) {
		ret = -EBUSY;
		goto free_irq;
	}

	ret = spi_register_master(master);
	if (ret < 0)
		goto unreg_master;
		goto free_irq;

	return ret;

unreg_master:
	destroy_workqueue(mps->workqueue);
free_irq:
	free_irq(mps->irq, mps);
free_master:
@@ -513,8 +546,6 @@ static int mpc512x_psc_spi_do_remove(struct device *dev)
	struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
	struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);

	flush_workqueue(mps->workqueue);
	destroy_workqueue(mps->workqueue);
	spi_unregister_master(master);
	free_irq(mps->irq, mps);
	if (mps->psc)