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

Commit 4374f332 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'spi/topic/omap-100k' into spi-next

parents 45bb5065 2d0c6148
Loading
Loading
Loading
Loading
+78 −198
Original line number Original line Diff line number Diff line
@@ -83,11 +83,6 @@
#define SPI_SHUTDOWN	1
#define SPI_SHUTDOWN	1


struct omap1_spi100k {
struct omap1_spi100k {
	struct work_struct      work;

	/* lock protects queue and registers */
	spinlock_t              lock;
	struct list_head        msg_queue;
	struct spi_master       *master;
	struct spi_master       *master;
	struct clk              *ick;
	struct clk              *ick;
	struct clk              *fck;
	struct clk              *fck;
@@ -104,8 +99,6 @@ struct omap1_spi100k_cs {
	int                     word_len;
	int                     word_len;
};
};


static struct workqueue_struct *omap1_spi100k_wq;

#define MOD_REG_BIT(val, mask, set) do { \
#define MOD_REG_BIT(val, mask, set) do { \
	if (set) \
	if (set) \
		val |= mask; \
		val |= mask; \
@@ -310,50 +303,36 @@ static int omap1_spi100k_setup(struct spi_device *spi)


	spi100k_open(spi->master);
	spi100k_open(spi->master);


	clk_enable(spi100k->ick);
	clk_prepare_enable(spi100k->ick);
	clk_enable(spi100k->fck);
	clk_prepare_enable(spi100k->fck);


	ret = omap1_spi100k_setup_transfer(spi, NULL);
	ret = omap1_spi100k_setup_transfer(spi, NULL);


	clk_disable(spi100k->ick);
	clk_disable_unprepare(spi100k->ick);
	clk_disable(spi100k->fck);
	clk_disable_unprepare(spi100k->fck);


	return ret;
	return ret;
}
}


static void omap1_spi100k_work(struct work_struct *work)
static int omap1_spi100k_prepare_hardware(struct spi_master *master)
{
{
	struct omap1_spi100k    *spi100k;
	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
	int status = 0;


	spi100k = container_of(work, struct omap1_spi100k, work);
	clk_prepare_enable(spi100k->ick);
	spin_lock_irq(&spi100k->lock);
	clk_prepare_enable(spi100k->fck);


	clk_enable(spi100k->ick);
	return 0;
	clk_enable(spi100k->fck);
}


	/* We only enable one channel at a time -- the one whose message is
static int omap1_spi100k_transfer_one_message(struct spi_master *master,
	 * at the head of the queue -- although this controller would gladly
					      struct spi_message *m)
	 * arbitrate among multiple channels.  This corresponds to "single
{
	 * channel" master mode.  As a side effect, we need to manage the
	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
	 * chipselect with the FORCE bit ... CS != channel enable.
	struct spi_device *spi = m->spi;
	 */
	 while (!list_empty(&spi100k->msg_queue)) {
		struct spi_message              *m;
		struct spi_device               *spi;
	struct spi_transfer *t = NULL;
	struct spi_transfer *t = NULL;
	int cs_active = 0;
	int cs_active = 0;
		struct omap1_spi100k_cs         *cs;
	int par_override = 0;
	int par_override = 0;

	int status = 0;
		m = container_of(spi100k->msg_queue.next, struct spi_message,
				 queue);

		list_del_init(&m->queue);
		spin_unlock_irq(&spi100k->lock);

		spi = m->spi;
		cs = spi->controller_state;


	list_for_each_entry(t, &m->transfers, transfer_list) {
	list_for_each_entry(t, &m->transfers, transfer_list) {
		if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
		if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
@@ -407,73 +386,19 @@ static void omap1_spi100k_work(struct work_struct *work)
		omap1_spi100k_force_cs(spi100k, 0);
		omap1_spi100k_force_cs(spi100k, 0);


	m->status = status;
	m->status = status;
		m->complete(m->context);


		spin_lock_irq(&spi100k->lock);
	spi_finalize_current_message(master);
	}


	clk_disable(spi100k->ick);
	return status;
	clk_disable(spi100k->fck);
	spin_unlock_irq(&spi100k->lock);

	if (status < 0)
		printk(KERN_WARNING "spi transfer failed with %d\n", status);
}
}


static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
static int omap1_spi100k_unprepare_hardware(struct spi_master *master)
{
{
	struct omap1_spi100k    *spi100k;
	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
	unsigned long           flags;
	struct spi_transfer     *t;

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

	spi100k = spi_master_get_devdata(spi->master);

	/* Don't accept new work if we're shutting down */
	if (spi100k->state == SPI_SHUTDOWN)
		return -ESHUTDOWN;

	/* reject invalid messages and transfers */
	if (list_empty(&m->transfers) || !m->complete)
		return -EINVAL;

	list_for_each_entry(t, &m->transfers, transfer_list) {
		const void      *tx_buf = t->tx_buf;
		void            *rx_buf = t->rx_buf;
		unsigned        len = t->len;

		if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
				|| (len && !(rx_buf || tx_buf))) {
			dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
					t->speed_hz,
					len,
					tx_buf ? "tx" : "",
					rx_buf ? "rx" : "",
					t->bits_per_word);
			return -EINVAL;
		}

		if (t->speed_hz && t->speed_hz < OMAP1_SPI100K_MAX_FREQ/(1<<16)) {
			dev_dbg(&spi->dev, "%d Hz max exceeds %d\n",
					t->speed_hz,
					OMAP1_SPI100K_MAX_FREQ/(1<<16));
			return -EINVAL;
		}

	}

	spin_lock_irqsave(&spi100k->lock, flags);
	list_add_tail(&m->queue, &spi100k->msg_queue);
	queue_work(omap1_spi100k_wq, &spi100k->work);
	spin_unlock_irqrestore(&spi100k->lock, flags);


	return 0;
	clk_disable_unprepare(spi100k->ick);
}
	clk_disable_unprepare(spi100k->fck);


