diff mbox

[4/4] spi: bcm2835aux: fix CPOL/CPHA setting

Message ID 1455041435-8015-5-git-send-email-stephanolbrich@gmx.de (mailing list archive)
State New, archived
Headers show

Commit Message

Stephan Olbrich Feb. 9, 2016, 6:10 p.m. UTC
From: Stephan Olbrich <stephanolbrich@gmx.de>

The auxiliary spi supports only CPHA=0 modes as the first bit is
always output to the pin before the first clock cycle. In CPHA=1
modes the first clock edge outputs the second bit hence the slave
can never read the first bit.

Also the CPHA registers switch between clocking data in/out on
rising/falling edge hence depend on the CPOL setting.

Signed-off-by: Stephan Olbrich <stephanolbrich@gmx.de>
---
 drivers/spi/spi-bcm2835aux.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

Comments

Stefan Wahren Feb. 9, 2016, 8:21 p.m. UTC | #1
Hi Stephan,

Am 09.02.2016 um 19:10 schrieb stephanolbrich@gmx.de:
> From: Stephan Olbrich <stephanolbrich@gmx.de>
>
> The auxiliary spi supports only CPHA=0 modes as the first bit is
> always output to the pin before the first clock cycle. In CPHA=1
> modes the first clock edge outputs the second bit hence the slave
> can never read the first bit.

in case auxiliary spi isn't able to handle all modes shouldn't we report 
this to the upper layers?

Regards
Eric Anholt Feb. 10, 2016, 12:13 a.m. UTC | #2
stephanolbrich@gmx.de writes:

> From: Stephan Olbrich <stephanolbrich@gmx.de>
>
> The auxiliary spi supports only CPHA=0 modes as the first bit is
> always output to the pin before the first clock cycle. In CPHA=1
> modes the first clock edge outputs the second bit hence the slave
> can never read the first bit.
>
> Also the CPHA registers switch between clocking data in/out on
> rising/falling edge hence depend on the CPOL setting.
>
> Signed-off-by: Stephan Olbrich <stephanolbrich@gmx.de>
> ---
>  drivers/spi/spi-bcm2835aux.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
> index b90aa34..169f521 100644
> --- a/drivers/spi/spi-bcm2835aux.c
> +++ b/drivers/spi/spi-bcm2835aux.c
> @@ -386,12 +386,12 @@ static int bcm2835aux_spi_prepare_message(struct spi_master *master,
>  	bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
>  
>  	/* handle all the modes */
> -	if (spi->mode & SPI_CPOL)
> +	if (spi->mode & SPI_CPOL) {
>  		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
> -	if (spi->mode & SPI_CPHA)
> -		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
> -			       BCM2835_AUX_SPI_CNTL0_CPHA_IN;
> -
> +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT;
> +	} else {
> +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_IN;
> +	}
>  	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
>  	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]);

(Note for other readers: A better name for CNTL0_CPHA_* would be
CNTL0_*_RISING).

I think you're right about not actually supporting CPHA.  I don't see
wany way to keep bit 1 out lasting through the first full clock cycle.
I think Stefan's right that we should drop CPHA from MODE_BITS
(actually, MODE_BITS would be nicer if we just merged it into its one
user, I think).

