blob: 8e4917c145bbad42c34c28aa2ffc82a6c49c3ab1 [file] [log] [blame]
Patrick Williamsd6baab92016-08-24 14:05:55 -05001#define _GNU_SOURCE
2
Norman Jamese7594922015-08-27 14:25:24 -05003#include <stdint.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <fcntl.h>
8#include <unistd.h>
9#include <argp.h>
10#include <sys/stat.h>
11#include <sys/mman.h>
Brad Bishopf6c85682016-06-27 11:56:39 -040012#include "openbmc_intf.h"
Norman Jamese7594922015-08-27 14:25:24 -050013#include "gpio.h"
Matt Spinler3a70e932018-08-07 14:16:47 -050014#include "gpio_json.h"
Norman Jamese7594922015-08-27 14:25:24 -050015
Matt Spinler3a70e932018-08-07 14:16:47 -050016#define GPIO_BASE_PATH "/sys/class/gpio"
17
18cJSON* gpio_json = NULL;
Norman Jamese7594922015-08-27 14:25:24 -050019
Norman James32e74e22015-09-15 21:28:06 -050020int gpio_writec(GPIO* gpio, char value)
Norman Jamese7594922015-08-27 14:25:24 -050021{
Norman James65a295a2015-09-26 22:21:10 -050022 g_assert (gpio != NULL);
Norman James32e74e22015-09-15 21:28:06 -050023 int rc = GPIO_OK;
Norman Jamese7594922015-08-27 14:25:24 -050024 char buf[1];
25 buf[0] = value;
Yong Li86101ea2017-11-17 14:34:18 +080026
27 if (lseek(gpio->fd, 0, SEEK_SET) == -1)
28 {
29 return GPIO_ERROR;
30 }
31
Norman Jamese7594922015-08-27 14:25:24 -050032 if (write(gpio->fd, buf, 1) != 1)
33 {
Norman James32e74e22015-09-15 21:28:06 -050034 rc = GPIO_WRITE_ERROR;
35 }
36 return rc;
Norman Jamese7594922015-08-27 14:25:24 -050037}
38
Norman James32e74e22015-09-15 21:28:06 -050039int gpio_write(GPIO* gpio, uint8_t value)
Norman Jamese7594922015-08-27 14:25:24 -050040{
Norman James65a295a2015-09-26 22:21:10 -050041 g_assert (gpio != NULL);
Norman James32e74e22015-09-15 21:28:06 -050042 int rc = GPIO_OK;
Norman Jamese7594922015-08-27 14:25:24 -050043 char buf[1];
44 buf[0] = '0';
45 if (value==1)
46 {
47 buf[0]='1';
Patrick Williams3a8fa6e2016-08-24 14:04:22 -050048 }
Yong Li86101ea2017-11-17 14:34:18 +080049
50 if (lseek(gpio->fd, 0, SEEK_SET) == -1)
51 {
52 return GPIO_ERROR;
53 }
54
Norman Jamese7594922015-08-27 14:25:24 -050055 if (write(gpio->fd, buf, 1) != 1)
56 {
Norman James32e74e22015-09-15 21:28:06 -050057 rc = GPIO_WRITE_ERROR;
58 }
59 return rc;
Norman Jamese7594922015-08-27 14:25:24 -050060}
61
Norman James88872672015-09-21 16:51:35 -050062int gpio_read(GPIO* gpio, uint8_t *value)
Norman Jamese7594922015-08-27 14:25:24 -050063{
Norman James65a295a2015-09-26 22:21:10 -050064 g_assert (gpio != NULL);
Norman Jamese7594922015-08-27 14:25:24 -050065 char buf[1];
Norman James32e74e22015-09-15 21:28:06 -050066 int r = GPIO_OK;
Norman James8abb50c2015-09-16 10:58:16 -050067 if (gpio->fd <= 0)
Norman Jamese7594922015-08-27 14:25:24 -050068 {
Patrick Williams3a8fa6e2016-08-24 14:04:22 -050069 r = GPIO_ERROR;
Norman James8abb50c2015-09-16 10:58:16 -050070 }
71 else
72 {
Yong Li86101ea2017-11-17 14:34:18 +080073 if (lseek(gpio->fd, 0, SEEK_SET) == -1)
74 {
75 return GPIO_ERROR;
76 }
77
Norman James8abb50c2015-09-16 10:58:16 -050078 if (read(gpio->fd,&buf,1) != 1)
79 {
Norman James8abb50c2015-09-16 10:58:16 -050080 r = GPIO_READ_ERROR;
Norman James32e74e22015-09-15 21:28:06 -050081 } else {
Norman James8abb50c2015-09-16 10:58:16 -050082 if (buf[0]=='1') {
83 *value = 1;
84 } else {
85 *value = 0;
86 }
Norman James32e74e22015-09-15 21:28:06 -050087 }
Norman Jamese7594922015-08-27 14:25:24 -050088 }
Norman James32e74e22015-09-15 21:28:06 -050089 return r;
Norman Jamese7594922015-08-27 14:25:24 -050090}
Norman James32e74e22015-09-15 21:28:06 -050091int gpio_clock_cycle(GPIO* gpio, int num_clks) {
Norman James65a295a2015-09-26 22:21:10 -050092 g_assert (gpio != NULL);
Norman Jamese7594922015-08-27 14:25:24 -050093 int i=0;
Norman James32e74e22015-09-15 21:28:06 -050094 int r=GPIO_OK;
Norman Jamese7594922015-08-27 14:25:24 -050095 for (i=0;i<num_clks;i++) {
Norman James32e74e22015-09-15 21:28:06 -050096 if (gpio_writec(gpio,'0') == -1) {
97 r = GPIO_WRITE_ERROR;
98 break;
99 }
100 if (gpio_writec(gpio,'1') == -1) {
101 r = GPIO_WRITE_ERROR;
102 break;
103 }
Norman Jamese7594922015-08-27 14:25:24 -0500104 }
Norman James32e74e22015-09-15 21:28:06 -0500105 return r;
Norman Jamese7594922015-08-27 14:25:24 -0500106}
107
Matt Spinler3a70e932018-08-07 14:16:47 -0500108int convert_gpio_to_num(const char* gpio)
109{
110 /* TODO */
111 return 0;
112}
113
114/**
115 * Returns the cJSON pointer to the GPIO definition
116 * for the GPIO passed in.
117 *
118 * @param[in] gpio_name - the GPIO name, like BMC_POWER_UP
119 *
120 * @return cJSON* - pointer to the cJSON object or NULL
121 * if not found.
122 */
123cJSON* get_gpio_def(const char* gpio_name)
124{
125 if (gpio_json == NULL)
126 {
127 gpio_json = load_json();
128 if (gpio_json == NULL)
129 {
130 return NULL;
131 }
132 }
133
134 cJSON* gpio_defs = cJSON_GetObjectItem(gpio_json, "gpio_definitions");
135 g_assert(gpio_defs != NULL);
136
137 cJSON* def;
138 cJSON_ArrayForEach(def, gpio_defs)
139 {
140 cJSON* name = cJSON_GetObjectItem(def, "name");
141 g_assert(name != NULL);
142
143 if (strcmp(name->valuestring, gpio_name) == 0)
144 {
145 return def;
146 }
147 }
148 return NULL;
149}
150
151/**
152 * Frees the gpio_json memory
153 *
154 * Can be called once when callers are done calling making calls
155 * to gpio_init() so that the JSON only needs to be loaded once.
156 */
157void gpio_inits_done()
158{
159 if (gpio_json != NULL)
160 {
161 cJSON_Delete(gpio_json);
162 gpio_json = NULL;
163 }
164}
165
166/**
167 * Fills in the dev, direction, and num elements in
168 * the GPIO structure.
169 *
170 * @param gpio - the GPIO structure to fill in
171 *
172 * @return GPIO_OK if successful
173 */
174int gpio_get_params(GPIO* gpio)
175{
176 gpio->dev = g_strdup(GPIO_BASE_PATH);
177
178 const cJSON* def = get_gpio_def(gpio->name);
179 if (def == NULL)
180 {
181 fprintf(stderr, "Unable to find GPIO %s in the JSON\n",
182 gpio->name);
183 return GPIO_LOOKUP_ERROR;
184 }
185
186 const cJSON* dir = cJSON_GetObjectItem(def, "direction");
187 g_assert(dir != NULL);
188 gpio->direction = g_strdup(dir->valuestring);
189
190 /* Must use either 'num', like 87, or 'pin', like "A5" */
191 const cJSON* num = cJSON_GetObjectItem(def, "num");
192 if ((num != NULL) && cJSON_IsNumber(num))
193 {
194 gpio->num = num->valueint;
195 }
196 else
197 {
198 const cJSON* pin = cJSON_GetObjectItem(def, "pin");
199 g_assert(pin != NULL);
200
201 gpio->num = convert_gpio_to_num(pin->valuestring);
202 if (gpio->num < 0)
203 {
204 return GPIO_LOOKUP_ERROR;
205 }
206 }
207 return GPIO_OK;
208}
209
Norman Jamese7594922015-08-27 14:25:24 -0500210// Gets the gpio device path from gpio manager object
Norman James32e74e22015-09-15 21:28:06 -0500211int gpio_init(GDBusConnection *connection, GPIO* gpio)
Norman Jamese7594922015-08-27 14:25:24 -0500212{
Matt Spinler3a70e932018-08-07 14:16:47 -0500213 int rc = gpio_get_params(gpio);
214 if (rc != GPIO_OK)
215 {
216 return rc;
Norman James32e74e22015-09-15 21:28:06 -0500217 }
Norman Jamese7594922015-08-27 14:25:24 -0500218
Norman Jamese7594922015-08-27 14:25:24 -0500219 g_print("GPIO Lookup: %s = %d,%s\n",gpio->name,gpio->num,gpio->direction);
Patrick Williams3a8fa6e2016-08-24 14:04:22 -0500220
Norman Jamese7594922015-08-27 14:25:24 -0500221 //export and set direction
222 char dev[254];
223 char data[4];
Norman James88872672015-09-21 16:51:35 -0500224 int fd;
Norman James32e74e22015-09-15 21:28:06 -0500225 do {
Norman James88872672015-09-21 16:51:35 -0500226 struct stat st;
Patrick Williams3a8fa6e2016-08-24 14:04:22 -0500227
Norman James5a7cc8d2015-10-06 12:31:06 -0500228 sprintf(dev,"%s/gpio%d/value",gpio->dev,gpio->num);
229 //check if gpio is exported, if not export
Norman James88872672015-09-21 16:51:35 -0500230 int result = stat(dev, &st);
231 if (result)
232 {
233 sprintf(dev,"%s/export",gpio->dev);
234 fd = open(dev, O_WRONLY);
235 if (fd == GPIO_ERROR) {
236 rc = GPIO_OPEN_ERROR;
237 break;
Patrick Williams3a8fa6e2016-08-24 14:04:22 -0500238 }
Norman James88872672015-09-21 16:51:35 -0500239 sprintf(data,"%d",gpio->num);
240 rc = write(fd,data,strlen(data));
241 close(fd);
242 if (rc != strlen(data)) {
243 rc = GPIO_WRITE_ERROR;
244 break;
245 }
Norman James32e74e22015-09-15 21:28:06 -0500246 }
Norman James5a7cc8d2015-10-06 12:31:06 -0500247 const char* file = "edge";
Patrick Williamsed1368d2016-08-24 14:23:45 -0500248 const char* direction = gpio->direction;
249 if (strcmp(direction, "in") == 0)
Norman James5a7cc8d2015-10-06 12:31:06 -0500250 {
251 file = "direction";
252 }
Patrick Williamsed1368d2016-08-24 14:23:45 -0500253 else if (strcmp(direction, "out") == 0)
254 {
255 file = "direction";
256
257 // Read current value, so we can set 'high' or 'low'.
258 // Setting direction directly to 'out' is the same as
259 // setting to 'low' which can change the value in the
260 // GPIO.
261 uint8_t value = 0;
262 rc = gpio_open(gpio);
263 if (rc) break;
264 rc = gpio_read(gpio, &value);
265 if (rc) break;
266 gpio_close(gpio);
267
268 direction = (value ? "high" : "low");
269 }
Norman James5a7cc8d2015-10-06 12:31:06 -0500270 sprintf(dev,"%s/gpio%d/%s",gpio->dev,gpio->num,file);
Norman James32e74e22015-09-15 21:28:06 -0500271 fd = open(dev,O_WRONLY);
272 if (fd == GPIO_ERROR) {
273 rc = GPIO_WRITE_ERROR;
274 break;
275 }
Patrick Williamsed1368d2016-08-24 14:23:45 -0500276 rc = write(fd,direction,strlen(direction));
277 if (rc != strlen(direction)) {
Norman James88872672015-09-21 16:51:35 -0500278 rc = GPIO_WRITE_ERROR;
279 break;
280 }
281
Norman James32e74e22015-09-15 21:28:06 -0500282 close(fd);
Norman James5a7cc8d2015-10-06 12:31:06 -0500283 rc = GPIO_OK;
Norman James32e74e22015-09-15 21:28:06 -0500284 } while(0);
Norman Jamese7594922015-08-27 14:25:24 -0500285
Norman James32e74e22015-09-15 21:28:06 -0500286 return rc;
Norman Jamese7594922015-08-27 14:25:24 -0500287}
Norman James5a7cc8d2015-10-06 12:31:06 -0500288
289
290
291
Norman James471ab592015-08-30 22:29:40 -0500292char* get_gpio_dev(GPIO* gpio)
293{
294 char* buf;
Patrick Williamsd6baab92016-08-24 14:05:55 -0500295 asprintf(&buf, "%s/gpio%d/value", gpio->dev, gpio->num);
Norman James471ab592015-08-30 22:29:40 -0500296 return buf;
297}
298
Norman James5a7cc8d2015-10-06 12:31:06 -0500299int gpio_open_interrupt(GPIO* gpio, GIOFunc func, gpointer user_data)
300{
301 int rc = GPIO_OK;
Norman James02b77f32015-10-28 18:59:29 -0500302 char buf[255];
Norman James5a7cc8d2015-10-06 12:31:06 -0500303 sprintf(buf, "%s/gpio%d/value", gpio->dev, gpio->num);
304 gpio->fd = open(buf, O_RDONLY | O_NONBLOCK );
Norman James02b77f32015-10-28 18:59:29 -0500305 gpio->irq_inited = false;
Norman James5a7cc8d2015-10-06 12:31:06 -0500306 if (gpio->fd == -1)
307 {
308 rc = GPIO_OPEN_ERROR;
309 }
310 else
311 {
Norman James02b77f32015-10-28 18:59:29 -0500312 GIOChannel* channel = g_io_channel_unix_new( gpio->fd);
Norman James5a7cc8d2015-10-06 12:31:06 -0500313 guint id = g_io_add_watch( channel, G_IO_PRI, func, user_data );
314 }
315 return rc;
316}
317
Norman Jamese7594922015-08-27 14:25:24 -0500318int gpio_open(GPIO* gpio)
319{
Norman James65a295a2015-09-26 22:21:10 -0500320 g_assert (gpio != NULL);
Norman Jamese7594922015-08-27 14:25:24 -0500321 // open gpio for writing or reading
322 char buf[254];
Norman James32e74e22015-09-15 21:28:06 -0500323 int rc = 0;
Norman James5a7cc8d2015-10-06 12:31:06 -0500324 gpio->fd = -1;
Norman James65a295a2015-09-26 22:21:10 -0500325 if (gpio->direction == NULL) {
326 return GPIO_OPEN_ERROR;
327 }
Norman Jamese7594922015-08-27 14:25:24 -0500328 if (strcmp(gpio->direction,"in")==0)
329 {
330 sprintf(buf, "%s/gpio%d/value", gpio->dev, gpio->num);
331 gpio->fd = open(buf, O_RDONLY);
332 }
333 else
334 {
335 sprintf(buf, "%s/gpio%d/value", gpio->dev, gpio->num);
Norman James25571112015-12-15 09:36:28 -0600336 gpio->fd = open(buf, O_RDWR);
Norman Jamese7594922015-08-27 14:25:24 -0500337
338 }
Norman James88872672015-09-21 16:51:35 -0500339 if (gpio->fd == -1) {
340 return GPIO_OPEN_ERROR;
341 }
342 return GPIO_OK;
Norman Jamese7594922015-08-27 14:25:24 -0500343}
344
345void gpio_close(GPIO* gpio)
346{
347 close(gpio->fd);
348}