driver/linuxgpiod: add support for opendrain srst
[fw/openocd] / src / jtag / drivers / linuxgpiod.c
index 661a926f502b9956bc24990ca4689c5601402b5a..dd50b44066616b207c745cdc1c43d743cd20e1d1 100644 (file)
@@ -27,6 +27,7 @@ static int trst_gpio = -1;
 static int srst_gpio = -1;
 static int swclk_gpio = -1;
 static int swdio_gpio = -1;
+static int led_gpio = -1;
 static int gpiochip = -1;
 
 static struct gpiod_chip *gpiod_chip;
@@ -38,6 +39,7 @@ static struct gpiod_line *gpiod_trst;
 static struct gpiod_line *gpiod_swclk;
 static struct gpiod_line *gpiod_swdio;
 static struct gpiod_line *gpiod_srst;
+static struct gpiod_line *gpiod_led;
 
 static int last_swclk;
 static int last_swdio;
@@ -171,13 +173,26 @@ static int linuxgpiod_swd_write(int swclk, int swdio)
        return ERROR_OK;
 }
 
+static int linuxgpiod_blink(int on)
+{
+       int retval;
+
+       if (!gpiod_led)
+               return ERROR_OK;
+
+       retval = gpiod_line_set_value(gpiod_led, on);
+       if (retval < 0)
+               LOG_WARNING("Fail set led");
+       return retval;
+}
+
 static struct bitbang_interface linuxgpiod_bitbang = {
        .read = linuxgpiod_read,
        .write = linuxgpiod_write,
        .swdio_read = linuxgpiod_swdio_read,
        .swdio_drive = linuxgpiod_swdio_drive,
        .swd_write = linuxgpiod_swd_write,
-       .blink = NULL,
+       .blink = linuxgpiod_blink,
 };
 
 /*
@@ -192,14 +207,14 @@ static int linuxgpiod_reset(int trst, int srst)
        LOG_DEBUG("linuxgpiod_reset");
 
        /* assume active low */