However, this hunk appears to be correct and would fix the timing of our
data going out in the CPOL=0 case and of sampling IN data for CPOL=1.
Stephan Olbrich Feb. 10, 2016, 8:45 p.m. UTC | #3
Am Tuesday 09 February 2016, 16:13:06 schrieb Eric Anholt:
> stephanolbrich@gmx.de writes:
> > From: Stephan Olbrich <stephanolbrich@gmx.de>
> > 
> > The auxiliary spi supports only CPHA=0 modes as the first bit is
> > always output to the pin before the first clock cycle. In CPHA=1
> > modes the first clock edge outputs the second bit hence the slave
> > can never read the first bit.
> > 
> > Also the CPHA registers switch between clocking data in/out on
> > rising/falling edge hence depend on the CPOL setting.
> > 
> > Signed-off-by: Stephan Olbrich <stephanolbrich@gmx.de>
> > ---
> > 
> >  drivers/spi/spi-bcm2835aux.c | 10 +++++-----
> >  1 file changed, 5 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
> > index b90aa34..169f521 100644
> > --- a/drivers/spi/spi-bcm2835aux.c
> > +++ b/drivers/spi/spi-bcm2835aux.c
> > @@ -386,12 +386,12 @@ static int bcm2835aux_spi_prepare_message(struct
> > spi_master *master,> 
> >  	bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
> >  	
> >  	/* handle all the modes */
> > 
> > -	if (spi->mode & SPI_CPOL)
> > +	if (spi->mode & SPI_CPOL) {
> > 
> >  		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
> > 
> > -	if (spi->mode & SPI_CPHA)
> > -		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
> > -			       BCM2835_AUX_SPI_CNTL0_CPHA_IN;
> > -
> > +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT;
> > +	} else {
> > +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_IN;
> > +	}
> > 
> >  	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
> >  	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]);
> 
> (Note for other readers: A better name for CNTL0_CPHA_* would be
> CNTL0_*_RISING).

Should I rename them? 

> I think you're right about not actually supporting CPHA.  I don't see
> wany way to keep bit 1 out lasting through the first full clock cycle.
> I think Stefan's right that we should drop CPHA from MODE_BITS
> (actually, MODE_BITS would be nicer if we just merged it into its one
> user, I think).

You are right. I'll fix that.
Eric Anholt Feb. 10, 2016, 9:24 p.m. UTC | #4
Stephan Olbrich <stephanolbrich@gmx.de> writes:

> Am Tuesday 09 February 2016, 16:13:06 schrieb Eric Anholt:
>> stephanolbrich@gmx.de writes:
>> > From: Stephan Olbrich <stephanolbrich@gmx.de>
>> > 
>> > The auxiliary spi supports only CPHA=0 modes as the first bit is
>> > always output to the pin before the first clock cycle. In CPHA=1
>> > modes the first clock edge outputs the second bit hence the slave
>> > can never read the first bit.
>> > 
>> > Also the CPHA registers switch between clocking data in/out on
>> > rising/falling edge hence depend on the CPOL setting.
>> > 
>> > Signed-off-by: Stephan Olbrich <stephanolbrich@gmx.de>
>> > ---
>> > 
>> >  drivers/spi/spi-bcm2835aux.c | 10 +++++-----
>> >  1 file changed, 5 insertions(+), 5 deletions(-)
>> > 
>> > diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
>> > index b90aa34..169f521 100644
>> > --- a/drivers/spi/spi-bcm2835aux.c
>> > +++ b/drivers/spi/spi-bcm2835aux.c
>> > @@ -386,12 +386,12 @@ static int bcm2835aux_spi_prepare_message(struct
>> > spi_master *master,> 
>> >  	bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
>> >  	
>> >  	/* handle all the modes */
>> > 
>> > -	if (spi->mode & SPI_CPOL)
>> > +	if (spi->mode & SPI_CPOL) {
>> > 
>> >  		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
>> > 
>> > -	if (spi->mode & SPI_CPHA)
>> > -		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
>> > -			       BCM2835_AUX_SPI_CNTL0_CPHA_IN;
>> > -
>> > +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT;
>> > +	} else {
>> > +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_IN;
>> > +	}
>> > 
>> >  	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
>> >  	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]);
>> 
>> (Note for other readers: A better name for CNTL0_CPHA_* would be
>> CNTL0_*_RISING).
>
> Should I rename them? 

