lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Sun, 20 Jul 2014 08:01:31 +0800
From:	Wang YanQing <udknight@...il.com>
To:	linus.walleij@...aro.org
Cc:	gregkh@...uxfoundation.org, jhovold@...il.com,
	linux-usb@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH] gpio:gpio-pl2303: add gpio driver for GPIOs on PL2303

PL2303HX has two GPIOs, this patch add driver for it.

Signed-off-by: Wang YanQing <udknight@...il.com>
---
 MAINTAINERS                 |   5 +
 drivers/gpio/Kconfig        |   7 ++
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/gpio-pl2303.c  | 238 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/serial/pl2303.c |  19 ++++
 5 files changed, 270 insertions(+)
 create mode 100644 drivers/gpio/gpio-pl2303.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 53feaaf..4a9d764 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6903,6 +6903,11 @@ F:	drivers/i2c/busses/i2c-puv3.c
 F:	drivers/video/fb-puv3.c
 F:	drivers/rtc/rtc-puv3.c
 
+PL2303 GPIO DRIVER
+M:	Wang YanQing <udknight@...il.com>
+S:	Maintained
+F:	drivers/gpio/gpio-pl2303.c
+
 PMBUS HARDWARE MONITORING DRIVERS
 M:	Guenter Roeck <linux@...ck-us.net>
 L:	lm-sensors@...sensors.org
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 4a1b511..0f90950 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -110,6 +110,13 @@ config GPIO_DA9055
 config GPIO_MAX730X
 	tristate
 
+config GPIO_PL2303
+	tristate "USB Prolific 2303 gpio support"
+	depends on USB_SERIAL_PL2303
+	help
+	  Enable support for GPIOs on USB Prolific 2303
+	  It support two GPIOs on PL2303HX currently.
+
 comment "Memory mapped GPIO drivers:"
 
 config GPIO_CLPS711X
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d10f6a9..4ff59f6 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -101,3 +101,4 @@ obj-$(CONFIG_GPIO_WM8994)	+= gpio-wm8994.o
 obj-$(CONFIG_GPIO_XILINX)	+= gpio-xilinx.o
 obj-$(CONFIG_GPIO_XTENSA)	+= gpio-xtensa.o
 obj-$(CONFIG_GPIO_ZEVIO)	+= gpio-zevio.o
