* [PATCH v3] spi: omap2-mcspi: Add support for GPIO chipselects
@ 2015-05-06 23:37 Michael Welling
[not found] ` <1430955472-11409-1-git-send-email-mwelling-EkmVulN54Sk@public.gmane.org>
0 siblings, 1 reply; 6+ messages in thread
From: Michael Welling @ 2015-05-06 23:37 UTC (permalink / raw)
To: broonie-DgEjT+Ai2ygdnm+yROfE0A, linux-spi-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Michael Welling
This patch allows for GPIOs specified in the devicetree to be used as SPI
chipselects on TI OMAP2 SoCs.
Tested on the AM3354.
Signed-off-by: Michael Welling <mwelling-EkmVulN54Sk@public.gmane.org>
---
v3: Switches driver to use transfer_one instead of transfer_one_message
allowing the spi core to handle toggling GPIO chip selects if specified.
v2: Considers the possible use of SPI_CS_HIGH during chip select activation.
drivers/spi/spi-omap2-mcspi.c | 251 +++++++++++++++++++----------------------
1 file changed, 117 insertions(+), 134 deletions(-)
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index d1a5b9f..7152d8e 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -35,6 +35,7 @@
#include <linux/gcd.h>
#include <linux/spi/spi.h>
+#include <linux/gpio.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
@@ -1015,6 +1016,12 @@ static int omap2_mcspi_setup(struct spi_device *spi)
if (ret < 0)
return ret;
+ if (gpio_is_valid(spi->cs_gpio)) {
+ if (gpio_request(spi->cs_gpio, dev_name(&spi->dev)) == 0)
+ gpio_direction_output(spi->cs_gpio,
+ !(spi->mode & SPI_CS_HIGH));
+ }
+
ret = omap2_mcspi_setup_transfer(spi, NULL);
pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev);
@@ -1052,7 +1059,8 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
}
}
-static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
+static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
+ struct spi_device *spi, struct spi_transfer *t)
{
/* We only enable one channel at a time -- the one whose message is
@@ -1062,8 +1070,6 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
* chipselect with the FORCE bit ... CS != channel enable.
*/
- struct spi_device *spi;
- struct spi_transfer *t = NULL;
struct spi_master *master;
struct omap2_mcspi_dma *mcspi_dma;
int cs_active = 0;
@@ -1073,7 +1079,6 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
int status = 0;
u32 chconf;
- spi = m->spi;
master = spi->master;
mcspi_dma = mcspi->dma_channels + spi->chip_select;
cs = spi->controller_state;
@@ -1090,94 +1095,89 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
par_override = 1;
omap2_mcspi_set_enable(spi, 0);
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
- status = -EINVAL;
- break;
- }
- if (par_override ||
- (t->speed_hz != spi->max_speed_hz) ||
- (t->bits_per_word != spi->bits_per_word)) {
- par_override = 1;
- status = omap2_mcspi_setup_transfer(spi, t);
- if (status < 0)
- break;
- if (t->speed_hz == spi->max_speed_hz &&
- t->bits_per_word == spi->bits_per_word)
- par_override = 0;
- }
- if (cd && cd->cs_per_word) {
- chconf = mcspi->ctx.modulctrl;
- chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
- mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
- mcspi->ctx.modulctrl =
- mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
- }
-
- if (!cs_active) {
- omap2_mcspi_force_cs(spi, 1);
- cs_active = 1;
- }
+ if (par_override ||
+ (t->speed_hz != spi->max_speed_hz) ||
+ (t->bits_per_word != spi->bits_per_word)) {
+ par_override = 1;
+ status = omap2_mcspi_setup_transfer(spi, t);
+ if (status < 0)
+ goto out;
+ if (t->speed_hz == spi->max_speed_hz &&
+ t->bits_per_word == spi->bits_per_word)
+ par_override = 0;
+ }
+ if (cd && cd->cs_per_word) {
+ chconf = mcspi->ctx.modulctrl;
+ chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
+ mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
+ mcspi->ctx.modulctrl =
+ mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
+ }
- chconf = mcspi_cached_chconf0(spi);
- chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
- chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
+ if (!cs_active) {
+ omap2_mcspi_force_cs(spi, 1);
+ cs_active = 1;
+ }
- if (t->tx_buf == NULL)
- chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
- else if (t->rx_buf == NULL)
- chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
-
- if (cd && cd->turbo_mode && t->tx_buf == NULL) {
- /* Turbo mode is for more than one word */
- if (t->len > ((cs->word_len + 7) >> 3))
- chconf |= OMAP2_MCSPI_CHCONF_TURBO;
- }
+ chconf = mcspi_cached_chconf0(spi);
+ chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+ chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
+
+ if (t->tx_buf == NULL)
+ chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
+ else if (t->rx_buf == NULL)
+ chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
+
+ if (cd && cd->turbo_mode && t->tx_buf == NULL) {
+ /* Turbo mode is for more than one word */
+ if (t->len > ((cs->word_len + 7) >> 3))
+ chconf |= OMAP2_MCSPI_CHCONF_TURBO;
+ }
- mcspi_write_chconf0(spi, chconf);
+ mcspi_write_chconf0(spi, chconf);
- if (t->len) {
- unsigned count;
+ if (t->len) {
+ unsigned count;
- if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
- (m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
- omap2_mcspi_set_fifo(spi, t, 1);
+ if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
+ (t->len >= DMA_MIN_BYTES))
+ omap2_mcspi_set_fifo(spi, t, 1);
- omap2_mcspi_set_enable(spi, 1);
+ omap2_mcspi_set_enable(spi, 1);
- /* RX_ONLY mode needs dummy data in TX reg */
- if (t->tx_buf == NULL)
- writel_relaxed(0, cs->base
- + OMAP2_MCSPI_TX0);
+ /* RX_ONLY mode needs dummy data in TX reg */
+ if (t->tx_buf == NULL)
+ writel_relaxed(0, cs->base
+ + OMAP2_MCSPI_TX0);
- if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
- (m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
- count = omap2_mcspi_txrx_dma(spi, t);
- else
- count = omap2_mcspi_txrx_pio(spi, t);
- m->actual_length += count;
+ if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
+ (t->len >= DMA_MIN_BYTES))
+ count = omap2_mcspi_txrx_dma(spi, t);
+ else
+ count = omap2_mcspi_txrx_pio(spi, t);
- if (count != t->len) {
- status = -EIO;
- break;
- }
+ if (count != t->len) {
+ status = -EIO;
+ goto out;
}
+ }
- if (t->delay_usecs)
- udelay(t->delay_usecs);
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
- /* ignore the "leave it on after last xfer" hint */
- if (t->cs_change) {
- omap2_mcspi_force_cs(spi, 0);
- cs_active = 0;
- }
+ /* ignore the "leave it on after last xfer" hint */
+ if (t->cs_change) {
+ omap2_mcspi_force_cs(spi, 0);
+ cs_active = 0;
+ }
- omap2_mcspi_set_enable(spi, 0);
+ omap2_mcspi_set_enable(spi, 0);
- if (mcspi->fifo_depth > 0)
- omap2_mcspi_set_fifo(spi, t, 0);
- }
+ if (mcspi->fifo_depth > 0)
+ omap2_mcspi_set_fifo(spi, t, 0);
+
+out:
/* Restore defaults if they were overriden */
if (par_override) {
par_override = 0;
@@ -1200,75 +1200,58 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
if (mcspi->fifo_depth > 0 && t)
omap2_mcspi_set_fifo(spi, t, 0);
- m->status = status;
+ return status;
}
-static int omap2_mcspi_transfer_one_message(struct spi_master *master,
- struct spi_message *m)
+static int omap2_mcspi_transfer_one(struct spi_master *master,
+ struct spi_device *spi, struct spi_transfer *t)
{
- struct spi_device *spi;
struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma;
- struct spi_transfer *t;
- int status;
+ const void *tx_buf = t->tx_buf;
+ void *rx_buf = t->rx_buf;
+ unsigned len = t->len;
- spi = m->spi;
mcspi = spi_master_get_devdata(master);
mcspi_dma = mcspi->dma_channels + spi->chip_select;
- m->actual_length = 0;
- m->status = 0;
-
- 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 ((len && !(rx_buf || tx_buf))) {
- dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
- t->speed_hz,
- len,
- tx_buf ? "tx" : "",
- rx_buf ? "rx" : "",
- t->bits_per_word);
- status = -EINVAL;
- goto out;
- }
- if (m->is_dma_mapped || len < DMA_MIN_BYTES)
- continue;
-
- if (mcspi_dma->dma_tx && tx_buf != NULL) {
- t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
- len, DMA_TO_DEVICE);
- if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
- dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
- 'T', len);
- status = -EINVAL;
- goto out;
- }
+ if ((len && !(rx_buf || tx_buf))) {
+ dev_dbg(mcspi->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 (len < DMA_MIN_BYTES)
+ goto skip_dma_map;
+
+ if (mcspi_dma->dma_tx && tx_buf != NULL) {
+ t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
+ len, DMA_TO_DEVICE);
+ if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
+ dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
+ 'T', len);
+ return -EINVAL;
}
- if (mcspi_dma->dma_rx && rx_buf != NULL) {
- t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
- dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
- 'R', len);
- if (tx_buf != NULL)
- dma_unmap_single(mcspi->dev, t->tx_dma,
- len, DMA_TO_DEVICE);
- status = -EINVAL;
- goto out;
- }
+ }
+ if (mcspi_dma->dma_rx && rx_buf != NULL) {
+ t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
+ dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
+ 'R', len);
+ if (tx_buf != NULL)
+ dma_unmap_single(mcspi->dev, t->tx_dma,
+ len, DMA_TO_DEVICE);
+ return -EINVAL;
}
}
- omap2_mcspi_work(mcspi, m);
- /* spi_finalize_current_message() changes the status inside the
- * spi_message, save the status here. */
- status = m->status;
-out:
- spi_finalize_current_message(master);
- return status;
+skip_dma_map:
+ return omap2_mcspi_work_one(mcspi, spi, t);
}
static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
@@ -1347,7 +1330,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
master->setup = omap2_mcspi_setup;
master->auto_runtime_pm = true;
- master->transfer_one_message = omap2_mcspi_transfer_one_message;
+ master->transfer_one = omap2_mcspi_transfer_one;
master->cleanup = omap2_mcspi_cleanup;
master->dev.of_node = node;
master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3] spi: omap2-mcspi: Add support for GPIO chipselects
[not found] ` <1430955472-11409-1-git-send-email-mwelling-EkmVulN54Sk@public.gmane.org>
@ 2015-05-07 18:58 ` Mark Brown
2015-05-07 19:20 ` Michael Welling
0 siblings, 1 reply; 6+ messages in thread
From: Mark Brown @ 2015-05-07 18:58 UTC (permalink / raw)
To: Michael Welling
Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1: Type: text/plain, Size: 780 bytes --]
On Wed, May 06, 2015 at 06:37:52PM -0500, Michael Welling wrote:
> This patch allows for GPIOs specified in the devicetree to be used as SPI
> chipselects on TI OMAP2 SoCs.
>
> Tested on the AM3354.
>
> Signed-off-by: Michael Welling <mwelling-EkmVulN54Sk@public.gmane.org>
> ---
> v3: Switches driver to use transfer_one instead of transfer_one_message
> allowing the spi core to handle toggling GPIO chip selects if specified.
This is now two changes so it should be two patches, one converting to
transfer_one() and another adding the GPIO chip select support. This
makes things easier to review and helps people trying to understand the
git history in the future (right now there's not even a mention of the
conversion to transfer_one() in the changelog).
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3] spi: omap2-mcspi: Add support for GPIO chipselects
2015-05-07 18:58 ` Mark Brown
@ 2015-05-07 19:20 ` Michael Welling
2015-05-07 19:27 ` Mark Brown
0 siblings, 1 reply; 6+ messages in thread
From: Michael Welling @ 2015-05-07 19:20 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-kernel
On Thu, May 07, 2015 at 07:58:31PM +0100, Mark Brown wrote:
> On Wed, May 06, 2015 at 06:37:52PM -0500, Michael Welling wrote:
> > This patch allows for GPIOs specified in the devicetree to be used as SPI
> > chipselects on TI OMAP2 SoCs.
> >
> > Tested on the AM3354.
> >
> > Signed-off-by: Michael Welling <mwelling@ieee.org>
> > ---
> > v3: Switches driver to use transfer_one instead of transfer_one_message
> > allowing the spi core to handle toggling GPIO chip selects if specified.
>
> This is now two changes so it should be two patches, one converting to
> transfer_one() and another adding the GPIO chip select support. This
> makes things easier to review and helps people trying to understand the
> git history in the future (right now there's not even a mention of the
> conversion to transfer_one() in the changelog).
Okay. I will break it down into a patch series.
Do you have any other suggestions or comments on the patch so that I
can incorporate those changes as well in the patch series?
I noticed a few oddities in the code when converting.
For instance:
http://lxr.free-electrons.com/source/drivers/spi/spi-omap2-mcspi.c#L1225
What is the point of trying to print tx or rx given the if statement
insures that rx_buff and tx_buff are NULL?
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3] spi: omap2-mcspi: Add support for GPIO chipselects
2015-05-07 19:20 ` Michael Welling
@ 2015-05-07 19:27 ` Mark Brown
[not found] ` <20150507192758.GR22845-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
0 siblings, 1 reply; 6+ messages in thread
From: Mark Brown @ 2015-05-07 19:27 UTC (permalink / raw)
To: Michael Welling
Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1: Type: text/plain, Size: 685 bytes --]
On Thu, May 07, 2015 at 02:20:19PM -0500, Michael Welling wrote:
> On Thu, May 07, 2015 at 07:58:31PM +0100, Mark Brown wrote:
> > makes things easier to review and helps people trying to understand the
> Do you have any other suggestions or comments on the patch so that I
> can incorporate those changes as well in the patch series?
No, that's part of the "easier to review" bit.
> I noticed a few oddities in the code when converting.
> For instance:
> http://lxr.free-electrons.com/source/drivers/spi/spi-omap2-mcspi.c#L1225
> What is the point of trying to print tx or rx given the if statement
> insures that rx_buff and tx_buff are NULL?
I expect it's just a buggy test.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3] spi: omap2-mcspi: Add support for GPIO chipselects
[not found] ` <20150507192758.GR22845-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2015-05-07 19:38 ` Michael Welling
2015-05-07 19:56 ` Mark Brown
0 siblings, 1 reply; 6+ messages in thread
From: Michael Welling @ 2015-05-07 19:38 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
On Thu, May 07, 2015 at 08:27:58PM +0100, Mark Brown wrote:
> On Thu, May 07, 2015 at 02:20:19PM -0500, Michael Welling wrote:
> > On Thu, May 07, 2015 at 07:58:31PM +0100, Mark Brown wrote:
>
> > > makes things easier to review and helps people trying to understand the
>
> > Do you have any other suggestions or comments on the patch so that I
> > can incorporate those changes as well in the patch series?
>
> No, that's part of the "easier to review" bit.
The first two hunks are the only GPIO related code.
The rest is all conversion to transfer_one.
>
> > I noticed a few oddities in the code when converting.
>
> > For instance:
> > http://lxr.free-electrons.com/source/drivers/spi/spi-omap2-mcspi.c#L1225
>
> > What is the point of trying to print tx or rx given the if statement
> > insures that rx_buff and tx_buff are NULL?
>
> I expect it's just a buggy test.
Not sure I understand what you mean.
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3] spi: omap2-mcspi: Add support for GPIO chipselects
2015-05-07 19:38 ` Michael Welling
@ 2015-05-07 19:56 ` Mark Brown
0 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2015-05-07 19:56 UTC (permalink / raw)
To: Michael Welling
Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1: Type: text/plain, Size: 671 bytes --]
On Thu, May 07, 2015 at 02:38:52PM -0500, Michael Welling wrote:
> On Thu, May 07, 2015 at 08:27:58PM +0100, Mark Brown wrote:
> > On Thu, May 07, 2015 at 02:20:19PM -0500, Michael Welling wrote:
> > > On Thu, May 07, 2015 at 07:58:31PM +0100, Mark Brown wrote:
> > > I noticed a few oddities in the code when converting.
> > > For instance:
> > > http://lxr.free-electrons.com/source/drivers/spi/spi-omap2-mcspi.c#L1225
> > > What is the point of trying to print tx or rx given the if statement
> > > insures that rx_buff and tx_buff are NULL?
> > I expect it's just a buggy test.
> Not sure I understand what you mean.
I expect that the code is just being silly.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2015-05-07 19:56 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-05-06 23:37 [PATCH v3] spi: omap2-mcspi: Add support for GPIO chipselects Michael Welling
[not found] ` <1430955472-11409-1-git-send-email-mwelling-EkmVulN54Sk@public.gmane.org>
2015-05-07 18:58 ` Mark Brown
2015-05-07 19:20 ` Michael Welling
2015-05-07 19:27 ` Mark Brown
[not found] ` <20150507192758.GR22845-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2015-05-07 19:38 ` Michael Welling
2015-05-07 19:56 ` Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).