Up to you.  I'm happy to see the work you've done fixing the driver
here, and I don't want to pile things on.
Martin Sperl Feb. 11, 2016, 3:25 p.m. UTC | #5
> On 10.02.2016, at 01:13, Eric Anholt <eric@anholt.net> wrote:
> 
> stephanolbrich@gmx.de writes:
> 
>> From: Stephan Olbrich <stephanolbrich@gmx.de>
>> 
>> The auxiliary spi supports only CPHA=0 modes as the first bit is
>> always output to the pin before the first clock cycle. In CPHA=1
>> modes the first clock edge outputs the second bit hence the slave
>> can never read the first bit.
>> 
>> Also the CPHA registers switch between clocking data in/out on
>> rising/falling edge hence depend on the CPOL setting.
>> 
>> Signed-off-by: Stephan Olbrich <stephanolbrich@gmx.de>
>> ---
>> drivers/spi/spi-bcm2835aux.c | 10 +++++-----
>> 1 file changed, 5 insertions(+), 5 deletions(-)
>> 
>> diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
>> index b90aa34..169f521 100644
>> --- a/drivers/spi/spi-bcm2835aux.c
>> +++ b/drivers/spi/spi-bcm2835aux.c
>> @@ -386,12 +386,12 @@ static int bcm2835aux_spi_prepare_message(struct spi_master *master,
>> 	bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
>> 
>> 	/* handle all the modes */
>> -	if (spi->mode & SPI_CPOL)
>> +	if (spi->mode & SPI_CPOL) {
>> 		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
>> -	if (spi->mode & SPI_CPHA)
>> -		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
>> -			       BCM2835_AUX_SPI_CNTL0_CPHA_IN;
>> -
>> +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT;
>> +	} else {
>> +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_IN;
>> +	}
>> 	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
>> 	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]);
> 
> (Note for other readers: A better name for CNTL0_CPHA_* would be
> CNTL0_*_RISING).
> 
> I think you're right about not actually supporting CPHA.  I don't see
> wany way to keep bit 1 out lasting through the first full clock cycle.
> I think Stefan's right that we should drop CPHA from MODE_BITS
> (actually, MODE_BITS would be nicer if we just merged it into its one
> user, I think).
> 
> However, this hunk appears to be correct and would fix the timing of our
> data going out in the CPOL=0 case and of sampling IN data for CPOL=1.

Are you sure that CPHA is not working?