+obj-$(CONFIG_GPIO_PL2303)	+= gpio-pl2303.o
diff --git a/drivers/gpio/gpio-pl2303.c b/drivers/gpio/gpio-pl2303.c
new file mode 100644
index 0000000..a703440
--- /dev/null
+++ b/drivers/gpio/gpio-pl2303.c
@@ -0,0 +1,238 @@
+/*
+ * PL2303 GPIO driver
+ *
+ * Copyright (C) 2014 Wang YanQing <udknight@...il.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Check pl2303.c for further details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/gpio.h>
+
+#define VENDOR_READ_REQUEST_TYPE	0xc0
+#define VENDOR_READ_REQUEST		0x01
+
+#define VENDOR_WRITE_REQUEST_TYPE	0x40
+#define VENDOR_WRITE_REQUEST		0x01
+
+struct pl2303_gpio_data {
+	struct usb_device *pl2303;
+	/*
+	 * 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;
+	struct gpio_chip gpio_chip;
+};
+
+static inline struct pl2303_gpio_data *to_pl2303_gpio(struct gpio_chip *chip)
+{
+	return container_of(chip, struct pl2303_gpio_data, gpio_chip);
+}
+
+static int pl2303_gpio_read(struct gpio_chip *chip, unsigned char buf[1])
+{
+	struct pl2303_gpio_data *pl2303_gpio = to_pl2303_gpio(chip);
+	struct usb_device *pl2303 = pl2303_gpio->pl2303;
+	struct device *dev = chip->dev;
+	int res;
+
+	res = usb_control_msg(pl2303, usb_rcvctrlpipe(pl2303, 0),
+			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
+			0x0081, 0, buf, 1, 100);
+	if (res != 1) {
+		dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__,
+			0x0081, res);
+		if (res >= 0)
+			res = -EIO;
+
+		return res;
+	}
+
+	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, 0x0081, buf[0]);
+
+	return 0;
+}
+
+static int pl2303_gpio_write(struct gpio_chip *chip)
+{
+	struct pl2303_gpio_data *pl2303_gpio = to_pl2303_gpio(chip);
+	struct usb_device *pl2303 = pl2303_gpio->pl2303;
+	struct device *dev = chip->dev;
+	int res;
+
+	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, 1, pl2303_gpio->index);
+
+	res = usb_control_msg(pl2303, usb_sndctrlpipe(pl2303, 0),
+			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
+			1, pl2303_gpio->index, NULL, 0, 100);
+	if (res) {
+		dev_err(dev, "%s - failed to write [%04x] = %02x: %d\n", __func__,
+			1, pl2303_gpio->index, res);
+		return res;
+	}
+
+	return 0;
+}
+
+static int pl2303_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	struct pl2303_gpio_data *pl2303_gpio = to_pl2303_gpio(chip);
+
+	if (offset == 0)
+		pl2303_gpio->index &= ~0x10;
+	else if (offset == 1)
+		pl2303_gpio->index &= ~0x20;
+	else
+		return -EINVAL;
+
+	pl2303_gpio_write(chip);
+	return 0;
+}
+
+static int pl2303_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct pl2303_gpio_data *pl2303_gpio = to_pl2303_gpio(chip);
+
+	if (offset == 0) {
+		pl2303_gpio->index |= 0x10;
+		if (value)
+			pl2303_gpio->index |= 0x40;
+		else
+			pl2303_gpio->index &= ~0x40;
+	} else if (offset == 1) {
+		pl2303_gpio->index |= 0x20;
+		if (value)
+			pl2303_gpio->index |= 0x80;
+		else
+			pl2303_gpio->index &= ~0x80;
+	} else {
+		return -EINVAL;
+	}
+
+	pl2303_gpio_write(chip);
+	return 0;
+}
+
+static void pl2303_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct pl2303_gpio_data *pl2303_gpio = to_pl2303_gpio(chip);
+
+	if (offset == 0) {
+		if (value)
+			pl2303_gpio->index |= 0x40;
+		else
+			pl2303_gpio->index &= ~0x40;
+	} else if (offset == 1) {
+		if (value)
+			pl2303_gpio->index |= 0x80;
+		else
+			pl2303_gpio->index &= ~0x80;
+	} else {
+		return;
+	}
+
+	pl2303_gpio_write(chip);
+}
+
+static int pl2303_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	unsigned char buf[1];
+	int value = 0;
+
+	if(pl2303_gpio_read(chip, buf) < 1)
+		return -EIO;
+	if (offset == 0)
+		value = buf[0] & 0x40;
+	else if (offset == 1)
+		value = buf[0] & 0x80;
+	else
+		return -EINVAL;
+	return value;
+}
+
+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,
+};
+
+static int pl2303_gpio_probe(struct platform_device *pdev)
+{
+	struct usb_device *pl2303 = platform_get_drvdata(pdev);
+	struct pl2303_gpio_data *pl2303_gpio;
+	int ret;
+
+	pl2303_gpio = kzalloc(sizeof(*pl2303_gpio), GFP_KERNEL);
+	if (pl2303_gpio == NULL)
+		return -ENOMEM;
+
+	/* initialize gpio0,gpio1 for input as default*/
+	pl2303_gpio->index = 0x00;
+	pl2303_gpio->pl2303 = pl2303;
+	pl2303_gpio->gpio_chip = template_chip;
+	pl2303_gpio->gpio_chip.ngpio = 2;
+	pl2303_gpio->gpio_chip.base = -1;
+	pl2303_gpio->gpio_chip.dev = &pdev->dev;
+	pl2303_gpio_write(&pl2303_gpio->gpio_chip);
+
+	ret = gpiochip_add(&pl2303_gpio->gpio_chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+		return ret;
+	}
+	platform_set_drvdata(pdev, pl2303_gpio);
+
+	return ret;
+}
+
+static int pl2303_gpio_remove(struct platform_device *pdev)
+{
+	struct pl2303_gpio_data *pl2303_gpio = platform_get_drvdata(pdev);
+
+	if (gpiochip_remove(&pl2303_gpio->gpio_chip))
+		dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
+	platform_set_drvdata(pdev, NULL);
+	kfree(pl2303_gpio);
+	return 0;
+}
+
+static struct platform_driver pl2303_gpio_driver = {
+	.driver.name	= "pl2303-gpio",
+	.driver.owner	= THIS_MODULE,
+	.probe		= pl2303_gpio_probe,
+	.remove		= pl2303_gpio_remove,
+};
+
+static int __init pl2303_gpio_init(void)
+{
+	return platform_driver_register(&pl2303_gpio_driver);
+}
+module_init(pl2303_gpio_init);
+
+static void __exit pl2303_gpio_exit(void)
+{
+	platform_driver_unregister(&pl2303_gpio_driver);
+}
+module_exit(pl2303_gpio_exit);
+
+MODULE_AUTHOR("Wang YanQing <udknight@...il.com>");
+MODULE_DESCRIPTION("GPIO driver for PL2303");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("platform:pl2303-gpio");
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index b3d5a35..1bb8928 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -28,6 +28,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include <asm/unaligned.h>
+#include <linux/platform_device.h>
 #include "pl2303.h"
 
 
@@ -146,6 +147,7 @@ struct pl2303_type_data {
 struct pl2303_serial_private {
 	const struct pl2303_type_data *type;
 	unsigned long quirks;
+	struct platform_device *pdev;
 };
 
 struct pl2303_private {
@@ -261,7 +263,22 @@ static int pl2303_startup(struct usb_serial *serial)
 		pl2303_vendor_write(serial, 2, 0x44);
 
 	kfree(buf);
+	if (type != TYPE_HX)
+		return 0;
 
+	spriv->pdev = platform_device_alloc("pl2303-gpio", PLATFORM_DEVID_AUTO);
+	if (spriv->pdev == NULL) {
+		dev_err(&serial->interface->dev, "Failed to allocate %s\n", "pl2303-gpio");
+	} else {
+		spriv->pdev->dev.parent = &serial->interface->dev;
+		platform_set_drvdata(spriv->pdev, serial->dev);
+		platform_device_add(spriv->pdev);
+		if (platform_device_add(spriv->pdev) != 0) {
+			dev_err(&serial->interface->dev, "Failed to register %s\n", "pl2303-gpio");
+			platform_device_put(spriv->pdev);
+			spriv->pdev = NULL;
+		}
+	}
 	return 0;
 }
 
@@ -269,6 +286,8 @@ static void pl2303_release(struct usb_serial *serial)
 {
 	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
 
+	if (spriv && spriv->pdev)
+		platform_device_unregister(spriv->pdev);
 	kfree(spriv);
 }
 
-- 
1.8.5.5.dirty
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists