2010-11-04 05:00:24     Clarification in SPIDEV driver

Document created by Aaronwu Employee on Aug 27, 2013
Version 1Show Document
  • View in full screen mode

2010-11-04 05:00:24     Clarification in SPIDEV driver

Shyam sundar (INDIA)

Message: 95548   

 

I am using spidev device driver(spidev0.6) for configuring a codec

 

The slave select goes low only when a data transfer happens from the blackfin(master) to codec(slave).How can I make the slave select line to go low untill all the control words are transmitted to the codec? (The codec chip is not being provided with the option to read back what was being configured). The codec works fine in the vdsp environment.Around 40% of the time I am not able to configure the codec successfully.

 

The following is the userspace code I am using to configure the codec

 

 

 

/******CONFIGURE SPI INTERFACE SENDING CONTROL WORDS CLOCK FOR CODEC*******/

 

    printf("Configuring codec through SPI........\n");

  

    spi_fd = open(device, O_RDWR);

    if (spi_fd < 0)

    {

        close(sport1_fd);

        printf("can't open SPI device");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_WR_MODE, &mode);

    if (ret == -1)

    {

        close(sport1_fd);

        printf("can't set SPI mode");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_RD_MODE, &mode);

    if (ret == -1)

    {

        close(sport1_fd);  

        printf("can't get SPI mode");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits);

    if (ret == -1)

    {

        close(sport1_fd);  

        printf("can't set bits per word for SPI");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits);

    if (ret == -1)

    {

        close(sport1_fd);

        printf("can't get bits per word for SPI");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);

    if (ret == -1)

    {

        close(sport1_fd);

        printf("can't set max speed hz for SPI");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);

    if (ret == -1)

    {

        close(sport1_fd);

        printf("can't get max speed hz for SPI");

        return -1;

    }

 

    printf("spi mode: %d\n", mode);

    printf("bits per word: %d\n", bits);

    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

 

 

/****SEND THE CONTROL WORDS FOR CODEC THROUGH SPI INTERFACE****/

 

    write(spi_fd,control_word_buf,8);

  

    close(spi_fd);

    close(sport1_fd);

QuoteReplyEditDelete

 

 

2010-11-04 05:44:52     Re: Clarification in SPIDEV driver

Aaron Wu (CHINA)

Message: 95550   

 

The CS line toggles once every SPI data transfer unit, this looks fine and should be compliant with the SPI timming chart. Do you think keeping the CS line permanently low will help in your case? if so think about connecting a resistor of low value like 100 Ohm between the CS line and ground then have a try.

QuoteReplyEditDelete

 

 

2010-11-04 07:21:28     Re: Clarification in SPIDEV driver

Shyam sundar (INDIA)

Message: 95556   

 

Hi Aaron.

 

I could have done that, but I do have other SPI devices,Hence I dont want the CS line to be permanently connected to go low. I just want to ensure the CS line remains low just before the config data is transmitted and goes back to high after the config data is transmitted.So how can control this CS line?

QuoteReplyEditDelete

 

 

2010-11-04 22:56:16     Re: Clarification in SPIDEV driver

Aaron Wu (CHINA)

Message: 95576   

 

Are you using the general SPI or SPI over SPORT?

 

In my understanding, the SPI protocol requires the CS line to toggle between each transfer words, and this is the default behavior of our SPI driver. From your description I guess the permanent low for CS line is required by your codec timming chart right?

 

I think you can try to configure this as needed, from the hardware reference manual this should be configurable, copy part of it for your reference:

 

Slave Select Value (FLGx) bits

When a PFx pin is configured as a slave select output, the FLGx bits

can determine the value driven onto the output. If the CPHA bit in

SPI_CTL is set, the output value is set by software control of the

FLGx bits. The SPI protocol permits the slave select line to either

remain asserted (low) or be deasserted between transferred words.

The user must set or clear the appropriate FLGx bits. For example,

to drive PF3 as a slave select, FLS3 in SPI_FLG must be set. Clearing

FLG3 in SPI_FLG drives PF3 low; setting FLG3 drives PF3 high. The

PF3 pin can be cycled high and low between transfers by setting

and clearing FLG3. Otherwise, PF3 remains active (low) between

transfers.

If CPHA = 0, the SPI hardware sets the output value and the FLGx

bits are ignored. The SPI protocol requires that the slave select be

deasserted between transferred words. In this case, the SPI hardware

controls the pins. For example, to use PF3 as a slave select pin,

it is only necessary to set the FLS3 bit in SPI_FLG. It is not necessary

to write to the FLG3 bit, because the SPI hardware automatically

drives the PF3 pin.

QuoteReplyEditDelete

 

 

