<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>