dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_spi.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  */
30 #include <pios.h>
31 
32 #if defined(PIOS_INCLUDE_SPI)
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <sys/ioctl.h>
37 #include <linux/types.h>
38 #include <linux/spi/spidev.h>
39 
40 #include <pios_spi_posix_priv.h>
41 
42 struct pios_spi_dev {
43  const struct pios_spi_cfg *cfg;
44  struct pios_semaphore *busy;
45  uint32_t slave_count;
46  uint32_t speed_hz;
47 
48  int fd[SPI_MAX_SUBDEV];
49 
50  int selected;
51 };
52 
53 static bool PIOS_SPI_validate(struct pios_spi_dev *com_dev)
54 {
55  return true;
56 }
57 
58 static struct pios_spi_dev *PIOS_SPI_alloc(void)
59 {
60  return (PIOS_malloc(sizeof(struct pios_spi_dev)));
61 }
62 
63 int32_t PIOS_SPI_Init(pios_spi_t *spi_id, const struct pios_spi_cfg *cfg)
64 {
65  PIOS_Assert(spi_id);
66  PIOS_Assert(cfg);
67 
68  struct pios_spi_dev *spi_dev;
69 
70  spi_dev = (struct pios_spi_dev *)PIOS_SPI_alloc();
71  if (!spi_dev) goto out_fail;
72 
73  /* Bind the configuration to the device instance */
74  spi_dev->cfg = cfg;
75 
76  spi_dev->busy = PIOS_Semaphore_Create();
77  spi_dev->slave_count = 0;
78 
79  for (int i = 0; i < SPI_MAX_SUBDEV; i++) {
80  char path[PATH_MAX + 2];
81 
82  snprintf(path, sizeof(path), "%s.%d", cfg->base_path, i);
83 
84  int fd = open(path, O_RDWR);
85 
86  if (fd < 0) {
87  break;
88  }
89 
90  spi_dev->slave_count = i+1;
91  spi_dev->fd[i] = fd;
92  }
93 
94  for (int i = 0; i < spi_dev->slave_count; i++) {
95  /* Twiddle / ensure slave selects are sane. */
96  PIOS_SPI_RC_PinSet(spi_dev, i, false);
97  PIOS_SPI_RC_PinSet(spi_dev, i, true);
98  }
99 
100 
101  printf("PIOS_SPI: Inited %s, %d subdevs\n", cfg->base_path,
102  spi_dev->slave_count);
103 
104  if (spi_dev->slave_count < 1) {
105  goto out_fail;
106  }
107 
108  /* Must store this before enabling interrupt */
109  *spi_id = spi_dev;
110 
111  return 0;
112 
113 out_fail:
114  printf("PIOS_SPI: fail.\n");
115  return -1;
116 }
117 
118 int32_t PIOS_SPI_SetClockSpeed(pios_spi_t spi_dev, uint32_t spi_speed)
119 {
120  bool valid = PIOS_SPI_validate(spi_dev);
121  PIOS_Assert(valid);
122 
123  spi_dev->speed_hz = spi_speed;
124 
125  return spi_speed; // Don't know the actual speed.
126 }
127 
128 int32_t PIOS_SPI_ClaimBus(pios_spi_t spi_dev)
129 {
130  bool valid = PIOS_SPI_validate(spi_dev);
131  PIOS_Assert(valid);
132 
133  if (PIOS_Semaphore_Take(spi_dev->busy, 65535) != true)
134  return -1;
135 
136  return 0;
137 }
138 
139 int32_t PIOS_SPI_ReleaseBus(pios_spi_t spi_dev)
140 {
141  bool valid = PIOS_SPI_validate(spi_dev);
142  PIOS_Assert(valid);
143 
144  PIOS_Semaphore_Give(spi_dev->busy);
145 
146  return 0;
147 }
148 
149 int32_t PIOS_SPI_RC_PinSet(pios_spi_t spi_dev, uint32_t slave_id, bool pin_value)
150 {
151  bool valid = PIOS_SPI_validate(spi_dev);
152  PIOS_Assert(valid);
153  PIOS_Assert(slave_id < spi_dev->slave_count);
154 
155  struct spi_ioc_transfer xfer = {
156  .delay_usecs = 1,
157  };
158 
159  if (!pin_value) { // Select this device
160  spi_dev->selected = slave_id;
161 
162  xfer.cs_change = 1; // In this context means "leave selected"
163  } else {
164  PIOS_Assert(spi_dev->selected == slave_id);
165 
166  spi_dev->selected = -1;
167 
168  xfer.cs_change = 0;
169  }
170 
171  int status = ioctl(spi_dev->fd[slave_id], SPI_IOC_MESSAGE(1), &xfer);
172 
173  if (status < 0) {
174  perror("ioctl-SPI_IOC_MESSAGE");
175  return -1;
176  }
177 
178  return 0;
179 }
180 
181 uint8_t PIOS_SPI_TransferByte(pios_spi_t spi_dev, uint8_t b)
182 {
183  uint8_t ret = 0;
184 
185  PIOS_SPI_TransferBlock(spi_dev, &b, &ret, 1);
186 
187  return ret;
188 }
189 
190 int32_t PIOS_SPI_TransferBlock(pios_spi_t spi_dev, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len)
191 {
192  bool valid = PIOS_SPI_validate(spi_dev);
193 
194  int slave_id = spi_dev->selected;
195 
196  PIOS_Assert(valid);
197  PIOS_Assert(slave_id < spi_dev->slave_count);
198  PIOS_Assert(slave_id >= 0);
199 
200  struct spi_ioc_transfer xfer = {
201  .rx_buf = (uintptr_t) receive_buffer,
202  .tx_buf = (uintptr_t) send_buffer,
203  .len = len,
204  .speed_hz = spi_dev->speed_hz,
205  .cs_change = 1 // Leave selected
206  };
207 
208  int status = ioctl(spi_dev->fd[slave_id], SPI_IOC_MESSAGE(1), &xfer);
209 
210  if (status < 0) {
211  perror("ioctl-SPI_IOC_MESSAGE");
212  return -1;
213  }
214 
215  return 0;
216 }
217 
218 #endif
219 
char base_path[PATH_MAX]
Main PiOS header to include all the compiled in PiOS options.
int32_t PIOS_SPI_RC_PinSet(pios_spi_t spi_dev, uint32_t slave_id, bool pin_value)
int32_t PIOS_SPI_ClaimBus(pios_spi_t spi_dev)
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
#define SPI_MAX_SUBDEV
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
int16_t status
Definition: main.c:61
struct pios_semaphore * PIOS_Semaphore_Create(void)
Creates a binary semaphore.
uint8_t PIOS_SPI_TransferByte(pios_spi_t spi_dev, uint8_t b)
int32_t PIOS_SPI_SetClockSpeed(pios_spi_t spi_dev, uint32_t speed)
int32_t PIOS_SPI_Init(pios_spi_t *spi_dev, const struct pios_spi_cfg *cfg)
int32_t PIOS_SPI_TransferBlock(pios_spi_t spi_dev, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len)
uint8_t i
Definition: msp_messages.h:97
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
Gives binary semaphore.
const struct pios_spi_cfg * cfg
Definition: pios_spi_priv.h:39
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
Takes binary semaphore.
int printf(const char *format,...)
int snprintf(char *buf, size_t count, const char *format,...)
int32_t PIOS_SPI_ReleaseBus(pios_spi_t spi_dev)
#define PIOS_Assert(test)
Definition: pios_debug.h:52
struct pios_semaphore * busy
Definition: pios_spi_priv.h:40