diff mbox

[08/10] spi: sh-msiof: Move clock management to (un)prepare_message()

Message ID 1392907389-21798-9-git-send-email-geert@linux-m68k.org (mailing list archive)
State New, archived
Delegated to: Mark Brown
Headers show

Commit Message

Geert Uytterhoeven Feb. 20, 2014, 2:43 p.m. UTC
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>

Move clock management and pin configuration from the bitbang chipselect()
method to the SPI core prepare_message() and unprepare_message() methods.

Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
 drivers/spi/spi-sh-msiof.c |   56 +++++++++++++++++++++++++++-----------------
 1 file changed, 34 insertions(+), 22 deletions(-)

Comments

Mark Brown Feb. 22, 2014, 3:27 a.m. UTC | #1
On Thu, Feb 20, 2014 at 03:43:07PM +0100, Geert Uytterhoeven wrote:

> +	if (!test_and_set_bit(0, &p->flags)) {
> +		pm_runtime_get_sync(&p->pdev->dev);
> +		clk_enable(p->clk);
> +	}

That test_and_set_bit() is a bit odd - what's going on there, perhaps a
comment is in order?  I'd also like to see return value checks, though
the original didn't have them so it's not a blocker, and ideally that
should be clk_prepare_enable().  I guess the clock stuff could even be
moved inside the runtime PM callbacks?  Again not a blocker if the
existing code doesn't have things but it'd be nice to do.

There's also auto_runtime_pm in the SPI core which will do the runtime
PM for you if you can do it unconditionally.
Geert Uytterhoeven Feb. 24, 2014, 9:48 a.m. UTC | #2
Hi Mark, Magnus,

On Sat, Feb 22, 2014 at 4:27 AM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Feb 20, 2014 at 03:43:07PM +0100, Geert Uytterhoeven wrote:
>
>> +     if (!test_and_set_bit(0, &p->flags)) {
>> +             pm_runtime_get_sync(&p->pdev->dev);
>> +             clk_enable(p->clk);
>> +     }
>
> That test_and_set_bit() is a bit odd - what's going on there, perhaps a
> comment is in order?  I'd also like to see return value checks, though

My first guess was to support multiple CS, but you can't have multiple
active SPI slaves at the same time.

Perhaps it's because the bitbang core may call the .chipselect() callback
multiple times with is_on == BITBANG_CS_ACTIVE, and obviously the
clock should be enabled/disabled only once?
The current code doesn't seem to do that, but perhaps it was different when
the sh-msiof driver was written?

Ah, there's also the initial .chipselect(..., BITBANG_CS_INACTIVE) call
in spi_bitbang_setup(), which should not disable the clock.
But it should still call sh_msiof_spi_set_pin_regs() and set the optional
GPIO CS. Which is no longer done after my series. I'll fix that.

Magnus, do you remember the rationale for the test_and_set_bit()?

Anyway, it seems safe to remove it, as .(un)prepare_message() is
guaranteed to be called in matching pairs.

> the original didn't have them so it's not a blocker, and ideally that
> should be clk_prepare_enable().  I guess the clock stuff could even be
> moved inside the runtime PM callbacks?  Again not a blocker if the
> existing code doesn't have things but it'd be nice to do.
>
> There's also auto_runtime_pm in the SPI core which will do the runtime
> PM for you if you can do it unconditionally.

As you mention yourself, all of this code existed before. It just got moved,
to make the conversion to the SPI core message handling easier.
If you don't mind, I'd like to defer these, and tackle runtime PM later.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown Feb. 24, 2014, 1:07 p.m. UTC | #3
On Mon, Feb 24, 2014 at 10:48:26AM +0100, Geert Uytterhoeven wrote:

> Perhaps it's because the bitbang core may call the .chipselect() callback
> multiple times with is_on == BITBANG_CS_ACTIVE, and obviously the
> clock should be enabled/disabled only once?
> The current code doesn't seem to do that, but perhaps it was different when
> the sh-msiof driver was written?

Possibly, or perhaps someone was being overly cautious.

> As you mention yourself, all of this code existed before. It just got moved,
> to make the conversion to the SPI core message handling easier.
> If you don't mind, I'd like to defer these, and tackle runtime PM later.

Sure.
Magnus Damm Feb. 25, 2014, 1:43 a.m. UTC | #4
Hi Geert,

