AST SoC supports *retain pin state* function when wdt reset. The patch adds set_config function for handling sgpio reset tolerance register. Signed-off-by: Steven Lee <steven_lee@xxxxxxxxxxxxxx> Reviewed-by: Andrew Jeffery <andrew@xxxxxxxx> --- drivers/gpio/gpio-aspeed-sgpio.c | 54 +++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c index 7d0a4f6fd9d1..31475846c5fc 100644 --- a/drivers/gpio/gpio-aspeed-sgpio.c +++ b/drivers/gpio/gpio-aspeed-sgpio.c @@ -39,9 +39,10 @@ struct aspeed_sgpio { }; struct aspeed_sgpio_bank { - uint16_t val_regs; - uint16_t rdata_reg; - uint16_t irq_regs; + u16 val_regs; + u16 rdata_reg; + u16 irq_regs; + u16 tolerance_regs; const char names[4][3]; }; @@ -57,24 +58,28 @@ static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = { .val_regs = 0x0000, .rdata_reg = 0x0070, .irq_regs = 0x0004, + .tolerance_regs = 0x0018, .names = { "A", "B", "C", "D" }, }, { .val_regs = 0x001C, .rdata_reg = 0x0074, .irq_regs = 0x0020, + .tolerance_regs = 0x0034, .names = { "E", "F", "G", "H" }, }, { .val_regs = 0x0038, .rdata_reg = 0x0078, .irq_regs = 0x003C, + .tolerance_regs = 0x0050, .names = { "I", "J", "K", "L" }, }, { .val_regs = 0x0090, .rdata_reg = 0x007C, .irq_regs = 0x0094, + .tolerance_regs = 0x00A8, .names = { "M", "N", "O", "P" }, }, }; @@ -87,6 +92,7 @@ enum aspeed_sgpio_reg { reg_irq_type1, reg_irq_type2, reg_irq_status, + reg_tolerance, }; #define GPIO_VAL_VALUE 0x00 @@ -115,6 +121,8 @@ static void __iomem *bank_reg(struct aspeed_sgpio *gpio, return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; case reg_irq_status: return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; + case reg_tolerance: + return gpio->base + bank->tolerance_regs; default: /* acturally if code runs to here, it's an error case */ BUG(); @@ -476,6 +484,44 @@ static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = { .pin_mask = GENMASK(9, 6), }; +static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, + unsigned int offset, bool enable) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(chip); + unsigned long flags; + void __iomem *reg; + u32 val; + + reg = bank_reg(gpio, to_bank(offset, gpio), reg_tolerance); + + spin_lock_irqsave(&gpio->lock, flags); + + val = readl(reg); + + if (enable) + val |= GPIO_BIT(gpio, offset); + else + val &= ~GPIO_BIT(gpio, offset); + + writel(val, reg); + + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + unsigned long param = pinconf_to_config_param(config); + u32 arg = pinconf_to_config_argument(config); + + if (param == PIN_CONFIG_PERSIST_STATE) + return aspeed_sgpio_reset_tolerance(chip, offset, arg); + + return -ENOTSUPP; +} + static const struct aspeed_sgpio_pdata ast2600_sgpiom_128_pdata = { .max_ngpios = 128, .pin_mask = GENMASK(10, 6), @@ -577,7 +623,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) gpio->chip.free = NULL; gpio->chip.get = aspeed_sgpio_get; gpio->chip.set = aspeed_sgpio_set; - gpio->chip.set_config = NULL; + gpio->chip.set_config = aspeed_sgpio_set_config; gpio->chip.label = dev_name(&pdev->dev); gpio->chip.base = -1; -- 2.17.1