2010-11-05 03:38:34     Re: Clarification in SPIDEV driver

Aaron Wu (CHINA)

Message: 95586   

 

one more thing, if the "CS pamerment low" is required by your device timming chart, I think the quick way to verify is to connect a resistor to ground as I suggested in the previous post, as the standard SPI framework in Linux does not support this from software I think.

 

For you consideration of multiple SPI devices in your system, I think it does not matter. As for SPI bus, each CS line is dedicately assigned to a single device only, multiple devices are connected to different CS lines, so hardware reworking the CS line to your codec is safe for other SPI devices.

QuoteReplyEditDelete

 

 

2010-11-05 13:05:38     Re: Clarification in SPIDEV driver

Wojtek Skulski (UNITED STATES)

Message: 95596   

 

The resistor to ground will only work if the CS line is tristated when the devices is deselected. In case the CS line is actively driven, it will overcome the resistor when it is driven HIGH. I do not know which is the case in Blackfin hardware, but I would be somewhat surprised to learn that the CS is left floating when the device is not selected. If this was the case then one would need a pullpup for every SPI device.

QuoteReplyEditDelete

 

 

2010-11-07 21:03:34     Re: Clarification in SPIDEV driver

Aaron Wu (CHINA)

Message: 95615   

 

Hi,

 

What's the latest status?

 

It's just a quick test for you to decide if the CS line should really be "always low" during bytes transfer in your case, as this does not confirm with the standard protocol.

 

If it really need to be "always low", then you need to hack the spi driver to meet the requirement, or use GPIO to achive it instead of the hardware SPI module.

QuoteReplyEditDelete

 

 

2010-11-07 22:32:27     Re: Clarification in SPIDEV driver

Sonic Zhang (CHINA)

Message: 95620   

 

You best choice for non stantard SPI device is to separate it from other standard SPI devices under Linux SPI framework. Connect it to SPI over SPORT and write your own SPI over SPORT driver.

QuoteReplyEditDelete

 

 

2010-11-09 01:43:31     Re: Clarification in SPIDEV driver

Shyam sundar (INDIA)

Message: 95678   

 

Sorry for reverting back lately,

 

I am using the normal SPI and not SPI over sport.

 

I am trying to configure the codec through the SPI, the codec's requirement for the master clock is accomplished using thethe serial clock generated by SPORT1 and the data samples to the codec are given through SPORT0.

 

When the codec gets configured, I do have a probing pin on the codec chip which will read 1.1 V when it gets configured.The codec fails to get configured for around 30% of the time. I am trying to analyse if there is any issues in the timings.

 

My doubt is if I enable the slave line permanently through hardware, will it not corrupt the codec chip configuration due to some junk data?

QuoteReplyEditDelete

 

 

2010-11-09 02:25:45     Re: Clarification in SPIDEV driver

Mike Frysinger (UNITED STATES)

Message: 95679   

 

please read the documentation in the spidev.h header.  create an array of spi transfers, set the cs_change field as you need, and then do a single SPI_IOC_MESSAGE() ioctl.

 

if you need a certain SPI mode where the Blackfin SPI master controls the CS via hardware, then use it in GPIO CS mode instead as documented in the wiki:

  docs.blackfin.uclinux.org/doku.php?id=spi#device_resources

QuoteReplyEditDelete

 

 

2010-11-09 02:26:15     Re: Clarification in SPIDEV driver

Mike Frysinger (UNITED STATES)

Message: 95680   

 

also, this is a Linux issue, not u-boot.  please select the correct forum in the future when posting questions.  ive moved it for you this time.

QuoteReplyEditDelete

 

 

2010-11-09 23:00:33     Re: Clarification in SPIDEV driver

Sonic Zhang (CHINA)

Message: 95718   

 

"Nonstandard SPI" here means your SPI device doens't obey the SPI protocol used by kernel SPI framework, no matter you connect it to SPI or SPORT.

QuoteReplyEditDelete

 

 

2010-11-10 03:26:56     Re: Clarification in SPIDEV driver

Shyam sundar (INDIA)

Message: 95734   

 

Thanks to all,

 

Please rectify,if I am wrong

 

So if the user wants to control the slave select manually then, we need to set chip_select = 0 and add a cs_gpio to our controller_data. i.e, if I want to use spidev0.6 then in the path uClinux-dist/linux-2.6.x/arch/blackfin/mach-bf537/boards/stamp.c the following lines should be present. Then the user can use the GPIO driver to make the slave select line go high or low accordingly.

 

 

 

#if defined(CONFIG_BFIN_SPI_CODEC)

 

static struct bfin5xx_spi_chip spi_codec_chip_info = {

    .enable_dma = 1,         /* use dma transfer with this chip*/

 

