Enable buttons GPIO passthrough

Wang, Kuiying kuiying.wang at intel.com
Mon Dec 24 13:56:15 AEDT 2018


Hi Linus,
Who could help and work w/ me on this?


Thanks,
Kwin.

-----Original Message-----
From: Joel Stanley [mailto:joel at jms.id.au] 
Sent: Thursday, December 13, 2018 9:21 AM
To: Wang, Kuiying <kuiying.wang at intel.com>; Linus Walleij <linus.walleij at linaro.org>; linux-gpio at vger.kernel.org; Andrew Jeffery <andrew at aj.id.au>
Cc: Andrew Geissler <geissonator at gmail.com>; OpenBMC Maillist <openbmc at lists.ozlabs.org>; Mauery, Vernon <vernon.mauery at intel.com>; Feist, James <james.feist at intel.com>; Yoo, Jae Hyun <jae.hyun.yoo at intel.com>
Subject: Re: Enable buttons GPIO passthrough

On Tue, 11 Dec 2018 at 18:32, Wang, Kuiying <kuiying.wang at intel.com> wrote:
>
> Hi Joel/Andrew,
>
> I write a drive to enable GPIO passthrough for buttons (like power/reset/id button) as following attached patch.
>
> Do you think it is acceptable?
>
> Or we could do it in pinmux and extend gpio driver? Design passthrough state except in/out.

I think that this direction would be better than a misc driver. I've added Linus, the maintainer for these subsystems, and the linux-gpio mailing list to cc.

Cheers,

Joel

