diff --git a/common/ratp/Kconfig b/common/ratp/Kconfig index 4b28d5f..ddbbd95 100644 --- a/common/ratp/Kconfig +++ b/common/ratp/Kconfig @@ -18,4 +18,12 @@ depends on I2C prompt "RATP i2c support" help - This option adds support for i2c read/write commands via RATP. \ No newline at end of file + This option adds support for i2c read/write commands via RATP. + +config RATP_CMD_GPIO + bool + depends on RATP + depends on GENERIC_GPIO + prompt "RATP GPIO support" + help + This option adds support for GPIO get/set/direction commands via RATP. \ No newline at end of file diff --git a/common/ratp/Makefile b/common/ratp/Makefile index b83c483..71288bc 100644 --- a/common/ratp/Makefile +++ b/common/ratp/Makefile @@ -5,3 +5,4 @@ obj-y += mw.o obj-y += reset.o obj-$(CONFIG_RATP_CMD_I2C) += i2c.o +obj-$(CONFIG_RATP_CMD_GPIO) += gpio.o diff --git a/common/ratp/gpio.c b/common/ratp/gpio.c new file mode 100644 index 0000000..d2c527a --- /dev/null +++ b/common/ratp/gpio.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2018 Sascha Hauer , Pengutronix + * Copyright (c) 2018 Zodiac Inflight Innovations + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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. + * + */ + +#define pr_fmt(fmt) "barebox-ratp: gpio: " fmt + +#include +#include +#include +#include +#include +#include + +struct ratp_bb_gpio_get_value_request { + struct ratp_bb header; + uint32_t gpio; +} __packed; + +struct ratp_bb_gpio_get_value_response { + struct ratp_bb header; + uint8_t value; +} __packed; + +static int ratp_cmd_gpio_get_value(const struct ratp_bb *req, int req_len, + struct ratp_bb **rsp, int *rsp_len) +{ + struct ratp_bb_gpio_get_value_request *gpio_req = (struct ratp_bb_gpio_get_value_request *)req; + struct ratp_bb_gpio_get_value_response *gpio_rsp; + int gpio_rsp_len; + + if (req_len < sizeof(*gpio_req)) { + pr_err("get value request ignored: size mismatch (%d < %zu)\n", req_len, sizeof(*gpio_req)); + return 2; + } + + gpio_rsp_len = sizeof(struct ratp_bb_gpio_get_value_response); + gpio_rsp = xzalloc(gpio_rsp_len); + gpio_rsp->header.type = cpu_to_be16(BB_RATP_TYPE_GPIO_GET_VALUE_RETURN); + gpio_rsp->value = !!gpio_get_value(be32_to_cpu(gpio_req->gpio)); + + *rsp_len = gpio_rsp_len; + *rsp = (struct ratp_bb *)gpio_rsp; + return 0; +} + +BAREBOX_RATP_CMD_START(GPIO_GET_VALUE) + .request_id = BB_RATP_TYPE_GPIO_GET_VALUE, + .response_id = BB_RATP_TYPE_GPIO_GET_VALUE_RETURN, + .cmd = ratp_cmd_gpio_get_value +BAREBOX_RATP_CMD_END + + +struct ratp_bb_gpio_set_value_request { + struct ratp_bb header; + uint32_t gpio; + uint8_t value; +} __packed; + +static int ratp_cmd_gpio_set_value(const struct ratp_bb *req, int req_len, + struct ratp_bb **rsp, int *rsp_len) +{ + struct ratp_bb_gpio_set_value_request *gpio_req = (struct ratp_bb_gpio_set_value_request *)req; + + if (req_len < sizeof(*gpio_req)) { + pr_err("set value request ignored: size mismatch (%d < %zu)\n", req_len, sizeof(*gpio_req)); + return 2; + } + + gpio_set_value(be32_to_cpu(gpio_req->gpio), gpio_req->value); + + *rsp_len = sizeof(struct ratp_bb); + *rsp = xzalloc(*rsp_len); + (*rsp)->type = cpu_to_be16(BB_RATP_TYPE_GPIO_SET_VALUE_RETURN); + return 0; +} + +BAREBOX_RATP_CMD_START(GPIO_SET_VALUE) + .request_id = BB_RATP_TYPE_GPIO_SET_VALUE, + .response_id = BB_RATP_TYPE_GPIO_SET_VALUE_RETURN, + .cmd = ratp_cmd_gpio_set_value +BAREBOX_RATP_CMD_END + + +struct ratp_bb_gpio_set_direction_request { + struct ratp_bb header; + uint32_t gpio; + uint8_t direction; /* 0: input, 1: output */ + uint8_t value; /* applicable only if direction output */ +} __packed; + +struct ratp_bb_gpio_set_direction_response { + struct ratp_bb header; + uint32_t errno; +} __packed; + +static int ratp_cmd_gpio_set_direction(const struct ratp_bb *req, int req_len, + struct ratp_bb **rsp, int *rsp_len) +{ + struct ratp_bb_gpio_set_direction_request *gpio_req = (struct ratp_bb_gpio_set_direction_request *)req; + struct ratp_bb_gpio_set_direction_response *gpio_rsp; + int gpio_rsp_len; + uint32_t gpio; + int ret; + + if (req_len < sizeof(*gpio_req)) { + pr_err("set direction request ignored: size mismatch (%d < %zu)\n", req_len, sizeof(*gpio_req)); + return 2; + } + + gpio = be32_to_cpu(gpio_req->gpio); + if (gpio_req->direction) + ret = gpio_direction_output(gpio, gpio_req->value); + else + ret = gpio_direction_input(gpio); + + gpio_rsp_len = sizeof(struct ratp_bb_gpio_set_direction_response); + gpio_rsp = xzalloc(gpio_rsp_len); + gpio_rsp->header.type = cpu_to_be16(BB_RATP_TYPE_GPIO_SET_DIRECTION_RETURN); + gpio_rsp->errno = (ret == 0 ? 0 : EIO); + + *rsp_len = gpio_rsp_len; + *rsp = (struct ratp_bb *)gpio_rsp; + return 0; +} + +BAREBOX_RATP_CMD_START(GPIO_SET_DIRECTION) + .request_id = BB_RATP_TYPE_GPIO_SET_DIRECTION, + .response_id = BB_RATP_TYPE_GPIO_SET_DIRECTION_RETURN, + .cmd = ratp_cmd_gpio_set_direction +BAREBOX_RATP_CMD_END diff --git a/include/ratp_bb.h b/include/ratp_bb.h index 32b8040..b669997 100644 --- a/include/ratp_bb.h +++ b/include/ratp_bb.h @@ -21,6 +21,12 @@ #define BB_RATP_TYPE_I2C_READ_RETURN 16 #define BB_RATP_TYPE_I2C_WRITE 17 #define BB_RATP_TYPE_I2C_WRITE_RETURN 18 +#define BB_RATP_TYPE_GPIO_GET_VALUE 19 +#define BB_RATP_TYPE_GPIO_GET_VALUE_RETURN 20 +#define BB_RATP_TYPE_GPIO_SET_VALUE 21 +#define BB_RATP_TYPE_GPIO_SET_VALUE_RETURN 22 +#define BB_RATP_TYPE_GPIO_SET_DIRECTION 23 +#define BB_RATP_TYPE_GPIO_SET_DIRECTION_RETURN 24 struct ratp_bb { uint16_t type;