-       if (gpiod_srst != NULL) {
+       if (gpiod_srst) {
                retval1 = gpiod_line_set_value(gpiod_srst, srst ? 0 : 1);
                if (retval1 < 0)
                        LOG_WARNING("set srst value failed");
        }
 
        /* assume active low */
-       if (gpiod_trst != NULL) {
+       if (gpiod_trst) {
                retval2 = gpiod_line_set_value(gpiod_trst, trst ? 0 : 1);
                if (retval2 < 0)
                        LOG_WARNING("set trst value failed");
@@ -248,6 +263,7 @@ static inline void helper_release(struct gpiod_line *line)
 
 static int linuxgpiod_quit(void)
 {
+       helper_release(gpiod_led);
        helper_release(gpiod_srst);
        helper_release(gpiod_swdio);
        helper_release(gpiod_swclk);
@@ -262,44 +278,45 @@ static int linuxgpiod_quit(void)
        return ERROR_OK;
 }
 
-static struct gpiod_line *helper_get_input_line(const char *label, unsigned int offset)
+static struct gpiod_line *helper_get_line(const char *label, unsigned int offset, int val, int dir, int flags)
 {
        struct gpiod_line *line;
        int retval;
 
        line = gpiod_chip_get_line(gpiod_chip, offset);
-       if (line == NULL) {
+       if (!line) {
                LOG_ERROR("Error get line %s", label);
                return NULL;
        }
 
-       retval = gpiod_line_request_input(line, "OpenOCD");
+       struct gpiod_line_request_config config = {
+               .consumer = "OpenOCD",
+               .request_type = dir,
+               .flags = flags,
+       };
+
+       retval = gpiod_line_request(line, &config, val);
        if (retval < 0) {
-               LOG_ERROR("Error request_input line %s", label);
+               LOG_ERROR("Error requesting gpio line %s", label);
                return NULL;
        }
 
        return line;
 }
 
-static struct gpiod_line *helper_get_output_line(const char *label, unsigned int offset, int val)
+static struct gpiod_line *helper_get_input_line(const char *label, unsigned int offset)
 {
-       struct gpiod_line *line;
-       int retval;
-
-       line = gpiod_chip_get_line(gpiod_chip, offset);
-       if (line == NULL) {
-               LOG_ERROR("Error get line %s", label);
-               return NULL;
-       }
+       return helper_get_line(label, offset, 0, GPIOD_LINE_REQUEST_DIRECTION_INPUT, 0);
+}
 
-       retval = gpiod_line_request_output(line, "OpenOCD", val);
-       if (retval < 0) {
-               LOG_ERROR("Error request_output line %s", label);
-               return NULL;
-       }
+static struct gpiod_line *helper_get_output_line(const char *label, unsigned int offset, int val)
+{
+       return helper_get_line(label, offset, val, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, 0);
+}
 
-       return line;
+static struct gpiod_line *helper_get_open_drain_output_line(const char *label, unsigned int offset, int val)
+{
+       return helper_get_line(label, offset, val, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN);
 }
 
 static int linuxgpiod_init(void)
@@ -309,7 +326,7 @@ static int linuxgpiod_init(void)
        bitbang_interface = &linuxgpiod_bitbang;
 
        gpiod_chip = gpiod_chip_open_by_number(gpiochip);
-       if (gpiod_chip == NULL) {
+       if (!gpiod_chip) {
                LOG_ERROR("Cannot open LinuxGPIOD gpiochip %d", gpiochip);
                return ERROR_JTAG_INIT_FAILED;
        }
@@ -327,24 +344,24 @@ static int linuxgpiod_init(void)
                }
 
                gpiod_tdo = helper_get_input_line("tdo", tdo_gpio);
-               if (gpiod_tdo == NULL)
+               if (!gpiod_tdo)
                        goto out_error;
 
                gpiod_tdi = helper_get_output_line("tdi", tdi_gpio, 0);
-               if (gpiod_tdi == NULL)
+               if (!gpiod_tdi)
                        goto out_error;
 
                gpiod_tck = helper_get_output_line("tck", tck_gpio, 0);
-               if (gpiod_tck == NULL)
+               if (!gpiod_tck)
                        goto out_error;
 
                gpiod_tms = helper_get_output_line("tms", tms_gpio, 1);
-               if (gpiod_tms == NULL)
+               if (!gpiod_tms)
                        goto out_error;
 
                if (is_gpio_valid(trst_gpio)) {
                        gpiod_trst = helper_get_output_line("trst", trst_gpio, 1);
-                       if (gpiod_trst == NULL)
+                       if (!gpiod_trst)
                                goto out_error;
                }
        }
@@ -356,17 +373,27 @@ static int linuxgpiod_init(void)
                }
 
                gpiod_swclk = helper_get_output_line("swclk", swclk_gpio, 1);
-               if (gpiod_swclk == NULL)
+               if (!gpiod_swclk)
                        goto out_error;
 
                gpiod_swdio = helper_get_output_line("swdio", swdio_gpio, 1);
-               if (gpiod_swdio == NULL)
+               if (!gpiod_swdio)
                        goto out_error;
        }
 
        if (is_gpio_valid(srst_gpio)) {
-               gpiod_srst = helper_get_output_line("srst", srst_gpio, 1);
-               if (gpiod_srst == NULL)
+               if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL)
+                       gpiod_srst = helper_get_output_line("srst", srst_gpio, 1);
+               else
+                       gpiod_srst = helper_get_open_drain_output_line("srst", srst_gpio, 1);
+
+               if (!gpiod_srst)
+                       goto out_error;
+       }
+
+       if (is_gpio_valid(led_gpio)) {
+               gpiod_led = helper_get_output_line("led", led_gpio, 0);
+               if (!gpiod_led)
                        goto out_error;
        }
 