>
> What’s your suggestions?
>
>
>
> Thanks Kwin.
>
>
>
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>
> index f2062546250c..e94ee86820d3 100644
>
> --- a/drivers/misc/Kconfig
>
> +++ b/drivers/misc/Kconfig
>
> @@ -4,6 +4,12 @@
>
>  menu "Misc devices"
>
> +config GPIO_PASS_THROUGH
>
> +             tristate "GPIO Pass Through"
>
> +             depends on (ARCH_ASPEED || COMPILE_TEST)
>
> +             help
>
> +               Enable this for buttons GPIO pass through.
>
> +
>
> config SENSORS_LIS3LV02D
>
>               tristate
>
>               depends on INPUT
>
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
>
> index bb89694e6b4b..13b8b8edbb70 100644
>
> --- a/drivers/misc/Makefile
>
> +++ b/drivers/misc/Makefile
>
> @@ -61,3 +61,4 @@ obj-$(CONFIG_ASPEED_LPC_SIO)   += aspeed-lpc-sio.o
>
> obj-$(CONFIG_PCI_ENDPOINT_TEST)      += pci_endpoint_test.o
>
> obj-$(CONFIG_OCXL)                     += ocxl/
>
> obj-$(CONFIG_MISC_RTSX)                         += cardreader/
>
> +obj-$(CONFIG_GPIO_PASS_THROUGH)   += gpio-passthrough.o
>
> diff --git a/drivers/misc/gpio-passthrough.c 
> b/drivers/misc/gpio-passthrough.c
>
> new file mode 100644
>
> index 000000000000..0126fc08ae55
>
> --- /dev/null
>
> +++ b/drivers/misc/gpio-passthrough.c
>
> @@ -0,0 +1,260 @@
>
> +// SPDX-License-Identifier: GPL-2.0
>
> +/*
>
> + * Copyright (c) 2018 Intel Corporation
>
> +*/
>
> +
>
> +#include "gpio-passthrough.h"
>
> +
>
> +struct aspeed_gpio_pass_through_dev {
>
> +             struct miscdevice              miscdev;
>
> +             unsigned int        addr;
>
> +             unsigned int        size;
>
> +};
>
> +
>
> +static struct aspeed_gpio_pass_through_dev 
> +ast_cdev_gpio_pass_through;
>
> +
>
> +static long ast_passthru_ioctl(struct file *filp, unsigned int cmd, 
> +unsigned long arg)
>
> +{
>
> +             long ret = 0;
>
> +             struct passthru_ioctl_data passthru_data;
>
> +
>
> +             if (cmd == GPIO_IOC_PASSTHRU)
>
> +             {
>
> +                            if (copy_from_user(&passthru_data,
>
> +                                           (void __user*)arg, 
> + sizeof(passthru_data)))
>
> +                                           return -EFAULT;
>
> +                            if (passthru_data.idx >= 
> + GPIO_PASSTHRU_MAX)
>
> +                                           return -EINVAL;
>
> +
>
> +                            switch (passthru_data.cmd) {
>
> +                            case SET_GPIO_PASSTHRU_ENABLE:
>
> +                                           
> + ast_set_passthru_enable(passthru_data.idx,
>
> +                                                                         
> + passthru_data.data);
>
> +                                           break;
>
> +                            case GET_GPIO_PASSTHRU_ENABLE:
>
> +                                           passthru_data.data = 
> + ast_get_passthru_enable(passthru_data.idx);
>
> +                                           if (copy_to_user((void 
> + __user*)arg, &passthru_data,
>
> +                                                                                                       
> + sizeof(passthru_data)))
>
> +                                           ret = -EFAULT;
>
> +                            break;
>
> +
>
> +                            case SET_GPIO_PASSTHRU_OUT:
>
> +                                           
> + ast_set_passthru_out(passthru_data.idx, passthru_data.data);
>
> +                            break;
>
> +
>
> +                            default:
>
> +                                           ret = -EINVAL;
>
> +                            break;
>
> +                            }
>
> +             }
>
> +             return ret;
>
> +
>
> +}
>
> +
>
> +static int ast_passthru_open(struct inode *inode, struct file *filp)
>
> +{
>
> +             return container_of(filp->private_data,
>
> +                            struct aspeed_gpio_pass_through_dev, 
> + miscdev);
>
> +}
>
> +
>
> +static const struct file_operations ast_gpio_pth_fops = {
>
> +             .owner          = THIS_MODULE,
>
> +             .llseek         = no_llseek,
>
> +             .unlocked_ioctl = ast_passthru_ioctl,
>
> +             .open           = ast_passthru_open,
>
> +};
>
> +
>
> +static struct miscdevice ast_gpio_pth_miscdev = {
>
> +             .minor = MISC_DYNAMIC_MINOR,
>
> +             .name = GPIO_PASS_THROUGH_NAME,
>
> +             .fops = &ast_gpio_pth_fops,
>
> +};
>
> +
>
> +static u32 ast_scu_base  = IO_ADDRESS(AST_SCU_BASE);
>
> +
>
> +static inline u32 ast_scu_read(u32 reg)
>
> +{
>
> +             return readl((void *)(ast_scu_base + reg));
>
> +}
>
> +
>
> +static inline void ast_scu_write(u32 val, u32 reg)
>
> +{
>
> +#ifdef CONFIG_AST_SCU_LOCK
>
> +             writel(SCU_PROTECT_UNLOCK, (void *)(ast_scu_base + 
> + AST_SCU_PROTECT));
>
> +             writel(val,                (void *)(ast_scu_base + reg));
>
> +             writel(0x000000AA,         (void *)(ast_scu_base + AST_SCU_PROTECT));
>
> +#else
>
> +             writel(SCU_PROTECT_UNLOCK, (void *)(ast_scu_base + 
> + AST_SCU_PROTECT));
>
> +             writel(val,                (void *)(ast_scu_base + reg));
>
> +#endif
>
> +}
>
> +
>
> +static int gpio_pass_through_probe(struct platform_device *pdev)
>
> +{
>
> +             struct aspeed_gpio_pass_through_dev   *gpio_pth_dev = &ast_cdev_gpio_pass_through;
>
> +             struct device *dev = &pdev->dev;
>
> +             struct resource *rc;
>
> +
>
> +             dev_set_drvdata(&pdev->dev, gpio_pth_dev);
>
> +             rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>
> +             if (!rc) {
>
> +                            dev_err(dev, "Fail to 
> + platform_get_resource\n");
>
> +                            return -ENXIO;
>
> +             }
>
> +             gpio_pth_dev->addr = rc->start;
>
> +             gpio_pth_dev->size = resource_size(rc);
>
> +             gpio_pth_dev->miscdev = ast_gpio_pth_miscdev;
>
> +             ast_passthru_init();
>
> +             printk("GPIO PASS THROUGH DRIVER is loaded \n");
>
> +             return misc_register(&gpio_pth_dev->miscdev);
>
> +}
>
> +
>
> +static int gpio_pass_through_remove(struct platform_device *pdev)
>
> +{
>
> +             struct aspeed_gpio_pass_through_dev *gpio_pth_dev =
>
> +                                                          
> + dev_get_drvdata(&pdev->dev);
>
> +             misc_deregister(&gpio_pth_dev->miscdev);
>
> +             printk("GPIO PASS THROUGH DRIVER is removing \n");
>
> +
>
> +             return 0;
>
> +}
>
> +
>
> +static struct platform_driver gpio_pass_through_driver = {
>
> +             .probe     = gpio_pass_through_probe,
>
> +             .remove    = gpio_pass_through_remove,
>
> +             .driver    = {
>
> +                            .name  = "gpio-pass-through",
>
> +        .owner = THIS_MODULE,
>
> +
>
> +             },
>
> +};
>
> +
>
> +/* GPIOE group only */
>
> +struct gpio_passthru {
>
> +             u32 passthru_mask;
>
> +             u16 pin_in;
>
> +             u16 pin_out;
>
> +};
>
> +
>
> +static struct gpio_passthru passthru_settings[GPIO_PASSTHRU_MAX] = {
>
> +             [GPIO_PASSTHRU0] = {
>
> +                                           .passthru_mask = (1 << 
> + 12), /* SCU8C[12] */
>
> +                                           .pin_in        = PGPIO_PIN(GPIOE, 0),
>
> +                                           .pin_out       = PGPIO_PIN(GPIOE, 1),
>
> +                            },
>
> +
>
> +             [GPIO_PASSTHRU1] = {
>
> +                                           .passthru_mask = (1 << 
> + 13), /* SCU8C[13] */
>
> +                                           .pin_in        = PGPIO_PIN(GPIOE, 2),
>
> +                                           .pin_out       = PGPIO_PIN(GPIOE, 3),
>
> +                            },
>
> +
>
> +             [GPIO_PASSTHRU2] = {
>
> +                                           .passthru_mask = (1 << 
> + 14), /* SCU8C[14] */
>
> +                                           .pin_in        = PGPIO_PIN(GPIOE, 4),
>
> +                                           .pin_out       = PGPIO_PIN(GPIOE, 5),
>
> +                            },
>
> +
>
> +             [GPIO_PASSTHRU3] = {
>
> +                                           .passthru_mask = (1 << 
> + 15), /* SCU8C[15] */
>
> +                                           .pin_in        = PGPIO_PIN(GPIOE, 6),
>
> +                                           .pin_out       = PGPIO_PIN(GPIOE, 7),
>
> +                            },
>
> +};
>
> +
>
> +static void ast_set_passthru_enable(
>
> +                                           unsigned short idx, 
> + unsigned int enable)
>
> +{
>
> +             u32 val;
>
> +             unsigned long flags;
>
> +             struct gpio_passthru *passthru = 
> + &passthru_settings[idx];
>
> +
>
> +             local_irq_save(flags);
>
> +
>
> +             val = ast_scu_read(AST_SCU_FUN_PIN_CTRL4);
>
> +             if (enable)
>
> +                            val |=  (passthru->passthru_mask);
>
> +             else
>
> +                            val &= ~(passthru->passthru_mask);
>
> +             ast_scu_write(val, AST_SCU_FUN_PIN_CTRL4);
>
> +
>
> +             local_irq_restore(flags);
>
> +}
>
> +
>
> +static unsigned int ast_get_passthru_enable(unsigned short idx)
>
> +{
>
> +             unsigned int enable;
>
> +             unsigned long flags;
>
> +             struct gpio_passthru *passthru = 
> + &passthru_settings[idx];
>
> +
>
> +             local_irq_save(flags);
>
> +
>
> +             enable = (ast_scu_read(AST_SCU_FUN_PIN_CTRL4) & 
> + passthru->passthru_mask) != 0 ? 1 : 0;
>
> +
>
> +             local_irq_restore(flags);
>
> +
>
> +             return enable;
>
> +}
>
> +
>
> +static void ast_set_passthru_out(
>
> +                                           unsigned short idx, 
> + unsigned int val)
>
> +{
>
> +             unsigned long flags;
>
> +             struct gpio_passthru *passthru = 
> + &passthru_settings[idx];
>
> +
>
> +             local_irq_save(flags);
>
> +
>
> +             /* Disable PASSTHRU */
>
> +             val  = ast_scu_read(AST_SCU_FUN_PIN_CTRL4);
>
> +             val &= ~(passthru->passthru_mask);
>
> +             ast_scu_write(val, AST_SCU_FUN_PIN_CTRL4);
>
> +
>
> +             local_irq_restore(flags);
>
> +}
>
> +
>
> +static void ast_passthru_init(void)
>
> +{
>
> +             int i;
>
> +             u32 val;
>
> +             unsigned long flags;
>
> +             struct gpio_passthru *passthru;
>
> +
>
> +             local_irq_save(flags);
>
> +
>
> +             /* 1. Enable GPIOE pin mode, SCU80[16:23] = 00 */
>
> +             ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) & 
> + (~0x00FF0000),
>
> +                           AST_SCU_FUN_PIN_CTRL1);
>
> +
>
> +             /* 2. Enable them by setting SCU8C[12:15] */
>
> +             for (i = 0; i < GPIO_PASSTHRU_MAX; i++) {
>
> +                            passthru = &passthru_settings[i];
>
> +
>
> +                            val  = 
> + ast_scu_read(AST_SCU_FUN_PIN_CTRL4);
>
> +                            val |= passthru->passthru_mask;
>
> +                            ast_scu_write(val, 
> + AST_SCU_FUN_PIN_CTRL4);
>
> +             }
>
> +
>
> +             
> + /**************************************************************
>
> +             * 3. Disable HWTrap for GPIOE pass-through mode
>
> +             *
>
> +             * Hardware strap register (SCU70) programming method.
>
> +             *   #Write '1' to SCU70 can set the specific bit with value '1'
>
> +             *    Write '0' has no effect.
>
> +             *   #Write '1' to SCU7C can clear the specific bit of SCU70 to
>
> +             *    value '0'. Write '0' has no effect.
>
> +             
> + **************************************************************/
>
> +             if (ast_scu_read(AST_SCU_HW_STRAP1) & (0x1 << 22))
>
> +                            ast_scu_write((0x1 << 22), 
> + AST_SCU_REVISION_ID);
>
> +
>
> +             local_irq_restore(flags);
>
> +
>
> +             printk("HW_STRAP1 = 0x%08X\n", 
> + ast_scu_read(AST_SCU_HW_STRAP1));
>
> +}
>
> +
>
> +module_platform_driver(gpio_pass_through_driver);
>
> +
>
> +MODULE_AUTHOR("Kuiying Wang <kuiying.wang at intel.com>");
>
> +MODULE_DESCRIPTION("GPIO Pass Through Control Driver for all buttons 
> +like Power/Reset/ID button");
>
> +MODULE_LICENSE("GPL v2");
>
> +
>
> diff --git a/drivers/misc/gpio-passthrough.h 
> b/drivers/misc/gpio-passthrough.h
>
> new file mode 100644
>
> index 000000000000..a7274b8ab31e
>
> --- /dev/null
>
> +++ b/drivers/misc/gpio-passthrough.h
>
> @@ -0,0 +1,60 @@
>
> +#ifndef __GPIO_PASS_THROUGH_H__
>
> +#define __GPIO_PASS_THROUGH_H__
>
> +
>
> +#include <linux/kernel.h>
>
> +#include <linux/miscdevice.h>
>
> +#include <linux/uaccess.h>
>
> +#include <linux/module.h>
>
> +#include <linux/of_platform.h>
>
> +#include <linux/mm.h>
>
> +#include <asm/io.h>
>
> +
>
> +#define PGPIO_PIN(PORT, PIN)   (((PORT) << 3) | ((PIN) & 0x07))
>
> +#define GPIOE    4
>
> +#define AST_SCU_BASE                    0x1E6E2000  /* SCU */
>
> +#define AST_SCU_PROTECT                 0x00        /*  protection key register */
>
> +#define SCU_PROTECT_UNLOCK              0x1688A8A8
>
> +#define AST_SCU_FUN_PIN_CTRL4           0x8C        /*  Multi-function Pin Control#4*/
>
> +#define AST_SCU_FUN_PIN_CTRL1           0x80        /*  Multi-function Pin Control#1*/
>
> +#define AST_SCU_HW_STRAP1               0x70        /*  hardware strapping register */
>
> +#define AST_SCU_REVISION_ID             0x7C        /*  Silicon revision ID register */
>
> +#define GPIO_PASS_THROUGH_NAME          "gpiopassthrough"
>
> +#define IO_ADDRESS(x)                   (x)
>
> +
>
> +enum GPIO_PASSTHRU_INDEX {
>
> +             GPIO_PASSTHRU0 = 0,  /* GPIOE0 -> GPIOE1 */
>
> +             GPIO_PASSTHRU1,      /* GPIOE2 -> GPIOE3 */
>
> +             GPIO_PASSTHRU2,      /* GPIOE4 -> GPIOE5 */
>
> +             GPIO_PASSTHRU3,      /* GPIOE6 -> GPIOE7 */
>
> +
>
> +             GPIO_PASSTHRU_MAX
>
> +};
>
> +
>
> +enum GPIO_PASSTHRU_CMD {
>
> +             SET_GPIO_PASSTHRU_ENABLE = 0,
>
> +             GET_GPIO_PASSTHRU_ENABLE,
>
> +             GET_GPIO_PASSTHRU_IN,
>
> +             SET_GPIO_PASSTHRU_OUT, /* !!! The PASSTHRU will be 
> + disabled !!! */
>
> +};
>
> +
>
> +struct passthru_ioctl_data {
>
> +             unsigned short cmd;
>
> +             unsigned short idx;
>
> +             unsigned int   data;
>
> +};
>
> +
>
> +static void ast_set_passthru_enable(
>
> +                                           unsigned short idx, 
> + unsigned int enable);
>
> +static unsigned int ast_get_passthru_enable(unsigned short idx);
>
> +static void ast_set_passthru_out(
>
> +                                           unsigned short idx, 
> + unsigned int val);
>
> +static void ast_passthru_init(void);
>
> +static inline u32 ast_scu_read(u32 reg);
>
> +static inline void ast_scu_write(u32 val, u32 reg);
>
> +
>
> +/* IOCTL */
>
> +#define GPIO_IOC_BASE       'G'
>
> +#define GPIO_IOC_PASSTHRU   _IOWR(GPIO_IOC_BASE, 1, struct passthru_ioctl_data)
>
> +
>
> +
>
> +#endif
>
> --
>
> 2.16.2
>
>
>
> Thanks,
>
> Kwin.
>
>


More information about the openbmc mailing list