From: Greg Ungerer <gerg@snapgear.com>
To: Steven King <sfking@fdwdc.com>
Cc: Grant Likely <grant.likely@secretlab.ca>,
spi-devel-general@lists.sourceforge.net,
uClinux development list <uclinux-dev@uclinux.org>,
gerg@uclinux.org
Subject: Re: [PATCH] spi: refactor spi-coldfire-qspi to use SPI queue framework.
Date: Fri, 11 May 2012 16:28:57 +1000 [thread overview]
Message-ID: <4FACB1A9.3060800@snapgear.com> (raw)
In-Reply-To: <201205100926.55444.sfking@fdwdc.com>
On 11/05/12 02:26, Steven King wrote:
> Use the new SPI queue framework; remove use of workqueue, replace
> mcfqspi_transfer with mcfqspi_transfer_one_message, add
> mcfqspi_prepare_transfer_hw and mcfqspi_unprepare_transfer_hw, update power
> management routines.
>
> Signed-off-by: Steven King<sfking@fdwdc.com>
I can't add much value reviewing this one, style wise it looks good.
Grant: if you don't want to take this through one of your trees
I can add it to the m68knommu git tree.
Regards
Greg
> drivers/spi/spi-coldfire-qspi.c | 255 +++++++++++++++++---------------------
> 1 files changed, 114 insertions(+), 141 deletions(-)
>
> diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
> index 6eee64a..b2d4b9e 100644
> --- a/drivers/spi/spi-coldfire-qspi.c
> +++ b/drivers/spi/spi-coldfire-qspi.c
> @@ -25,12 +25,12 @@
> #include<linux/errno.h>
> #include<linux/platform_device.h>
> #include<linux/sched.h>
> -#include<linux/workqueue.h>
> #include<linux/delay.h>
> #include<linux/io.h>
> #include<linux/clk.h>
> #include<linux/err.h>
> #include<linux/spi/spi.h>
> +#include<linux/pm_runtime.h>
>
> #include<asm/coldfire.h>
> #include<asm/mcfsim.h>
> @@ -78,10 +78,7 @@ struct mcfqspi {
>
> wait_queue_head_t waitq;
>
> - struct work_struct work;
> - struct workqueue_struct *workq;
> - spinlock_t lock;
> - struct list_head msgq;
> + struct device *dev;
> };
>
> static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
> @@ -303,120 +300,80 @@ 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);
> - unsigned long flags;
> -
> - 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;
> -
> - msg = container_of(mcfqspi->msgq.next, struct spi_message,
> - 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;
> - u16 qmr = MCFQSPI_QMR_MSTR;
> -
> - if (xfer->bits_per_word)
> - qmr |= xfer->bits_per_word<< 10;
> - else
> - qmr |= spi->bits_per_word<< 10;
> - if (spi->mode& SPI_CPHA)
> - qmr |= MCFQSPI_QMR_CPHA;
> - if (spi->mode& SPI_CPOL)
> - qmr |= MCFQSPI_QMR_CPOL;
> - if (xfer->speed_hz)
> - qmr |= mcfqspi_qmr_baud(xfer->speed_hz);
> - else
> - qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
> - mcfqspi_wr_qmr(mcfqspi, qmr);
> -
> - mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
> -
> - mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
> - if ((xfer->bits_per_word ? xfer->bits_per_word :
> - spi->bits_per_word) == 8)
> - mcfqspi_transfer_msg8(mcfqspi, xfer->len,
> - xfer->tx_buf,
> - xfer->rx_buf);
> - else
> - mcfqspi_transfer_msg16(mcfqspi, xfer->len / 2,
> - xfer->tx_buf,
> - xfer->rx_buf);
> - mcfqspi_wr_qir(mcfqspi, 0);
> -
> - if (xfer->delay_usecs)
> - udelay(xfer->delay_usecs);
> - if (xfer->cs_change) {
> - if (!list_is_last(&xfer->transfer_list,
> - &msg->transfers))
> - mcfqspi_cs_deselect(mcfqspi,
> - spi->chip_select,
> - cs_high);
> - } else {
> - if (list_is_last(&xfer->transfer_list,
> - &msg->transfers))
> - mcfqspi_cs_deselect(mcfqspi,
> - spi->chip_select,
> - cs_high);
> - }
> - msg->actual_length += xfer->len;
> + struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
> + struct spi_device *spi = msg->spi;
> + struct spi_transfer *t;
> + int status = 0;
> +
> + list_for_each_entry(t,&msg->transfers, transfer_list) {
> + bool cs_high = spi->mode& SPI_CS_HIGH;
> + u16 qmr = MCFQSPI_QMR_MSTR;
> +
> + if (t->bits_per_word)
> + qmr |= t->bits_per_word<< 10;
> + else
> + qmr |= spi->bits_per_word<< 10;
> + if (spi->mode& SPI_CPHA)
> + qmr |= MCFQSPI_QMR_CPHA;
> + if (spi->mode& SPI_CPOL)
> + qmr |= MCFQSPI_QMR_CPOL;
> + if (t->speed_hz)
> + qmr |= mcfqspi_qmr_baud(t->speed_hz);
> + else
> + qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
> + mcfqspi_wr_qmr(mcfqspi, qmr);
> +
> + mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
> +
> + mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
> + if ((t->bits_per_word ? t->bits_per_word :
> + spi->bits_per_word) == 8)
> + mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
> + t->rx_buf);
> + else
> + mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
> + t->rx_buf);
> + mcfqspi_wr_qir(mcfqspi, 0);
> +
> + if (t->delay_usecs)
> + udelay(t->delay_usecs);
> + if (t->cs_change) {
> + if (!list_is_last(&t->transfer_list,&msg->transfers))
> + mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
> + cs_high);
> + } else {
> + if (list_is_last(&t->transfer_list,&msg->transfers))
> + mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
> + cs_high);
> }
> - msg->status = status;
> - msg->complete(msg->context);
> -
> - spin_lock_irqsave(&mcfqspi->lock, flags);
> + msg->actual_length += t->len;
> }
> - spin_unlock_irqrestore(&mcfqspi->lock, flags);
> + msg->status = status;
> + spi_finalize_current_message(master);
> +
> + return status;
> +
> }
>
> -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 spi_transfer *xfer;
> - unsigned long flags;
> -
> - mcfqspi = spi_master_get_devdata(spi->master);
> -
> - list_for_each_entry(xfer,&msg->transfers, transfer_list) {
> - 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;
> + struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
>
> - spin_lock_irqsave(&mcfqspi->lock, flags);
> - list_add_tail(&msg->queue,&mcfqspi->msgq);
> - queue_work(mcfqspi->workq,&mcfqspi->work);
> - spin_unlock_irqrestore(&mcfqspi->lock, flags);
> + pm_runtime_get_sync(mcfqspi->dev);
> +
> + return 0;
> +}
> +
> +static int mcfqspi_unprepare_transfer_hw(struct spi_master *master)
> +{
> + struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
> +
> + pm_runtime_put_sync(mcfqspi->dev);
>
> return 0;
> -fail:
> - msg->status = -EINVAL;
> - return -EINVAL;
> }
>
> 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);
>
> - 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;
> if (!pdata) {
> dev_dbg(&pdev->dev, "platform data is missing\n");
> - goto fail5;
> + goto fail4;
> }
> master->bus_num = pdata->bus_num;
> master->num_chipselect = pdata->num_chipselect;
> @@ -525,28 +471,33 @@ static int __devinit mcfqspi_probe(struct platform_device *pdev)
> status = mcfqspi_cs_setup(mcfqspi);
> if (status) {
> 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->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);
>
> status = spi_register_master(master);
> if (status) {
> 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");
>
> return 0;
>
> -fail6:
> - mcfqspi_cs_teardown(mcfqspi);
> fail5:
> - destroy_workqueue(mcfqspi->workq);
> + mcfqspi_cs_teardown(mcfqspi);
> fail4:
> clk_disable(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 resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>
> + pm_runtime_disable(mcfqspi->dev);
> /* disable the hardware (set the baud rate to 0) */
> mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
>
> platform_set_drvdata(pdev, NULL);
> mcfqspi_cs_teardown(mcfqspi);
> - destroy_workqueue(mcfqspi->workq);
> clk_disable(mcfqspi->clk);
> clk_put(mcfqspi->clk);
> free_irq(mcfqspi->irq, mcfqspi);
> @@ -587,11 +538,13 @@ static int __devexit mcfqspi_remove(struct platform_device *pdev)
> return 0;
> }
>
> -#ifdef CONFIG_PM
> -
> +#ifdef CONFIG_PM_SLEEP
> 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);
>
> @@ -600,27 +553,47 @@ static int mcfqspi_suspend(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);
>
> return 0;
> }
> +#endif
>
> -static struct dev_pm_ops mcfqspi_dev_pm_ops = {
> - .suspend = mcfqspi_suspend,
> - .resume = mcfqspi_resume,
> -};
> +#ifdef CONFIG_PM_RUNTIME
> +static int mcfqspi_runtime_suspend(struct device *dev)
> +{
> + struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
>
> -#define MCFQSPI_DEV_PM_OPS (&mcfqspi_dev_pm_ops)
> -#else
> -#define MCFQSPI_DEV_PM_OPS NULL
> + clk_disable(mcfqspi->clk);
> +
> + 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
>
> +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 = {
> .driver.name = DRIVER_NAME,
> .driver.owner = THIS_MODULE,
> - .driver.pm = MCFQSPI_DEV_PM_OPS,
> + .driver.pm =&mcfqspi_pm,
> .probe = mcfqspi_probe,
> .remove = __devexit_p(mcfqspi_remove),
> };
>
>
>
--
------------------------------------------------------------------------
Greg Ungerer -- Principal Engineer EMAIL: gerg@snapgear.com
SnapGear Group, McAfee PHONE: +61 7 3435 2888
8 Gardner Close FAX: +61 7 3217 5323
Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com
_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev
next prev parent reply other threads:[~2012-05-11 6:28 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-05-10 16:26 [PATCH] spi: refactor spi-coldfire-qspi to use SPI queue framework Steven King
2012-05-11 6:28 ` Greg Ungerer [this message]
[not found] ` <4FACB1A9.3060800-XXXsiaCtIV5Wk0Htik3J/w@public.gmane.org>
2012-05-20 4:57 ` Grant Likely
[not found] ` <201205100926.55444.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>
2012-05-11 8:33 ` Shubhrajyoti Datta
2012-05-11 10:33 ` Steven King
[not found] ` <201205110333.22096.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>
2012-05-11 13:21 ` Shubhrajyoti Datta
2012-05-14 19:50 ` Linus Walleij
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4FACB1A9.3060800@snapgear.com \
--to=gerg@snapgear.com \
--cc=gerg@uclinux.org \
--cc=grant.likely@secretlab.ca \
--cc=sfking@fdwdc.com \
--cc=spi-devel-general@lists.sourceforge.net \
--cc=uclinux-dev@uclinux.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.