UBUNTU: ODM: gpio: add driver for AAEON devices

BugLink: https://bugs.launchpad.net/bugs/1929504

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>
Review-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Review-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
This commit is contained in:
Kunyang_Fan
2021-06-16 13:56:59 +08:00
committed by Paolo Pisati
parent 0cf5311691
commit 93d1e6cb39
3 changed files with 218 additions and 0 deletions
+12
View File
@@ -1586,6 +1586,18 @@ endmenu
menu "PCI GPIO expanders"
depends on PCI
config GPIO_AAEON
tristate "AAEON GPIO support"
depends on ASUS_WMI
depends on UBUNTU_ODM_DRIVERS
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
+1
View File
@@ -24,6 +24,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_AGGREGATOR) += gpio-aggregator.o
+205
View File
@@ -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");