diff mbox series

[2/5] gpio: add driver for AAEON devices

Message ID 20210525054149.1792-2-kunyang_fan@asus.com
State New
Headers show
Series [1/5] mfd: Add support for IO functions of AAEON devices | expand

Commit Message

aaeon.asus@gmail.com May 25, 2021, 5:41 a.m. UTC
From: Kunyang_Fan <kunyang_fan@asus.com>

This patch add support for the GPIO pins whose control are
transported to BIOS through ASUS WMI interface.

Signed-off-by: Kunyang_Fan <kunyang_fan@asus.com>
---
 drivers/gpio/Kconfig      |  11 ++
 drivers/gpio/Makefile     |   1 +
 drivers/gpio/gpio-aaeon.c | 205 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 217 insertions(+)
 create mode 100644 drivers/gpio/gpio-aaeon.c

Comments

Krzysztof Kozlowski May 26, 2021, 12:06 p.m. UTC | #1
On Tue, 25 May 2021 at 04:43, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
>
> On Tue, May 25, 2021 at 8:42 AM <aaeon.asus@gmail.com> wrote:
> >
> > From: Kunyang_Fan <kunyang_fan@asus.com>
> >
> > This patch add support for the GPIO pins whose control are
> > transported to BIOS through ASUS WMI interface.
> >
> > Signed-off-by: Kunyang_Fan <kunyang_fan@asus.com>
>
> Missed SoB of the submitter. Dunno if it's a critical issue.

Yes, it is. Every person touching patch, which includes sender, must
SoB it. This applies also to other patches in the series.

Best regards,
Krzysztof
diff mbox series

Patch

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 6d2437676a75..26acac425583 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1356,6 +1356,17 @@  endmenu
 menu "PCI GPIO expanders"
 	depends on PCI
 
+config GPIO_AAEON
+	tristate "AAEON GPIO support"
+	depends on ASUS_WMI
+	select MFD_AAEON
+	help
+	  Say yes here to support GPIO pins on Single Board Computers produced
+	  by AAEON.
+
+	  This driver leverages the ASUS WMI interface to access device
+	  resources.
+
 config GPIO_AMD8111
 	tristate "AMD 8111 GPIO driver"
 	depends on X86 || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 1e4894e0bf0f..50682c5c49d3 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -23,6 +23,7 @@  obj-$(CONFIG_GPIO_104_IDI_48)		+= gpio-104-idi-48.o
 obj-$(CONFIG_GPIO_104_IDIO_16)		+= gpio-104-idio-16.o
 obj-$(CONFIG_GPIO_74X164)		+= gpio-74x164.o
 obj-$(CONFIG_GPIO_74XX_MMIO)		+= gpio-74xx-mmio.o
+obj-$(CONFIG_GPIO_AAEON)                += gpio-aaeon.o
 obj-$(CONFIG_GPIO_ADNP)			+= gpio-adnp.o
 obj-$(CONFIG_GPIO_ADP5520)		+= gpio-adp5520.o
 obj-$(CONFIG_GPIO_ADP5588)		+= gpio-adp5588.o
