简体   繁体   中英

SPI doesn't work as expected in MODE_0 on Odroid-C1. Linux Kernel pinctrl subsystem.

I'm trying to use a UBlox NEO-7M GPS receiver on an Odroid-C1 board.

By default the GPS module works in the SPI's first mode. That's why I use this userspace code snippet to select the proper SPI mode.

    int mode = SPI_MODE_0;

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

    if (ret < 0) {
        perror("can't set spi mode");        
        exit(1);
    }   

After that I'm trying to read a byte at a time and send it to stdout. It doesn't work out, though.

After some thought I plugged my Salaea's logic analyzer and got this picture

spi模式

This doesn't seem right at all. If I'm not mistaken SCL should be driven low between transactions.

I tried to fix this issue by pulling SCL line down in spicc.ko kernel module (I use this kernel with a RT-patch to compile the module. RT-patch doesn't really make any difference. The issue is experienced on a vanilla kernel as well).

Thus, the main question is: is pulling this pin down the right thing to do?

As I further looked into the code I noticed that spicc_set_mode() does set mode as described in Amlogic S805 datasheet (section 15.5.3 describes CONREG register layout). Maybe that's not enough?

Either way, what is the intended way to pull down a pin using Linux' pinctrl interface?

I'm also trying to understand spicc's code. It uses

ret = of_property_read_string(pdev->dev.of_node, "pinctrl-names", &prop_name);
if(ret || IS_ERR(prop_name)) {
    dev_err(&pdev->dev, "match pinctrl-names failed!\n");
    return -ENODEV;
}
pdata->pinctrl = devm_pinctrl_get_select(&pdev->dev, prop_name);
if(IS_ERR(pdata->pinctrl)) {
    dev_err(&pdev->dev, "pinmux error\n");
    return -ENODEV;
}
dev_info(&pdev->dev, "pinctrl_name = %s\n", prop_name);

to get pinctrl handle from Device Tree Blob, doesn't it? Am I supposed to edit .dts file to pull down the pin or it can be done in runtime?

At first I tried to use it by dumb brutal force code but it didn't work (pinctrl is already using this pin as declared in .dts file in spicc section).

static void spicc_sclk_init(void)
{
    int ret;
    int gpio;
    char *owner = "spicc_sclk";
    char *pin_name = "GPIOX_8";

    gpio = amlogic_gpio_name_map_num(pin_name);

    if (gpio < 0) {
        printk(KERN_ERR "amlogic_gpio_name_map_num() failed. gpio: %d\n", gpio);
        goto out_map;
    }

    ret = amlogic_gpio_request(gpio, owner);

    if (ret < 0) {
        printk(KERN_ERR "amlogic_gpio_request_one() failed. ret: %d\n", ret);
        goto out_request;
    }

    ret = amlogic_set_pull_up_down(gpio, 0, owner);

    if (ret < 0) {
        printk(KERN_ERR "amlogic_set_pull_up_down() failed. ret: %d\n", ret);
        goto out_pull_up_down;
    }

out_pull_up_down:
out_request:
out_map:
    ;
}

Does anyone have any suggestions how this issue can be fixed?

PS: I use the same userspace code on a RPi with a same UBlox and the code does work and modes are switched as expected.

I tried to hook up another SPI-driven device to Odroid-C1 (it was Invensense's MPU9260, if that matters.) and did it work. My guess that it's just more SPI mode tolerant .

Maybe the PIN configuration for this PIN has some internal Pull-UP activated. You can try to check if any of the SPI Modes are working. Another point toch check if there is any Pull-UP in the system. And it may worth to measure the voltage in the idle state.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM