On Sun, Sep 16, 2018 at 07:58:47PM +0200, Karoly Pados wrote: > This patch allows using the CBUS pins of FT-X devices as GPIO in CBUS > bitbanging mode. There is no conflict between the GPIO and VCP > functionality in this mode. Tested on FT230X and FT231X. > > As there is no way to request the current CBUS register configuration > from the device, all CBUS pins are set to a known state when the first > GPIO is requested. This allows using libftdi to set the GPIO pins > before loading this module for UART functionality, a behavior that > existing applications might be relying upon (though no specific case > is known to the authors of this patch). > > Signed-off-by: Karoly Pados <pados@xxxxxxxx> > --- > Changelog: > - v2: Fix compile error when CONFIG_GPIOLIB is not defined. > - v3: Incorporate review feedback. > - v4: Include linux/gpio/driver.h unconditionally. > Replace and invert gpio_input with gpio_output. > Make ftdi_gpio_direction_get return 0/1. > Change dev_err msg in ftdi_set_bitmode_req. > Change formatting of error checking in ftdi_gpio_get. > Drop dev_err in ftdi_gpio_set. > Remove some line breaks and empty lines. > Change error handling in ftdi_read_eeprom (and adjust caller). > Replace SIO->FTX in FTDI_SIO_CBUS_MUX_GPIO macro name. Really nice job with this; looks nice and clean over all. Just a few comments below. > +static int ftx_gpioconf_init(struct usb_serial_port *port) > +{ > + struct ftdi_private *priv = usb_get_serial_port_data(port); > + struct usb_serial *serial = port->serial; > + const u16 cbus_cfg_addr = 0x1a; > + const u16 cbus_cfg_size = 8; Looks like you only need to read four bytes. > + u8 *cbus_cfg_buf; > + int result; > + u8 i; > + > + /* Read a part of device EEPROM */ > + cbus_cfg_buf = kmalloc(cbus_cfg_size, GFP_KERNEL); > + if (!cbus_cfg_buf) > + return -ENOMEM; > + > + result = ftdi_read_eeprom(serial, cbus_cfg_buf, > + cbus_cfg_addr, cbus_cfg_size); > + if (result != 0) result < 0 would be more informative here. > + goto out_free; > + > + /* Chip-type guessing logic based on libftdi. */ > + priv->gc.ngpio = 4; /* FT230X, FT231X */ > + if (le16_to_cpu(serial->dev->descriptor.bcdDevice) != 0x1000) > + priv->gc.ngpio = 1; /* FT234XD */ As I mentioned in my last mail: I've asked FTDI about this, but I fear that FTX234XD has bcdDevice 0x1000 and we may need to just always register all four pins after all. > + /* Determine which pins are configured for CBUS bitbanging */ > + priv->gpio_altfunc = 0xff; > + for (i = 0; i < priv->gc.ngpio; ++i) { > + if (cbus_cfg_buf[i] == FTDI_FTX_CBUS_MUX_GPIO) > + priv->gpio_altfunc &= ~BIT(i); > + } > + > +out_free: > + kfree(cbus_cfg_buf); > + > + return result; > +} > +static void ftdi_gpio_remove(struct usb_serial_port *port) > +{ > + struct ftdi_private *priv = usb_get_serial_port_data(port); > + > + if (priv->gpio_used) { > + /* Remark: Exiting CBUS-mode does not reset pin states too */ > + ftdi_exit_cbus_mode(port); > + priv->gpio_used = false; > + } This should go after deregistration or we have a tiny race window here. > + if (priv->gpio_registered) { > + gpiochip_remove(&priv->gc); > + priv->gpio_registered = false; > + } > +} > diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h > index dcd0b6e05baf..6856ccdac9b4 100644 > --- a/drivers/usb/serial/ftdi_sio.h > +++ b/drivers/usb/serial/ftdi_sio.h > @@ -35,7 +35,10 @@ > #define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ > #define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ > #define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ > -#define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */ > +#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */ > +#define FTDI_SIO_SET_BITMODE 0x0b /* Set GPIO mode */ Nit: "Set bitbang mode", I think would be more correct here as this request is also used to configure the asynchronous bitbang mode, etc. Thanks, Johan