I have used the following to test all combinations:
 for C in "" "-C"; do
  for O in "" "-O"; do
   for H in "" "-H"; do
    spidev_test -vD /dev/*.1 $H $O -p "\x00\x82\x00" -s 1000000;
   done
  done
 done

I have tested with the 4.5-rc3 kernel without any of your patches.

And looked at the logic-analyzer: I see distinct waveform pattern
for clk and data for all events!

The bug with regards to clock polarity needs to get fixed!

I will now apply patch4 only and see how it looks then...

Thanks,
	Martin
Stephan Olbrich Feb. 11, 2016, 4:05 p.m. UTC | #6
Martin,

Am Thursday 11 February 2016, 16:25:43 schrieb Martin Sperl:
> > On 10.02.2016, at 01:13, Eric Anholt <eric@anholt.net> wrote:
> > 
> > stephanolbrich@gmx.de writes:
> >> From: Stephan Olbrich <stephanolbrich@gmx.de>
> >> 
> >> The auxiliary spi supports only CPHA=0 modes as the first bit is
> >> always output to the pin before the first clock cycle. In CPHA=1
> >> modes the first clock edge outputs the second bit hence the slave
> >> can never read the first bit.
> >> 
> >> Also the CPHA registers switch between clocking data in/out on
> >> rising/falling edge hence depend on the CPOL setting.
> >> 
> >> Signed-off-by: Stephan Olbrich <stephanolbrich@gmx.de>
> >> ---
> >> drivers/spi/spi-bcm2835aux.c | 10 +++++-----
> >> 1 file changed, 5 insertions(+), 5 deletions(-)
> >> 
> >> diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
> >> index b90aa34..169f521 100644
> >> --- a/drivers/spi/spi-bcm2835aux.c
> >> +++ b/drivers/spi/spi-bcm2835aux.c
> >> @@ -386,12 +386,12 @@ static int bcm2835aux_spi_prepare_message(struct
> >> spi_master *master,>> 
> >> 	bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
> >> 	
> >> 	/* handle all the modes */
> >> 
> >> -	if (spi->mode & SPI_CPOL)
> >> +	if (spi->mode & SPI_CPOL) {
> >> 
> >> 		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
> >> 
> >> -	if (spi->mode & SPI_CPHA)
> >> -		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
> >> -			       BCM2835_AUX_SPI_CNTL0_CPHA_IN;
> >> -
> >> +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT;
> >> +	} else {
> >> +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_IN;
> >> +	}
> >> 
> >> 	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
> >> 	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]);
> > 
> > (Note for other readers: A better name for CNTL0_CPHA_* would be
> > CNTL0_*_RISING).
> > 
> > I think you're right about not actually supporting CPHA.  I don't see
> > wany way to keep bit 1 out lasting through the first full clock cycle.
> > I think Stefan's right that we should drop CPHA from MODE_BITS
> > (actually, MODE_BITS would be nicer if we just merged it into its one
> > user, I think).
> > 
> > However, this hunk appears to be correct and would fix the timing of our
> > data going out in the CPOL=0 case and of sampling IN data for CPOL=1.
> 
> Are you sure that CPHA is not working?
> 
> I have used the following to test all combinations:
>  for C in "" "-C"; do
>   for O in "" "-O"; do
>    for H in "" "-H"; do
>     spidev_test -vD /dev/*.1 $H $O -p "\x00\x82\x00" -s 1000000;
>    done
>   done
>  done
> 
> I have tested with the 4.5-rc3 kernel without any of your patches.
> 
> And looked at the logic-analyzer: I see distinct waveform pattern
> for clk and data for all events!

The problem I see, is not that there is no waveform but that it has the wrong 
timing.
I'll make an example:
Data is 0xAA,0xFF, CPOL=1, CPHA=1
What happens is this:
CS goes active and MOSI goes high (first bit in 1)
After a short time, SCLK goes from low to high and MOSI goes to low (second 
bit is 0)
Then SCLK goes low (sampling data)
Then SCLK goes high and MOSI goes high (third bit is 1) 
and so on.
At the end with the last rising edge of SCLK MOSI goes to low and stays there 
while SCLK goes to low and then CS to inactive.

So the slave has no chance to get the first bit but gets an additional 0 at the 
end.
It may not be easy visible with 0x00,0x82,0x00 as data, so could you repeat 
your test with 0xAA,0xFF if you see the same as I do or not?

Thanks,
Stephan
Martin Sperl Feb. 11, 2016, 4:19 p.m. UTC | #7
> On 11.02.2016, at 17:05, Stephan Olbrich <stephanolbrich@gmx.de> wrote:
> 
> Martin,
> 
> Am Thursday 11 February 2016, 16:25:43 schrieb Martin Sperl:
>>> On 10.02.2016, at 01:13, Eric Anholt <eric@anholt.net> wrote:
>>> 
>>> stephanolbrich@gmx.de writes:
>>>> From: Stephan Olbrich <stephanolbrich@gmx.de>
>>>> 
>>>> The auxiliary spi supports only CPHA=0 modes as the first bit is
>>>> always output to the pin before the first clock cycle. In CPHA=1
>>>> modes the first clock edge outputs the second bit hence the slave
>>>> can never read the first bit.
>>>> 
>>>> Also the CPHA registers switch between clocking data in/out on
>>>> rising/falling edge hence depend on the CPOL setting.
>>>> 
>>>> Signed-off-by: Stephan Olbrich <stephanolbrich@gmx.de>
>>>> ---
>>>> drivers/spi/spi-bcm2835aux.c | 10 +++++-----
>>>> 1 file changed, 5 insertions(+), 5 deletions(-)
>>>> 
>>>> diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
>>>> index b90aa34..169f521 100644
>>>> --- a/drivers/spi/spi-bcm2835aux.c
>>>> +++ b/drivers/spi/spi-bcm2835aux.c
>>>> @@ -386,12 +386,12 @@ static int bcm2835aux_spi_prepare_message(struct
>>>> spi_master *master,>> 
>>>> 	bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
>>>> 	
>>>> 	/* handle all the modes */
>>>> 
>>>> -	if (spi->mode & SPI_CPOL)
>>>> +	if (spi->mode & SPI_CPOL) {
>>>> 
>>>> 		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
>>>> 
>>>> -	if (spi->mode & SPI_CPHA)
>>>> -		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
>>>> -			       BCM2835_AUX_SPI_CNTL0_CPHA_IN;
>>>> -
>>>> +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT;
>>>> +	} else {
>>>> +		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_IN;
>>>> +	}
>>>> 
>>>> 	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
>>>> 	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]);
>>> 
>>> (Note for other readers: A better name for CNTL0_CPHA_* would be
>>> CNTL0_*_RISING).
>>> 
>>> I think you're right about not actually supporting CPHA.  I don't see
>>> wany way to keep bit 1 out lasting through the first full clock cycle.
>>> I think Stefan's right that we should drop CPHA from MODE_BITS
>>> (actually, MODE_BITS would be nicer if we just merged it into its one
>>> user, I think).
>>> 
>>> However, this hunk appears to be correct and would fix the timing of our
>>> data going out in the CPOL=0 case and of sampling IN data for CPOL=1.
>> 
>> Are you sure that CPHA is not working?
>> 
>> I have used the following to test all combinations:
>> for C in "" "-C"; do
>>  for O in "" "-O"; do
>>   for H in "" "-H"; do
>>    spidev_test -vD /dev/*.1 $H $O -p "\x00\x82\x00" -s 1000000;
>>   done
>>  done
>> done
>> 
>> I have tested with the 4.5-rc3 kernel without any of your patches.
>> 
>> And looked at the logic-analyzer: I see distinct waveform pattern
>> for clk and data for all events!
> 
> The problem I see, is not that there is no waveform but that it has the wrong 
> timing.
> I'll make an example:
> Data is 0xAA,0xFF, CPOL=1, CPHA=1
> What happens is this:
> CS goes active and MOSI goes high (first bit in 1)
> After a short time, SCLK goes from low to high and MOSI goes to low (second 
> bit is 0)
> Then SCLK goes low (sampling data)
> Then SCLK goes high and MOSI goes high (third bit is 1) 
> and so on.
> At the end with the last rising edge of SCLK MOSI goes to low and stays there 
> while SCLK goes to low and then CS to inactive.
> 
> So the slave has no chance to get the first bit but gets an additional 0 at the 
> end.
> It may not be easy visible with 0x00,0x82,0x00 as data, so could you repeat 
> your test with 0xAA,0xFF if you see the same as I do or not?

I did retest also with 0x81,0x00,0x81 and saw my expected behavior - but maybe
me understanding of those modes is wrong.

I will send you the images for the pattern I have generated with 
0x81, 0x00, 0x81 as a personal email.

Martin
diff mbox

Patch

diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index b90aa34..169f521 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -386,12 +386,12 @@  static int bcm2835aux_spi_prepare_message(struct spi_master *master,
 	bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
 
 	/* handle all the modes */
-	if (spi->mode & SPI_CPOL)
+	if (spi->mode & SPI_CPOL) {
 		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
-	if (spi->mode & SPI_CPHA)
-		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
-			       BCM2835_AUX_SPI_CNTL0_CPHA_IN;
-
+		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT;
+	} else {
+		bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_IN;
+	}
 	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
 	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]);