<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:SimSun;
        panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:SimSun;
        panose-1:2 1 6 0 3 1 1 1 1 1;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
p.MsoDate, li.MsoDate, div.MsoDate
        {mso-style-priority:99;
        mso-style-link:"Date Char";
        margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:#0563C1;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:#954F72;
        text-decoration:underline;}
span.EmailStyle17
        {mso-style-type:personal-compose;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
span.DateChar
        {mso-style-name:"Date Char";
        mso-style-priority:99;
        mso-style-link:Date;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.25in 1.0in 1.25in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="#0563C1" vlink="#954F72">
<div class="WordSection1">
<p class="MsoNormal">Hi Joel/Andrew,<o:p></o:p></p>
<p class="MsoNormal">I write a drive to enable GPIO passthrough for buttons (like power/reset/id button) as following attached patch.<o:p></o:p></p>
<p class="MsoNormal">Do you think it is acceptable?<o:p></o:p></p>
<p class="MsoNormal">Or we could do it in pinmux and extend gpio driver? Design passthrough state except in/out.<o:p></o:p></p>
<p class="MsoNormal">What’s your suggestions?<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Thanks Kwin.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig<o:p></o:p></p>
<p class="MsoNormal">index f2062546250c..e94ee86820d3 100644<o:p></o:p></p>
<p class="MsoNormal">--- a/drivers/misc/Kconfig<o:p></o:p></p>
<p class="MsoNormal">+++ b/drivers/misc/Kconfig<o:p></o:p></p>
<p class="MsoNormal">@@ -4,6 +4,12 @@<o:p></o:p></p>
<p class="MsoNormal"><o:p></o:p></p>
<p class="MsoNormal"> menu "Misc devices"<o:p></o:p></p>
<p class="MsoNormal"><o:p></o:p></p>
<p class="MsoNormal">+config GPIO_PASS_THROUGH<o:p></o:p></p>
<p class="MsoNormal">+             tristate "GPIO Pass Through"<o:p></o:p></p>
<p class="MsoNormal">+             depends on (ARCH_ASPEED || COMPILE_TEST)<o:p></o:p></p>
<p class="MsoNormal">+             help<o:p></o:p></p>
<p class="MsoNormal">+               Enable this for buttons GPIO pass through.<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">config SENSORS_LIS3LV02D<o:p></o:p></p>
<p class="MsoNormal">              tristate<o:p></o:p></p>
<p class="MsoNormal">              depends on INPUT<o:p></o:p></p>
<p class="MsoNormal">diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile<o:p></o:p></p>
<p class="MsoNormal">index bb89694e6b4b..13b8b8edbb70 100644<o:p></o:p></p>
<p class="MsoNormal">--- a/drivers/misc/Makefile<o:p></o:p></p>
<p class="MsoNormal">+++ b/drivers/misc/Makefile<o:p></o:p></p>
<p class="MsoNormal">@@ -61,3 +61,4 @@ obj-$(CONFIG_ASPEED_LPC_SIO)   += aspeed-lpc-sio.o<o:p></o:p></p>
<p class="MsoNormal">obj-$(CONFIG_PCI_ENDPOINT_TEST)      += pci_endpoint_test.o<o:p></o:p></p>
<p class="MsoNormal">obj-$(CONFIG_OCXL)                     += ocxl/<o:p></o:p></p>
<p class="MsoNormal">obj-$(CONFIG_MISC_RTSX)                         += cardreader/<o:p></o:p></p>
<p class="MsoNormal">+obj-$(CONFIG_GPIO_PASS_THROUGH)   += gpio-passthrough.o<o:p></o:p></p>
<p class="MsoNormal">diff --git a/drivers/misc/gpio-passthrough.c b/drivers/misc/gpio-passthrough.c<o:p></o:p></p>
<p class="MsoNormal">new file mode 100644<o:p></o:p></p>
<p class="MsoNormal">index 000000000000..0126fc08ae55<o:p></o:p></p>
<p class="MsoNormal">--- /dev/null<o:p></o:p></p>
<p class="MsoNormal">+++ b/drivers/misc/gpio-passthrough.c<o:p></o:p></p>
<p class="MsoNormal">@@ -0,0 +1,260 @@<o:p></o:p></p>
<p class="MsoNormal">+// SPDX-License-Identifier: GPL-2.0<o:p></o:p></p>
<p class="MsoNormal">+/*<o:p></o:p></p>
<p class="MsoNormal">+ * Copyright (c) 2018 Intel Corporation<o:p></o:p></p>
<p class="MsoNormal">+*/<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+#include "gpio-passthrough.h"<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+struct aspeed_gpio_pass_through_dev {<o:p></o:p></p>
<p class="MsoNormal">+             struct miscdevice              miscdev;<o:p></o:p></p>
<p class="MsoNormal">+             unsigned int        addr;<o:p></o:p></p>
<p class="MsoNormal">+             unsigned int        size;<o:p></o:p></p>
<p class="MsoNormal">+};<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static struct aspeed_gpio_pass_through_dev ast_cdev_gpio_pass_through;<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static long ast_passthru_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+             long ret = 0;<o:p></o:p></p>
<p class="MsoNormal">+             struct passthru_ioctl_data passthru_data;<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             if (cmd == GPIO_IOC_PASSTHRU)<o:p></o:p></p>
<p class="MsoNormal">+             {<o:p></o:p></p>
<p class="MsoNormal">+                            if (copy_from_user(&passthru_data,<o:p></o:p></p>
<p class="MsoNormal">+                                           (void __user*)arg, sizeof(passthru_data)))<o:p></o:p></p>
<p class="MsoNormal">+                                           return -EFAULT;<o:p></o:p></p>
<p class="MsoNormal">+                            if (passthru_data.idx >= GPIO_PASSTHRU_MAX)<o:p></o:p></p>
<p class="MsoNormal">+                                           return -EINVAL;<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+                            switch (passthru_data.cmd) {<o:p></o:p></p>
<p class="MsoNormal">+                            case SET_GPIO_PASSTHRU_ENABLE:<o:p></o:p></p>
<p class="MsoNormal">+                                           ast_set_passthru_enable(passthru_data.idx,<o:p></o:p></p>
<p class="MsoNormal">+                                                                         passthru_data.data);<o:p></o:p></p>
<p class="MsoNormal">+                                           break;<o:p></o:p></p>
<p class="MsoNormal">+                            case GET_GPIO_PASSTHRU_ENABLE:<o:p></o:p></p>
<p class="MsoNormal">+                                           passthru_data.data = ast_get_passthru_enable(passthru_data.idx);<o:p></o:p></p>
<p class="MsoNormal">+                                           if (copy_to_user((void __user*)arg, &passthru_data,<o:p></o:p></p>
<p class="MsoNormal">+                                                                                                       sizeof(passthru_data)))<o:p></o:p></p>
<p class="MsoNormal">+                                           ret = -EFAULT;<o:p></o:p></p>
<p class="MsoNormal">+                            break;<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+                            case SET_GPIO_PASSTHRU_OUT:<o:p></o:p></p>
<p class="MsoNormal">+                                           ast_set_passthru_out(passthru_data.idx, passthru_data.data);<o:p></o:p></p>
<p class="MsoNormal">+                            break;<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+                            default:<o:p></o:p></p>
<p class="MsoNormal">+                                           ret = -EINVAL;<o:p></o:p></p>
<p class="MsoNormal">+                            break;<o:p></o:p></p>
<p class="MsoNormal">+                            }<o:p></o:p></p>
<p class="MsoNormal">+             }<o:p></o:p></p>
<p class="MsoNormal">+             return ret;<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static int ast_passthru_open(struct inode *inode, struct file *filp)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+             return container_of(filp->private_data,<o:p></o:p></p>
<p class="MsoNormal">+                            struct aspeed_gpio_pass_through_dev, miscdev);<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static const struct file_operations ast_gpio_pth_fops = {<o:p></o:p></p>
<p class="MsoNormal">+             .owner          = THIS_MODULE,<o:p></o:p></p>
<p class="MsoNormal">+             .llseek         = no_llseek,<o:p></o:p></p>
<p class="MsoNormal">+             .unlocked_ioctl = ast_passthru_ioctl,<o:p></o:p></p>
<p class="MsoNormal">+             .open           = ast_passthru_open,<o:p></o:p></p>
<p class="MsoNormal">+};<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static struct miscdevice ast_gpio_pth_miscdev = {<o:p></o:p></p>
<p class="MsoNormal">+             .minor = MISC_DYNAMIC_MINOR,<o:p></o:p></p>
<p class="MsoNormal">+             .name = GPIO_PASS_THROUGH_NAME,<o:p></o:p></p>
<p class="MsoNormal">+             .fops = &ast_gpio_pth_fops,<o:p></o:p></p>
<p class="MsoNormal">+};<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static u32 ast_scu_base  = IO_ADDRESS(AST_SCU_BASE);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static inline u32 ast_scu_read(u32 reg)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+             return readl((void *)(ast_scu_base + reg));<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static inline void ast_scu_write(u32 val, u32 reg)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+#ifdef CONFIG_AST_SCU_LOCK<o:p></o:p></p>
<p class="MsoNormal">+             writel(SCU_PROTECT_UNLOCK, (void *)(ast_scu_base + AST_SCU_PROTECT));<o:p></o:p></p>
<p class="MsoNormal">+             writel(val,                (void *)(ast_scu_base + reg));<o:p></o:p></p>
<p class="MsoNormal">+             writel(0x000000AA,         (void *)(ast_scu_base + AST_SCU_PROTECT));<o:p></o:p></p>
<p class="MsoNormal">+#else<o:p></o:p></p>
<p class="MsoNormal">+             writel(SCU_PROTECT_UNLOCK, (void *)(ast_scu_base + AST_SCU_PROTECT));<o:p></o:p></p>
<p class="MsoNormal">+             writel(val,                (void *)(ast_scu_base + reg));<o:p></o:p></p>
<p class="MsoNormal">+#endif<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static int gpio_pass_through_probe(struct platform_device *pdev)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+             struct aspeed_gpio_pass_through_dev   *gpio_pth_dev = &ast_cdev_gpio_pass_through;<o:p></o:p></p>
<p class="MsoNormal">+             struct device *dev = &pdev->dev;<o:p></o:p></p>
<p class="MsoNormal">+             struct resource *rc;<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             dev_set_drvdata(&pdev->dev, gpio_pth_dev);<o:p></o:p></p>
<p class="MsoNormal">+             rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);<o:p></o:p></p>
<p class="MsoNormal">+             if (!rc) {<o:p></o:p></p>
<p class="MsoNormal">+                            dev_err(dev, "Fail to platform_get_resource\n");<o:p></o:p></p>
<p class="MsoNormal">+                            return -ENXIO;<o:p></o:p></p>
<p class="MsoNormal">+             }<o:p></o:p></p>
<p class="MsoNormal">+             gpio_pth_dev->addr = rc->start;<o:p></o:p></p>
<p class="MsoNormal">+             gpio_pth_dev->size = resource_size(rc);<o:p></o:p></p>
<p class="MsoNormal">+             gpio_pth_dev->miscdev = ast_gpio_pth_miscdev;<o:p></o:p></p>
<p class="MsoNormal">+             ast_passthru_init();<o:p></o:p></p>
<p class="MsoNormal">+             printk("GPIO PASS THROUGH DRIVER is loaded \n");<o:p></o:p></p>
<p class="MsoNormal">+             return misc_register(&gpio_pth_dev->miscdev);<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static int gpio_pass_through_remove(struct platform_device *pdev)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+             struct aspeed_gpio_pass_through_dev *gpio_pth_dev =<o:p></o:p></p>
<p class="MsoNormal">+                                                          dev_get_drvdata(&pdev->dev);<o:p></o:p></p>
<p class="MsoNormal">+             misc_deregister(&gpio_pth_dev->miscdev);<o:p></o:p></p>
<p class="MsoNormal">+             printk("GPIO PASS THROUGH DRIVER is removing \n");<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             return 0;<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static struct platform_driver gpio_pass_through_driver = {<o:p></o:p></p>
<p class="MsoNormal">+             .probe     = gpio_pass_through_probe,<o:p></o:p></p>
<p class="MsoNormal">+             .remove    = gpio_pass_through_remove,<o:p></o:p></p>
<p class="MsoNormal">+             .driver    = {<o:p></o:p></p>
<p class="MsoNormal">+                            .name  = "gpio-pass-through",<o:p></o:p></p>
<p class="MsoNormal">+        .owner = THIS_MODULE,<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             },<o:p></o:p></p>
<p class="MsoNormal">+};<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+/* GPIOE group only */<o:p></o:p></p>
<p class="MsoNormal">+struct gpio_passthru {<o:p></o:p></p>
<p class="MsoNormal">+             u32 passthru_mask;<o:p></o:p></p>
<p class="MsoNormal">+             u16 pin_in;<o:p></o:p></p>
<p class="MsoNormal">+             u16 pin_out;<o:p></o:p></p>
<p class="MsoNormal">+};<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static struct gpio_passthru passthru_settings[GPIO_PASSTHRU_MAX] = {<o:p></o:p></p>
<p class="MsoNormal">+             [GPIO_PASSTHRU0] = {<o:p></o:p></p>
<p class="MsoNormal">+                                           .passthru_mask = (1 << 12), /* SCU8C[12] */<o:p></o:p></p>
<p class="MsoNormal">+                                           .pin_in        = PGPIO_PIN(GPIOE, 0),<o:p></o:p></p>
<p class="MsoNormal">+                                           .pin_out       = PGPIO_PIN(GPIOE, 1),<o:p></o:p></p>
<p class="MsoNormal">+                            },<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             [GPIO_PASSTHRU1] = {<o:p></o:p></p>
<p class="MsoNormal">+                                           .passthru_mask = (1 << 13), /* SCU8C[13] */<o:p></o:p></p>
<p class="MsoNormal">+                                           .pin_in        = PGPIO_PIN(GPIOE, 2),<o:p></o:p></p>
<p class="MsoNormal">+                                           .pin_out       = PGPIO_PIN(GPIOE, 3),<o:p></o:p></p>
<p class="MsoNormal">+                            },<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             [GPIO_PASSTHRU2] = {<o:p></o:p></p>
<p class="MsoNormal">+                                           .passthru_mask = (1 << 14), /* SCU8C[14] */<o:p></o:p></p>
<p class="MsoNormal">+                                           .pin_in        = PGPIO_PIN(GPIOE, 4),<o:p></o:p></p>
<p class="MsoNormal">+                                           .pin_out       = PGPIO_PIN(GPIOE, 5),<o:p></o:p></p>
<p class="MsoNormal">+                            },<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             [GPIO_PASSTHRU3] = {<o:p></o:p></p>
<p class="MsoNormal">+                                           .passthru_mask = (1 << 15), /* SCU8C[15] */<o:p></o:p></p>
<p class="MsoNormal">+                                           .pin_in        = PGPIO_PIN(GPIOE, 6),<o:p></o:p></p>
<p class="MsoNormal">+                                           .pin_out       = PGPIO_PIN(GPIOE, 7),<o:p></o:p></p>
<p class="MsoNormal">+                            },<o:p></o:p></p>
<p class="MsoNormal">+};<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static void ast_set_passthru_enable(<o:p></o:p></p>
<p class="MsoNormal">+                                           unsigned short idx, unsigned int enable)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+             u32 val;<o:p></o:p></p>
<p class="MsoNormal">+             unsigned long flags;<o:p></o:p></p>
<p class="MsoNormal">+             struct gpio_passthru *passthru = &passthru_settings[idx];<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             local_irq_save(flags);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             val = ast_scu_read(AST_SCU_FUN_PIN_CTRL4);<o:p></o:p></p>
<p class="MsoNormal">+             if (enable)<o:p></o:p></p>
<p class="MsoNormal">+                            val |=  (passthru->passthru_mask);<o:p></o:p></p>
<p class="MsoNormal">+             else<o:p></o:p></p>
<p class="MsoNormal">+                            val &= ~(passthru->passthru_mask);<o:p></o:p></p>
<p class="MsoNormal">+             ast_scu_write(val, AST_SCU_FUN_PIN_CTRL4);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             local_irq_restore(flags);<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static unsigned int ast_get_passthru_enable(unsigned short idx)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+             unsigned int enable;<o:p></o:p></p>
<p class="MsoNormal">+             unsigned long flags;<o:p></o:p></p>
<p class="MsoNormal">+             struct gpio_passthru *passthru = &passthru_settings[idx];<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             local_irq_save(flags);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             enable = (ast_scu_read(AST_SCU_FUN_PIN_CTRL4) & passthru->passthru_mask) != 0 ? 1 : 0;<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             local_irq_restore(flags);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             return enable;<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static void ast_set_passthru_out(<o:p></o:p></p>
<p class="MsoNormal">+                                           unsigned short idx, unsigned int val)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+             unsigned long flags;<o:p></o:p></p>
<p class="MsoNormal">+             struct gpio_passthru *passthru = &passthru_settings[idx];<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             local_irq_save(flags);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             /* Disable PASSTHRU */<o:p></o:p></p>
<p class="MsoNormal">+             val  = ast_scu_read(AST_SCU_FUN_PIN_CTRL4);<o:p></o:p></p>
<p class="MsoNormal">+             val &= ~(passthru->passthru_mask);<o:p></o:p></p>
<p class="MsoNormal">+             ast_scu_write(val, AST_SCU_FUN_PIN_CTRL4);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             local_irq_restore(flags);<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static void ast_passthru_init(void)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+             int i;<o:p></o:p></p>
<p class="MsoNormal">+             u32 val;<o:p></o:p></p>
<p class="MsoNormal">+             unsigned long flags;<o:p></o:p></p>
<p class="MsoNormal">+             struct gpio_passthru *passthru;<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             local_irq_save(flags);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             /* 1. Enable GPIOE pin mode, SCU80[16:23] = 00 */<o:p></o:p></p>
<p class="MsoNormal">+             ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) & (~0x00FF0000),<o:p></o:p></p>
<p class="MsoNormal">+                           AST_SCU_FUN_PIN_CTRL1);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             /* 2. Enable them by setting SCU8C[12:15] */<o:p></o:p></p>
<p class="MsoNormal">+             for (i = 0; i < GPIO_PASSTHRU_MAX; i++) {<o:p></o:p></p>
<p class="MsoNormal">+                            passthru = &passthru_settings[i];<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+                            val  = ast_scu_read(AST_SCU_FUN_PIN_CTRL4);<o:p></o:p></p>
<p class="MsoNormal">+                            val |= passthru->passthru_mask;<o:p></o:p></p>
<p class="MsoNormal">+                            ast_scu_write(val, AST_SCU_FUN_PIN_CTRL4);<o:p></o:p></p>
<p class="MsoNormal">+             }<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             /**************************************************************<o:p></o:p></p>
<p class="MsoNormal">+             * 3. Disable HWTrap for GPIOE pass-through mode<o:p></o:p></p>
<p class="MsoNormal">+             *<o:p></o:p></p>
<p class="MsoNormal">+             * Hardware strap register (SCU70) programming method.<o:p></o:p></p>
<p class="MsoNormal">+             *   #Write '1' to SCU70 can set the specific bit with value '1'<o:p></o:p></p>
<p class="MsoNormal">+             *    Write '0' has no effect.<o:p></o:p></p>
<p class="MsoNormal">+             *   #Write '1' to SCU7C can clear the specific bit of SCU70 to<o:p></o:p></p>
<p class="MsoNormal">+             *    value '0'. Write '0' has no effect.<o:p></o:p></p>
<p class="MsoNormal">+             **************************************************************/<o:p></o:p></p>
<p class="MsoNormal">+             if (ast_scu_read(AST_SCU_HW_STRAP1) & (0x1 << 22))<o:p></o:p></p>
<p class="MsoNormal">+                            ast_scu_write((0x1 << 22), AST_SCU_REVISION_ID);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             local_irq_restore(flags);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             printk("HW_STRAP1 = 0x%08X\n", ast_scu_read(AST_SCU_HW_STRAP1));<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+module_platform_driver(gpio_pass_through_driver);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+MODULE_AUTHOR("Kuiying Wang <kuiying.wang@intel.com>");<o:p></o:p></p>
<p class="MsoNormal">+MODULE_DESCRIPTION("GPIO Pass Through Control Driver for all buttons like Power/Reset/ID button");<o:p></o:p></p>
<p class="MsoNormal">+MODULE_LICENSE("GPL v2");<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">diff --git a/drivers/misc/gpio-passthrough.h b/drivers/misc/gpio-passthrough.h<o:p></o:p></p>
<p class="MsoNormal">new file mode 100644<o:p></o:p></p>
<p class="MsoNormal">index 000000000000..a7274b8ab31e<o:p></o:p></p>
<p class="MsoNormal">--- /dev/null<o:p></o:p></p>
<p class="MsoNormal">+++ b/drivers/misc/gpio-passthrough.h<o:p></o:p></p>
<p class="MsoNormal">@@ -0,0 +1,60 @@<o:p></o:p></p>
<p class="MsoNormal">+#ifndef __GPIO_PASS_THROUGH_H__<o:p></o:p></p>
<p class="MsoNormal">+#define __GPIO_PASS_THROUGH_H__<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+#include <linux/kernel.h><o:p></o:p></p>
<p class="MsoNormal">+#include <linux/miscdevice.h><o:p></o:p></p>
<p class="MsoNormal">+#include <linux/uaccess.h><o:p></o:p></p>
<p class="MsoNormal">+#include <linux/module.h><o:p></o:p></p>
<p class="MsoNormal">+#include <linux/of_platform.h><o:p></o:p></p>
<p class="MsoNormal">+#include <linux/mm.h><o:p></o:p></p>
<p class="MsoNormal">+#include <asm/io.h><o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+#define PGPIO_PIN(PORT, PIN)   (((PORT) << 3) | ((PIN) & 0x07))<o:p></o:p></p>
<p class="MsoNormal">+#define GPIOE    4<o:p></o:p></p>
<p class="MsoNormal">+#define AST_SCU_BASE                    0x1E6E2000  /* SCU */<o:p></o:p></p>
<p class="MsoNormal">+#define AST_SCU_PROTECT                 0x00        /*  protection key register */<o:p></o:p></p>
<p class="MsoNormal">+#define SCU_PROTECT_UNLOCK              0x1688A8A8<o:p></o:p></p>
<p class="MsoNormal">+#define AST_SCU_FUN_PIN_CTRL4           0x8C        /*  Multi-function Pin Control#4*/<o:p></o:p></p>
<p class="MsoNormal">+#define AST_SCU_FUN_PIN_CTRL1           0x80        /*  Multi-function Pin Control#1*/<o:p></o:p></p>
<p class="MsoNormal">+#define AST_SCU_HW_STRAP1               0x70        /*  hardware strapping register */<o:p></o:p></p>
<p class="MsoNormal">+#define AST_SCU_REVISION_ID             0x7C        /*  Silicon revision ID register */<o:p></o:p></p>
<p class="MsoNormal">+#define GPIO_PASS_THROUGH_NAME          "gpiopassthrough"<o:p></o:p></p>
<p class="MsoNormal">+#define IO_ADDRESS(x)                   (x)<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+enum GPIO_PASSTHRU_INDEX {<o:p></o:p></p>
<p class="MsoNormal">+             GPIO_PASSTHRU0 = 0,  /* GPIOE0 -> GPIOE1 */<o:p></o:p></p>
<p class="MsoNormal">+             GPIO_PASSTHRU1,      /* GPIOE2 -> GPIOE3 */<o:p></o:p></p>
<p class="MsoNormal">+             GPIO_PASSTHRU2,      /* GPIOE4 -> GPIOE5 */<o:p></o:p></p>
<p class="MsoNormal">+             GPIO_PASSTHRU3,      /* GPIOE6 -> GPIOE7 */<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+             GPIO_PASSTHRU_MAX<o:p></o:p></p>
<p class="MsoNormal">+};<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+enum GPIO_PASSTHRU_CMD {<o:p></o:p></p>
<p class="MsoNormal">+             SET_GPIO_PASSTHRU_ENABLE = 0,<o:p></o:p></p>
<p class="MsoNormal">+             GET_GPIO_PASSTHRU_ENABLE,<o:p></o:p></p>
<p class="MsoNormal">+             GET_GPIO_PASSTHRU_IN,<o:p></o:p></p>
<p class="MsoNormal">+             SET_GPIO_PASSTHRU_OUT, /* !!! The PASSTHRU will be disabled !!! */<o:p></o:p></p>
<p class="MsoNormal">+};<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+struct passthru_ioctl_data {<o:p></o:p></p>
<p class="MsoNormal">+             unsigned short cmd;<o:p></o:p></p>
<p class="MsoNormal">+             unsigned short idx;<o:p></o:p></p>
<p class="MsoNormal">+             unsigned int   data;<o:p></o:p></p>
<p class="MsoNormal">+};<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static void ast_set_passthru_enable(<o:p></o:p></p>
<p class="MsoNormal">+                                           unsigned short idx, unsigned int enable);<o:p></o:p></p>
<p class="MsoNormal">+static unsigned int ast_get_passthru_enable(unsigned short idx);<o:p></o:p></p>
<p class="MsoNormal">+static void ast_set_passthru_out(<o:p></o:p></p>
<p class="MsoNormal">+                                           unsigned short idx, unsigned int val);<o:p></o:p></p>
<p class="MsoNormal">+static void ast_passthru_init(void);<o:p></o:p></p>
<p class="MsoNormal">+static inline u32 ast_scu_read(u32 reg);<o:p></o:p></p>
<p class="MsoNormal">+static inline void ast_scu_write(u32 val, u32 reg);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+/* IOCTL */<o:p></o:p></p>
<p class="MsoNormal">+#define GPIO_IOC_BASE       'G'<o:p></o:p></p>
<p class="MsoNormal">+#define GPIO_IOC_PASSTHRU   _IOWR(GPIO_IOC_BASE, 1, struct passthru_ioctl_data)<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+#endif<o:p></o:p></p>
<p class="MsoNormal">-- <o:p></o:p></p>
<p class="MsoNormal">2.16.2<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Thanks,<o:p></o:p></p>
<p class="MsoNormal">Kwin.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
</body>
</html>