From: "Ji-Ze Hong (Peter Hong)" <hpeter@gmail.com>
To: johan@kernel.org
Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org,
linux-kernel@vger.kernel.org, peter_hong@fintek.com.tw,
"Ji-Ze Hong (Peter Hong)" <hpeter+linux_kernel@gmail.com>
Subject: [PATCH V2 7/7] USB: serial: f81232: Add gpiolib to GPIO device
Date: Mon, 23 Sep 2019 10:24:49 +0800 [thread overview]
Message-ID: <20190923022449.10952-8-hpeter+linux_kernel@gmail.com> (raw)
In-Reply-To: <20190923022449.10952-1-hpeter+linux_kernel@gmail.com>
The Fintek F81534A series contains 3 GPIOs per UART and The max GPIOs
is 12x3 = 36 GPIOs and this patch will implements GPIO device as a
gpiochip to control all GPIO pins even transforms to transceiver pins.
Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
---
drivers/usb/serial/f81232.c | 249 ++++++++++++++++++++++++++++++++++++
1 file changed, 249 insertions(+)
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 82cc1e6cff62..dc9b28738b80 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -18,6 +18,7 @@
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
+#include <linux/gpio.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial_reg.h>
@@ -104,6 +105,8 @@ MODULE_DEVICE_TABLE(usb, all_serial_id_table);
#define F81534A_TRIGGER_MULTPILE_4X BIT(3)
#define F81534A_FIFO_128BYTE (BIT(1) | BIT(0))
+#define F81534A_MAX_PORT 12
+
/* Serial port self GPIO control, 2bytes [control&output data][input data] */
#define F81534A_GPIO_REG 0x10e
#define F81534A_GPIO_MODE2_DIR BIT(6) /* 1: input, 0: output */
@@ -115,6 +118,13 @@ MODULE_DEVICE_TABLE(usb, all_serial_id_table);
#define F81534A_CMD_ENABLE_PORT 0x116
+/*
+ * Control device global GPIO control,
+ * 2bytes [control&output data][input data]
+ */
+#define F81534A_CTRL_GPIO_REG 0x1601
+#define F81534A_CTRL_GPIO_MAX_PIN 3
+
struct f81232_private {
struct mutex lock;
u8 modem_control;
@@ -126,6 +136,12 @@ struct f81232_private {
struct usb_serial_port *port;
};
+struct f81534a_ctrl_private {
+ struct usb_interface *intf;
+ struct gpio_chip chip;
+ struct mutex lock;
+};
+
static u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 };
static u8 const clock_table[] = { F81232_CLK_1_846_MHZ, F81232_CLK_14_77_MHZ,
F81232_CLK_18_46_MHZ, F81232_CLK_24_MHZ };
@@ -863,6 +879,50 @@ static void f81232_lsr_worker(struct work_struct *work)
dev_warn(&port->dev, "read LSR failed: %d\n", status);
}
+static int f81534a_ctrl_get_register(struct usb_device *dev, u16 reg, u16 size,
+ void *val)
+{
+ int retry = F81534A_ACCESS_REG_RETRY;
+ int status;
+ u8 *tmp;
+
+ tmp = kmalloc(size, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ while (retry--) {
+ status = usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ F81534A_REGISTER_REQUEST,
+ F81534A_GET_REGISTER,
+ reg,
+ 0,
+ tmp,
+ size,
+ USB_CTRL_GET_TIMEOUT);
+ if (status != size) {
+ status = usb_translate_errors(status);
+ if (status == -EIO)
+ continue;
+
+ status = -EIO;
+ } else {
+ status = 0;
+ memcpy(val, tmp, size);
+ }
+
+ break;
+ }
+
+ if (status) {
+ dev_err(&dev->dev, "get reg: %x, failed status: %d\n", reg,
+ status);
+ }
+
+ kfree(tmp);
+ return status;
+}
+
static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size,
void *val)
{
@@ -908,6 +968,182 @@ static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size,
return status;
}
+#ifdef CONFIG_GPIOLIB
+static int f81534a_ctrl_set_mask_register(struct usb_device *dev, u16 reg,
+ u8 mask, u8 val)
+{
+ int status;
+ u8 tmp;
+
+ status = f81534a_ctrl_get_register(dev, reg, 1, &tmp);
+ if (status)
+ return status;
+
+
+ tmp = (tmp & ~mask) | (val & mask);
+
+ status = f81534a_ctrl_set_register(dev, reg, 1, &tmp);
+ if (status)
+ return status;
+
+ return 0;
+}
+
+static int f81534a_gpio_get(struct gpio_chip *chip, unsigned int gpio_num)
+{
+ struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+ struct usb_interface *intf = priv->intf;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ int status;
+ u8 tmp[2];
+ int set;
+ int idx;
+ int reg;
+
+ set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+ idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+ reg = F81534A_CTRL_GPIO_REG + set;
+
+ mutex_lock(&priv->lock);
+
+ status = f81534a_ctrl_get_register(dev, reg, sizeof(tmp), tmp);
+ if (status) {
+ mutex_unlock(&priv->lock);
+ return status;
+ }
+
+ mutex_unlock(&priv->lock);
+
+ return !!(tmp[1] & BIT(idx));
+}
+
+static int f81534a_gpio_direction_in(struct gpio_chip *chip,
+ unsigned int gpio_num)
+{
+ struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+ struct usb_interface *intf = priv->intf;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ int status;
+ int set;
+ int idx;
+ int reg;
+ u8 mask;
+
+ set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+ idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+ mask = F81534A_GPIO_MODE0_DIR << idx;
+ reg = F81534A_CTRL_GPIO_REG + set;
+
+ mutex_lock(&priv->lock);
+ status = f81534a_ctrl_set_mask_register(dev, reg, mask, mask);
+ mutex_unlock(&priv->lock);
+
+ return status;
+}
+
+static int f81534a_gpio_direction_out(struct gpio_chip *chip,
+ unsigned int gpio_num, int val)
+{
+ struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+ struct usb_interface *intf = priv->intf;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ int status;
+ int set;
+ int idx;
+ int reg;
+ u8 mask;
+ u8 data;
+
+ set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+ idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+ mask = (F81534A_GPIO_MODE0_DIR << idx) | BIT(idx);
+ reg = F81534A_CTRL_GPIO_REG + set;
+ data = val ? BIT(idx) : 0;
+
+ mutex_lock(&priv->lock);
+ status = f81534a_ctrl_set_mask_register(dev, reg, mask, data);
+ mutex_unlock(&priv->lock);
+
+ return status;
+}
+
+static void f81534a_gpio_set(struct gpio_chip *chip, unsigned int gpio_num,
+ int val)
+{
+ f81534a_gpio_direction_out(chip, gpio_num, val);
+}
+
+static int f81534a_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int gpio_num)
+{
+ struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+ struct usb_interface *intf = priv->intf;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ int status;
+ u8 tmp[2];
+ int set;
+ int idx;
+ int reg;
+ u8 mask;
+
+ set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+ idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+ mask = F81534A_GPIO_MODE0_DIR << idx;
+ reg = F81534A_CTRL_GPIO_REG + set;
+
+ mutex_lock(&priv->lock);
+
+ status = f81534a_ctrl_get_register(dev, reg, sizeof(tmp), tmp);
+ if (status) {
+ mutex_unlock(&priv->lock);
+ return status;
+ }
+
+ mutex_unlock(&priv->lock);
+
+ if (tmp[0] & mask)
+ return GPIOF_DIR_IN;
+
+ return GPIOF_DIR_OUT;
+}
+
+static int f81534a_prepare_gpio(struct usb_interface *intf)
+{
+ struct f81534a_ctrl_private *priv = usb_get_intfdata(intf);
+ int status;
+
+ priv->chip.parent = &intf->dev;
+ priv->chip.owner = THIS_MODULE;
+ priv->chip.get_direction = f81534a_gpio_get_direction,
+ priv->chip.get = f81534a_gpio_get;
+ priv->chip.direction_input = f81534a_gpio_direction_in;
+ priv->chip.set = f81534a_gpio_set;
+ priv->chip.direction_output = f81534a_gpio_direction_out;
+ priv->chip.label = "f81534a";
+ priv->chip.can_sleep = true;
+ /* M0(SD)/M1/M2 */
+ priv->chip.ngpio = F81534A_CTRL_GPIO_MAX_PIN * F81534A_MAX_PORT;
+ priv->chip.base = -1;
+
+ priv->intf = intf;
+ mutex_init(&priv->lock);
+
+ status = devm_gpiochip_add_data(&intf->dev, &priv->chip, priv);
+ if (status) {
+ dev_err(&intf->dev, "failed to register gpiochip: %d\n",
+ status);
+ return status;
+ }
+
+ return 0;
+}
+#else
+static int f81534a_prepare_gpio(struct usb_interface *intf)
+{
+ return 0;
+}
+#endif
+
static int f81534a_ctrl_enable_all_ports(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev(intf);
@@ -930,8 +1166,21 @@ static int f81534a_ctrl_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
+ struct f81534a_ctrl_private *priv;
int status;
+ priv = devm_kzalloc(&intf->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ mutex_init(&priv->lock);
+ usb_set_intfdata(intf, priv);
+ priv->intf = intf;
+
+ status = f81534a_prepare_gpio(intf);
+ if (status)
+ return status;
+
status = f81534a_ctrl_enable_all_ports(intf);
if (status)
return status;
--
2.17.1
next prev parent reply other threads:[~2019-09-23 2:25 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-09-23 2:24 [PATCH V2 0/7] Add Fintek F81534A series usb-to-serial driver Ji-Ze Hong (Peter Hong)
2019-09-23 2:24 ` [PATCH V2 1/7] USB: serial: f81232: Extract LSR handler Ji-Ze Hong (Peter Hong)
2019-10-23 9:23 ` Johan Hovold
2019-09-23 2:24 ` [PATCH V2 2/7] USB: serial: f81232: Add tx_empty function Ji-Ze Hong (Peter Hong)
2019-10-23 9:15 ` Johan Hovold
2019-09-23 2:24 ` [PATCH V2 3/7] USB: serial: f81232: Use devm_kzalloc Ji-Ze Hong (Peter Hong)
2019-09-23 2:24 ` [PATCH V2 4/7] USB: serial: f81232: Add F81534A support Ji-Ze Hong (Peter Hong)
2019-10-23 9:59 ` Johan Hovold
2019-09-23 2:24 ` [PATCH V2 5/7] USB: serial: f81232: Set F81534A serial port with RS232 mode Ji-Ze Hong (Peter Hong)
2019-10-23 11:53 ` Johan Hovold
2019-10-24 8:52 ` Ji-Ze Hong (Peter Hong)
2020-01-08 14:35 ` Johan Hovold
[not found] ` <3c79f786-de34-550e-3964-d7fb334f6d56@gmail.com>
2020-01-13 15:17 ` Johan Hovold
2020-01-14 1:08 ` Ji-Ze Hong (Peter Hong)
2019-09-23 2:24 ` [PATCH V2 6/7] USB: serial: f81232: Add generator for F81534A Ji-Ze Hong (Peter Hong)
2019-10-23 12:05 ` Johan Hovold
2019-10-23 12:25 ` Johan Hovold
2019-09-23 2:24 ` Ji-Ze Hong (Peter Hong) [this message]
2019-10-23 12:22 ` [PATCH V2 7/7] USB: serial: f81232: Add gpiolib to GPIO device Johan Hovold
2019-10-30 2:00 ` Ji-Ze Hong (Peter Hong)
2020-01-08 14:46 ` Johan Hovold
2020-01-09 2:43 ` Ji-Ze Hong (Peter Hong)
2020-01-13 15:24 ` Johan Hovold
2019-10-23 9:21 ` [PATCH V2 0/7] Add Fintek F81534A series usb-to-serial driver Johan Hovold
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190923022449.10952-8-hpeter+linux_kernel@gmail.com \
--to=hpeter@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=hpeter+linux_kernel@gmail.com \
--cc=johan@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=peter_hong@fintek.com.tw \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).