usb:serial:pl2303: add GPIOs interface on PL2303
Subsystems (2)
PATCH v3 1/1 usb:serial:pl2303: add GPIOs interface on PL2303
PL2303HX has two GPIOs, this patch add interface for it.
---
Changes v2-v3:
1: fix errors and warnings reported by Daniele Forsi checked with checkpatch.pl 2: fix missing GPIOLIB dependence in Kconfig
3: fix pl2303_gpio_get can't work
Known issue:
If gpios are in use(export to userspace through sysfs interface, etc), then call pl2303_release(unplug usb-serial convertor, modprobe -r, etc), will cause trouble, so we need to make sure there is no gpio user before call pl2303_release.
drivers/usb/serial/Kconfig | 10 ++++ drivers/usb/serial/pl2303.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+)
drivers/usb/serial/Kconfig +10 -0
@@ -516,6 +516,16 @@ config USB_SERIAL_PL2303 To compile this driver as a module, choose M here: the module will be called pl2303. +config USB_SERIAL_PL2303_GPIO + bool "USB Prolific 2303 Single Port GPIOs support" + depends on USB_SERIAL_PL2303 && GPIOLIB + ---help--- + Say Y here if you want to use the GPIOs on PL2303 USB Serial single port + adapter from Prolific. + + It support 2 GPIOs on PL2303HX currently, + if unsure, say N. + config USB_SERIAL_OTI6858 tristate "USB Ours Technology Inc. OTi-6858 USB To RS232 Bridge Controller" help
drivers/usb/serial/pl2303.c +141 -0
174 lines not on this page · raw message
Signature · 1 line
1.8.5.5.dirty
Hi,
Did some more review, sorry ;)
drivers/usb/serial/pl2303.c static int pl2303_probe(struct usb_serial *serial, · line 317
Quoted 9 lines · Wang YanQing
drivers/usb/serial/pl2303.c +9
-0+static struct gpio_chip template_chip = { + .label ="pl2303-gpio" , + .owner =THIS_MODULE , + .direction_input = pl2303_gpio_direction_in, + .get = pl2303_gpio_get, + .direction_output = pl2303_gpio_direction_out, + .set = pl2303_gpio_set, + .can_sleep =1 , +};
Could this be made static const? (since it's for one-time copy purposes only)
drivers/usb/serial/pl2303.c struct pl2303_type_data { · line 160
Quoted 9 lines
drivers/usb/serial/pl2303.c +9
-0+struct pl2303_gpio { +/* +* 0..3: unknown (zero) +* 4: gp0 output enable (1: gp0 pin is output, 0: gp0 pin is input) +* 5: gp1 output enable (1: gp1 pin is output, 0: gp1 pin is input) +* 6: gp0 pin value +* 7: gp1 pin value +*/ +u8 index;
Most frequently accessed member at first position - good.
drivers/usb/serial/pl2303.c static int pl2303_probe(struct usb_serial *serial, · line 246
Quoted 5 lines
+static inline struct
pl2303_gpio*to_pl2303_gpio(structgpio_chip*chip)drivers/usb/serial/pl2303.c +3
-0+{ + return container_of(chip, struct pl2303_gpio, gpio_chip); +}
Nicely cast-avoiding helper :)
drivers/usb/serial/pl2303.c static int pl2303_startup(struct usb_serial *serial) · line 387
Quoted 8 lines
drivers/usb/serial/pl2303.c +8
-0+ spriv->gpio->index =0x00 ; + spriv->gpio->serial = serial; + spriv->gpio->gpio_chip = template_chip; + spriv->gpio->gpio_chip.ngpio =GPIO_NUM ; + spriv->gpio->gpio_chip.base =-1 ; + spriv->gpio->gpio_chip.dev = &serial->interface->dev; +/* initialize GPIOs, input mode as default */ +pl2303_vendor_write (spriv->gpio->serial,1 , spriv->gpio->index);
Perhaps the index line should better be moved
right before the pl2303_vendor_write() line,
to more obviously hint at why it's "input mode"
(but OTOH currently you're cleanly initializing things in correct member order, so it's probably better to keep it that way).
Also, it's perhaps a better idea to do this initial init call via calls of actual GPIO API rather than implementation-specific call (e.g. that way one could simple reuse the generic GPIO call for devices which happen to implement GPIO via a different mechanism...). (hmm, nope, from a layering POV it's not recommendable, since we clearly are at hardware-specific init here,
where you want to firmly guarantee
that the hardware is directly and fully initialized).
Since there are several repeated pl2303_vendor_write(...serial, 1, ...index) calls,
it's possibly a good idea to wrap these calls in a convenience pl2303_gpio_state_update(gpio)
This would also increase GPIO hardware abstraction,
by then simply having to provide an alternative for this single function if needed.
Also, it may (depending on the number of callers,
which is on the low side here unfortunately)
reduce instruction cache footprint.
So these are my additional thoughts about the implementation, which you may or may not choose to adopt.
HTH,
Andreas Mohr
Signature · 1 line
GNU/Linux. It's not the software that's free, it's you.
Quoted 5 lines · Andreas Mohr
Hi,
Did some more review, sorry ;)
On Mon, Jul 21, 2014 at 10:46:24AM +0800, Wang YanQing wrote:
Quoted 13 lines
drivers/usb/serial/pl2303.c static int pl2303_probe(struct usb_serial *serial, · line 317
Quoted 9 lines
drivers/usb/serial/pl2303.c +9
-0+static struct gpio_chip template_chip = { + .label ="pl2303-gpio" , + .owner =THIS_MODULE , + .direction_input = pl2303_gpio_direction_in, + .get = pl2303_gpio_get, + .direction_output = pl2303_gpio_direction_out, + .set = pl2303_gpio_set, + .can_sleep =1 , +};Could this be made static const? (since it's for one-time copy purposes only)
OK, I will add const.
Quoted 37 lines
drivers/usb/serial/pl2303.c struct pl2303_type_data { · line 160
Quoted 9 lines
drivers/usb/serial/pl2303.c +9
-0+struct pl2303_gpio { +/* +* 0..3: unknown (zero) +* 4: gp0 output enable (1: gp0 pin is output, 0: gp0 pin is input) +* 5: gp1 output enable (1: gp1 pin is output, 0: gp1 pin is input) +* 6: gp0 pin value +* 7: gp1 pin value +*/ +u8 index;Most frequently accessed member at first position - good.
drivers/usb/serial/pl2303.c static int pl2303_probe(struct usb_serial *serial, · line 246
Quoted 5 lines
+static inline struct
pl2303_gpio*to_pl2303_gpio(structgpio_chip*chip)drivers/usb/serial/pl2303.c +3
-0+{ + return container_of(chip, struct pl2303_gpio, gpio_chip); +}Nicely cast-avoiding helper :)
drivers/usb/serial/pl2303.c static int pl2303_startup(struct usb_serial *serial) · line 387
Quoted 8 lines
drivers/usb/serial/pl2303.c +8
-0+ spriv->gpio->index =0x00 ; + spriv->gpio->serial = serial; + spriv->gpio->gpio_chip = template_chip; + spriv->gpio->gpio_chip.ngpio =GPIO_NUM ; + spriv->gpio->gpio_chip.base =-1 ; + spriv->gpio->gpio_chip.dev = &serial->interface->dev; +/* initialize GPIOs, input mode as default */ +pl2303_vendor_write (spriv->gpio->serial,1 , spriv->gpio->index);Perhaps the index line should better be moved
right before thepl2303_vendor_write()line,
to more obviously hint at why it's "input mode"
(but OTOH currently you're cleanly initializing things in correct member order, so it's probably better to keep it that way).
Quoted 10 lines
Also, it's perhaps a better idea to do this initial init call via calls of actual GPIO API rather than implementation-specific call (e.g. that way one could simple reuse the generic GPIO call for devices which happen to implement GPIO via a different mechanism...). (hmm, nope, from a layering POV it's not recommendable, since we clearly are at hardware-specific init here,
where you want to firmly guarantee
that the hardware is directly and fully initialized).
Thanks very much for review :)
Quoted 10 lines
Since there are several repeated
pl2303_vendor_write(...serial, 1, ...index)calls,
it's possibly a good idea to wrap these calls in a conveniencepl2303_gpio_state_update(gpio)
This would also increase GPIO hardware abstraction,
by then simply having to provide an alternative for this single function if needed.
Also, it may (depending on the number of callers,
which is on the low side here unfortunately)
reduce instruction cache footprint.
The reason I don't want to add more abstraction here are:
1: Abstraction don't reduce code lines, then reuse
pl2303_vendor_write|read is a better choice, i think.
2: pl2303_vendor_write|read is more generic than abstraction,
then someone maybe could use pl2303_vendor_write|read to support another two Auxiliary GPIOs on PL2303HXD(I don't have one) directly without play with abstraction.
Thanks.
Quoted 9 lines · Wang YanQing
PL2303HX has two GPIOs, this patch add interface for it.
Signed-off-by Wang YanQing <[email protected]>---
Changes v2-v3:
1: fix errors and warnings reported by Daniele Forsi checked with checkpatch.pl 2: fix missing GPIOLIB dependence inKconfig
3: fixpl2303_gpio_getcan't work
Quoted 5 lines
Known issue:
If gpios are inuse(export to userspace through sysfs interface, etc), then callpl2303_release(unplug usb-serial convertor, modprobe -r, etc), will cause trouble, so we need to make sure there is no gpio user before callpl2303_release.
The sysfs ABI is not sound, using it is a recipe for trouble. IIRC it was merged at a time when drivers/gpio was unmaintained :-(
(...)
drivers/usb/serial/pl2303.c static int pl2303_probe(struct usb_serial *serial, · line 316
Quoted 8 lines
drivers/usb/serial/pl2303.c +8
-0+static struct gpio_chip template_chip = { + .label ="pl2303-gpio" , + .owner =THIS_MODULE , + .direction_input = pl2303_gpio_direction_in, + .get = pl2303_gpio_get, + .direction_output = pl2303_gpio_direction_out, + .set = pl2303_gpio_set, + .can_sleep =1 ,
This is a bool so use = true,
drivers/usb/serial/pl2303.c static void pl2303_release(struct usb_serial *serial) · line 409
Quoted 5 lines
drivers/usb/serial/pl2303.c +5
-0+#ifdef CONFIG_USB_SERIAL_PL2303_GPIO +if (spriv && spriv->gpio) { +if (gpiochip_remove (&spriv->gpio->gpio_chip)) +dev_err (&serial->interface->dev, +"unable to remove gpio_chip?\n" );
I'm getting rid of the return code from gpiochip_remove() and have removed the __must_check tag in the gpio tree, so just call gpiochip_remove() unconditionally and ignore any compile error messages for now.
Yours,
Linus Walleij