diff --git a/drivers/gpio/gpio-aaeon.c b/drivers/gpio/gpio-aaeon.c
new file mode 100644
index 000000000000..3183c45dd194
--- /dev/null
+++ b/drivers/gpio/gpio-aaeon.c
@@ -0,0 +1,205 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AAEON GPIO driver
+ * Copyright (c) 2021, AAEON Ltd.
+ *
+ * Author: Edward Lin <edward1_lin@aaeon.com.tw>
+ *
+ * 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.
+ */
+#include <linux/acpi.h>
+#include <linux/bitops.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_data/x86/asus-wmi.h>
+#include <linux/platform_device.h>
+
+#define DRVNAME "gpio_aaeon"
+#define ASUS_NB_WMI_EVENT_GUID   "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
+#define AAEON_WMI_MGMT_GUID      "97845ED0-4E6D-11DE-8A39-0800200C9A66"
+
+#define GET_GPIO_NUMBER_ID       0x00010000
+#define GET_LEVEL_METHOD_ID      0x00010001
+#define SET_LEVEL_METHOD_ID      0x00010002
+#define GET_DIRECTION_METHOD_ID  0x00010003
+#define SET_DIRECTION_METHOD_ID  0x00010004
+#define GET_SIO_NUMBER_METHOD_ID 0xF0010
+
+struct aaeon_gpio_bank {
+	struct gpio_chip chip;
+	unsigned int regbase;
+	struct aaeon_gpio_data *data;
+};
+
+struct aaeon_gpio_data {
+	int nr_bank;
+	struct aaeon_gpio_bank *bank;
+};
+
+static int aaeon_gpio_get_number(void);
+static int aaeon_gpio_get_direction(struct gpio_chip *chip,
+				 unsigned int offset);
+static int aaeon_gpio_output_set_direction(struct gpio_chip *chip,
+				 unsigned int offset, int value);
+static int aaeon_gpio_input_set_direction(struct gpio_chip *chip,
+				 unsigned int offset);
+static int aaeon_gpio_get(struct gpio_chip *chip,
+				 unsigned int offset);
+static void aaeon_gpio_set(struct gpio_chip *chip, unsigned int offset,
+				 int value);
+
+#define AAEON_GPIO_BANK(_base, _ngpio, _regbase)			\
+{									\
+	.chip = {							\
+		.label            = DRVNAME,				\
+		.owner            = THIS_MODULE,			\
+		.get_direction    = aaeon_gpio_get_direction,		\
+		.direction_input  = aaeon_gpio_input_set_direction,     \
+		.direction_output = aaeon_gpio_output_set_direction,    \
+		.get              = aaeon_gpio_get,			\
+		.set              = aaeon_gpio_set,			\
+		.base             = _base,				\
+		.ngpio            = _ngpio,				\
+		.can_sleep        = true,				\
+	},								\
+	.regbase = _regbase,						\
+}
+
+static struct aaeon_gpio_bank aaeon_gpio_bank[] = {
+	AAEON_GPIO_BANK(0, 0, 0xF0),
+};
+
+static int aaeon_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+	int err, retval;
+	u32 dev_id = 0x0;
+
+	dev_id |= offset;
+	err = asus_wmi_evaluate_method(GET_DIRECTION_METHOD_ID, dev_id,
+				       0, &retval);
+	if (err)
+		return err;
+
+	return retval;
+}
+
+static int aaeon_gpio_input_set_direction(struct gpio_chip *chip,
+					  unsigned int offset)
+{
+	int err, retval;
+	u32 dev_id;
+
+	dev_id = BIT(16) | offset;
+	err = asus_wmi_evaluate_method(SET_DIRECTION_METHOD_ID, dev_id,
+				       0, &retval);
+	if (err)
+		return err;
+
+	return retval;
+}
+
+static int aaeon_gpio_output_set_direction(struct gpio_chip *chip,
+					   unsigned int offset, int value)
+{
+	int err, retval;
+	u32 dev_id = 0x0;
+
+	dev_id |= offset;
+	err = asus_wmi_evaluate_method(SET_DIRECTION_METHOD_ID, dev_id,
+				       0, &retval);
+	if (err)
+		return err;
+
+	return retval;
+}
+
+static int aaeon_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	int err, retval;
+	u32 dev_id = 0x0;
+
+	dev_id |= offset;
+	err = asus_wmi_evaluate_method(GET_LEVEL_METHOD_ID, dev_id, 0, &retval);
+	if (err)
+		return err;
+
+	return retval;
+}
+
+static void aaeon_gpio_set(struct gpio_chip *chip, unsigned int offset,
+			   int value)
+{
+	int retval;
+	u32 dev_id = offset;
+
+	if (value)
+		dev_id = BIT(16) | dev_id;
+
+	asus_wmi_evaluate_method(SET_LEVEL_METHOD_ID, dev_id, 0, &retval);
+}
+
+static int aaeon_gpio_get_number(void)
+{
+	int err, retval;
+
+	err = asus_wmi_evaluate_method(GET_GPIO_NUMBER_ID,
+				       GET_SIO_NUMBER_METHOD_ID,
+				       0, &retval);
+	if (err)
+		return err;
+
+	return retval;
+}
+
+static int __init aaeon_gpio_probe(struct platform_device *pdev)
+{
+	int err, i;
+	int dio_number = 0;
+	struct aaeon_gpio_data *data;
+	struct aaeon_gpio_bank *bank;
+
+	/* Prevent other drivers adding this platfom device */
+	if (!wmi_has_guid(AAEON_WMI_MGMT_GUID)) {
+		pr_debug("AAEON Management GUID not found\n");
+		return -ENODEV;
+	}
+
+	dio_number = aaeon_gpio_get_number();
+	if (dio_number < 0)
+		return -ENODEV;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->nr_bank = ARRAY_SIZE(aaeon_gpio_bank);
+	data->bank = aaeon_gpio_bank;
+	platform_set_drvdata(pdev, data);
+	bank = &data->bank[0];
+	bank->chip.parent = &pdev->dev;
+	bank->chip.ngpio = dio_number;
+	bank->data = data;
+	err = devm_gpiochip_add_data(&pdev->dev, &bank->chip, bank);
+	if (err)
+		pr_debug("Failed to register gpiochip %d: %d\n", i, err);
+
+	return err;
+}
+
+static struct platform_driver aaeon_gpio_driver = {
+	.driver = {
+		.name = "gpio-aaeon",
+	},
+};
+
+module_platform_driver_probe(aaeon_gpio_driver, aaeon_gpio_probe);
+
+MODULE_ALIAS("platform:gpio-aaeon");
+MODULE_DESCRIPTION("AAEON GPIO Driver");
+MODULE_AUTHOR("Edward Lin <edward1_lin@aaeon.com.tw>");
+MODULE_LICENSE("GPL v2");