On Mon, Feb 24, 2014 at 6:48 PM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> Hi Mark, Magnus,
>
> On Sat, Feb 22, 2014 at 4:27 AM, Mark Brown <broonie@kernel.org> wrote:
>> On Thu, Feb 20, 2014 at 03:43:07PM +0100, Geert Uytterhoeven wrote:
>>
>>> +     if (!test_and_set_bit(0, &p->flags)) {
>>> +             pm_runtime_get_sync(&p->pdev->dev);
>>> +             clk_enable(p->clk);
>>> +     }
>>
>> That test_and_set_bit() is a bit odd - what's going on there, perhaps a
>> comment is in order?  I'd also like to see return value checks, though
>
> My first guess was to support multiple CS, but you can't have multiple
> active SPI slaves at the same time.
>
> Perhaps it's because the bitbang core may call the .chipselect() callback
> multiple times with is_on == BITBANG_CS_ACTIVE, and obviously the
> clock should be enabled/disabled only once?
> The current code doesn't seem to do that, but perhaps it was different when
> the sh-msiof driver was written?
>
> Ah, there's also the initial .chipselect(..., BITBANG_CS_INACTIVE) call
> in spi_bitbang_setup(), which should not disable the clock.
> But it should still call sh_msiof_spi_set_pin_regs() and set the optional
> GPIO CS. Which is no longer done after my series. I'll fix that.
>
> Magnus, do you remember the rationale for the test_and_set_bit()?

Sorry, I don't remember. Perhaps it was related to the CS bitbang handling.

> Anyway, it seems safe to remove it, as .(un)prepare_message() is
> guaranteed to be called in matching pairs.

Yes, I agree!

Thanks,

/ magnus
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 31624fb4997d..7add4be37987 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -472,9 +472,40 @@  static int sh_msiof_spi_setup(struct spi_device *spi)
 	return spi_bitbang_setup(spi);
 }
 
+static int sh_msiof_prepare_message(struct spi_master *master,
+				    struct spi_message *msg)
+{
+	struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
+	const struct spi_device *spi = msg->spi;
+
+	if (!test_and_set_bit(0, &p->flags)) {
+		pm_runtime_get_sync(&p->pdev->dev);
+		clk_enable(p->clk);
+	}
+
+	/* Configure pins before asserting CS */
+	sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+				  !!(spi->mode & SPI_CPHA),
+				  !!(spi->mode & SPI_3WIRE),
+				  !!(spi->mode & SPI_LSB_FIRST),
+				  !!(spi->mode & SPI_CS_HIGH));
+	return 0;
+}
+
+static int sh_msiof_unprepare_message(struct spi_master *master,
+				      struct spi_message *msg)
+{
+	struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
+
+	if (test_and_clear_bit(0, &p->flags)) {
+		clk_disable(p->clk);
+		pm_runtime_put(&p->pdev->dev);
+	}
+	return 0;
+}
+
 static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on)
 {
-	struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
 	int value;
 
 	/* chip select is active low unless SPI_CS_HIGH is set */
@@ -483,29 +514,8 @@  static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on)
 	else
 		value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1;
 
-	if (is_on == BITBANG_CS_ACTIVE) {
-		if (!test_and_set_bit(0, &p->flags)) {
-			pm_runtime_get_sync(&p->pdev->dev);
-			clk_enable(p->clk);
-		}
-
-		/* Configure pins before asserting CS */
-		sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
-					  !!(spi->mode & SPI_CPHA),
-					  !!(spi->mode & SPI_3WIRE),
-					  !!(spi->mode & SPI_LSB_FIRST),
-					  !!(spi->mode & SPI_CS_HIGH));
-	}
-
 	if (spi->cs_gpio >= 0)
 		gpio_set_value(spi->cs_gpio, value);
-
-	if (is_on == BITBANG_CS_INACTIVE) {
-		if (test_and_clear_bit(0, &p->flags)) {
-			clk_disable(p->clk);
-			pm_runtime_put(&p->pdev->dev);
-		}
-	}
 }
 
 static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
@@ -810,6 +820,8 @@  static int sh_msiof_spi_probe(struct platform_device *pdev)
 	master->num_chipselect = p->info->num_chipselect;
 	master->setup = sh_msiof_spi_setup;
 	master->cleanup = spi_bitbang_cleanup;
+	master->prepare_message = sh_msiof_prepare_message;
+	master->unprepare_message = sh_msiof_unprepare_message;
 
 	p->bitbang.master = master;
 	p->bitbang.chipselect = sh_msiof_spi_chipselect;