static int omap1_spi100k_reset(struct omap1_spi100k *spi100k)
{
	return 0;
	return 0;
}
}


@@ -496,11 +421,15 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
	       master->bus_num = pdev->id;
	       master->bus_num = pdev->id;


	master->setup = omap1_spi100k_setup;
	master->setup = omap1_spi100k_setup;
	master->transfer = omap1_spi100k_transfer;
	master->transfer_one_message = omap1_spi100k_transfer_one_message;
	master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware;
	master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware;
	master->cleanup = NULL;
	master->cleanup = NULL;
	master->num_chipselect = 2;
	master->num_chipselect = 2;
	master->mode_bits = MODEBITS;
	master->mode_bits = MODEBITS;
	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
	master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16);
	master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ;


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


@@ -514,40 +443,29 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
	 */
	 */
	spi100k->base = (void __iomem *) pdev->dev.platform_data;
	spi100k->base = (void __iomem *) pdev->dev.platform_data;


	INIT_WORK(&spi100k->work, omap1_spi100k_work);
	spi100k->ick = devm_clk_get(&pdev->dev, "ick");

	spin_lock_init(&spi100k->lock);
	INIT_LIST_HEAD(&spi100k->msg_queue);
	spi100k->ick = clk_get(&pdev->dev, "ick");
	if (IS_ERR(spi100k->ick)) {
	if (IS_ERR(spi100k->ick)) {
		dev_dbg(&pdev->dev, "can't get spi100k_ick\n");
		dev_dbg(&pdev->dev, "can't get spi100k_ick\n");
		status = PTR_ERR(spi100k->ick);
		status = PTR_ERR(spi100k->ick);
		goto err1;
		goto err;
	}
	}


	spi100k->fck = clk_get(&pdev->dev, "fck");
	spi100k->fck = devm_clk_get(&pdev->dev, "fck");
	if (IS_ERR(spi100k->fck)) {
	if (IS_ERR(spi100k->fck)) {
		dev_dbg(&pdev->dev, "can't get spi100k_fck\n");
		dev_dbg(&pdev->dev, "can't get spi100k_fck\n");
		status = PTR_ERR(spi100k->fck);
		status = PTR_ERR(spi100k->fck);
		goto err2;
		goto err;
	}
	}


	if (omap1_spi100k_reset(spi100k) < 0)
		goto err3;

	status = spi_register_master(master);
	status = spi_register_master(master);
	if (status < 0)
	if (status < 0)
		goto err3;
		goto err;


	spi100k->state = SPI_RUNNING;
	spi100k->state = SPI_RUNNING;


	return status;
	return status;


err3:
err:
	clk_put(spi100k->fck);
err2:
	clk_put(spi100k->ick);
err1:
	spi_master_put(master);
	spi_master_put(master);
	return status;
	return status;
}
}
@@ -557,33 +475,14 @@ static int omap1_spi100k_remove(struct platform_device *pdev)
	struct spi_master       *master;
	struct spi_master       *master;
	struct omap1_spi100k    *spi100k;
	struct omap1_spi100k    *spi100k;
	struct resource         *r;
	struct resource         *r;
	unsigned		limit = 500;
	unsigned long		flags;
	int			status = 0;
	int			status = 0;


	master = platform_get_drvdata(pdev);
	master = platform_get_drvdata(pdev);
	spi100k = spi_master_get_devdata(master);
	spi100k = spi_master_get_devdata(master);


	spin_lock_irqsave(&spi100k->lock, flags);

	spi100k->state = SPI_SHUTDOWN;
	while (!list_empty(&spi100k->msg_queue) && limit--) {
		spin_unlock_irqrestore(&spi100k->lock, flags);
		msleep(10);
		spin_lock_irqsave(&spi100k->lock, flags);
	}

	if (!list_empty(&spi100k->msg_queue))
		status = -EBUSY;

	spin_unlock_irqrestore(&spi100k->lock, flags);

	if (status != 0)
	if (status != 0)
		return status;
		return status;


	clk_put(spi100k->fck);
	clk_put(spi100k->ick);

	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);


	spi_unregister_master(master);
	spi_unregister_master(master);
@@ -596,30 +495,11 @@ static struct platform_driver omap1_spi100k_driver = {
		.name		= "omap1_spi100k",
		.name		= "omap1_spi100k",
		.owner		= THIS_MODULE,
		.owner		= THIS_MODULE,
	},
	},
	.probe		= omap1_spi100k_probe,
	.remove		= omap1_spi100k_remove,
	.remove		= omap1_spi100k_remove,
};
};



module_platform_driver(omap1_spi100k_driver);
static int __init omap1_spi100k_init(void)
{
	omap1_spi100k_wq = create_singlethread_workqueue(
			omap1_spi100k_driver.driver.name);

	if (omap1_spi100k_wq == NULL)
		return -1;

	return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe);
}

static void __exit omap1_spi100k_exit(void)
{
	platform_driver_unregister(&omap1_spi100k_driver);

	destroy_workqueue(omap1_spi100k_wq);
}

module_init(omap1_spi100k_init);
module_exit(omap1_spi100k_exit);


MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver");
MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver");
MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>");
MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>");