aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/lib/spi/spidev.c
blob: 929b61aa9f421270ba82d5faf450dcc6827a76b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//
// Copyright 2017 Ettus Research (National Instruments)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include "spidev.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <stdio.h>

int init_spi(int *fd, const char *device,
    const uint32_t mode,
    const uint32_t speed_hz,
    const uint8_t bits_per_word,
    const uint16_t delay_us
) {
    int err;

    *fd = open(device, O_RDWR);
    if (*fd < 0) {
        fprintf(stderr, "%s: Failed to open device\n", __func__);
        return err;
    }

    uint32_t requested_mode = mode;
    err = ioctl(*fd, SPI_IOC_WR_MODE32, &mode);
    if (err < 0) {
        fprintf(stderr, "%s: Failed to set mode\n", __func__);
        return err;;
    }

    err = ioctl(*fd, SPI_IOC_RD_MODE32, &mode);
    if (err < 0) {
        fprintf(stderr, "%s: Failed to get mode\n", __func__);
        return err;
    }
    if (requested_mode != mode) {
        return 2;
    }

    uint8_t requested_bits_per_word;
    err = ioctl(*fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word);
    if (err < 0) {
        fprintf(stderr, "%s: Failed to set bits per word\n", __func__);
        return err;
    }
    err = ioctl(*fd, SPI_IOC_RD_BITS_PER_WORD, &bits_per_word);
    if (err) {
        fprintf(stderr, "%s: Failed to get bits per word\n", __func__);
        return err;
    }
    if (requested_bits_per_word != bits_per_word) {
        return 2;
    }

    uint32_t requested_speed_hz = speed_hz;
    err = ioctl(*fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed_hz);
    if (err < 0) {
        fprintf(stderr, "%s: Failed to set speed\n", __func__);
        return err;
    }
    err = ioctl(*fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed_hz);
    if (err < 0) {
        fprintf(stderr, "%s: Failed to get speed\n", __func__);
        return err;
    }
    if (requested_speed_hz != speed_hz) {
        return 2;
    }

    return 0;
}

int transfer(
        int fd,
        uint8_t *tx, uint8_t *rx, uint32_t len,
        uint32_t speed_hz, uint8_t bits_per_word, uint16_t delay_us
) {
    int err;

    struct spi_ioc_transfer tr = {
        .tx_buf = (unsigned long) tx,
        .rx_buf = (unsigned long) rx,
        .len = len,
        .speed_hz = speed_hz,
        .delay_usecs = delay_us,
        .bits_per_word = bits_per_word,
        .cs_change = 0,
        .tx_nbits = 1, // Standard SPI
        .rx_nbits = 1 // Standard SPI
    };

    err = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if (err < 0) {
        fprintf(stderr, "%s: Failed ioctl: %d\n", __func__, err);
        perror("ioctl: \n");
	return err;
    }

    return 0;
}