175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2dbad75ddSKen Xue /* 3dbad75ddSKen Xue * GPIO driver for AMD 4dbad75ddSKen Xue * 5dbad75ddSKen Xue * Copyright (c) 2014,2015 AMD Corporation. 6dbad75ddSKen Xue * Authors: Ken Xue <Ken.Xue@amd.com> 7dbad75ddSKen Xue * Wu, Jeff <Jeff.Wu@amd.com> 8dbad75ddSKen Xue * 9add7bfceSShyam Sundar S K * Contact Information: Nehal Shah <Nehal-bakulchandra.Shah@amd.com> 10add7bfceSShyam Sundar S K * Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 11dbad75ddSKen Xue */ 12dbad75ddSKen Xue 13dbad75ddSKen Xue #include <linux/err.h> 14dbad75ddSKen Xue #include <linux/bug.h> 15dbad75ddSKen Xue #include <linux/kernel.h> 16dbad75ddSKen Xue #include <linux/module.h> 17dbad75ddSKen Xue #include <linux/spinlock.h> 18dbad75ddSKen Xue #include <linux/compiler.h> 19dbad75ddSKen Xue #include <linux/types.h> 20dbad75ddSKen Xue #include <linux/errno.h> 21dbad75ddSKen Xue #include <linux/log2.h> 22dbad75ddSKen Xue #include <linux/io.h> 231c5fb66aSLinus Walleij #include <linux/gpio/driver.h> 24dbad75ddSKen Xue #include <linux/slab.h> 25dbad75ddSKen Xue #include <linux/platform_device.h> 26dbad75ddSKen Xue #include <linux/mutex.h> 27dbad75ddSKen Xue #include <linux/acpi.h> 28dbad75ddSKen Xue #include <linux/seq_file.h> 29dbad75ddSKen Xue #include <linux/interrupt.h> 30dbad75ddSKen Xue #include <linux/list.h> 31dbad75ddSKen Xue #include <linux/bitops.h> 32dbad75ddSKen Xue #include <linux/pinctrl/pinconf.h> 33dbad75ddSKen Xue #include <linux/pinctrl/pinconf-generic.h> 34dbad75ddSKen Xue 3579d2c8beSDaniel Drake #include "core.h" 36dbad75ddSKen Xue #include "pinctrl-utils.h" 37dbad75ddSKen Xue #include "pinctrl-amd.h" 38dbad75ddSKen Xue 3912b10f47SDaniel Kurtz static int amd_gpio_get_direction(struct gpio_chip *gc, unsigned offset) 4012b10f47SDaniel Kurtz { 4112b10f47SDaniel Kurtz unsigned long flags; 4212b10f47SDaniel Kurtz u32 pin_reg; 4312b10f47SDaniel Kurtz struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 4412b10f47SDaniel Kurtz 4512b10f47SDaniel Kurtz raw_spin_lock_irqsave(&gpio_dev->lock, flags); 4612b10f47SDaniel Kurtz pin_reg = readl(gpio_dev->base + offset * 4); 4712b10f47SDaniel Kurtz raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 4812b10f47SDaniel Kurtz 4912b10f47SDaniel Kurtz return !(pin_reg & BIT(OUTPUT_ENABLE_OFF)); 5012b10f47SDaniel Kurtz } 5112b10f47SDaniel Kurtz 52dbad75ddSKen Xue static int amd_gpio_direction_input(struct gpio_chip *gc, unsigned offset) 53dbad75ddSKen Xue { 54dbad75ddSKen Xue unsigned long flags; 55dbad75ddSKen Xue u32 pin_reg; 5604d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 57dbad75ddSKen Xue 58229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 59dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + offset * 4); 60dbad75ddSKen Xue pin_reg &= ~BIT(OUTPUT_ENABLE_OFF); 61dbad75ddSKen Xue writel(pin_reg, gpio_dev->base + offset * 4); 62229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 63dbad75ddSKen Xue 64dbad75ddSKen Xue return 0; 65dbad75ddSKen Xue } 66dbad75ddSKen Xue 67dbad75ddSKen Xue static int amd_gpio_direction_output(struct gpio_chip *gc, unsigned offset, 68dbad75ddSKen Xue int value) 69dbad75ddSKen Xue { 70dbad75ddSKen Xue u32 pin_reg; 71dbad75ddSKen Xue unsigned long flags; 7204d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 73dbad75ddSKen Xue 74229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 75dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + offset * 4); 76dbad75ddSKen Xue pin_reg |= BIT(OUTPUT_ENABLE_OFF); 77dbad75ddSKen Xue if (value) 78dbad75ddSKen Xue pin_reg |= BIT(OUTPUT_VALUE_OFF); 79dbad75ddSKen Xue else 80dbad75ddSKen Xue pin_reg &= ~BIT(OUTPUT_VALUE_OFF); 81dbad75ddSKen Xue writel(pin_reg, gpio_dev->base + offset * 4); 82229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 83dbad75ddSKen Xue 84dbad75ddSKen Xue return 0; 85dbad75ddSKen Xue } 86dbad75ddSKen Xue 87dbad75ddSKen Xue static int amd_gpio_get_value(struct gpio_chip *gc, unsigned offset) 88dbad75ddSKen Xue { 89dbad75ddSKen Xue u32 pin_reg; 90dbad75ddSKen Xue unsigned long flags; 9104d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 92dbad75ddSKen Xue 93229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 94dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + offset * 4); 95229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 96dbad75ddSKen Xue 97dbad75ddSKen Xue return !!(pin_reg & BIT(PIN_STS_OFF)); 98dbad75ddSKen Xue } 99dbad75ddSKen Xue 100dbad75ddSKen Xue static void amd_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value) 101dbad75ddSKen Xue { 102dbad75ddSKen Xue u32 pin_reg; 103dbad75ddSKen Xue unsigned long flags; 10404d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 105dbad75ddSKen Xue 106229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 107dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + offset * 4); 108dbad75ddSKen Xue if (value) 109dbad75ddSKen Xue pin_reg |= BIT(OUTPUT_VALUE_OFF); 110dbad75ddSKen Xue else 111dbad75ddSKen Xue pin_reg &= ~BIT(OUTPUT_VALUE_OFF); 112dbad75ddSKen Xue writel(pin_reg, gpio_dev->base + offset * 4); 113229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 114dbad75ddSKen Xue } 115dbad75ddSKen Xue 116dbad75ddSKen Xue static int amd_gpio_set_debounce(struct gpio_chip *gc, unsigned offset, 117dbad75ddSKen Xue unsigned debounce) 118dbad75ddSKen Xue { 119dbad75ddSKen Xue u32 time; 12025a853d0SKen Xue u32 pin_reg; 12125a853d0SKen Xue int ret = 0; 122dbad75ddSKen Xue unsigned long flags; 12304d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 124dbad75ddSKen Xue 125229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 126dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + offset * 4); 127dbad75ddSKen Xue 128dbad75ddSKen Xue if (debounce) { 129dbad75ddSKen Xue pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF; 130dbad75ddSKen Xue pin_reg &= ~DB_TMR_OUT_MASK; 131dbad75ddSKen Xue /* 132dbad75ddSKen Xue Debounce Debounce Timer Max 133dbad75ddSKen Xue TmrLarge TmrOutUnit Unit Debounce 134dbad75ddSKen Xue Time 135dbad75ddSKen Xue 0 0 61 usec (2 RtcClk) 976 usec 136dbad75ddSKen Xue 0 1 244 usec (8 RtcClk) 3.9 msec 137dbad75ddSKen Xue 1 0 15.6 msec (512 RtcClk) 250 msec 138dbad75ddSKen Xue 1 1 62.5 msec (2048 RtcClk) 1 sec 139dbad75ddSKen Xue */ 140dbad75ddSKen Xue 141dbad75ddSKen Xue if (debounce < 61) { 142dbad75ddSKen Xue pin_reg |= 1; 143dbad75ddSKen Xue pin_reg &= ~BIT(DB_TMR_OUT_UNIT_OFF); 144dbad75ddSKen Xue pin_reg &= ~BIT(DB_TMR_LARGE_OFF); 145dbad75ddSKen Xue } else if (debounce < 976) { 146dbad75ddSKen Xue time = debounce / 61; 147dbad75ddSKen Xue pin_reg |= time & DB_TMR_OUT_MASK; 148dbad75ddSKen Xue pin_reg &= ~BIT(DB_TMR_OUT_UNIT_OFF); 149dbad75ddSKen Xue pin_reg &= ~BIT(DB_TMR_LARGE_OFF); 150dbad75ddSKen Xue } else if (debounce < 3900) { 151dbad75ddSKen Xue time = debounce / 244; 152dbad75ddSKen Xue pin_reg |= time & DB_TMR_OUT_MASK; 153dbad75ddSKen Xue pin_reg |= BIT(DB_TMR_OUT_UNIT_OFF); 154dbad75ddSKen Xue pin_reg &= ~BIT(DB_TMR_LARGE_OFF); 155dbad75ddSKen Xue } else if (debounce < 250000) { 156dbad75ddSKen Xue time = debounce / 15600; 157dbad75ddSKen Xue pin_reg |= time & DB_TMR_OUT_MASK; 158dbad75ddSKen Xue pin_reg &= ~BIT(DB_TMR_OUT_UNIT_OFF); 159dbad75ddSKen Xue pin_reg |= BIT(DB_TMR_LARGE_OFF); 160dbad75ddSKen Xue } else if (debounce < 1000000) { 161dbad75ddSKen Xue time = debounce / 62500; 162dbad75ddSKen Xue pin_reg |= time & DB_TMR_OUT_MASK; 163dbad75ddSKen Xue pin_reg |= BIT(DB_TMR_OUT_UNIT_OFF); 164dbad75ddSKen Xue pin_reg |= BIT(DB_TMR_LARGE_OFF); 165dbad75ddSKen Xue } else { 166dbad75ddSKen Xue pin_reg &= ~DB_CNTRl_MASK; 16725a853d0SKen Xue ret = -EINVAL; 168dbad75ddSKen Xue } 169dbad75ddSKen Xue } else { 170dbad75ddSKen Xue pin_reg &= ~BIT(DB_TMR_OUT_UNIT_OFF); 171dbad75ddSKen Xue pin_reg &= ~BIT(DB_TMR_LARGE_OFF); 172dbad75ddSKen Xue pin_reg &= ~DB_TMR_OUT_MASK; 173dbad75ddSKen Xue pin_reg &= ~DB_CNTRl_MASK; 174dbad75ddSKen Xue } 175dbad75ddSKen Xue writel(pin_reg, gpio_dev->base + offset * 4); 176229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 177dbad75ddSKen Xue 17825a853d0SKen Xue return ret; 179dbad75ddSKen Xue } 180dbad75ddSKen Xue 1812956b5d9SMika Westerberg static int amd_gpio_set_config(struct gpio_chip *gc, unsigned offset, 1822956b5d9SMika Westerberg unsigned long config) 1832956b5d9SMika Westerberg { 1842956b5d9SMika Westerberg u32 debounce; 1852956b5d9SMika Westerberg 1862956b5d9SMika Westerberg if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) 1872956b5d9SMika Westerberg return -ENOTSUPP; 1882956b5d9SMika Westerberg 1892956b5d9SMika Westerberg debounce = pinconf_to_config_argument(config); 1902956b5d9SMika Westerberg return amd_gpio_set_debounce(gc, offset, debounce); 1912956b5d9SMika Westerberg } 1922956b5d9SMika Westerberg 193dbad75ddSKen Xue #ifdef CONFIG_DEBUG_FS 194dbad75ddSKen Xue static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) 195dbad75ddSKen Xue { 196dbad75ddSKen Xue u32 pin_reg; 197dbad75ddSKen Xue unsigned long flags; 198dbad75ddSKen Xue unsigned int bank, i, pin_num; 19904d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 200dbad75ddSKen Xue 201dbad75ddSKen Xue char *level_trig; 202dbad75ddSKen Xue char *active_level; 203dbad75ddSKen Xue char *interrupt_enable; 204dbad75ddSKen Xue char *interrupt_mask; 205dbad75ddSKen Xue char *wake_cntrl0; 206dbad75ddSKen Xue char *wake_cntrl1; 207dbad75ddSKen Xue char *wake_cntrl2; 208dbad75ddSKen Xue char *pin_sts; 209dbad75ddSKen Xue char *pull_up_sel; 210dbad75ddSKen Xue char *pull_up_enable; 211dbad75ddSKen Xue char *pull_down_enable; 212dbad75ddSKen Xue char *output_value; 213dbad75ddSKen Xue char *output_enable; 214dbad75ddSKen Xue 2153bfd4430SShah, Nehal-bakulchandra for (bank = 0; bank < gpio_dev->hwbank_num; bank++) { 216dbad75ddSKen Xue seq_printf(s, "GPIO bank%d\t", bank); 217dbad75ddSKen Xue 218dbad75ddSKen Xue switch (bank) { 219dbad75ddSKen Xue case 0: 220dbad75ddSKen Xue i = 0; 221dbad75ddSKen Xue pin_num = AMD_GPIO_PINS_BANK0; 222dbad75ddSKen Xue break; 223dbad75ddSKen Xue case 1: 224dbad75ddSKen Xue i = 64; 225dbad75ddSKen Xue pin_num = AMD_GPIO_PINS_BANK1 + i; 226dbad75ddSKen Xue break; 227dbad75ddSKen Xue case 2: 228dbad75ddSKen Xue i = 128; 229dbad75ddSKen Xue pin_num = AMD_GPIO_PINS_BANK2 + i; 230dbad75ddSKen Xue break; 2313bfd4430SShah, Nehal-bakulchandra case 3: 2323bfd4430SShah, Nehal-bakulchandra i = 192; 2333bfd4430SShah, Nehal-bakulchandra pin_num = AMD_GPIO_PINS_BANK3 + i; 2343bfd4430SShah, Nehal-bakulchandra break; 2356ac4c1adSLinus Walleij default: 2366ac4c1adSLinus Walleij /* Illegal bank number, ignore */ 2376ac4c1adSLinus Walleij continue; 238dbad75ddSKen Xue } 239dbad75ddSKen Xue for (; i < pin_num; i++) { 240dbad75ddSKen Xue seq_printf(s, "pin%d\t", i); 241229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 242dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + i * 4); 243229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 244dbad75ddSKen Xue 245dbad75ddSKen Xue if (pin_reg & BIT(INTERRUPT_ENABLE_OFF)) { 2461766e4b7SDaniel Kurtz u8 level = (pin_reg >> ACTIVE_LEVEL_OFF) & 2471766e4b7SDaniel Kurtz ACTIVE_LEVEL_MASK; 248dbad75ddSKen Xue interrupt_enable = "interrupt is enabled|"; 249dbad75ddSKen Xue 2501766e4b7SDaniel Kurtz if (level == ACTIVE_LEVEL_HIGH) 251dbad75ddSKen Xue active_level = "Active high|"; 2521766e4b7SDaniel Kurtz else if (level == ACTIVE_LEVEL_LOW) 2531766e4b7SDaniel Kurtz active_level = "Active low|"; 2541766e4b7SDaniel Kurtz else if (!(pin_reg & BIT(LEVEL_TRIG_OFF)) && 2551766e4b7SDaniel Kurtz level == ACTIVE_LEVEL_BOTH) 256dbad75ddSKen Xue active_level = "Active on both|"; 257dbad75ddSKen Xue else 2580a95160eSMasanari Iida active_level = "Unknown Active level|"; 259dbad75ddSKen Xue 260dbad75ddSKen Xue if (pin_reg & BIT(LEVEL_TRIG_OFF)) 261dbad75ddSKen Xue level_trig = "Level trigger|"; 262dbad75ddSKen Xue else 263dbad75ddSKen Xue level_trig = "Edge trigger|"; 264dbad75ddSKen Xue 265dbad75ddSKen Xue } else { 266dbad75ddSKen Xue interrupt_enable = 267dbad75ddSKen Xue "interrupt is disabled|"; 268dbad75ddSKen Xue active_level = " "; 269dbad75ddSKen Xue level_trig = " "; 270dbad75ddSKen Xue } 271dbad75ddSKen Xue 272dbad75ddSKen Xue if (pin_reg & BIT(INTERRUPT_MASK_OFF)) 273dbad75ddSKen Xue interrupt_mask = 274dbad75ddSKen Xue "interrupt is unmasked|"; 275dbad75ddSKen Xue else 276dbad75ddSKen Xue interrupt_mask = 277dbad75ddSKen Xue "interrupt is masked|"; 278dbad75ddSKen Xue 2793bfd4430SShah, Nehal-bakulchandra if (pin_reg & BIT(WAKE_CNTRL_OFF_S0I3)) 280dbad75ddSKen Xue wake_cntrl0 = "enable wakeup in S0i3 state|"; 281dbad75ddSKen Xue else 282dbad75ddSKen Xue wake_cntrl0 = "disable wakeup in S0i3 state|"; 283dbad75ddSKen Xue 2843bfd4430SShah, Nehal-bakulchandra if (pin_reg & BIT(WAKE_CNTRL_OFF_S3)) 285dbad75ddSKen Xue wake_cntrl1 = "enable wakeup in S3 state|"; 286dbad75ddSKen Xue else 287dbad75ddSKen Xue wake_cntrl1 = "disable wakeup in S3 state|"; 288dbad75ddSKen Xue 2893bfd4430SShah, Nehal-bakulchandra if (pin_reg & BIT(WAKE_CNTRL_OFF_S4)) 290dbad75ddSKen Xue wake_cntrl2 = "enable wakeup in S4/S5 state|"; 291dbad75ddSKen Xue else 292dbad75ddSKen Xue wake_cntrl2 = "disable wakeup in S4/S5 state|"; 293dbad75ddSKen Xue 294dbad75ddSKen Xue if (pin_reg & BIT(PULL_UP_ENABLE_OFF)) { 295dbad75ddSKen Xue pull_up_enable = "pull-up is enabled|"; 296dbad75ddSKen Xue if (pin_reg & BIT(PULL_UP_SEL_OFF)) 297dbad75ddSKen Xue pull_up_sel = "8k pull-up|"; 298dbad75ddSKen Xue else 299dbad75ddSKen Xue pull_up_sel = "4k pull-up|"; 300dbad75ddSKen Xue } else { 301dbad75ddSKen Xue pull_up_enable = "pull-up is disabled|"; 302dbad75ddSKen Xue pull_up_sel = " "; 303dbad75ddSKen Xue } 304dbad75ddSKen Xue 305dbad75ddSKen Xue if (pin_reg & BIT(PULL_DOWN_ENABLE_OFF)) 306dbad75ddSKen Xue pull_down_enable = "pull-down is enabled|"; 307dbad75ddSKen Xue else 308dbad75ddSKen Xue pull_down_enable = "Pull-down is disabled|"; 309dbad75ddSKen Xue 310dbad75ddSKen Xue if (pin_reg & BIT(OUTPUT_ENABLE_OFF)) { 311dbad75ddSKen Xue pin_sts = " "; 312dbad75ddSKen Xue output_enable = "output is enabled|"; 313dbad75ddSKen Xue if (pin_reg & BIT(OUTPUT_VALUE_OFF)) 314dbad75ddSKen Xue output_value = "output is high|"; 315dbad75ddSKen Xue else 316dbad75ddSKen Xue output_value = "output is low|"; 317dbad75ddSKen Xue } else { 318dbad75ddSKen Xue output_enable = "output is disabled|"; 319dbad75ddSKen Xue output_value = " "; 320dbad75ddSKen Xue 321dbad75ddSKen Xue if (pin_reg & BIT(PIN_STS_OFF)) 322dbad75ddSKen Xue pin_sts = "input is high|"; 323dbad75ddSKen Xue else 324dbad75ddSKen Xue pin_sts = "input is low|"; 325dbad75ddSKen Xue } 326dbad75ddSKen Xue 327dbad75ddSKen Xue seq_printf(s, "%s %s %s %s %s %s\n" 328dbad75ddSKen Xue " %s %s %s %s %s %s %s 0x%x\n", 329dbad75ddSKen Xue level_trig, active_level, interrupt_enable, 330dbad75ddSKen Xue interrupt_mask, wake_cntrl0, wake_cntrl1, 331dbad75ddSKen Xue wake_cntrl2, pin_sts, pull_up_sel, 332dbad75ddSKen Xue pull_up_enable, pull_down_enable, 333dbad75ddSKen Xue output_value, output_enable, pin_reg); 334dbad75ddSKen Xue } 335dbad75ddSKen Xue } 336dbad75ddSKen Xue } 337dbad75ddSKen Xue #else 338dbad75ddSKen Xue #define amd_gpio_dbg_show NULL 339dbad75ddSKen Xue #endif 340dbad75ddSKen Xue 341dbad75ddSKen Xue static void amd_gpio_irq_enable(struct irq_data *d) 342dbad75ddSKen Xue { 343dbad75ddSKen Xue u32 pin_reg; 344dbad75ddSKen Xue unsigned long flags; 345dbad75ddSKen Xue struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 34604d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 347dbad75ddSKen Xue 348229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 349dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + (d->hwirq)*4); 350dbad75ddSKen Xue pin_reg |= BIT(INTERRUPT_ENABLE_OFF); 351dbad75ddSKen Xue pin_reg |= BIT(INTERRUPT_MASK_OFF); 352dbad75ddSKen Xue writel(pin_reg, gpio_dev->base + (d->hwirq)*4); 353229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 354dbad75ddSKen Xue } 355dbad75ddSKen Xue 356dbad75ddSKen Xue static void amd_gpio_irq_disable(struct irq_data *d) 357dbad75ddSKen Xue { 358dbad75ddSKen Xue u32 pin_reg; 359dbad75ddSKen Xue unsigned long flags; 360dbad75ddSKen Xue struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 36104d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 362dbad75ddSKen Xue 363229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 364dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + (d->hwirq)*4); 365dbad75ddSKen Xue pin_reg &= ~BIT(INTERRUPT_ENABLE_OFF); 366dbad75ddSKen Xue pin_reg &= ~BIT(INTERRUPT_MASK_OFF); 367dbad75ddSKen Xue writel(pin_reg, gpio_dev->base + (d->hwirq)*4); 368229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 369dbad75ddSKen Xue } 370dbad75ddSKen Xue 371dbad75ddSKen Xue static void amd_gpio_irq_mask(struct irq_data *d) 372dbad75ddSKen Xue { 373dbad75ddSKen Xue u32 pin_reg; 374dbad75ddSKen Xue unsigned long flags; 375dbad75ddSKen Xue struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 37604d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 377dbad75ddSKen Xue 378229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 379dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + (d->hwirq)*4); 380dbad75ddSKen Xue pin_reg &= ~BIT(INTERRUPT_MASK_OFF); 381dbad75ddSKen Xue writel(pin_reg, gpio_dev->base + (d->hwirq)*4); 382229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 383dbad75ddSKen Xue } 384dbad75ddSKen Xue 385dbad75ddSKen Xue static void amd_gpio_irq_unmask(struct irq_data *d) 386dbad75ddSKen Xue { 387dbad75ddSKen Xue u32 pin_reg; 388dbad75ddSKen Xue unsigned long flags; 389dbad75ddSKen Xue struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 39004d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 391dbad75ddSKen Xue 392229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 393dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + (d->hwirq)*4); 394dbad75ddSKen Xue pin_reg |= BIT(INTERRUPT_MASK_OFF); 395dbad75ddSKen Xue writel(pin_reg, gpio_dev->base + (d->hwirq)*4); 396229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 397dbad75ddSKen Xue } 398dbad75ddSKen Xue 399dbad75ddSKen Xue static void amd_gpio_irq_eoi(struct irq_data *d) 400dbad75ddSKen Xue { 401dbad75ddSKen Xue u32 reg; 402dbad75ddSKen Xue unsigned long flags; 403dbad75ddSKen Xue struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 40404d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 405dbad75ddSKen Xue 406229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 407dbad75ddSKen Xue reg = readl(gpio_dev->base + WAKE_INT_MASTER_REG); 408dbad75ddSKen Xue reg |= EOI_MASK; 409dbad75ddSKen Xue writel(reg, gpio_dev->base + WAKE_INT_MASTER_REG); 410229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 411dbad75ddSKen Xue } 412dbad75ddSKen Xue 413dbad75ddSKen Xue static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) 414dbad75ddSKen Xue { 415dbad75ddSKen Xue int ret = 0; 416b85bfa24SDaniel Kurtz u32 pin_reg, pin_reg_irq_en, mask; 4172983f296SShyam Sundar S K unsigned long flags, irq_flags; 418dbad75ddSKen Xue struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 41904d36723SLinus Walleij struct amd_gpio *gpio_dev = gpiochip_get_data(gc); 420dbad75ddSKen Xue 421229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 422dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + (d->hwirq)*4); 423dbad75ddSKen Xue 4242983f296SShyam Sundar S K /* Ignore the settings coming from the client and 4252983f296SShyam Sundar S K * read the values from the ACPI tables 4262983f296SShyam Sundar S K * while setting the trigger type 427499c7196SAgrawal, Nitesh-kumar */ 428499c7196SAgrawal, Nitesh-kumar 4292983f296SShyam Sundar S K irq_flags = irq_get_trigger_type(d->irq); 4302983f296SShyam Sundar S K if (irq_flags != IRQ_TYPE_NONE) 4312983f296SShyam Sundar S K type = irq_flags; 432499c7196SAgrawal, Nitesh-kumar 433dbad75ddSKen Xue switch (type & IRQ_TYPE_SENSE_MASK) { 434dbad75ddSKen Xue case IRQ_TYPE_EDGE_RISING: 435dbad75ddSKen Xue pin_reg &= ~BIT(LEVEL_TRIG_OFF); 436dbad75ddSKen Xue pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); 437dbad75ddSKen Xue pin_reg |= ACTIVE_HIGH << ACTIVE_LEVEL_OFF; 438dbad75ddSKen Xue pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF; 4399d829314SThomas Gleixner irq_set_handler_locked(d, handle_edge_irq); 440dbad75ddSKen Xue break; 441dbad75ddSKen Xue 442dbad75ddSKen Xue case IRQ_TYPE_EDGE_FALLING: 443dbad75ddSKen Xue pin_reg &= ~BIT(LEVEL_TRIG_OFF); 444dbad75ddSKen Xue pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); 445dbad75ddSKen Xue pin_reg |= ACTIVE_LOW << ACTIVE_LEVEL_OFF; 446dbad75ddSKen Xue pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF; 4479d829314SThomas Gleixner irq_set_handler_locked(d, handle_edge_irq); 448dbad75ddSKen Xue break; 449dbad75ddSKen Xue 450dbad75ddSKen Xue case IRQ_TYPE_EDGE_BOTH: 451dbad75ddSKen Xue pin_reg &= ~BIT(LEVEL_TRIG_OFF); 452dbad75ddSKen Xue pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); 453dbad75ddSKen Xue pin_reg |= BOTH_EADGE << ACTIVE_LEVEL_OFF; 454dbad75ddSKen Xue pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF; 4559d829314SThomas Gleixner irq_set_handler_locked(d, handle_edge_irq); 456dbad75ddSKen Xue break; 457dbad75ddSKen Xue 458dbad75ddSKen Xue case IRQ_TYPE_LEVEL_HIGH: 459dbad75ddSKen Xue pin_reg |= LEVEL_TRIGGER << LEVEL_TRIG_OFF; 460dbad75ddSKen Xue pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); 461dbad75ddSKen Xue pin_reg |= ACTIVE_HIGH << ACTIVE_LEVEL_OFF; 462dbad75ddSKen Xue pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF); 463dbad75ddSKen Xue pin_reg |= DB_TYPE_PRESERVE_LOW_GLITCH << DB_CNTRL_OFF; 4649d829314SThomas Gleixner irq_set_handler_locked(d, handle_level_irq); 465dbad75ddSKen Xue break; 466dbad75ddSKen Xue 467dbad75ddSKen Xue case IRQ_TYPE_LEVEL_LOW: 468dbad75ddSKen Xue pin_reg |= LEVEL_TRIGGER << LEVEL_TRIG_OFF; 469dbad75ddSKen Xue pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); 470dbad75ddSKen Xue pin_reg |= ACTIVE_LOW << ACTIVE_LEVEL_OFF; 471dbad75ddSKen Xue pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF); 472dbad75ddSKen Xue pin_reg |= DB_TYPE_PRESERVE_HIGH_GLITCH << DB_CNTRL_OFF; 4739d829314SThomas Gleixner irq_set_handler_locked(d, handle_level_irq); 474dbad75ddSKen Xue break; 475dbad75ddSKen Xue 476dbad75ddSKen Xue case IRQ_TYPE_NONE: 477dbad75ddSKen Xue break; 478dbad75ddSKen Xue 479dbad75ddSKen Xue default: 480dbad75ddSKen Xue dev_err(&gpio_dev->pdev->dev, "Invalid type value\n"); 481dbad75ddSKen Xue ret = -EINVAL; 482dbad75ddSKen Xue } 483dbad75ddSKen Xue 484dbad75ddSKen Xue pin_reg |= CLR_INTR_STAT << INTERRUPT_STS_OFF; 485b85bfa24SDaniel Kurtz /* 486b85bfa24SDaniel Kurtz * If WAKE_INT_MASTER_REG.MaskStsEn is set, a software write to the 487b85bfa24SDaniel Kurtz * debounce registers of any GPIO will block wake/interrupt status 48848c67f1fSMatteo Croce * generation for *all* GPIOs for a length of time that depends on 489b85bfa24SDaniel Kurtz * WAKE_INT_MASTER_REG.MaskStsLength[11:0]. During this period the 490b85bfa24SDaniel Kurtz * INTERRUPT_ENABLE bit will read as 0. 491b85bfa24SDaniel Kurtz * 492b85bfa24SDaniel Kurtz * We temporarily enable irq for the GPIO whose configuration is 493b85bfa24SDaniel Kurtz * changing, and then wait for it to read back as 1 to know when 494b85bfa24SDaniel Kurtz * debounce has settled and then disable the irq again. 495b85bfa24SDaniel Kurtz * We do this polling with the spinlock held to ensure other GPIO 496b85bfa24SDaniel Kurtz * access routines do not read an incorrect value for the irq enable 497b85bfa24SDaniel Kurtz * bit of other GPIOs. We keep the GPIO masked while polling to avoid 498b85bfa24SDaniel Kurtz * spurious irqs, and disable the irq again after polling. 499b85bfa24SDaniel Kurtz */ 500b85bfa24SDaniel Kurtz mask = BIT(INTERRUPT_ENABLE_OFF); 501b85bfa24SDaniel Kurtz pin_reg_irq_en = pin_reg; 502b85bfa24SDaniel Kurtz pin_reg_irq_en |= mask; 503b85bfa24SDaniel Kurtz pin_reg_irq_en &= ~BIT(INTERRUPT_MASK_OFF); 504b85bfa24SDaniel Kurtz writel(pin_reg_irq_en, gpio_dev->base + (d->hwirq)*4); 505b85bfa24SDaniel Kurtz while ((readl(gpio_dev->base + (d->hwirq)*4) & mask) != mask) 506b85bfa24SDaniel Kurtz continue; 507dbad75ddSKen Xue writel(pin_reg, gpio_dev->base + (d->hwirq)*4); 508229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 509dbad75ddSKen Xue 510dbad75ddSKen Xue return ret; 511dbad75ddSKen Xue } 512dbad75ddSKen Xue 513dbad75ddSKen Xue static void amd_irq_ack(struct irq_data *d) 514dbad75ddSKen Xue { 515dbad75ddSKen Xue /* 516dbad75ddSKen Xue * based on HW design,there is no need to ack HW 517dbad75ddSKen Xue * before handle current irq. But this routine is 518dbad75ddSKen Xue * necessary for handle_edge_irq 519dbad75ddSKen Xue */ 520dbad75ddSKen Xue } 521dbad75ddSKen Xue 522dbad75ddSKen Xue static struct irq_chip amd_gpio_irqchip = { 523dbad75ddSKen Xue .name = "amd_gpio", 524dbad75ddSKen Xue .irq_ack = amd_irq_ack, 525dbad75ddSKen Xue .irq_enable = amd_gpio_irq_enable, 526dbad75ddSKen Xue .irq_disable = amd_gpio_irq_disable, 527dbad75ddSKen Xue .irq_mask = amd_gpio_irq_mask, 528dbad75ddSKen Xue .irq_unmask = amd_gpio_irq_unmask, 529dbad75ddSKen Xue .irq_eoi = amd_gpio_irq_eoi, 530dbad75ddSKen Xue .irq_set_type = amd_gpio_irq_set_type, 5313bfd4430SShah, Nehal-bakulchandra .flags = IRQCHIP_SKIP_SET_WAKE, 532dbad75ddSKen Xue }; 533dbad75ddSKen Xue 534ba714a9cSThomas Gleixner #define PIN_IRQ_PENDING (BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF)) 535ba714a9cSThomas Gleixner 536ba714a9cSThomas Gleixner static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) 537dbad75ddSKen Xue { 538ba714a9cSThomas Gleixner struct amd_gpio *gpio_dev = dev_id; 539ba714a9cSThomas Gleixner struct gpio_chip *gc = &gpio_dev->gc; 540ba714a9cSThomas Gleixner irqreturn_t ret = IRQ_NONE; 541ba714a9cSThomas Gleixner unsigned int i, irqnr; 542dbad75ddSKen Xue unsigned long flags; 543ba714a9cSThomas Gleixner u32 *regs, regval; 544ba714a9cSThomas Gleixner u64 status, mask; 545dbad75ddSKen Xue 546ba714a9cSThomas Gleixner /* Read the wake status */ 547229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 548ba714a9cSThomas Gleixner status = readl(gpio_dev->base + WAKE_INT_STATUS_REG1); 549ba714a9cSThomas Gleixner status <<= 32; 550ba714a9cSThomas Gleixner status |= readl(gpio_dev->base + WAKE_INT_STATUS_REG0); 551229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 552dbad75ddSKen Xue 553ba714a9cSThomas Gleixner /* Bit 0-45 contain the relevant status bits */ 554ba714a9cSThomas Gleixner status &= (1ULL << 46) - 1; 555ba714a9cSThomas Gleixner regs = gpio_dev->base; 556ba714a9cSThomas Gleixner for (mask = 1, irqnr = 0; status; mask <<= 1, regs += 4, irqnr += 4) { 557ba714a9cSThomas Gleixner if (!(status & mask)) 558ba714a9cSThomas Gleixner continue; 559ba714a9cSThomas Gleixner status &= ~mask; 560ba714a9cSThomas Gleixner 561ba714a9cSThomas Gleixner /* Each status bit covers four pins */ 562dbad75ddSKen Xue for (i = 0; i < 4; i++) { 563ba714a9cSThomas Gleixner regval = readl(regs + i); 5648bbed1eeSDaniel Kurtz if (!(regval & PIN_IRQ_PENDING) || 5658bbed1eeSDaniel Kurtz !(regval & BIT(INTERRUPT_MASK_OFF))) 566ba714a9cSThomas Gleixner continue; 567f0fbe7bcSThierry Reding irq = irq_find_mapping(gc->irq.domain, irqnr + i); 568dbad75ddSKen Xue generic_handle_irq(irq); 5696afb1026SDaniel Drake 5706afb1026SDaniel Drake /* Clear interrupt. 5716afb1026SDaniel Drake * We must read the pin register again, in case the 5726afb1026SDaniel Drake * value was changed while executing 5736afb1026SDaniel Drake * generic_handle_irq() above. 5746afb1026SDaniel Drake */ 5756afb1026SDaniel Drake raw_spin_lock_irqsave(&gpio_dev->lock, flags); 5766afb1026SDaniel Drake regval = readl(regs + i); 577ba714a9cSThomas Gleixner writel(regval, regs + i); 5786afb1026SDaniel Drake raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 579ba714a9cSThomas Gleixner ret = IRQ_HANDLED; 580dbad75ddSKen Xue } 581dbad75ddSKen Xue } 582dbad75ddSKen Xue 583ba714a9cSThomas Gleixner /* Signal EOI to the GPIO unit */ 584229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 585ba714a9cSThomas Gleixner regval = readl(gpio_dev->base + WAKE_INT_MASTER_REG); 586ba714a9cSThomas Gleixner regval |= EOI_MASK; 587ba714a9cSThomas Gleixner writel(regval, gpio_dev->base + WAKE_INT_MASTER_REG); 588229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 589dbad75ddSKen Xue 590ba714a9cSThomas Gleixner return ret; 591dbad75ddSKen Xue } 592dbad75ddSKen Xue 593dbad75ddSKen Xue static int amd_get_groups_count(struct pinctrl_dev *pctldev) 594dbad75ddSKen Xue { 595dbad75ddSKen Xue struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev); 596dbad75ddSKen Xue 597dbad75ddSKen Xue return gpio_dev->ngroups; 598dbad75ddSKen Xue } 599dbad75ddSKen Xue 600dbad75ddSKen Xue static const char *amd_get_group_name(struct pinctrl_dev *pctldev, 601dbad75ddSKen Xue unsigned group) 602dbad75ddSKen Xue { 603dbad75ddSKen Xue struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev); 604dbad75ddSKen Xue 605dbad75ddSKen Xue return gpio_dev->groups[group].name; 606dbad75ddSKen Xue } 607dbad75ddSKen Xue 608dbad75ddSKen Xue static int amd_get_group_pins(struct pinctrl_dev *pctldev, 609dbad75ddSKen Xue unsigned group, 610dbad75ddSKen Xue const unsigned **pins, 611dbad75ddSKen Xue unsigned *num_pins) 612dbad75ddSKen Xue { 613dbad75ddSKen Xue struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev); 614dbad75ddSKen Xue 615dbad75ddSKen Xue *pins = gpio_dev->groups[group].pins; 616dbad75ddSKen Xue *num_pins = gpio_dev->groups[group].npins; 617dbad75ddSKen Xue return 0; 618dbad75ddSKen Xue } 619dbad75ddSKen Xue 620dbad75ddSKen Xue static const struct pinctrl_ops amd_pinctrl_ops = { 621dbad75ddSKen Xue .get_groups_count = amd_get_groups_count, 622dbad75ddSKen Xue .get_group_name = amd_get_group_name, 623dbad75ddSKen Xue .get_group_pins = amd_get_group_pins, 624dbad75ddSKen Xue #ifdef CONFIG_OF 625dbad75ddSKen Xue .dt_node_to_map = pinconf_generic_dt_node_to_map_group, 626d32f7fd3SIrina Tirdea .dt_free_map = pinctrl_utils_free_map, 627dbad75ddSKen Xue #endif 628dbad75ddSKen Xue }; 629dbad75ddSKen Xue 630dbad75ddSKen Xue static int amd_pinconf_get(struct pinctrl_dev *pctldev, 631dbad75ddSKen Xue unsigned int pin, 632dbad75ddSKen Xue unsigned long *config) 633dbad75ddSKen Xue { 634dbad75ddSKen Xue u32 pin_reg; 635dbad75ddSKen Xue unsigned arg; 636dbad75ddSKen Xue unsigned long flags; 637dbad75ddSKen Xue struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev); 638dbad75ddSKen Xue enum pin_config_param param = pinconf_to_config_param(*config); 639dbad75ddSKen Xue 640229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 641dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + pin*4); 642229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 643dbad75ddSKen Xue switch (param) { 644dbad75ddSKen Xue case PIN_CONFIG_INPUT_DEBOUNCE: 645dbad75ddSKen Xue arg = pin_reg & DB_TMR_OUT_MASK; 646dbad75ddSKen Xue break; 647dbad75ddSKen Xue 648dbad75ddSKen Xue case PIN_CONFIG_BIAS_PULL_DOWN: 649dbad75ddSKen Xue arg = (pin_reg >> PULL_DOWN_ENABLE_OFF) & BIT(0); 650dbad75ddSKen Xue break; 651dbad75ddSKen Xue 652dbad75ddSKen Xue case PIN_CONFIG_BIAS_PULL_UP: 653dbad75ddSKen Xue arg = (pin_reg >> PULL_UP_SEL_OFF) & (BIT(0) | BIT(1)); 654dbad75ddSKen Xue break; 655dbad75ddSKen Xue 656dbad75ddSKen Xue case PIN_CONFIG_DRIVE_STRENGTH: 657dbad75ddSKen Xue arg = (pin_reg >> DRV_STRENGTH_SEL_OFF) & DRV_STRENGTH_SEL_MASK; 658dbad75ddSKen Xue break; 659dbad75ddSKen Xue 660dbad75ddSKen Xue default: 661dbad75ddSKen Xue dev_err(&gpio_dev->pdev->dev, "Invalid config param %04x\n", 662dbad75ddSKen Xue param); 663dbad75ddSKen Xue return -ENOTSUPP; 664dbad75ddSKen Xue } 665dbad75ddSKen Xue 666dbad75ddSKen Xue *config = pinconf_to_config_packed(param, arg); 667dbad75ddSKen Xue 668dbad75ddSKen Xue return 0; 669dbad75ddSKen Xue } 670dbad75ddSKen Xue 671dbad75ddSKen Xue static int amd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, 672dbad75ddSKen Xue unsigned long *configs, unsigned num_configs) 673dbad75ddSKen Xue { 674dbad75ddSKen Xue int i; 675dbad75ddSKen Xue u32 arg; 67625a853d0SKen Xue int ret = 0; 67725a853d0SKen Xue u32 pin_reg; 678dbad75ddSKen Xue unsigned long flags; 679dbad75ddSKen Xue enum pin_config_param param; 680dbad75ddSKen Xue struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev); 681dbad75ddSKen Xue 682229710feSJulia Cartwright raw_spin_lock_irqsave(&gpio_dev->lock, flags); 683dbad75ddSKen Xue for (i = 0; i < num_configs; i++) { 684dbad75ddSKen Xue param = pinconf_to_config_param(configs[i]); 685dbad75ddSKen Xue arg = pinconf_to_config_argument(configs[i]); 686dbad75ddSKen Xue pin_reg = readl(gpio_dev->base + pin*4); 687dbad75ddSKen Xue 688dbad75ddSKen Xue switch (param) { 689dbad75ddSKen Xue case PIN_CONFIG_INPUT_DEBOUNCE: 690dbad75ddSKen Xue pin_reg &= ~DB_TMR_OUT_MASK; 691dbad75ddSKen Xue pin_reg |= arg & DB_TMR_OUT_MASK; 692dbad75ddSKen Xue break; 693dbad75ddSKen Xue 694dbad75ddSKen Xue case PIN_CONFIG_BIAS_PULL_DOWN: 695dbad75ddSKen Xue pin_reg &= ~BIT(PULL_DOWN_ENABLE_OFF); 696dbad75ddSKen Xue pin_reg |= (arg & BIT(0)) << PULL_DOWN_ENABLE_OFF; 697dbad75ddSKen Xue break; 698dbad75ddSKen Xue 699dbad75ddSKen Xue case PIN_CONFIG_BIAS_PULL_UP: 700dbad75ddSKen Xue pin_reg &= ~BIT(PULL_UP_SEL_OFF); 701dbad75ddSKen Xue pin_reg |= (arg & BIT(0)) << PULL_UP_SEL_OFF; 702dbad75ddSKen Xue pin_reg &= ~BIT(PULL_UP_ENABLE_OFF); 703dbad75ddSKen Xue pin_reg |= ((arg>>1) & BIT(0)) << PULL_UP_ENABLE_OFF; 704dbad75ddSKen Xue break; 705dbad75ddSKen Xue 706dbad75ddSKen Xue case PIN_CONFIG_DRIVE_STRENGTH: 707dbad75ddSKen Xue pin_reg &= ~(DRV_STRENGTH_SEL_MASK 708dbad75ddSKen Xue << DRV_STRENGTH_SEL_OFF); 709dbad75ddSKen Xue pin_reg |= (arg & DRV_STRENGTH_SEL_MASK) 710dbad75ddSKen Xue << DRV_STRENGTH_SEL_OFF; 711dbad75ddSKen Xue break; 712dbad75ddSKen Xue 713dbad75ddSKen Xue default: 714dbad75ddSKen Xue dev_err(&gpio_dev->pdev->dev, 715dbad75ddSKen Xue "Invalid config param %04x\n", param); 71625a853d0SKen Xue ret = -ENOTSUPP; 717dbad75ddSKen Xue } 718dbad75ddSKen Xue 719dbad75ddSKen Xue writel(pin_reg, gpio_dev->base + pin*4); 720dbad75ddSKen Xue } 721229710feSJulia Cartwright raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); 722dbad75ddSKen Xue 72325a853d0SKen Xue return ret; 724dbad75ddSKen Xue } 725dbad75ddSKen Xue 726dbad75ddSKen Xue static int amd_pinconf_group_get(struct pinctrl_dev *pctldev, 727dbad75ddSKen Xue unsigned int group, 728dbad75ddSKen Xue unsigned long *config) 729dbad75ddSKen Xue { 730dbad75ddSKen Xue const unsigned *pins; 731dbad75ddSKen Xue unsigned npins; 732dbad75ddSKen Xue int ret; 733dbad75ddSKen Xue 734dbad75ddSKen Xue ret = amd_get_group_pins(pctldev, group, &pins, &npins); 735dbad75ddSKen Xue if (ret) 736dbad75ddSKen Xue return ret; 737dbad75ddSKen Xue 738dbad75ddSKen Xue if (amd_pinconf_get(pctldev, pins[0], config)) 739dbad75ddSKen Xue return -ENOTSUPP; 740dbad75ddSKen Xue 741dbad75ddSKen Xue return 0; 742dbad75ddSKen Xue } 743dbad75ddSKen Xue 744dbad75ddSKen Xue static int amd_pinconf_group_set(struct pinctrl_dev *pctldev, 745dbad75ddSKen Xue unsigned group, unsigned long *configs, 746dbad75ddSKen Xue unsigned num_configs) 747dbad75ddSKen Xue { 748dbad75ddSKen Xue const unsigned *pins; 749dbad75ddSKen Xue unsigned npins; 750dbad75ddSKen Xue int i, ret; 751dbad75ddSKen Xue 752dbad75ddSKen Xue ret = amd_get_group_pins(pctldev, group, &pins, &npins); 753dbad75ddSKen Xue if (ret) 754dbad75ddSKen Xue return ret; 755dbad75ddSKen Xue for (i = 0; i < npins; i++) { 756dbad75ddSKen Xue if (amd_pinconf_set(pctldev, pins[i], configs, num_configs)) 757dbad75ddSKen Xue return -ENOTSUPP; 758dbad75ddSKen Xue } 759dbad75ddSKen Xue return 0; 760dbad75ddSKen Xue } 761dbad75ddSKen Xue 762dbad75ddSKen Xue static const struct pinconf_ops amd_pinconf_ops = { 763dbad75ddSKen Xue .pin_config_get = amd_pinconf_get, 764dbad75ddSKen Xue .pin_config_set = amd_pinconf_set, 765dbad75ddSKen Xue .pin_config_group_get = amd_pinconf_group_get, 766dbad75ddSKen Xue .pin_config_group_set = amd_pinconf_group_set, 767dbad75ddSKen Xue }; 768dbad75ddSKen Xue 76979d2c8beSDaniel Drake #ifdef CONFIG_PM_SLEEP 77079d2c8beSDaniel Drake static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin) 77179d2c8beSDaniel Drake { 77279d2c8beSDaniel Drake const struct pin_desc *pd = pin_desc_get(gpio_dev->pctrl, pin); 77379d2c8beSDaniel Drake 77479d2c8beSDaniel Drake if (!pd) 77579d2c8beSDaniel Drake return false; 77679d2c8beSDaniel Drake 77779d2c8beSDaniel Drake /* 77879d2c8beSDaniel Drake * Only restore the pin if it is actually in use by the kernel (or 77979d2c8beSDaniel Drake * by userspace). 78079d2c8beSDaniel Drake */ 78179d2c8beSDaniel Drake if (pd->mux_owner || pd->gpio_owner || 78279d2c8beSDaniel Drake gpiochip_line_is_irq(&gpio_dev->gc, pin)) 78379d2c8beSDaniel Drake return true; 78479d2c8beSDaniel Drake 78579d2c8beSDaniel Drake return false; 78679d2c8beSDaniel Drake } 78779d2c8beSDaniel Drake 7882d71dfa2SColin Ian King static int amd_gpio_suspend(struct device *dev) 78979d2c8beSDaniel Drake { 7909f540c3eSWolfram Sang struct amd_gpio *gpio_dev = dev_get_drvdata(dev); 79179d2c8beSDaniel Drake struct pinctrl_desc *desc = gpio_dev->pctrl->desc; 79279d2c8beSDaniel Drake int i; 79379d2c8beSDaniel Drake 79479d2c8beSDaniel Drake for (i = 0; i < desc->npins; i++) { 79579d2c8beSDaniel Drake int pin = desc->pins[i].number; 79679d2c8beSDaniel Drake 79779d2c8beSDaniel Drake if (!amd_gpio_should_save(gpio_dev, pin)) 79879d2c8beSDaniel Drake continue; 79979d2c8beSDaniel Drake 80079d2c8beSDaniel Drake gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin*4); 80179d2c8beSDaniel Drake } 80279d2c8beSDaniel Drake 80379d2c8beSDaniel Drake return 0; 80479d2c8beSDaniel Drake } 80579d2c8beSDaniel Drake 8062d71dfa2SColin Ian King static int amd_gpio_resume(struct device *dev) 80779d2c8beSDaniel Drake { 8089f540c3eSWolfram Sang struct amd_gpio *gpio_dev = dev_get_drvdata(dev); 80979d2c8beSDaniel Drake struct pinctrl_desc *desc = gpio_dev->pctrl->desc; 81079d2c8beSDaniel Drake int i; 81179d2c8beSDaniel Drake 81279d2c8beSDaniel Drake for (i = 0; i < desc->npins; i++) { 81379d2c8beSDaniel Drake int pin = desc->pins[i].number; 81479d2c8beSDaniel Drake 81579d2c8beSDaniel Drake if (!amd_gpio_should_save(gpio_dev, pin)) 81679d2c8beSDaniel Drake continue; 81779d2c8beSDaniel Drake 81879d2c8beSDaniel Drake writel(gpio_dev->saved_regs[i], gpio_dev->base + pin*4); 81979d2c8beSDaniel Drake } 82079d2c8beSDaniel Drake 82179d2c8beSDaniel Drake return 0; 82279d2c8beSDaniel Drake } 82379d2c8beSDaniel Drake 82479d2c8beSDaniel Drake static const struct dev_pm_ops amd_gpio_pm_ops = { 82579d2c8beSDaniel Drake SET_LATE_SYSTEM_SLEEP_PM_OPS(amd_gpio_suspend, 82679d2c8beSDaniel Drake amd_gpio_resume) 82779d2c8beSDaniel Drake }; 82879d2c8beSDaniel Drake #endif 82979d2c8beSDaniel Drake 830dbad75ddSKen Xue static struct pinctrl_desc amd_pinctrl_desc = { 831dbad75ddSKen Xue .pins = kerncz_pins, 832dbad75ddSKen Xue .npins = ARRAY_SIZE(kerncz_pins), 833dbad75ddSKen Xue .pctlops = &amd_pinctrl_ops, 834dbad75ddSKen Xue .confops = &amd_pinconf_ops, 835dbad75ddSKen Xue .owner = THIS_MODULE, 836dbad75ddSKen Xue }; 837dbad75ddSKen Xue 838dbad75ddSKen Xue static int amd_gpio_probe(struct platform_device *pdev) 839dbad75ddSKen Xue { 840dbad75ddSKen Xue int ret = 0; 84125a853d0SKen Xue int irq_base; 842dbad75ddSKen Xue struct resource *res; 843dbad75ddSKen Xue struct amd_gpio *gpio_dev; 844dbad75ddSKen Xue 845dbad75ddSKen Xue gpio_dev = devm_kzalloc(&pdev->dev, 846dbad75ddSKen Xue sizeof(struct amd_gpio), GFP_KERNEL); 847dbad75ddSKen Xue if (!gpio_dev) 848dbad75ddSKen Xue return -ENOMEM; 849dbad75ddSKen Xue 850229710feSJulia Cartwright raw_spin_lock_init(&gpio_dev->lock); 851dbad75ddSKen Xue 852dbad75ddSKen Xue res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 853dbad75ddSKen Xue if (!res) { 854dbad75ddSKen Xue dev_err(&pdev->dev, "Failed to get gpio io resource.\n"); 855dbad75ddSKen Xue return -EINVAL; 856dbad75ddSKen Xue } 857dbad75ddSKen Xue 858dbad75ddSKen Xue gpio_dev->base = devm_ioremap_nocache(&pdev->dev, res->start, 859dbad75ddSKen Xue resource_size(res)); 860424a6c60SWei Yongjun if (!gpio_dev->base) 861424a6c60SWei Yongjun return -ENOMEM; 862dbad75ddSKen Xue 863dbad75ddSKen Xue irq_base = platform_get_irq(pdev, 0); 86464c4dcbfSStephen Boyd if (irq_base < 0) 8652e6424abSGustavo A. R. Silva return irq_base; 866dbad75ddSKen Xue 86779d2c8beSDaniel Drake #ifdef CONFIG_PM_SLEEP 86879d2c8beSDaniel Drake gpio_dev->saved_regs = devm_kcalloc(&pdev->dev, amd_pinctrl_desc.npins, 86979d2c8beSDaniel Drake sizeof(*gpio_dev->saved_regs), 87079d2c8beSDaniel Drake GFP_KERNEL); 87179d2c8beSDaniel Drake if (!gpio_dev->saved_regs) 87279d2c8beSDaniel Drake return -ENOMEM; 87379d2c8beSDaniel Drake #endif 87479d2c8beSDaniel Drake 875dbad75ddSKen Xue gpio_dev->pdev = pdev; 87612b10f47SDaniel Kurtz gpio_dev->gc.get_direction = amd_gpio_get_direction; 877dbad75ddSKen Xue gpio_dev->gc.direction_input = amd_gpio_direction_input; 878dbad75ddSKen Xue gpio_dev->gc.direction_output = amd_gpio_direction_output; 879dbad75ddSKen Xue gpio_dev->gc.get = amd_gpio_get_value; 880dbad75ddSKen Xue gpio_dev->gc.set = amd_gpio_set_value; 8812956b5d9SMika Westerberg gpio_dev->gc.set_config = amd_gpio_set_config; 882dbad75ddSKen Xue gpio_dev->gc.dbg_show = amd_gpio_dbg_show; 883dbad75ddSKen Xue 8843bfd4430SShah, Nehal-bakulchandra gpio_dev->gc.base = -1; 885dbad75ddSKen Xue gpio_dev->gc.label = pdev->name; 886dbad75ddSKen Xue gpio_dev->gc.owner = THIS_MODULE; 88758383c78SLinus Walleij gpio_dev->gc.parent = &pdev->dev; 8883bfd4430SShah, Nehal-bakulchandra gpio_dev->gc.ngpio = resource_size(res) / 4; 889dbad75ddSKen Xue #if defined(CONFIG_OF_GPIO) 890dbad75ddSKen Xue gpio_dev->gc.of_node = pdev->dev.of_node; 891dbad75ddSKen Xue #endif 892dbad75ddSKen Xue 8933bfd4430SShah, Nehal-bakulchandra gpio_dev->hwbank_num = gpio_dev->gc.ngpio / 64; 894dbad75ddSKen Xue gpio_dev->groups = kerncz_groups; 895dbad75ddSKen Xue gpio_dev->ngroups = ARRAY_SIZE(kerncz_groups); 896dbad75ddSKen Xue 897dbad75ddSKen Xue amd_pinctrl_desc.name = dev_name(&pdev->dev); 898251e22abSLaxman Dewangan gpio_dev->pctrl = devm_pinctrl_register(&pdev->dev, &amd_pinctrl_desc, 899251e22abSLaxman Dewangan gpio_dev); 900323de9efSMasahiro Yamada if (IS_ERR(gpio_dev->pctrl)) { 901dbad75ddSKen Xue dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); 902323de9efSMasahiro Yamada return PTR_ERR(gpio_dev->pctrl); 903dbad75ddSKen Xue } 904dbad75ddSKen Xue 90504d36723SLinus Walleij ret = gpiochip_add_data(&gpio_dev->gc, gpio_dev); 906dbad75ddSKen Xue if (ret) 907251e22abSLaxman Dewangan return ret; 908dbad75ddSKen Xue 909dbad75ddSKen Xue ret = gpiochip_add_pin_range(&gpio_dev->gc, dev_name(&pdev->dev), 9103bfd4430SShah, Nehal-bakulchandra 0, 0, gpio_dev->gc.ngpio); 911dbad75ddSKen Xue if (ret) { 912dbad75ddSKen Xue dev_err(&pdev->dev, "Failed to add pin range\n"); 913dbad75ddSKen Xue goto out2; 914dbad75ddSKen Xue } 915dbad75ddSKen Xue 916dbad75ddSKen Xue ret = gpiochip_irqchip_add(&gpio_dev->gc, 917dbad75ddSKen Xue &amd_gpio_irqchip, 918dbad75ddSKen Xue 0, 919dbad75ddSKen Xue handle_simple_irq, 920dbad75ddSKen Xue IRQ_TYPE_NONE); 921dbad75ddSKen Xue if (ret) { 922dbad75ddSKen Xue dev_err(&pdev->dev, "could not add irqchip\n"); 923dbad75ddSKen Xue ret = -ENODEV; 924dbad75ddSKen Xue goto out2; 925dbad75ddSKen Xue } 926dbad75ddSKen Xue 927279ffafaSSandeep Singh ret = devm_request_irq(&pdev->dev, irq_base, amd_gpio_irq_handler, 928279ffafaSSandeep Singh IRQF_SHARED, KBUILD_MODNAME, gpio_dev); 929ba714a9cSThomas Gleixner if (ret) 930ba714a9cSThomas Gleixner goto out2; 931ba714a9cSThomas Gleixner 932dbad75ddSKen Xue platform_set_drvdata(pdev, gpio_dev); 933dbad75ddSKen Xue 934dbad75ddSKen Xue dev_dbg(&pdev->dev, "amd gpio driver loaded\n"); 935dbad75ddSKen Xue return ret; 936dbad75ddSKen Xue 937dbad75ddSKen Xue out2: 938dbad75ddSKen Xue gpiochip_remove(&gpio_dev->gc); 939dbad75ddSKen Xue 940dbad75ddSKen Xue return ret; 941dbad75ddSKen Xue } 942dbad75ddSKen Xue 943dbad75ddSKen Xue static int amd_gpio_remove(struct platform_device *pdev) 944dbad75ddSKen Xue { 945dbad75ddSKen Xue struct amd_gpio *gpio_dev; 946dbad75ddSKen Xue 947dbad75ddSKen Xue gpio_dev = platform_get_drvdata(pdev); 948dbad75ddSKen Xue 949dbad75ddSKen Xue gpiochip_remove(&gpio_dev->gc); 950dbad75ddSKen Xue 951dbad75ddSKen Xue return 0; 952dbad75ddSKen Xue } 953dbad75ddSKen Xue 954dbad75ddSKen Xue static const struct acpi_device_id amd_gpio_acpi_match[] = { 955dbad75ddSKen Xue { "AMD0030", 0 }, 95642a44402SWang Hongcheng { "AMDI0030", 0}, 957dbad75ddSKen Xue { }, 958dbad75ddSKen Xue }; 959dbad75ddSKen Xue MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match); 960dbad75ddSKen Xue 961dbad75ddSKen Xue static struct platform_driver amd_gpio_driver = { 962dbad75ddSKen Xue .driver = { 963dbad75ddSKen Xue .name = "amd_gpio", 964dbad75ddSKen Xue .acpi_match_table = ACPI_PTR(amd_gpio_acpi_match), 96579d2c8beSDaniel Drake #ifdef CONFIG_PM_SLEEP 96679d2c8beSDaniel Drake .pm = &amd_gpio_pm_ops, 96779d2c8beSDaniel Drake #endif 968dbad75ddSKen Xue }, 969dbad75ddSKen Xue .probe = amd_gpio_probe, 970dbad75ddSKen Xue .remove = amd_gpio_remove, 971dbad75ddSKen Xue }; 972dbad75ddSKen Xue 973dbad75ddSKen Xue module_platform_driver(amd_gpio_driver); 974dbad75ddSKen Xue 975dbad75ddSKen Xue MODULE_LICENSE("GPL v2"); 976dbad75ddSKen Xue MODULE_AUTHOR("Ken Xue <Ken.Xue@amd.com>, Jeff Wu <Jeff.Wu@amd.com>"); 977dbad75ddSKen Xue MODULE_DESCRIPTION("AMD GPIO pinctrl driver"); 978