    .bits_per_word = 16,

 

.cs_gpio = GPIO_PF04

 

};

#endif

 

 

static struct spi_board_info bfin_spi_board_info[] __initdata = {

 

#if defined(CONFIG_BFIN_SPI_CODEC)

    {

        .modalias = "spidev", /* Name of spi_driver for this device */

        .max_speed_hz = 3250000,     /* max spi clock (SCK) speed in HZ */

        .bus_num = 0, /* Framework bus number */

        .chip_select = 0, /* Framework chip select. */

        .platform_data = NULL, /* No spi_driver specific config */

        .controller_data = &spi_codec_chip_info,

    },

#endif

}

QuoteReplyEditDelete

 

 

2010-11-10 04:02:50     Re: Clarification in SPIDEV driver

Sonic Zhang (CHINA)

Message: 95735   

 

The spi_bfin5xx always driver the CS automatically no matter which kind of CS PIN you enabled. Because the kernel SPI framework driver doesn't allow manual CS control by upper level users.

 

Your only choice is to write your own SPI char driver out of the SPI framework.

QuoteReplyEditDelete

 

 

2010-11-10 04:09:58     Re: Clarification in SPIDEV driver

Mike Frysinger (UNITED STATES)

Message: 95736   

 

if our SPI master driver doesnt respect spi_transfer.cs_change, then our driver is broken.  but both our masters support it.

QuoteReplyEditDelete

 

 

2010-11-10 04:41:54     Re: Clarification in SPIDEV driver

Sonic Zhang (CHINA)

Message: 95742   

 

But, the customer wants to low the CS during all messages transfered through SPI, according to his sample code. The cs_change only toggles the CS between transfers within a message, other than between messages.

 

If the customer can bundle all messages into one message with several transfers, cs_change can be an option.

QuoteReplyEditDelete

 

 

2010-11-10 04:44:14     Re: Clarification in SPIDEV driver

Sonic Zhang (CHINA)

Message: 95743   

 

OK. Look again, it seems the customer want to send only one buffer? If so, the setting cs_change = 0 is the solution.

QuoteReplyEditDelete

 

 

2010-11-10 04:52:34     Re: Clarification in SPIDEV driver

Mike Frysinger (UNITED STATES)

Message: 95744   

 

which is what i suggested

  blackfin.uclinux.org/gf/forummessage/95679

QuoteReplyEditDelete

 

 

2010-11-10 05:30:36     Re: Clarification in SPIDEV driver

Shyam sundar (INDIA)

Message: 95746   

 

Ooops, I am getting little confused with the discussions going on here

 

Sonic Zhang says that user will not have the manual control of the slave select pin.

 

So what is the use of  setting chip_select = 0 and add a cs_gpio to in the controller_data, when you can directly specify the the slave line using chip_select?

QuoteReplyEditDelete

 

 

2010-11-10 05:38:29     Re: Clarification in SPIDEV driver

Shyam sundar (INDIA)

Message: 95747   

 

Does my assumption as posted  in the following link,holds true??

 

  blackfin.uclinux.org/gf/forummessage/95734

QuoteReplyEditDelete

 

 

2010-11-10 05:54:05     Re: Clarification in SPIDEV driver

Aaron Wu (CHINA)

Message: 95748   

 

Could you try Mike's suggestion and check if it will solve your problem? If not please probe the waveform of the SPI interface with a oscilloscope and compare it with the expected one specified in your codec specificaiton or the working ones in other situation you mentioned, tell us the difference and let's go on to figure out a solution.

QuoteReplyEditDelete

 

 

2010-11-10 09:22:54     Re: Clarification in SPIDEV driver

Shyam sundar (INDIA)

Message: 95750   

 

Before Mike's suggestion I had earlier used SPI_IOC_MESSAGE() ioctl to write the config words for the codec. During that time I was using SPI in SPI_MODE_0 mode. In this mode, I was seeing the slave select line going high between the transfer words.When I used SPI_MODE_1 mode, I saw the slave select line going low at the start of the data transfer and then high when all the data was transfered. This I think, is the behaviour of the standard SPI protocol.

 

I will try to use the settings which I have posted in the forum as suggested by Mike and revert back !!

QuoteReplyEditDelete

 

 

2010-11-11 06:54:24     Re: Clarification in SPIDEV driver

Shyam sundar (INDIA)

Message: 95773   

 

