diff mbox series

[v3,1/6] spi: Add SPI mode bit for MOSI idle state configuration

Message ID e1d5d57f7a7481c84f64a764f9898122e278739b.1717539384.git.marcelo.schmitt@analog.com (mailing list archive)
State Superseded
Headers show
Series Add support for AD4000 series of ADCs | expand

Commit Message

Marcelo Schmitt June 4, 2024, 10:41 p.m. UTC
The behavior of an SPI controller data output line (SDO or MOSI or COPI
(Controller Output Peripheral Input) for disambiguation) is not specified
when the controller is not clocking out data on SCLK edges. However, there
exist SPI peripherals that require specific COPI line state when data is
not being clocked out of the controller.
Add SPI mode bit to allow pheripherals to request explicit COPI idle
behavior when needed.

Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
---
 drivers/spi/spi.c            | 6 ++++++
 include/uapi/linux/spi/spi.h | 3 ++-
 2 files changed, 8 insertions(+), 1 deletion(-)

Comments

Nuno Sá June 5, 2024, 9:14 a.m. UTC | #1
On Tue, 2024-06-04 at 19:41 -0300, Marcelo Schmitt wrote:
> The behavior of an SPI controller data output line (SDO or MOSI or COPI
> (Controller Output Peripheral Input) for disambiguation) is not specified
> when the controller is not clocking out data on SCLK edges. However, there
> exist SPI peripherals that require specific COPI line state when data is
> not being clocked out of the controller.
> Add SPI mode bit to allow pheripherals to request explicit COPI idle
> behavior when needed.
> 
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> ---
>  drivers/spi/spi.c            | 6 ++++++
>  include/uapi/linux/spi/spi.h | 3 ++-
>  2 files changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index 289feccca376..6072b6e93bef 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -3921,6 +3921,12 @@ int spi_setup(struct spi_device *spi)
>  		(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
>  		 SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
>  		return -EINVAL;
> +	/* Check against conflicting MOSI idle configuration */
> +	if ((spi->mode & SPI_MOSI_IDLE_LOW) && (spi->mode &
> SPI_MOSI_IDLE_HIGH)) {
> +		dev_warn(&spi->dev,
> +			 "setup: erratic MOSI idle configuration. Set to idle
> low\n");
> +		spi->mode &= ~SPI_MOSI_IDLE_HIGH;
> +	}

Should we assume such a thing? IOW, should this be treated as a warning or a
real error? I would assume this should be a configuration error and return -
EINVAL but...

- Nuno Sá
Mark Brown June 5, 2024, 12:02 p.m. UTC | #2
On Wed, Jun 05, 2024 at 11:14:33AM +0200, Nuno Sá wrote:
> On Tue, 2024-06-04 at 19:41 -0300, Marcelo Schmitt wrote:

> > +	/* Check against conflicting MOSI idle configuration */
> > +	if ((spi->mode & SPI_MOSI_IDLE_LOW) && (spi->mode &
> > SPI_MOSI_IDLE_HIGH)) {
> > +		dev_warn(&spi->dev,
> > +			 "setup: erratic MOSI idle configuration. Set to idle
> > low\n");
> > +		spi->mode &= ~SPI_MOSI_IDLE_HIGH;
> > +	}

> Should we assume such a thing? IOW, should this be treated as a warning or a
> real error? I would assume this should be a configuration error and return -
> EINVAL but...

Right, and the error message isn't very clear.
Mark Brown June 5, 2024, 12:24 p.m. UTC | #3
On Tue, Jun 04, 2024 at 07:41:47PM -0300, Marcelo Schmitt wrote:

> The behavior of an SPI controller data output line (SDO or MOSI or COPI
> (Controller Output Peripheral Input) for disambiguation) is not specified
> when the controller is not clocking out data on SCLK edges. However, there
> exist SPI peripherals that require specific COPI line state when data is
> not being clocked out of the controller.

This is an optimisation for accelerating devices that need a specific
value, really if these devices need a value they should send it.

>  #define SPI_MOSI_IDLE_LOW	_BITUL(17)	/* leave mosi line low when idle */
> +#define SPI_MOSI_IDLE_HIGH	_BITUL(18)	/* leave mosi line high when idle */

Realistically we'll have a large set of drivers that are expecting the
line to be held low so I'm not sure we need that option.  I would also
expect to have an implementation of these options in the core which
supplies buffers with the relevant data for use with controllers that
don't have the feature (similar to how _MUST_TX and _MUST_RX are done).
Even without that we'd need feature detection so that drivers that try
to use this aren't just buggy when used with a controller that doesn't
implement it, but once you're detecting you may as well just make things
work.
David Lechner June 5, 2024, 4:37 p.m. UTC | #4
On 6/5/24 7:24 AM, Mark Brown wrote:
> On Tue, Jun 04, 2024 at 07:41:47PM -0300, Marcelo Schmitt wrote:
> 
>> The behavior of an SPI controller data output line (SDO or MOSI or COPI
>> (Controller Output Peripheral Input) for disambiguation) is not specified
>> when the controller is not clocking out data on SCLK edges. However, there
>> exist SPI peripherals that require specific COPI line state when data is
>> not being clocked out of the controller.

I think this description is missing a key detail that the tx data line
needs to be high just before and also during the CS assertion at the start
of each message.

And it would be helpful to have this more detailed description in the
source code somewhere and not just in the commit message.

> 
> This is an optimisation for accelerating devices that need a specific
> value, really if these devices need a value they should send it.
> 
>>  #define SPI_MOSI_IDLE_LOW	_BITUL(17)	/* leave mosi line low when idle */
>> +#define SPI_MOSI_IDLE_HIGH	_BITUL(18)	/* leave mosi line high when idle */
> 
> Realistically we'll have a large set of drivers that are expecting the
> line to be held low so I'm not sure we need that option.  I would also
> expect to have an implementation of these options in the core which
> supplies buffers with the relevant data for use with controllers that
> don't have the feature (similar to how _MUST_TX and _MUST_RX are done).
> Even without that we'd need feature detection so that drivers that try
> to use this aren't just buggy when used with a controller that doesn't
> implement it, but once you're detecting you may as well just make things
> work.

I could see something like this working for controllers that leave the
tx data line in the state of the last bit of a write transfer. I.e. do a
write transfer of 0xff (using the smallest number of bits per word
supported by the controller) with CS not asserted, then assert CS, then
do the rest of actual the transfers requested by the peripheral.

But it doesn't seem like it would work for controllers that always
return the tx data line to a low state after a write since this would
mean that the data line would still be low during the CS assertion
which is what we need to prevent.
Mark Brown June 5, 2024, 5:04 p.m. UTC | #5
On Wed, Jun 05, 2024 at 11:37:48AM -0500, David Lechner wrote:
> On 6/5/24 7:24 AM, Mark Brown wrote:
> > On Tue, Jun 04, 2024 at 07:41:47PM -0300, Marcelo Schmitt wrote:

> >> The behavior of an SPI controller data output line (SDO or MOSI or COPI
> >> (Controller Output Peripheral Input) for disambiguation) is not specified
> >> when the controller is not clocking out data on SCLK edges. However, there
> >> exist SPI peripherals that require specific COPI line state when data is
> >> not being clocked out of the controller.

> I think this description is missing a key detail that the tx data line
> needs to be high just before and also during the CS assertion at the start
> of each message.

> And it would be helpful to have this more detailed description in the
> source code somewhere and not just in the commit message.

Yes, there's no way anyone could infer this from any aspect of the
series.  I think the properties also need a clearer name since someone
might want the accelerator functionality at some point.

> > Even without that we'd need feature detection so that drivers that try
> > to use this aren't just buggy when used with a controller that doesn't
> > implement it, but once you're detecting you may as well just make things
> > work.

> I could see something like this working for controllers that leave the
> tx data line in the state of the last bit of a write transfer. I.e. do a
> write transfer of 0xff (using the smallest number of bits per word
> supported by the controller) with CS not asserted, then assert CS, then
> do the rest of actual the transfers requested by the peripheral.

> But it doesn't seem like it would work for controllers that always
> return the tx data line to a low state after a write since this would
> mean that the data line would still be low during the CS assertion
> which is what we need to prevent.

With the additional requirement it's not emulatable, but we'd still need
the checks in the core.
Marcelo Schmitt June 6, 2024, 7:57 p.m. UTC | #6
Hi,

On 06/05, Mark Brown wrote:
> On Tue, Jun 04, 2024 at 07:41:47PM -0300, Marcelo Schmitt wrote:
> 
> > The behavior of an SPI controller data output line (SDO or MOSI or COPI
> > (Controller Output Peripheral Input) for disambiguation) is not specified
> > when the controller is not clocking out data on SCLK edges. However, there
> > exist SPI peripherals that require specific COPI line state when data is
> > not being clocked out of the controller.
> 
> This is an optimisation for accelerating devices that need a specific
> value, really if these devices need a value they should send it.

I see it more like an extension of SPI controller functionality.
Though I guess it might also be used for optimization if tx is known to be
always 0s or always 1s for a device.

> 
> >  #define SPI_MOSI_IDLE_LOW	_BITUL(17)	/* leave mosi line low when idle */
> > +#define SPI_MOSI_IDLE_HIGH	_BITUL(18)	/* leave mosi line high when idle */
> 
> Realistically we'll have a large set of drivers that are expecting the
> line to be held low so I'm not sure we need that option.  I would also
Yes, I also think most SPI devices, if ever requiring anything, would
expect the MOSI line to be low. But this patchset is about the exception to that. :)

> expect to have an implementation of these options in the core which
> supplies buffers with the relevant data for use with controllers that
> don't have the feature (similar to how _MUST_TX and _MUST_RX are done).
> Even without that we'd need feature detection so that drivers that try
> to use this aren't just buggy when used with a controller that doesn't
> implement it, but once you're detecting you may as well just make things
> work.

As far as I searched, the definitions for SPI protocol usually don't specify any
behavior for the MOSI line when the controller is not clocking out data.
So, I think SPI controllers that are not capable of implementing any type
of MOSI idle configuration are anyway compliant to what is usual SPI.
For those that can implement such feature, I thought peripherals could request
it by setting SPI mode bits.
If the controller can provide MOSI idle state configuration, then the controller
sets itself to act according to what peripheral asked.
If MOSI idle configuration is not supported, then we just move on and let
peripheral driver adapt to what is supported?
Guess we can't blame an SPI controller for it not supporting something that is
not specified in usual SPI protocols.

But yeah, it's not that evident what this patch set is all about and why this is
wanted so I made a wiki page to explain the reasoning for this set.
https://wiki.analog.com/software/linux/docs/spi/spi_copi_idle?rev=1717699755
Hopefully the figures with timing diagrams and transfer captures there will 
provide quicker understanding of this rather than I try to explain it with
only text.

If you still think we need feature detection for MOSI idle capability just let
me know, I'll implement what be needed.

Thanks,
Marcelo
Marcelo Schmitt June 6, 2024, 8:10 p.m. UTC | #7
On 06/05, Mark Brown wrote:
> On Wed, Jun 05, 2024 at 11:14:33AM +0200, Nuno Sá wrote:
> > On Tue, 2024-06-04 at 19:41 -0300, Marcelo Schmitt wrote:
> 
> > > +	/* Check against conflicting MOSI idle configuration */
> > > +	if ((spi->mode & SPI_MOSI_IDLE_LOW) && (spi->mode &
> > > SPI_MOSI_IDLE_HIGH)) {
> > > +		dev_warn(&spi->dev,
> > > +			 "setup: erratic MOSI idle configuration. Set to idle
> > > low\n");
> > > +		spi->mode &= ~SPI_MOSI_IDLE_HIGH;
> > > +	}
> 
> > Should we assume such a thing? IOW, should this be treated as a warning or a
> > real error? I would assume this should be a configuration error and return -
> > EINVAL but...
> 
> Right, and the error message isn't very clear.

Yeah, the message is not all that clear. I'll think of something better.
I'm biased towards having this as a warning because I don't see this as a
feature of usual SPI protocol but not really sure about either ...
Marcelo Schmitt June 6, 2024, 10:08 p.m. UTC | #8
On 06/05, Mark Brown wrote:
> On Wed, Jun 05, 2024 at 11:37:48AM -0500, David Lechner wrote:
> > On 6/5/24 7:24 AM, Mark Brown wrote:
> > > On Tue, Jun 04, 2024 at 07:41:47PM -0300, Marcelo Schmitt wrote:
> 
> > >> The behavior of an SPI controller data output line (SDO or MOSI or COPI
> > >> (Controller Output Peripheral Input) for disambiguation) is not specified
> > >> when the controller is not clocking out data on SCLK edges. However, there
> > >> exist SPI peripherals that require specific COPI line state when data is
> > >> not being clocked out of the controller.
> 
> > I think this description is missing a key detail that the tx data line
> > needs to be high just before and also during the CS assertion at the start
> > of each message.
> 
> > And it would be helpful to have this more detailed description in the
> > source code somewhere and not just in the commit message.
> 
> Yes, there's no way anyone could infer this from any aspect of the
> series.  I think the properties also need a clearer name since someone
> might want the accelerator functionality at some point.

So, if I understand correctly, it would be desirable to also have flags and
descriptions for the MOSI idle configuration capabilities in include/linux/spi/spi.h.

Does the following definitions look good?
#define SPI_CONTROLLER_MOSI_IDLE_LOW		BIT(8)
#define SPI_CONTROLLER_MOSI_IDLE_HIGH		BIT(9)

Maybe also document the MOSI idle configuration feature in spi-summary.rst?

> 
> > > Even without that we'd need feature detection so that drivers that try
> > > to use this aren't just buggy when used with a controller that doesn't
> > > implement it, but once you're detecting you may as well just make things
> > > work.
> 
> > I could see something like this working for controllers that leave the
> > tx data line in the state of the last bit of a write transfer. I.e. do a
> > write transfer of 0xff (using the smallest number of bits per word
> > supported by the controller) with CS not asserted, then assert CS, then
> > do the rest of actual the transfers requested by the peripheral.
> 
> > But it doesn't seem like it would work for controllers that always
> > return the tx data line to a low state after a write since this would
> > mean that the data line would still be low during the CS assertion
> > which is what we need to prevent.
> 
> With the additional requirement it's not emulatable, but we'd still need
> the checks in the core.
Mark Brown June 7, 2024, 1:50 p.m. UTC | #9
On Thu, Jun 06, 2024 at 04:57:52PM -0300, Marcelo Schmitt wrote:

> As far as I searched, the definitions for SPI protocol usually don't specify any
> behavior for the MOSI line when the controller is not clocking out data.
> So, I think SPI controllers that are not capable of implementing any type
> of MOSI idle configuration are anyway compliant to what is usual SPI.
> For those that can implement such feature, I thought peripherals could request
> it by setting SPI mode bits.

The issue here is the one that Richard highlighted with it not being
clear exactly what the intended behaviour is.

> But yeah, it's not that evident what this patch set is all about and why this is
> wanted so I made a wiki page to explain the reasoning for this set.
> https://wiki.analog.com/software/linux/docs/spi/spi_copi_idle?rev=1717699755
> Hopefully the figures with timing diagrams and transfer captures there will 
> provide quicker understanding of this rather than I try to explain it with
> only text.

It needs to be apparent to someone looking at the kernel what the code
is intended to do.

> If you still think we need feature detection for MOSI idle capability just let
> me know, I'll implement what be needed.

If the devices actually require this mode then we can't just randomly
ignore them when they request it.
Mark Brown June 7, 2024, 1:51 p.m. UTC | #10
On Thu, Jun 06, 2024 at 07:08:30PM -0300, Marcelo Schmitt wrote:

> So, if I understand correctly, it would be desirable to also have flags and
> descriptions for the MOSI idle configuration capabilities in include/linux/spi/spi.h.

> Does the following definitions look good?
> #define SPI_CONTROLLER_MOSI_IDLE_LOW		BIT(8)
> #define SPI_CONTROLLER_MOSI_IDLE_HIGH		BIT(9)

Yes.

> Maybe also document the MOSI idle configuration feature in spi-summary.rst?

Yes.
Mark Brown June 7, 2024, 1:52 p.m. UTC | #11
On Thu, Jun 06, 2024 at 05:10:04PM -0300, Marcelo Schmitt wrote:
> On 06/05, Mark Brown wrote:

> > > Should we assume such a thing? IOW, should this be treated as a warning or a
> > > real error? I would assume this should be a configuration error and return -
> > > EINVAL but...

> > Right, and the error message isn't very clear.

> Yeah, the message is not all that clear. I'll think of something better.
> I'm biased towards having this as a warning because I don't see this as a
> feature of usual SPI protocol but not really sure about either ...

The less usual it is the more likely it is that it won't be supported
and we should actually check that to try to avoid data corruption.
Marcelo Schmitt June 7, 2024, 2:55 p.m. UTC | #12
On 06/07, Mark Brown wrote:
> On Thu, Jun 06, 2024 at 04:57:52PM -0300, Marcelo Schmitt wrote:
> 
> > As far as I searched, the definitions for SPI protocol usually don't specify any
> > behavior for the MOSI line when the controller is not clocking out data.
> > So, I think SPI controllers that are not capable of implementing any type
> > of MOSI idle configuration are anyway compliant to what is usual SPI.
> > For those that can implement such feature, I thought peripherals could request
> > it by setting SPI mode bits.
> 
> The issue here is the one that Richard highlighted with it not being
> clear exactly what the intended behaviour is.
> 
> > But yeah, it's not that evident what this patch set is all about and why this is
> > wanted so I made a wiki page to explain the reasoning for this set.
> > https://wiki.analog.com/software/linux/docs/spi/spi_copi_idle?rev=1717699755
> > Hopefully the figures with timing diagrams and transfer captures there will 
> > provide quicker understanding of this rather than I try to explain it with
> > only text.
> 
> It needs to be apparent to someone looking at the kernel what the code
> is intended to do.

Ack

> 
> > If you still think we need feature detection for MOSI idle capability just let
> > me know, I'll implement what be needed.
> 
> If the devices actually require this mode then we can't just randomly
> ignore them when they request it.

Ok. Yes, when connected in that datasheet "3-wire" mode the MOSI idle high
feature is pretty much required otherwise users won't be able to sample the ADC.
Will document the behavior for the MOSI idle feature and make spi_setup() fail
with better message if the controller can't support a device requesting it.

Thanks,
Marcelo
diff mbox series

Patch

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 289feccca376..6072b6e93bef 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -3921,6 +3921,12 @@  int spi_setup(struct spi_device *spi)
 		(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
 		 SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
 		return -EINVAL;
+	/* Check against conflicting MOSI idle configuration */
+	if ((spi->mode & SPI_MOSI_IDLE_LOW) && (spi->mode & SPI_MOSI_IDLE_HIGH)) {
+		dev_warn(&spi->dev,
+			 "setup: erratic MOSI idle configuration. Set to idle low\n");
+		spi->mode &= ~SPI_MOSI_IDLE_HIGH;
+	}
 	/*
 	 * Help drivers fail *cleanly* when they need options
 	 * that aren't supported with their current controller.
diff --git a/include/uapi/linux/spi/spi.h b/include/uapi/linux/spi/spi.h
index ca56e477d161..ba9adba25927 100644
--- a/include/uapi/linux/spi/spi.h
+++ b/include/uapi/linux/spi/spi.h
@@ -29,6 +29,7 @@ 
 #define	SPI_3WIRE_HIZ		_BITUL(15)	/* high impedance turnaround */
 #define	SPI_RX_CPHA_FLIP	_BITUL(16)	/* flip CPHA on Rx only xfer */
 #define SPI_MOSI_IDLE_LOW	_BITUL(17)	/* leave mosi line low when idle */
+#define SPI_MOSI_IDLE_HIGH	_BITUL(18)	/* leave mosi line high when idle */
 
 /*
  * All the bits defined above should be covered by SPI_MODE_USER_MASK.
@@ -38,6 +39,6 @@ 
  * These bits must not overlap. A static assert check should make sure of that.
  * If adding extra bits, make sure to increase the bit index below as well.
  */
-#define SPI_MODE_USER_MASK	(_BITUL(18) - 1)
+#define SPI_MODE_USER_MASK	(_BITUL(19) - 1)
 
 #endif /* _UAPI_SPI_H */