@@ -484,6 +511,15 @@ COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(linuxgpiod_handle_gpionum_led)
+{
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], led_gpio);
+
+       command_print(CMD, "LinuxGPIOD num: led = %d", led_gpio);
+       return ERROR_OK;
+}
+
 COMMAND_HANDLER(linuxgpiod_handle_gpiochip)
 {
        if (CMD_ARGC == 1)
@@ -493,79 +529,86 @@ COMMAND_HANDLER(linuxgpiod_handle_gpiochip)
        return ERROR_OK;
 }
 
-static const struct command_registration linuxgpiod_command_handlers[] = {
+static const struct command_registration linuxgpiod_subcommand_handlers[] = {
        {
-               .name = "linuxgpiod_jtag_nums",
+               .name = "jtag_nums",
                .handler = linuxgpiod_handle_jtag_gpionums,
                .mode = COMMAND_CONFIG,
                .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
                .usage = "tck tms tdi tdo",
        },
        {
-               .name = "linuxgpiod_tck_num",
+               .name = "tck_num",
                .handler = linuxgpiod_handle_jtag_gpionum_tck,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for tck.",
                .usage = "tck",
        },
        {
-               .name = "linuxgpiod_tms_num",
+               .name = "tms_num",
                .handler = linuxgpiod_handle_jtag_gpionum_tms,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for tms.",
                .usage = "tms",
        },
        {
-               .name = "linuxgpiod_tdo_num",
+               .name = "tdo_num",
                .handler = linuxgpiod_handle_jtag_gpionum_tdo,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for tdo.",
                .usage = "tdo",
        },
        {
-               .name = "linuxgpiod_tdi_num",
+               .name = "tdi_num",
                .handler = linuxgpiod_handle_jtag_gpionum_tdi,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for tdi.",
                .usage = "tdi",
        },
        {
-               .name = "linuxgpiod_srst_num",
+               .name = "srst_num",
                .handler = linuxgpiod_handle_jtag_gpionum_srst,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for srst.",
                .usage = "srst",
        },
        {
-               .name = "linuxgpiod_trst_num",
+               .name = "trst_num",
                .handler = linuxgpiod_handle_jtag_gpionum_trst,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for trst.",
                .usage = "trst",
        },
        {
-               .name = "linuxgpiod_swd_nums",
+               .name = "swd_nums",
                .handler = linuxgpiod_handle_swd_gpionums,
                .mode = COMMAND_CONFIG,
                .help = "gpio numbers for swclk, swdio. (in that order)",
                .usage = "swclk swdio",
        },
        {
-               .name = "linuxgpiod_swclk_num",
+               .name = "swclk_num",
                .handler = linuxgpiod_handle_swd_gpionum_swclk,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for swclk.",
                .usage = "swclk",
        },
        {
-               .name = "linuxgpiod_swdio_num",
+               .name = "swdio_num",
                .handler = linuxgpiod_handle_swd_gpionum_swdio,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for swdio.",
                .usage = "swdio",
        },
        {
-               .name = "linuxgpiod_gpiochip",
+               .name = "led_num",
+               .handler = linuxgpiod_handle_gpionum_led,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for LED.",
+               .usage = "led",
+       },
+       {
+               .name = "gpiochip",
                .handler = linuxgpiod_handle_gpiochip,
                .mode = COMMAND_CONFIG,
                .help = "number of the gpiochip.",
@@ -574,6 +617,17 @@ static const struct command_registration linuxgpiod_command_handlers[] = {
        COMMAND_REGISTRATION_DONE
 };
 
+static const struct command_registration linuxgpiod_command_handlers[] = {
+       {
+               .name = "linuxgpiod",
+               .mode = COMMAND_ANY,
+               .help = "perform linuxgpiod management",
+               .chain = linuxgpiod_subcommand_handlers,
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
 static const char *const linuxgpiod_transport[] = { "swd", "jtag", NULL };
 
 static struct jtag_interface linuxgpiod_interface = {