I am not able to control the slave select manually :(c ! This is the code I am using in the userspace.

 

Do i need to control the slave select (gpio pf4) in the spidev driver? I am using SPI in SPI_MODE_1

 

 

 

    sleep(4);

 

    pf4_fd = open("/dev/gpio4",O_WRONLY);

    write(pf4_fd,&set_low,1);

 

    sleep(2);

 

 

/******CONFIGURE SPI INTERFACE SENDING CONTROL WORDS CLOCK FOR CODEC*******/

 

    printf("Configuring codec through SPI........\n");

  

    spi_fd = open(device, O_RDWR);

    if (spi_fd < 0)

    {

        close(sport1_fd);

        printf("can't open SPI device");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_WR_MODE, &mode);

    if (ret == -1)

    {

        close(sport1_fd);

        printf("can't set SPI mode");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_RD_MODE, &mode);

    if (ret == -1)

    {

        close(sport1_fd);  

        printf("can't get SPI mode");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits);

    if (ret == -1)

    {

        close(sport1_fd);  

        printf("can't set bits per word for SPI");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits);

    if (ret == -1)

    {

        close(sport1_fd);

        printf("can't get bits per word for SPI");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);

    if (ret == -1)

    {

        close(sport1_fd);

        printf("can't set max speed hz for SPI");

        return -1;

    }

 

    ret = ioctl(spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);

    if (ret == -1)

    {

        close(sport1_fd);

        printf("can't get max speed hz for SPI");

        return -1;

    }

 

    printf("spi mode: %d\n", mode);

    printf("bits per word: %d\n", bits);

    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

 

 

/****SEND THE CONTROL WORDS FOR CODEC THROUGH SPI INTERFACE****/

 

 

      sleep(1);

      tx_codec_ctl_word(spi_fd);

  

    sleep(4);

    write(pf4_fd,&set_high,1);

  

    close(spi_fd);

    close(pf4_fd);

    close(sport1_fd);

 

 

 

 

 

static void tx_codec_ctl_word(int fd)

{

    int ret;

 

    uint8_t tx[] = {0x88,0x84,0x25,0x89,};

 

    uint8_t rx[ARRAY_SIZE(tx)] = {0, };

 

    struct spi_ioc_transfer tr = {

        .tx_buf = (unsigned long)tx,

        .rx_buf = (unsigned long)rx,

        .len = ARRAY_SIZE(tx),

        .delay_usecs = delay,

        .speed_hz = speed,

        .bits_per_word = bits,

 

    };

 

    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);

    if (ret == 1)

    {

        close(spi_fd);      

        close(sport1_fd);

        printf("can't send spi message");

    }

 

}

QuoteReplyEditDelete

 

 

2010-11-11 09:48:10     Re: Clarification in SPIDEV driver

Mike Frysinger (UNITED STATES)

Message: 95776   

 

you cannot use a pin as both GPIO and slave CS at the same time.  forget about driving the GPIO manually for now.

QuoteReplyEditDelete

 

 

2010-11-12 07:22:11     Re: Clarification in SPIDEV driver

Rob Maris (GERMANY)

Message: 95801   

 

Shyam, which version of Linux are you using? I have to emphasize that the wiki information only applies to recent linux (from 2.6.34 on, yet into distribution version 2010. There have been introduced signicant changes in how to specify the gpio-mode GPIO.

 

Add .cs_change = 0 into your 'tr' struct definition.

QuoteReplyEditDelete

 

 

2011-05-12 12:33:10     Re: Clarification in SPIDEV driver

Ciaran Watterson (IRELAND)

Message: 100619   

 

"if our SPI master driver doesnt respect spi_transfer.cs_change, then our driver is broken.  but both our masters support it."

 

I've been doing some testing of spidev recently, and as far as I can make out it doesn't except when a GPIO CS is used. This is on a BF-527.

 

"So what is the use of  setting chip_select = 0 and add a cs_gpio to in the controller_data, when you can directly specify the the slave line using chip_select?"

 

The Chip Select pin is used as a GPIO, with software, still controlled by the spi_bfin5xx driver. In the latest version cs_gpio is no longer exposed. As explained in the wiki:

 

.chip_select = GPIO_XXX + MAX_CTRL_CS

 

But not mentioned in the wiki: for your spi master

 

.num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS;

 

IMO the other way was better. My tests were done using the SPI_IOC_MESSAGE() ioctl method. Using this method, I think the mode you want can be achieved. A falling edge at the start of tx and rising edge only when all the bytes have been written, possibly in several batches. I've attached a scope capture in case I misunderstood the mode being discussed.

 

ucLin_SPI_GPIO.png

QuoteReplyEditDelete

 

 

2011-05-12 12:38:31     Re: Clarification in SPIDEV driver

Mike Frysinger (UNITED STATES)

Message: 100620   

 

the old way of "hiding" the CS from the common code via .cs_gpio is simply not possible.  the common code detects and rejects this behavior.

Attachments

Outcomes