diff options
Diffstat (limited to 'drivers/gpio')
30 files changed, 1740 insertions, 697 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index dc1aaa8..38d875d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -90,27 +90,11 @@ config GPIO_GENERIC # put drivers in the right section, in alphabetical order -config GPIO_DA9052 - tristate "Dialog DA9052 GPIO" - depends on PMIC_DA9052 - help - Say yes here to enable the GPIO driver for the DA9052 chip. - -config GPIO_DA9055 - tristate "Dialog Semiconductor DA9055 GPIO" - depends on MFD_DA9055 - help - Say yes here to enable the GPIO driver for the DA9055 chip. - - The Dialog DA9055 PMIC chip has 3 GPIO pins that can be - be controller by this driver. - - If driver is built as a module it will be called gpio-da9055. - +# This symbol is selected by both I2C and SPI expanders config GPIO_MAX730X tristate -comment "Memory mapped GPIO drivers:" +menu "Memory mapped GPIO drivers" config GPIO_74XX_MMIO tristate "GPIO driver for 74xx-ICs with MMIO access" @@ -126,6 +110,22 @@ config GPIO_74XX_MMIO 8 bits: 74244 (Input), 74273 (Output) 16 bits: 741624 (Input), 7416374 (Output) +config GPIO_ALTERA + tristate "Altera GPIO" + depends on OF_GPIO + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say Y or M here to build support for the Altera PIO device. + + If driver is built as a module it will be called gpio-altera. + +config GPIO_BCM_KONA + bool "Broadcom Kona GPIO" + depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) + help + Turn on GPIO support for Broadcom "Kona" chips. + config GPIO_CLPS711X tristate "CLPS711X GPIO support" depends on ARCH_CLPS711X || COMPILE_TEST @@ -140,28 +140,14 @@ config GPIO_DAVINCI help Say yes here to enable GPIO support for TI Davinci/Keystone SoCs. -config GPIO_GENERIC_PLATFORM - tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" - select GPIO_GENERIC - help - Say yes here to support basic platform_device memory-mapped GPIO controllers. - config GPIO_DWAPB tristate "Synopsys DesignWare APB GPIO driver" - depends on ARM - depends on OF_GPIO select GPIO_GENERIC select GENERIC_IRQ_CHIP help Say Y or M here to build support for the Synopsys DesignWare APB GPIO block. -config GPIO_IT8761E - tristate "IT8761E GPIO support" - depends on X86 # unconditional access to IO space. - help - Say yes here to support GPIO functionality of IT8761E super I/O chip. - config GPIO_EM tristate "Emma Mobile GPIO" depends on ARM && OF_GPIO @@ -173,36 +159,99 @@ config GPIO_EP93XX depends on ARCH_EP93XX select GPIO_GENERIC -config GPIO_ZEVIO - bool "LSI ZEVIO SoC memory mapped GPIOs" - depends on ARM && OF_GPIO - help - Say yes here to support the GPIO controller in LSI ZEVIO SoCs. - -config GPIO_MM_LANTIQ - bool "Lantiq Memory mapped GPIOs" - depends on LANTIQ && SOC_XWAY - help - This enables support for memory mapped GPIOs on the External Bus Unit - (EBU) found on Lantiq SoCs. The gpios are output only as they are - created by attaching a 16bit latch to the bus. - config GPIO_F7188X - tristate "F71882FG and F71889F GPIO support" + tristate "F71869, F71869A, F71882FG and F71889F GPIO support" depends on X86 help This option enables support for GPIOs found on Fintek Super-I/O - chips F71882FG and F71889F. + chips F71869, F71869A, F71882FG and F71889F. To compile this driver as a module, choose M here: the module will be called f7188x-gpio. +config GPIO_GE_FPGA + bool "GE FPGA based GPIO" + depends on GE_FPGA + select GPIO_GENERIC + help + Support for common GPIO functionality provided on some GE Single Board + Computers. + + This driver provides basic support (configure as input or output, read + and write pin state) for GPIO implemented in a number of GE single + board computers. + +config GPIO_GENERIC_PLATFORM + tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" + select GPIO_GENERIC + help + Say yes here to support basic platform_device memory-mapped GPIO controllers. + +config GPIO_GRGPIO + tristate "Aeroflex Gaisler GRGPIO support" + depends on OF + select GPIO_GENERIC + select IRQ_DOMAIN + help + Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB + VHDL IP core library. + +config GPIO_ICH + tristate "Intel ICH GPIO" + depends on PCI && X86 + select MFD_CORE + select LPC_ICH + help + Say yes here to support the GPIO functionality of a number of Intel + ICH-based chipsets. Currently supported devices: ICH6, ICH7, ICH8 + ICH9, ICH10, Series 5/3400 (eg Ibex Peak), Series 6/C200 (eg + Cougar Point), NM10 (Tiger Point), and 3100 (Whitmore Lake). + + If unsure, say N. + +config GPIO_IOP + tristate "Intel IOP GPIO" + depends on ARM && (ARCH_IOP32X || ARCH_IOP33X) + help + Say yes here to support the GPIO functionality of a number of Intel + IOP32X or IOP33X. + + If unsure, say N. + +config GPIO_IT8761E + tristate "IT8761E GPIO support" + depends on X86 # unconditional access to IO space. + help + Say yes here to support GPIO functionality of IT8761E super I/O chip. + +config GPIO_LOONGSON + bool "Loongson-2/3 GPIO support" + depends on CPU_LOONGSON2 || CPU_LOONGSON3 + help + driver for GPIO functionality on Loongson-2F/3A/3B processors. + +config GPIO_LYNXPOINT + tristate "Intel Lynxpoint GPIO support" + depends on ACPI && X86 + select GPIOLIB_IRQCHIP + help + driver for GPIO functionality on Intel Lynxpoint PCH chipset + Requires ACPI device enumeration code to set up a platform device. + config GPIO_MB86S7X bool "GPIO support for Fujitsu MB86S7x Platforms" depends on ARCH_MB86S7X help Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs. +config GPIO_MM_LANTIQ + bool "Lantiq Memory mapped GPIOs" + depends on LANTIQ && SOC_XWAY + help + This enables support for memory mapped GPIOs on the External Bus Unit + (EBU) found on Lantiq SoCs. The gpios are output only as they are + created by attaching a 16bit latch to the bus. + config GPIO_MOXART bool "MOXART GPIO support" depends on ARCH_MOXART @@ -303,6 +352,33 @@ config GPIO_SAMSUNG Legacy GPIO support. Use only for platforms without support for pinctrl. +config GPIO_SCH + tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" + depends on PCI && X86 + select MFD_CORE + select LPC_SCH + help + Say yes here to support GPIO interface on Intel Poulsbo SCH, + Intel Tunnel Creek processor, Intel Centerton processor or + Intel Quark X1000 SoC. + + The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are + powered by the core power rail and are turned off during sleep + modes (S3 and higher). The remaining four GPIOs are powered by + the Intel SCH suspend power supply. These GPIOs remain + active during S3. The suspend powered GPIOs can be used to wake the + system from the Suspend-to-RAM state. + + The Intel Tunnel Creek processor has 5 GPIOs powered by the + core power rail and 9 from suspend power supply. + + The Intel Centerton processor has a total of 30 GPIO pins. + Twenty-one are powered by the core power rail and 9 from the + suspend power supply. + + The Intel Quark X1000 SoC has 2 GPIOs powered by the core + power well and 6 from the suspend power well. + config GPIO_SCH311X tristate "SMSC SCH311x SuperI/O GPIO" help @@ -327,12 +403,27 @@ config GPIO_STA2X11 Say yes here to support the STA2x11/ConneXt GPIO device. The GPIO module has 128 GPIO pins with alternate functions. +config GPIO_STP_XWAY + bool "XWAY STP GPIOs" + depends on SOC_XWAY + help + This enables support for the Serial To Parallel (STP) unit found on + XWAY SoC. The STP allows the SoC to drive a shift registers cascade, + that can be up to 24 bit. This peripheral is aimed at driving leds. + Some of the gpios/leds can be auto updated by the soc with dsl and + phy status. + config GPIO_SYSCON tristate "GPIO based on SYSCON" depends on MFD_SYSCON && OF help Say yes here to support GPIO functionality though SYSCON driver. +config GPIO_TB10X + bool + select GENERIC_IRQ_CHIP + select OF_GPIO + config GPIO_TS5500 tristate "TS-5500 DIO blocks and compatibles" depends on TS5500 || COMPILE_TEST @@ -364,6 +455,24 @@ config GPIO_VF610 help Say yes here to support Vybrid vf610 GPIOs. +config GPIO_VR41XX + tristate "NEC VR4100 series General-purpose I/O Uint support" + depends on CPU_VR41XX + help + Say yes here to support the NEC VR4100 series General-purpose I/O Uint + +config GPIO_VX855 + tristate "VIA VX855/VX875 GPIO" + depends on PCI + select MFD_CORE + select MFD_VX855 + help + Support access to the VX855/VX875 GPIO lines through the gpio library. + + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. + config GPIO_XGENE bool "APM X-Gene GPIO controller support" depends on ARM64 && OF_GPIO @@ -387,13 +496,6 @@ config GPIO_XILINX help Say yes here to support the Xilinx FPGA GPIO device -config GPIO_ZYNQ - tristate "Xilinx Zynq GPIO support" - depends on ARCH_ZYNQ - select GPIOLIB_IRQCHIP - help - Say yes here to support Xilinx Zynq GPIO controller. - config GPIO_XTENSA bool "Xtensa GPIO32 support" depends on XTENSA @@ -403,135 +505,49 @@ config GPIO_XTENSA Say yes here to support the Xtensa internal GPIO32 IMPWIRE (input) and EXPSTATE (output) ports -config GPIO_VR41XX - tristate "NEC VR4100 series General-purpose I/O Uint support" - depends on CPU_VR41XX - help - Say yes here to support the NEC VR4100 series General-purpose I/O Uint - -config GPIO_SCH - tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" - depends on PCI && X86 - select MFD_CORE - select LPC_SCH - help - Say yes here to support GPIO interface on Intel Poulsbo SCH, - Intel Tunnel Creek processor, Intel Centerton processor or - Intel Quark X1000 SoC. - - The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are - powered by the core power rail and are turned off during sleep - modes (S3 and higher). The remaining four GPIOs are powered by - the Intel SCH suspend power supply. These GPIOs remain - active during S3. The suspend powered GPIOs can be used to wake the - system from the Suspend-to-RAM state. - - The Intel Tunnel Creek processor has 5 GPIOs powered by the - core power rail and 9 from suspend power supply. - - The Intel Centerton processor has a total of 30 GPIO pins. - Twenty-one are powered by the core power rail and 9 from the - suspend power supply. - - The Intel Quark X1000 SoC has 2 GPIOs powered by the core - power well and 6 from the suspend power well. - -config GPIO_ICH - tristate "Intel ICH GPIO" - depends on PCI && X86 - select MFD_CORE - select LPC_ICH - help - Say yes here to support the GPIO functionality of a number of Intel - ICH-based chipsets. Currently supported devices: ICH6, ICH7, ICH8 - ICH9, ICH10, Series 5/3400 (eg Ibex Peak), Series 6/C200 (eg - Cougar Point), NM10 (Tiger Point), and 3100 (Whitmore Lake). - - If unsure, say N. - -config GPIO_IOP - tristate "Intel IOP GPIO" - depends on ARM && (ARCH_IOP32X || ARCH_IOP33X) - help - Say yes here to support the GPIO functionality of a number of Intel - IOP32X or IOP33X. - - If unsure, say N. - -config GPIO_VX855 - tristate "VIA VX855/VX875 GPIO" - depends on PCI - select MFD_CORE - select MFD_VX855 - help - Support access to the VX855/VX875 GPIO lines through the gpio library. - - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - -config GPIO_GE_FPGA - bool "GE FPGA based GPIO" - depends on GE_FPGA - select GPIO_GENERIC +config GPIO_ZEVIO + bool "LSI ZEVIO SoC memory mapped GPIOs" + depends on ARM && OF_GPIO help - Support for common GPIO functionality provided on some GE Single Board - Computers. - - This driver provides basic support (configure as input or output, read - and write pin state) for GPIO implemented in a number of GE single - board computers. + Say yes here to support the GPIO controller in LSI ZEVIO SoCs. -config GPIO_LYNXPOINT - tristate "Intel Lynxpoint GPIO support" - depends on ACPI && X86 +config GPIO_ZYNQ + tristate "Xilinx Zynq GPIO support" + depends on ARCH_ZYNQ select GPIOLIB_IRQCHIP help - driver for GPIO functionality on Intel Lynxpoint PCH chipset - Requires ACPI device enumeration code to set up a platform device. - -config GPIO_GRGPIO - tristate "Aeroflex Gaisler GRGPIO support" - depends on OF - select GPIO_GENERIC - select IRQ_DOMAIN - help - Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB - VHDL IP core library. + Say yes here to support Xilinx Zynq GPIO controller. -config GPIO_TB10X - bool - select GENERIC_IRQ_CHIP - select OF_GPIO +endmenu -comment "I2C GPIO expanders:" +menu "I2C GPIO expanders" + depends on I2C -config GPIO_ARIZONA - tristate "Wolfson Microelectronics Arizona class devices" - depends on MFD_ARIZONA +config GPIO_ADP5588 + tristate "ADP5588 I2C GPIO expander" + depends on I2C help - Support for GPIOs on Wolfson Arizona class devices. + This option enables support for 18 GPIOs found + on Analog Devices ADP5588 GPIO Expanders. -config GPIO_CRYSTAL_COVE - tristate "GPIO support for Crystal Cove PMIC" - depends on INTEL_SOC_PMIC - select GPIOLIB_IRQCHIP +config GPIO_ADP5588_IRQ + bool "Interrupt controller support for ADP5588" + depends on GPIO_ADP5588=y help - Support for GPIO pins on Crystal Cove PMIC. - - Say Yes if you have a Intel SoC based tablet with Crystal Cove PMIC - inside. - - This driver can also be built as a module. If so, the module will be - called gpio-crystalcove. + Say yes here to enable the adp5588 to be used as an interrupt + controller. It requires the driver to be built in the kernel. -config GPIO_LP3943 - tristate "TI/National Semiconductor LP3943 GPIO expander" - depends on MFD_LP3943 +config GPIO_ADNP + tristate "Avionic Design N-bit GPIO expander" + depends on I2C && OF_GPIO + select GPIOLIB_IRQCHIP help - GPIO driver for LP3943 MFD. - LP3943 can be used as a GPIO expander which provides up to 16 GPIOs. - Open drain outputs are required for this usage. + This option enables support for N GPIOs found on Avionic Design + I2C GPIO expanders. The register space will be extended by powers + of two, so the controller will need to accommodate for that. For + example: if a controller provides 48 pins, 6 registers will be + enough to represent all pins, but the driver will assume a + register layout for 64 pins (8 registers). config GPIO_MAX7300 tristate "Maxim MAX7300 GPIO expander" @@ -543,7 +559,6 @@ config GPIO_MAX7300 config GPIO_MAX732X tristate "MAX7319, MAX7320-7327 I2C Port Expanders" depends on I2C - select IRQ_DOMAIN help Say yes here to support the MAX7319, MAX7320-7327 series of I2C Port Expanders. Each IO port on these chips has a fixed role of @@ -563,6 +578,7 @@ config GPIO_MAX732X config GPIO_MAX732X_IRQ bool "Interrupt controller support for MAX732x" depends on GPIO_MAX732X=y + select GPIOLIB_IRQCHIP help Say yes here to enable the max732x to be used as an interrupt controller. It requires the driver to be built in the kernel. @@ -604,6 +620,7 @@ config GPIO_PCA953X_IRQ config GPIO_PCF857X tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders" depends on I2C + select GPIOLIB_IRQCHIP select IRQ_DOMAIN help Say yes here to provide access to most "quasi-bidirectional" I2C @@ -626,15 +643,6 @@ config GPIO_PCF857X This driver provides an in-kernel interface to those GPIOs using platform-neutral GPIO calls. -config GPIO_RC5T583 - bool "RICOH RC5T583 GPIO" - depends on MFD_RC5T583 - help - Select this option to enable GPIO driver for the Ricoh RC5T583 - chip family. - This driver provides the support for driving/reading the gpio pins - of RC5T583 device through standard gpio library. - config GPIO_SX150X bool "Semtech SX150x I2C GPIO expander" depends on I2C=y @@ -647,6 +655,124 @@ config GPIO_SX150X 8 bits: sx1508q 16 bits: sx1509q +endmenu + +menu "MFD GPIO expanders" + +config GPIO_ADP5520 + tristate "GPIO Support for ADP5520 PMIC" + depends on PMIC_ADP5520 + help + This option enables support for on-chip GPIO found + on Analog Devices ADP5520 PMICs. + +config GPIO_ARIZONA + tristate "Wolfson Microelectronics Arizona class devices" + depends on MFD_ARIZONA + help + Support for GPIOs on Wolfson Arizona class devices. + +config GPIO_CRYSTAL_COVE + tristate "GPIO support for Crystal Cove PMIC" + depends on INTEL_SOC_PMIC + select GPIOLIB_IRQCHIP + help + Support for GPIO pins on Crystal Cove PMIC. + + Say Yes if you have a Intel SoC based tablet with Crystal Cove PMIC + inside. + + This driver can also be built as a module. If so, the module will be + called gpio-crystalcove. + +config GPIO_CS5535 + tristate "AMD CS5535/CS5536 GPIO support" + depends on MFD_CS5535 + help + The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that + can be used for quite a number of things. The CS5535/6 is found on + AMD Geode and Lemote Yeeloong devices. + + If unsure, say N. + +config GPIO_DA9052 + tristate "Dialog DA9052 GPIO" + depends on PMIC_DA9052 + help + Say yes here to enable the GPIO driver for the DA9052 chip. + +config GPIO_DA9055 + tristate "Dialog Semiconductor DA9055 GPIO" + depends on MFD_DA9055 + help + Say yes here to enable the GPIO driver for the DA9055 chip. + + The Dialog DA9055 PMIC chip has 3 GPIO pins that can be + be controller by this driver. + + If driver is built as a module it will be called gpio-da9055. + +config GPIO_DLN2 + tristate "Diolan DLN2 GPIO support" + depends on MFD_DLN2 + select GPIOLIB_IRQCHIP + + help + Select this option to enable GPIO driver for the Diolan DLN2 + board. + + This driver can also be built as a module. If so, the module + will be called gpio-dln2. + +config GPIO_JANZ_TTL + tristate "Janz VMOD-TTL Digital IO Module" + depends on MFD_JANZ_CMODIO + help + This enables support for the Janz VMOD-TTL Digital IO module. + This driver provides support for driving the pins in output + mode only. Input mode is not supported. + +config GPIO_KEMPLD + tristate "Kontron ETX / COMexpress GPIO" + depends on MFD_KEMPLD + help + This enables support for the PLD GPIO interface on some Kontron ETX + and COMexpress (ETXexpress) modules. + + This driver can also be built as a module. If so, the module will be + called gpio-kempld. + +config GPIO_LP3943 + tristate "TI/National Semiconductor LP3943 GPIO expander" + depends on MFD_LP3943 + help + GPIO driver for LP3943 MFD. + LP3943 can be used as a GPIO expander which provides up to 16 GPIOs. + Open drain outputs are required for this usage. + +config GPIO_MSIC + bool "Intel MSIC mixed signal gpio support" + depends on MFD_INTEL_MSIC + help + Enable support for GPIO on intel MSIC controllers found in + intel MID devices + +config GPIO_PALMAS + bool "TI PALMAS series PMICs GPIO" + depends on MFD_PALMAS + help + Select this option to enable GPIO driver for the TI PALMAS + series chip family. + +config GPIO_RC5T583 + bool "RICOH RC5T583 GPIO" + depends on MFD_RC5T583 + help + Select this option to enable GPIO driver for the Ricoh RC5T583 + chip family. + This driver provides the support for driving/reading the gpio pins + of RC5T583 device through standard gpio library. + config GPIO_STMPE bool "STMPE GPIOs" depends on MFD_STMPE @@ -656,16 +782,6 @@ config GPIO_STMPE This enables support for the GPIOs found on the STMPE I/O Expanders. -config GPIO_STP_XWAY - bool "XWAY STP GPIOs" - depends on SOC_XWAY - help - This enables support for the Serial To Parallel (STP) unit found on - XWAY SoC. The STP allows the SoC to drive a shift registers cascade, - that can be up to 24 bit. This peripheral is aimed at driving leds. - Some of the gpios/leds can be auto updated by the soc with dsl and - phy status. - config GPIO_TC3589X bool "TC3589X GPIOs" depends on MFD_TC3589X @@ -675,6 +791,26 @@ config GPIO_TC3589X This enables support for the GPIOs found on the TC3589X I/O Expander. +config GPIO_TIMBERDALE + bool "Support for timberdale GPIO IP" + depends on MFD_TIMBERDALE + ---help--- + Add support for the GPIO IP in the timberdale FPGA. + +config GPIO_TPS6586X + bool "TPS6586X GPIO" + depends on MFD_TPS6586X + help + Select this option to enable GPIO driver for the TPS6586X + chip family. + +config GPIO_TPS65910 + bool "TPS65910 GPIO" + depends on MFD_TPS65910 + help + Select this option to enable GPIO driver for the TPS65910 + chip family. + config GPIO_TPS65912 tristate "TI TPS65912 GPIO" depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI) @@ -695,6 +831,13 @@ config GPIO_TWL6040 Say yes here to access the GPO signals of twl6040 audio chip from Texas Instruments. +config GPIO_UCB1400 + tristate "Philips UCB1400 GPIO" + depends on UCB1400_CORE + help + This enables support for the Philips UCB1400 GPIO pins. + The UCB1400 is an AC97 audio codec. + config GPIO_WM831X tristate "WM831x GPIOs" depends on MFD_WM831X @@ -716,50 +859,22 @@ config GPIO_WM8994 Say yes here to access the GPIO signals of WM8994 audio hub CODECs from Wolfson Microelectronics. -config GPIO_ADP5520 - tristate "GPIO Support for ADP5520 PMIC" - depends on PMIC_ADP5520 - help - This option enables support for on-chip GPIO found - on Analog Devices ADP5520 PMICs. +endmenu -config GPIO_ADP5588 - tristate "ADP5588 I2C GPIO expander" - depends on I2C - help - This option enables support for 18 GPIOs found - on Analog Devices ADP5588 GPIO Expanders. - -config GPIO_ADP5588_IRQ - bool "Interrupt controller support for ADP5588" - depends on GPIO_ADP5588=y - help - Say yes here to enable the adp5588 to be used as an interrupt - controller. It requires the driver to be built in the kernel. +menu "PCI GPIO expanders" + depends on PCI -config GPIO_ADNP - tristate "Avionic Design N-bit GPIO expander" - depends on I2C && OF_GPIO - select GPIOLIB_IRQCHIP +config GPIO_AMD8111 + tristate "AMD 8111 GPIO driver" + depends on PCI help - This option enables support for N GPIOs found on Avionic Design - I2C GPIO expanders. The register space will be extended by powers - of two, so the controller will need to accommodate for that. For - example: if a controller provides 48 pins, 6 registers will be - enough to represent all pins, but the driver will assume a - register layout for 64 pins (8 registers). - -comment "PCI GPIO expanders:" + The AMD 8111 south bridge contains 32 GPIO pins which can be used. -config GPIO_CS5535 - tristate "AMD CS5535/CS5536 GPIO support" - depends on MFD_CS5535 - help - The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that - can be used for quite a number of things. The CS5535/6 is found on - AMD Geode and Lemote Yeeloong devices. + Note, that usually system firmware/ACPI handles GPIO pins on their + own and users might easily break their systems with uncarefull usage + of this driver! - If unsure, say N. + If unsure, say N config GPIO_BT8XX tristate "BT8XX GPIO abuser" @@ -777,18 +892,6 @@ config GPIO_BT8XX If unsure, say N. -config GPIO_AMD8111 - tristate "AMD 8111 GPIO driver" - depends on PCI - help - The AMD 8111 south bridge contains 32 GPIO pins which can be used. - - Note, that usually system firmware/ACPI handles GPIO pins on their - own and users might easily break their systems with uncarefull usage - of this driver! - - If unsure, say N - config GPIO_INTEL_MID bool "Intel Mid GPIO support" depends on PCI && X86 @@ -796,6 +899,16 @@ config GPIO_INTEL_MID help Say Y here to support Intel Mid GPIO. +config GPIO_ML_IOH + tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" + depends on PCI + select GENERIC_IRQ_CHIP + help + ML7213 is companion chip for Intel Atom E6xx series. + This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output + Hub) which is for IVI(In-Vehicle Infotainment) use. + This driver can access the IOH's GPIO device. + config GPIO_PCH tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO" depends on PCI && (X86_32 || COMPILE_TEST) @@ -812,15 +925,14 @@ config GPIO_PCH ML7223/ML7831 is companion chip for Intel Atom E6xx series. ML7223/ML7831 is completely compatible for Intel EG20T PCH. -config GPIO_ML_IOH - tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" +config GPIO_RDC321X + tristate "RDC R-321x GPIO support" depends on PCI - select GENERIC_IRQ_CHIP + select MFD_CORE + select MFD_RDC321X help - ML7213 is companion chip for Intel Atom E6xx series. - This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output - Hub) which is for IVI(In-Vehicle Infotainment) use. - This driver can access the IOH's GPIO device. + Support for the RDC R321x SoC GPIOs over southbridge + PCI configuration space. config GPIO_SODAVILLE bool "Intel Sodaville GPIO support" @@ -830,22 +942,18 @@ config GPIO_SODAVILLE help Say Y here to support Intel Sodaville GPIO. -config GPIO_TIMBERDALE - bool "Support for timberdale GPIO IP" - depends on MFD_TIMBERDALE - ---help--- - Add support for the GPIO IP in the timberdale FPGA. +endmenu -config GPIO_RDC321X - tristate "RDC R-321x GPIO support" - depends on PCI - select MFD_CORE - select MFD_RDC321X - help - Support for the RDC R321x SoC GPIOs over southbridge - PCI configuration space. +menu "SPI GPIO expanders" + depends on SPI_MASTER -comment "SPI GPIO expanders:" +config GPIO_74X164 + tristate "74x164 serial-in/parallel-out 8-bits shift register" + depends on SPI_MASTER && OF + help + Driver for 74x164 compatible serial-in/parallel-out 8-outputs + shift registers. This driver can be used to provide access + to more gpio outputs. config GPIO_MAX7301 tristate "Maxim MAX7301 GPIO expander" @@ -870,80 +978,10 @@ config GPIO_MC33880 SPI driver for Freescale MC33880 high-side/low-side switch. This provides GPIO interface supporting inputs and outputs. -config GPIO_74X164 - tristate "74x164 serial-in/parallel-out 8-bits shift register" - depends on SPI_MASTER && OF - help - Driver for 74x164 compatible serial-in/parallel-out 8-outputs - shift registers. This driver can be used to provide access - to more gpio outputs. - -comment "AC97 GPIO expanders:" - -config GPIO_UCB1400 - tristate "Philips UCB1400 GPIO" - depends on UCB1400_CORE - help - This enables support for the Philips UCB1400 GPIO pins. - The UCB1400 is an AC97 audio codec. - -comment "LPC GPIO expanders:" - -config GPIO_KEMPLD - tristate "Kontron ETX / COMexpress GPIO" - depends on MFD_KEMPLD - help - This enables support for the PLD GPIO interface on some Kontron ETX - and COMexpress (ETXexpress) modules. - - This driver can also be built as a module. If so, the module will be - called gpio-kempld. - -comment "MODULbus GPIO expanders:" - -config GPIO_JANZ_TTL - tristate "Janz VMOD-TTL Digital IO Module" - depends on MFD_JANZ_CMODIO - help - This enables support for the Janz VMOD-TTL Digital IO module. - This driver provides support for driving the pins in output - mode only. Input mode is not supported. - -config GPIO_PALMAS - bool "TI PALMAS series PMICs GPIO" - depends on MFD_PALMAS - help - Select this option to enable GPIO driver for the TI PALMAS - series chip family. - -config GPIO_TPS6586X - bool "TPS6586X GPIO" - depends on MFD_TPS6586X - help - Select this option to enable GPIO driver for the TPS6586X - chip family. +endmenu -config GPIO_TPS65910 - bool "TPS65910 GPIO" - depends on MFD_TPS65910 - help - Select this option to enable GPIO driver for the TPS65910 - chip family. - -config GPIO_MSIC - bool "Intel MSIC mixed signal gpio support" - depends on MFD_INTEL_MSIC - help - Enable support for GPIO on intel MSIC controllers found in - intel MID devices - -config GPIO_BCM_KONA - bool "Broadcom Kona GPIO" - depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) - help - Turn on GPIO support for Broadcom "Kona" chips. - -comment "USB GPIO expanders:" +menu "USB GPIO expanders" + depends on USB config GPIO_VIPERBOARD tristate "Viperboard GPIO a & b support" @@ -956,16 +994,6 @@ config GPIO_VIPERBOARD River Tech's viperboard.h for detailed meaning of the module parameters. -config GPIO_DLN2 - tristate "Diolan DLN2 GPIO support" - depends on MFD_DLN2 - select GPIOLIB_IRQCHIP - - help - Select this option to enable GPIO driver for the Diolan DLN2 - board. - - This driver can also be built as a module. If so, the module - will be called gpio-dln2. +endmenu endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index bdda6a9..07b816b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o +obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o @@ -41,6 +42,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o +obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 13dbd3d..07ba823 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -35,6 +35,20 @@ static int devm_gpiod_match(struct device *dev, void *res, void *data) return *this == *gpio; } +static void devm_gpiod_release_array(struct device *dev, void *res) +{ + struct gpio_descs **descs = res; + + gpiod_put_array(*descs); +} + +static int devm_gpiod_match_array(struct device *dev, void *res, void *data) +{ + struct gpio_descs **this = res, **gpios = data; + + return *this == *gpios; +} + /** * devm_gpiod_get - Resource-managed gpiod_get() * @dev: GPIO consumer @@ -111,23 +125,39 @@ EXPORT_SYMBOL(__devm_gpiod_get_index); /** * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node * @dev: GPIO consumer + * @con_id: function within the GPIO consumer * @child: firmware node (child of @dev) * * GPIO descriptors returned from this function are automatically disposed on * driver detach. */ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, + const char *con_id, struct fwnode_handle *child) { + static const char * const suffixes[] = { "gpios", "gpio" }; + char prop_name[32]; /* 32 is max size of property name */ struct gpio_desc **dr; struct gpio_desc *desc; + unsigned int i; dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), GFP_KERNEL); if (!dr) return ERR_PTR(-ENOMEM); - desc = fwnode_get_named_gpiod(child, "gpios"); + for (i = 0; i < ARRAY_SIZE(suffixes); i++) { + if (con_id) + snprintf(prop_name, sizeof(prop_name), "%s-%s", + con_id, suffixes[i]); + else + snprintf(prop_name, sizeof(prop_name), "%s", + suffixes[i]); + + desc = fwnode_get_named_gpiod(child, prop_name); + if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER)) + break; + } if (IS_ERR(desc)) { devres_free(dr); return desc; @@ -170,6 +200,66 @@ struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *de EXPORT_SYMBOL(__devm_gpiod_get_index_optional); /** + * devm_gpiod_get_array - Resource-managed gpiod_get_array() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * Managed gpiod_get_array(). GPIO descriptors returned from this function are + * automatically disposed on driver detach. See gpiod_get_array() for detailed + * information about behavior and return values. + */ +struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_descs **dr; + struct gpio_descs *descs; + + dr = devres_alloc(devm_gpiod_release_array, + sizeof(struct gpio_descs *), GFP_KERNEL); + if (!dr) + return ERR_PTR(-ENOMEM); + + descs = gpiod_get_array(dev, con_id, flags); + if (IS_ERR(descs)) { + devres_free(dr); + return descs; + } + + *dr = descs; + devres_add(dev, dr); + + return descs; +} +EXPORT_SYMBOL(devm_gpiod_get_array); + +/** + * devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * Managed gpiod_get_array_optional(). GPIO descriptors returned from this + * function are automatically disposed on driver detach. + * See gpiod_get_array_optional() for detailed information about behavior and + * return values. + */ +struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_descs *descs; + + descs = devm_gpiod_get_array(dev, con_id, flags); + if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT)) + return NULL; + + return descs; +} +EXPORT_SYMBOL(devm_gpiod_get_array_optional); + +/** * devm_gpiod_put - Resource-managed gpiod_put() * @desc: GPIO descriptor to dispose of * @@ -184,6 +274,21 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) } EXPORT_SYMBOL(devm_gpiod_put); +/** + * devm_gpiod_put_array - Resource-managed gpiod_put_array() + * @descs: GPIO descriptor array to dispose of + * + * Dispose of an array of GPIO descriptors obtained with devm_gpiod_get_array(). + * Normally this function will not be called as the GPIOs will be disposed of + * by the resource management code. + */ +void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs) +{ + WARN_ON(devres_release(dev, devm_gpiod_release_array, + devm_gpiod_match_array, &descs)); +} +EXPORT_SYMBOL(devm_gpiod_put_array); + diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 3beed6e..d3fe6a6 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -367,7 +367,7 @@ static int adp5588_gpio_probe(struct i2c_client *client, struct gpio_chip *gc; int ret, i, revid; - if (pdata == NULL) { + if (!pdata) { dev_err(&client->dev, "missing platform data\n"); return -ENODEV; } @@ -378,8 +378,8 @@ static int adp5588_gpio_probe(struct i2c_client *client, return -EIO; } - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) + dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) return -ENOMEM; dev->client = client; @@ -446,7 +446,6 @@ static int adp5588_gpio_probe(struct i2c_client *client, err_irq: adp5588_irq_teardown(dev); err: - kfree(dev); return ret; } @@ -472,7 +471,6 @@ static int adp5588_gpio_remove(struct i2c_client *client) gpiochip_remove(&dev->gpio_chip); - kfree(dev); return 0; } diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c new file mode 100644 index 0000000..449fb46 --- /dev/null +++ b/drivers/gpio/gpio-altera.c @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2013 Altera Corporation + * Based on gpio-mpc8xxx.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/io.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> + +#define ALTERA_GPIO_MAX_NGPIO 32 +#define ALTERA_GPIO_DATA 0x0 +#define ALTERA_GPIO_DIR 0x4 +#define ALTERA_GPIO_IRQ_MASK 0x8 +#define ALTERA_GPIO_EDGE_CAP 0xc + +/** +* struct altera_gpio_chip +* @mmchip : memory mapped chip structure. +* @gpio_lock : synchronization lock so that new irq/set/get requests + will be blocked until the current one completes. +* @interrupt_trigger : specifies the hardware configured IRQ trigger type + (rising, falling, both, high) +* @mapped_irq : kernel mapped irq number. +*/ +struct altera_gpio_chip { + struct of_mm_gpio_chip mmchip; + spinlock_t gpio_lock; + int interrupt_trigger; + int mapped_irq; +}; + +static void altera_gpio_irq_unmask(struct irq_data *d) +{ + struct altera_gpio_chip *altera_gc; + struct of_mm_gpio_chip *mm_gc; + unsigned long flags; + u32 intmask; + + altera_gc = irq_data_get_irq_chip_data(d); + mm_gc = &altera_gc->mmchip; + + spin_lock_irqsave(&altera_gc->gpio_lock, flags); + intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); + /* Set ALTERA_GPIO_IRQ_MASK bit to unmask */ + intmask |= BIT(irqd_to_hwirq(d)); + writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK); + spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); +} + +static void altera_gpio_irq_mask(struct irq_data *d) +{ + struct altera_gpio_chip *altera_gc; + struct of_mm_gpio_chip *mm_gc; + unsigned long flags; + u32 intmask; + + altera_gc = irq_data_get_irq_chip_data(d); + mm_gc = &altera_gc->mmchip; + + spin_lock_irqsave(&altera_gc->gpio_lock, flags); + intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); + /* Clear ALTERA_GPIO_IRQ_MASK bit to mask */ + intmask &= ~BIT(irqd_to_hwirq(d)); + writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK); + spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); +} + +/** + * This controller's IRQ type is synthesized in hardware, so this function + * just checks if the requested set_type matches the synthesized IRQ type + */ +static int altera_gpio_irq_set_type(struct irq_data *d, + unsigned int type) +{ + struct altera_gpio_chip *altera_gc; + + altera_gc = irq_data_get_irq_chip_data(d); + + if (type == IRQ_TYPE_NONE) + return 0; + if (type == IRQ_TYPE_LEVEL_HIGH && + altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH) + return 0; + if (type == IRQ_TYPE_EDGE_RISING && + altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_RISING) + return 0; + if (type == IRQ_TYPE_EDGE_FALLING && + altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_FALLING) + return 0; + if (type == IRQ_TYPE_EDGE_BOTH && + altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_BOTH) + return 0; + + return -EINVAL; +} + +static unsigned int altera_gpio_irq_startup(struct irq_data *d) { + altera_gpio_irq_unmask(d); + + return 0; +} + +static struct irq_chip altera_irq_chip = { + .name = "altera-gpio", + .irq_mask = altera_gpio_irq_mask, + .irq_unmask = altera_gpio_irq_unmask, + .irq_set_type = altera_gpio_irq_set_type, + .irq_startup = altera_gpio_irq_startup, + .irq_shutdown = altera_gpio_irq_mask, +}; + +static int altera_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + struct of_mm_gpio_chip *mm_gc; + + mm_gc = to_of_mm_gpio_chip(gc); + + return !!(readl(mm_gc->regs + ALTERA_GPIO_DATA) & BIT(offset)); +} + +static void altera_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +{ + struct of_mm_gpio_chip *mm_gc; + struct altera_gpio_chip *chip; + unsigned long flags; + unsigned int data_reg; + + mm_gc = to_of_mm_gpio_chip(gc); + chip = container_of(mm_gc, struct altera_gpio_chip, mmchip); + + spin_lock_irqsave(&chip->gpio_lock, flags); + data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA); + if (value) + data_reg |= BIT(offset); + else + data_reg &= ~BIT(offset); + writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA); + spin_unlock_irqrestore(&chip->gpio_lock, flags); +} + +static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct of_mm_gpio_chip *mm_gc; + struct altera_gpio_chip *chip; + unsigned long flags; + unsigned int gpio_ddr; + + mm_gc = to_of_mm_gpio_chip(gc); + chip = container_of(mm_gc, struct altera_gpio_chip, mmchip); + + spin_lock_irqsave(&chip->gpio_lock, flags); + /* Set pin as input, assumes software controlled IP */ + gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR); + gpio_ddr &= ~BIT(offset); + writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR); + spin_unlock_irqrestore(&chip->gpio_lock, flags); + + return 0; +} + +static int altera_gpio_direction_output(struct gpio_chip *gc, + unsigned offset, int value) +{ + struct of_mm_gpio_chip *mm_gc; + struct altera_gpio_chip *chip; + unsigned long flags; + unsigned int data_reg, gpio_ddr; + + mm_gc = to_of_mm_gpio_chip(gc); + chip = container_of(mm_gc, struct altera_gpio_chip, mmchip); + + spin_lock_irqsave(&chip->gpio_lock, flags); + /* Sets the GPIO value */ + data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA); + if (value) + data_reg |= BIT(offset); + else + data_reg &= ~BIT(offset); + writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA); + + /* Set pin as output, assumes software controlled IP */ + gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR); + gpio_ddr |= BIT(offset); + writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR); + spin_unlock_irqrestore(&chip->gpio_lock, flags); + + return 0; +} + +static void altera_gpio_irq_edge_handler(unsigned int irq, + struct irq_desc *desc) +{ + struct altera_gpio_chip *altera_gc; + struct irq_chip *chip; + struct of_mm_gpio_chip *mm_gc; + struct irq_domain *irqdomain; + unsigned long status; + int i; + + altera_gc = irq_desc_get_handler_data(desc); + chip = irq_desc_get_chip(desc); + mm_gc = &altera_gc->mmchip; + irqdomain = altera_gc->mmchip.gc.irqdomain; + + chained_irq_enter(chip, desc); + + while ((status = + (readl(mm_gc->regs + ALTERA_GPIO_EDGE_CAP) & + readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK)))) { + writel(status, mm_gc->regs + ALTERA_GPIO_EDGE_CAP); + for_each_set_bit(i, &status, mm_gc->gc.ngpio) { + generic_handle_irq(irq_find_mapping(irqdomain, i)); + } + } + + chained_irq_exit(chip, desc); +} + + +static void altera_gpio_irq_leveL_high_handler(unsigned int irq, + struct irq_desc *desc) +{ + struct altera_gpio_chip *altera_gc; + struct irq_chip *chip; + struct of_mm_gpio_chip *mm_gc; + struct irq_domain *irqdomain; + unsigned long status; + int i; + + altera_gc = irq_desc_get_handler_data(desc); + chip = irq_desc_get_chip(desc); + mm_gc = &altera_gc->mmchip; + irqdomain = altera_gc->mmchip.gc.irqdomain; + + chained_irq_enter(chip, desc); + + status = readl(mm_gc->regs + ALTERA_GPIO_DATA); + status &= readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); + + for_each_set_bit(i, &status, mm_gc->gc.ngpio) { + generic_handle_irq(irq_find_mapping(irqdomain, i)); + } + chained_irq_exit(chip, desc); +} + +static int altera_gpio_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + int reg, ret; + struct altera_gpio_chip *altera_gc; + + altera_gc = devm_kzalloc(&pdev->dev, sizeof(*altera_gc), GFP_KERNEL); + if (!altera_gc) + return -ENOMEM; + + spin_lock_init(&altera_gc->gpio_lock); + + if (of_property_read_u32(node, "altr,ngpio", ®)) + /* By default assume maximum ngpio */ + altera_gc->mmchip.gc.ngpio = ALTERA_GPIO_MAX_NGPIO; + else + altera_gc->mmchip.gc.ngpio = reg; + + if (altera_gc->mmchip.gc.ngpio > ALTERA_GPIO_MAX_NGPIO) { + dev_warn(&pdev->dev, + "ngpio is greater than %d, defaulting to %d\n", + ALTERA_GPIO_MAX_NGPIO, ALTERA_GPIO_MAX_NGPIO); + altera_gc->mmchip.gc.ngpio = ALTERA_GPIO_MAX_NGPIO; + } + + altera_gc->mmchip.gc.direction_input = altera_gpio_direction_input; + altera_gc->mmchip.gc.direction_output = altera_gpio_direction_output; + altera_gc->mmchip.gc.get = altera_gpio_get; + altera_gc->mmchip.gc.set = altera_gpio_set; + altera_gc->mmchip.gc.owner = THIS_MODULE; + altera_gc->mmchip.gc.dev = &pdev->dev; + + ret = of_mm_gpiochip_add(node, &altera_gc->mmchip); + if (ret) { + dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n"); + return ret; + } + + platform_set_drvdata(pdev, altera_gc); + + altera_gc->mapped_irq = platform_get_irq(pdev, 0); + + if (altera_gc->mapped_irq < 0) + goto skip_irq; + + if (of_property_read_u32(node, "altr,interrupt-type", ®)) { + ret = -EINVAL; + dev_err(&pdev->dev, + "altr,interrupt-type value not set in device tree\n"); + goto teardown; + } + altera_gc->interrupt_trigger = reg; + + ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0, + handle_simple_irq, IRQ_TYPE_NONE); + + if (ret) { + dev_info(&pdev->dev, "could not add irqchip\n"); + return ret; + } + + gpiochip_set_chained_irqchip(&altera_gc->mmchip.gc, + &altera_irq_chip, + altera_gc->mapped_irq, + altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH ? + altera_gpio_irq_leveL_high_handler : + altera_gpio_irq_edge_handler); + +skip_irq: + return 0; +teardown: + pr_err("%s: registration failed with status %d\n", + node->full_name, ret); + + return ret; +} + +static int altera_gpio_remove(struct platform_device *pdev) +{ + struct altera_gpio_chip *altera_gc = platform_get_drvdata(pdev); + + gpiochip_remove(&altera_gc->mmchip.gc); + + return -EIO; +} + +static const struct of_device_id altera_gpio_of_match[] = { + { .compatible = "altr,pio-1.0", }, + {}, +}; +MODULE_DEVICE_TABLE(of, altera_gpio_of_match); + +static struct platform_driver altera_gpio_driver = { + .driver = { + .name = "altera_gpio", + .of_match_table = of_match_ptr(altera_gpio_of_match), + }, + .probe = altera_gpio_probe, + .remove = altera_gpio_remove, +}; + +static int __init altera_gpio_init(void) +{ + return platform_driver_register(&altera_gpio_driver); +} +subsys_initcall(altera_gpio_init); + +static void __exit altera_gpio_exit(void) +{ + platform_driver_unregister(&altera_gpio_driver); +} +module_exit(altera_gpio_exit); + +MODULE_AUTHOR("Tien Hock Loh <thloh@altera.com>"); +MODULE_DESCRIPTION("Altera GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 9665d0a..052fbc8 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -103,7 +103,7 @@ static int arizona_gpio_probe(struct platform_device *pdev) arizona_gpio = devm_kzalloc(&pdev->dev, sizeof(*arizona_gpio), GFP_KERNEL); - if (arizona_gpio == NULL) + if (!arizona_gpio) return -ENOMEM; arizona_gpio->arizona = arizona; @@ -156,7 +156,6 @@ static int arizona_gpio_remove(struct platform_device *pdev) static struct platform_driver arizona_gpio_driver = { .driver.name = "arizona-gpio", - .driver.owner = THIS_MODULE, .probe = arizona_gpio_probe, .remove = arizona_gpio_remove, }; diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index 3d9e08f..91a7ffe 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -24,7 +24,7 @@ #include <linux/mfd/intel_soc_pmic.h> #define CRYSTALCOVE_GPIO_NUM 16 -#define CRYSTALCOVE_VGPIO_NUM 94 +#define CRYSTALCOVE_VGPIO_NUM 95 #define UPDATE_IRQ_TYPE BIT(0) #define UPDATE_IRQ_MASK BIT(1) @@ -39,6 +39,7 @@ #define GPIO0P0CTLI 0x33 #define GPIO1P0CTLO 0x3b #define GPIO1P0CTLI 0x43 +#define GPIOPANELCTL 0x52 #define CTLI_INTCNT_DIS (0) #define CTLI_INTCNT_NE (1 << 1) @@ -93,6 +94,10 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type) { int reg; + if (gpio == 94) { + return GPIOPANELCTL; + } + if (reg_type == CTRL_IN) { if (gpio < 8) reg = GPIO0P0CTLI; diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 389a4d2..2e9578e 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -212,7 +212,7 @@ static int da9052_gpio_probe(struct platform_device *pdev) int ret; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (gpio == NULL) + if (!gpio) return -ENOMEM; gpio->da9052 = dev_get_drvdata(pdev->dev.parent); diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c index b8d7570..7227e6e 100644 --- a/drivers/gpio/gpio-da9055.c +++ b/drivers/gpio/gpio-da9055.c @@ -146,7 +146,7 @@ static int da9055_gpio_probe(struct platform_device *pdev) int ret; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (gpio == NULL) + if (!gpio) return -ENOMEM; gpio->da9055 = dev_get_drvdata(pdev->dev.parent); diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index 1be291a..dbda843 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -1,5 +1,5 @@ /* - * GPIO driver for Fintek Super-I/O F71882 and F71889 + * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882 and F71889 * * Copyright (C) 2010-2013 LaCie * @@ -32,12 +32,16 @@ #define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */ #define SIO_FINTEK_ID 0x1934 /* Manufacturer ID */ +#define SIO_F71869_ID 0x0814 /* F71869 chipset ID */ +#define SIO_F71869A_ID 0x1007 /* F71869A chipset ID */ #define SIO_F71882_ID 0x0541 /* F71882 chipset ID */ #define SIO_F71889_ID 0x0909 /* F71889 chipset ID */ -enum chips { f71882fg, f71889f }; +enum chips { f71869, f71869a, f71882fg, f71889f }; static const char * const f7188x_names[] = { + "f71869", + "f71869a", "f71882fg", "f71889f", }; @@ -146,6 +150,27 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value); /* Output mode register (0:open drain 1:push-pull). */ #define gpio_out_mode(base) (base + 3) +static struct f7188x_gpio_bank f71869_gpio_bank[] = { + F7188X_GPIO_BANK(0, 6, 0xF0), + F7188X_GPIO_BANK(10, 8, 0xE0), + F7188X_GPIO_BANK(20, 8, 0xD0), + F7188X_GPIO_BANK(30, 8, 0xC0), + F7188X_GPIO_BANK(40, 8, 0xB0), + F7188X_GPIO_BANK(50, 5, 0xA0), + F7188X_GPIO_BANK(60, 6, 0x90), +}; + +static struct f7188x_gpio_bank f71869a_gpio_bank[] = { + F7188X_GPIO_BANK(0, 6, 0xF0), + F7188X_GPIO_BANK(10, 8, 0xE0), + F7188X_GPIO_BANK(20, 8, 0xD0), + F7188X_GPIO_BANK(30, 8, 0xC0), + F7188X_GPIO_BANK(40, 8, 0xB0), + F7188X_GPIO_BANK(50, 5, 0xA0), + F7188X_GPIO_BANK(60, 8, 0x90), + F7188X_GPIO_BANK(70, 8, 0x80), +}; + static struct f7188x_gpio_bank f71882_gpio_bank[] = { F7188X_GPIO_BANK(0 , 8, 0xF0), F7188X_GPIO_BANK(10, 8, 0xE0), @@ -281,6 +306,14 @@ static int f7188x_gpio_probe(struct platform_device *pdev) return -ENOMEM; switch (sio->type) { + case f71869: + data->nr_bank = ARRAY_SIZE(f71869_gpio_bank); + data->bank = f71869_gpio_bank; + break; + case f71869a: + data->nr_bank = ARRAY_SIZE(f71869a_gpio_bank); + data->bank = f71869a_gpio_bank; + break; case f71882fg: data->nr_bank = ARRAY_SIZE(f71882_gpio_bank); data->bank = f71882_gpio_bank; @@ -354,6 +387,12 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio) devid = superio_inw(addr, SIO_DEVID); switch (devid) { + case SIO_F71869_ID: + sio->type = f71869; + break; + case SIO_F71869A_ID: + sio->type = f71869a; + break; case SIO_F71882_ID: sio->type = f71882fg; break; @@ -410,7 +449,7 @@ err: } /* - * Try to match a supported Fintech device by reading the (hard-wired) + * Try to match a supported Fintek device by reading the (hard-wired) * configuration I/O ports. If available, then register both the platform * device and driver to support the GPIOs. */ @@ -450,6 +489,6 @@ static void __exit f7188x_gpio_exit(void) } module_exit(f7188x_gpio_exit); -MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71882FG and F71889F"); +MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG and F71889F"); MODULE_AUTHOR("Simon Guinot <simon.guinot@sequanux.org>"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 7818cd1..4ba7ed5 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -173,6 +173,11 @@ static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) return !!(ichx_priv.use_gpio & (1 << (nr / 32))); } +static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr) +{ + return ichx_read_bit(GPIO_IO_SEL, nr) ? GPIOF_DIR_IN : GPIOF_DIR_OUT; +} + static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) { /* @@ -286,6 +291,7 @@ static void ichx_gpiolib_setup(struct gpio_chip *chip) ichx_priv.desc->get : ichx_gpio_get; chip->set = ichx_gpio_set; + chip->get_direction = ichx_gpio_get_direction; chip->direction_input = ichx_gpio_direction_input; chip->direction_output = ichx_gpio_direction_output; chip->base = modparam_gpiobase; diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index 443518f..6b8115f 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -156,7 +156,7 @@ static int kempld_gpio_probe(struct platform_device *pdev) } gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL); - if (gpio == NULL) + if (!gpio) return -ENOMEM; gpio->pld = pld; diff --git a/drivers/gpio/gpio-loongson.c b/drivers/gpio/gpio-loongson.c new file mode 100644 index 0000000..ccc65a1 --- /dev/null +++ b/drivers/gpio/gpio-loongson.c @@ -0,0 +1,115 @@ +/* + * Loongson-2F/3A/3B GPIO Support + * + * Copyright (c) 2008 Richard Liu, STMicroelectronics <richard.liu@st.com> + * Copyright (c) 2008-2010 Arnaud Patard <apatard@mandriva.com> + * Copyright (c) 2013 Hongbing Hu <huhb@lemote.com> + * Copyright (c) 2014 Huacai Chen <chenhc@lemote.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/err.h> +#include <asm/types.h> +#include <loongson.h> +#include <linux/gpio.h> + +#define STLS2F_N_GPIO 4 +#define STLS3A_N_GPIO 16 + +#ifdef CONFIG_CPU_LOONGSON3 +#define LOONGSON_N_GPIO STLS3A_N_GPIO +#else +#define LOONGSON_N_GPIO STLS2F_N_GPIO +#endif + +#define LOONGSON_GPIO_IN_OFFSET 16 + +static DEFINE_SPINLOCK(gpio_lock); + +static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + u32 temp; + u32 mask; + + spin_lock(&gpio_lock); + mask = 1 << gpio; + temp = LOONGSON_GPIOIE; + temp |= mask; + LOONGSON_GPIOIE = temp; + spin_unlock(&gpio_lock); + + return 0; +} + +static int loongson_gpio_direction_output(struct gpio_chip *chip, + unsigned gpio, int level) +{ + u32 temp; + u32 mask; + + gpio_set_value(gpio, level); + spin_lock(&gpio_lock); + mask = 1 << gpio; + temp = LOONGSON_GPIOIE; + temp &= (~mask); + LOONGSON_GPIOIE = temp; + spin_unlock(&gpio_lock); + + return 0; +} + +static int loongson_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + u32 val; + u32 mask; + + mask = 1 << (gpio + LOONGSON_GPIO_IN_OFFSET); + spin_lock(&gpio_lock); + val = LOONGSON_GPIODATA; + spin_unlock(&gpio_lock); + + return (val & mask) != 0; +} + +static void loongson_gpio_set_value(struct gpio_chip *chip, + unsigned gpio, int value) +{ + u32 val; + u32 mask; + + mask = 1 << gpio; + + spin_lock(&gpio_lock); + val = LOONGSON_GPIODATA; + if (value) + val |= mask; + else + val &= (~mask); + LOONGSON_GPIODATA = val; + spin_unlock(&gpio_lock); +} + +static struct gpio_chip loongson_chip = { + .label = "Loongson-gpio-chip", + .direction_input = loongson_gpio_direction_input, + .get = loongson_gpio_get_value, + .direction_output = loongson_gpio_direction_output, + .set = loongson_gpio_set_value, + .base = 0, + .ngpio = LOONGSON_N_GPIO, + .can_sleep = false, +}; + +static int __init loongson_gpio_setup(void) +{ + return gpiochip_add(&loongson_chip); +} +postcore_initcall(loongson_gpio_setup); diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c index 40ab6df..0cc2c27 100644 --- a/drivers/gpio/gpio-max7300.c +++ b/drivers/gpio/gpio-max7300.c @@ -35,7 +35,6 @@ static int max7300_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max7301 *ts; - int ret; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -49,8 +48,7 @@ static int max7300_probe(struct i2c_client *client, ts->write = max7300_i2c_write; ts->dev = &client->dev; - ret = __max730x_probe(ts); - return ret; + return __max730x_probe(ts); } static int max7300_remove(struct i2c_client *client) diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index a095b23..0fa4543c 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -4,6 +4,7 @@ * Copyright (C) 2007 Marvell International Ltd. * Copyright (C) 2008 Jack Ren <jack.ren@marvell.com> * Copyright (C) 2008 Eric Miao <eric.miao@marvell.com> + * Copyright (C) 2015 Linus Walleij <linus.walleij@linaro.org> * * Derived from drivers/gpio/pca953x.c * @@ -16,10 +17,8 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/irqdomain.h> #include <linux/i2c.h> #include <linux/i2c/max732x.h> #include <linux/of.h> @@ -150,9 +149,7 @@ struct max732x_chip { uint8_t reg_out[2]; #ifdef CONFIG_GPIO_MAX732X_IRQ - struct irq_domain *irq_domain; struct mutex irq_lock; - int irq_base; uint8_t irq_mask; uint8_t irq_mask_cur; uint8_t irq_trig_raise; @@ -356,35 +353,26 @@ static void max732x_irq_update_mask(struct max732x_chip *chip) mutex_unlock(&chip->lock); } -static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off) -{ - struct max732x_chip *chip = to_max732x(gc); - - if (chip->irq_domain) { - return irq_create_mapping(chip->irq_domain, - chip->irq_base + off); - } else { - return -ENXIO; - } -} - static void max732x_irq_mask(struct irq_data *d) { - struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max732x_chip *chip = to_max732x(gc); chip->irq_mask_cur &= ~(1 << d->hwirq); } static void max732x_irq_unmask(struct irq_data *d) { - struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max732x_chip *chip = to_max732x(gc); chip->irq_mask_cur |= 1 << d->hwirq; } static void max732x_irq_bus_lock(struct irq_data *d) { - struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max732x_chip *chip = to_max732x(gc); mutex_lock(&chip->irq_lock); chip->irq_mask_cur = chip->irq_mask; @@ -392,7 +380,8 @@ static void max732x_irq_bus_lock(struct irq_data *d) static void max732x_irq_bus_sync_unlock(struct irq_data *d) { - struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max732x_chip *chip = to_max732x(gc); uint16_t new_irqs; uint16_t level; @@ -410,7 +399,8 @@ static void max732x_irq_bus_sync_unlock(struct irq_data *d) static int max732x_irq_set_type(struct irq_data *d, unsigned int type) { - struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max732x_chip *chip = to_max732x(gc); uint16_t off = d->hwirq; uint16_t mask = 1 << off; @@ -492,7 +482,8 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - handle_nested_irq(irq_find_mapping(chip->irq_domain, level)); + handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain, + level)); pending &= ~(1 << level); } while (pending); @@ -500,86 +491,50 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) return IRQ_HANDLED; } -static int max732x_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct max732x_chip *chip = h->host_data; - - if (!(chip->dir_input & (1 << hw))) { - dev_err(&chip->client->dev, - "Attempt to map output line as IRQ line: %lu\n", - hw); - return -EPERM; - } - - irq_set_chip_data(virq, chip); - irq_set_chip_and_handler(virq, &max732x_irq_chip, - handle_edge_irq); - irq_set_nested_thread(virq, 1); -#ifdef CONFIG_ARM - /* ARM needs us to explicitly flag the IRQ as valid - * and will set them noprobe when we do so. */ - set_irq_flags(virq, IRQF_VALID); -#else - irq_set_noprobe(virq); -#endif - - return 0; -} - -static struct irq_domain_ops max732x_irq_domain_ops = { - .map = max732x_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static void max732x_irq_teardown(struct max732x_chip *chip) -{ - if (chip->client->irq && chip->irq_domain) - irq_domain_remove(chip->irq_domain); -} - static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) { struct i2c_client *client = chip->client; struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); int has_irq = max732x_features[id->driver_data] >> 32; + int irq_base = 0; int ret; if (((pdata && pdata->irq_base) || client->irq) && has_irq != INT_NONE) { if (pdata) - chip->irq_base = pdata->irq_base; + irq_base = pdata->irq_base; chip->irq_features = has_irq; mutex_init(&chip->irq_lock); - chip->irq_domain = irq_domain_add_simple(client->dev.of_node, - chip->gpio_chip.ngpio, chip->irq_base, - &max732x_irq_domain_ops, chip); - if (!chip->irq_domain) { - dev_err(&client->dev, "Failed to create IRQ domain\n"); - return -ENOMEM; - } - - ret = request_threaded_irq(client->irq, - NULL, - max732x_irq_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(&client->dev), chip); + ret = devm_request_threaded_irq(&client->dev, + client->irq, + NULL, + max732x_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(&client->dev), chip); if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); - goto out_failed; + return ret; } - - chip->gpio_chip.to_irq = max732x_gpio_to_irq; + ret = gpiochip_irqchip_add(&chip->gpio_chip, + &max732x_irq_chip, + irq_base, + handle_edge_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(&client->dev, + "could not connect irqchip to gpiochip\n"); + return ret; + } + gpiochip_set_chained_irqchip(&chip->gpio_chip, + &max732x_irq_chip, + client->irq, + NULL); } return 0; - -out_failed: - max732x_irq_teardown(chip); - return ret; } #else /* CONFIG_GPIO_MAX732X_IRQ */ @@ -595,10 +550,6 @@ static int max732x_irq_setup(struct max732x_chip *chip, return 0; } - -static void max732x_irq_teardown(struct max732x_chip *chip) -{ -} #endif static int max732x_setup_gpio(struct max732x_chip *chip, @@ -730,13 +681,15 @@ static int max732x_probe(struct i2c_client *client, if (nr_port > 8) max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]); - ret = max732x_irq_setup(chip, id); + ret = gpiochip_add(&chip->gpio_chip); if (ret) goto out_failed; - ret = gpiochip_add(&chip->gpio_chip); - if (ret) + ret = max732x_irq_setup(chip, id); + if (ret) { + gpiochip_remove(&chip->gpio_chip); goto out_failed; + } if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, @@ -751,7 +704,6 @@ static int max732x_probe(struct i2c_client *client, out_failed: if (chip->client_dummy) i2c_unregister_device(chip->client_dummy); - max732x_irq_teardown(chip); return ret; } @@ -774,8 +726,6 @@ static int max732x_remove(struct i2c_client *client) gpiochip_remove(&chip->gpio_chip); - max732x_irq_teardown(chip); - /* unregister any dummy i2c_client */ if (chip->client_dummy) i2c_unregister_device(chip->client_dummy); diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index 21b1ce5..ee93c0a 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -58,6 +58,11 @@ static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio) spin_lock_irqsave(&gchip->lock, flags); val = readl(gchip->base + PFR(gpio)); + if (!(val & OFFSET(gpio))) { + spin_unlock_irqrestore(&gchip->lock, flags); + return -EINVAL; + } + val &= ~OFFSET(gpio); writel(val, gchip->base + PFR(gpio)); diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 4e3e160..a431604 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -151,7 +151,7 @@ static int mc33880_remove(struct spi_device *spi) struct mc33880 *mc; mc = spi_get_drvdata(spi); - if (mc == NULL) + if (!mc) return -ENODEV; gpiochip_remove(&mc->chip); diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index eea5d7e..2fc7ff8 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -949,10 +949,12 @@ static int mcp23s08_probe(struct spi_device *spi) if (!chips) return -ENODEV; - data = kzalloc(sizeof(*data) + chips * sizeof(struct mcp23s08), - GFP_KERNEL); + data = devm_kzalloc(&spi->dev, + sizeof(*data) + chips * sizeof(struct mcp23s08), + GFP_KERNEL); if (!data) return -ENOMEM; + spi_set_drvdata(spi, data); spi->irq = irq_of_parse_and_map(spi->dev.of_node, 0); @@ -989,7 +991,6 @@ fail: continue; gpiochip_remove(&data->mcp[addr]->chip); } - kfree(data); return status; } @@ -1007,7 +1008,7 @@ static int mcp23s08_remove(struct spi_device *spi) mcp23s08_irq_teardown(data->mcp[addr]); gpiochip_remove(&data->mcp[addr]->chip); } - kfree(data); + return 0; } diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index d0bc123..1a54205 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -320,11 +320,13 @@ static void mvebu_gpio_edge_irq_mask(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mvebu_gpio_chip *mvchip = gc->private; + struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - gc->mask_cache &= ~mask; - writel_relaxed(gc->mask_cache, mvebu_gpioreg_edge_mask(mvchip)); + ct->mask_cache_priv &= ~mask; + + writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip)); irq_gc_unlock(gc); } @@ -332,11 +334,13 @@ static void mvebu_gpio_edge_irq_unmask(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mvebu_gpio_chip *mvchip = gc->private; + struct irq_chip_type *ct = irq_data_get_chip_type(d); + u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - gc->mask_cache |= mask; - writel_relaxed(gc->mask_cache, mvebu_gpioreg_edge_mask(mvchip)); + ct->mask_cache_priv |= mask; + writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip)); irq_gc_unlock(gc); } @@ -344,11 +348,13 @@ static void mvebu_gpio_level_irq_mask(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mvebu_gpio_chip *mvchip = gc->private; + struct irq_chip_type *ct = irq_data_get_chip_type(d); + u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - gc->mask_cache &= ~mask; - writel_relaxed(gc->mask_cache, mvebu_gpioreg_level_mask(mvchip)); + ct->mask_cache_priv &= ~mask; + writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip)); irq_gc_unlock(gc); } @@ -356,11 +362,13 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mvebu_gpio_chip *mvchip = gc->private; + struct irq_chip_type *ct = irq_data_get_chip_type(d); + u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - gc->mask_cache |= mask; - writel_relaxed(gc->mask_cache, mvebu_gpioreg_level_mask(mvchip)); + ct->mask_cache_priv |= mask; + writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip)); irq_gc_unlock(gc); } diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f476ae2..cd1d5bf 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -75,14 +75,12 @@ struct gpio_bank { int power_mode; bool workaround_enabled; - void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable); + void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable); int (*get_context_loss_count)(struct device *dev); struct omap_gpio_reg_offs *regs; }; -#define GPIO_INDEX(bank, gpio) (gpio % bank->width) -#define GPIO_BIT(bank, gpio) (BIT(GPIO_INDEX(bank, gpio))) #define GPIO_MOD_CTRL_BIT BIT(0) #define BANK_USED(bank) (bank->mod_usage || bank->irq_usage) @@ -90,11 +88,6 @@ struct gpio_bank { static void omap_gpio_unmask_irq(struct irq_data *d); -static int omap_irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) -{ - return bank->chip.base + gpio_irq; -} - static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); @@ -119,11 +112,11 @@ static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio, /* set data out value using dedicate set/clear register */ -static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, +static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, unsigned offset, int enable) { void __iomem *reg = bank->base; - u32 l = GPIO_BIT(bank, gpio); + u32 l = BIT(offset); if (enable) { reg += bank->regs->set_dataout; @@ -137,11 +130,11 @@ static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, } /* set data out value using mask register */ -static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, +static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, unsigned offset, int enable) { void __iomem *reg = bank->base + bank->regs->dataout; - u32 gpio_bit = GPIO_BIT(bank, gpio); + u32 gpio_bit = BIT(offset); u32 l; l = readl_relaxed(reg); @@ -208,13 +201,13 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) /** * omap2_set_gpio_debounce - low level gpio debounce time * @bank: the gpio bank we're acting upon - * @gpio: the gpio number on this @gpio + * @offset: the gpio number on this @bank * @debounce: debounce time to use * * OMAP's debounce time is in 31us steps so we need * to convert and round up to the closest unit. */ -static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, +static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, unsigned debounce) { void __iomem *reg; @@ -231,7 +224,7 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, else debounce = (debounce / 0x1f) - 1; - l = GPIO_BIT(bank, gpio); + l = BIT(offset); clk_prepare_enable(bank->dbck); reg = bank->base + bank->regs->debounce; @@ -266,16 +259,16 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, /** * omap_clear_gpio_debounce - clear debounce settings for a gpio * @bank: the gpio bank we're acting upon - * @gpio: the gpio number on this @gpio + * @offset: the gpio number on this @bank * * If a gpio is using debounce, then clear the debounce enable bit and if * this is the only gpio in this bank using debounce, then clear the debounce * time too. The debounce clock will also be disabled when calling this function * if this is the only gpio in the bank using debounce. */ -static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio) +static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset) { - u32 gpio_bit = GPIO_BIT(bank, gpio); + u32 gpio_bit = BIT(offset); if (!bank->dbck_flag) return; @@ -472,42 +465,32 @@ static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset) } } -static int omap_gpio_is_input(struct gpio_bank *bank, int mask) +static int omap_gpio_is_input(struct gpio_bank *bank, unsigned offset) { void __iomem *reg = bank->base + bank->regs->direction; - return readl_relaxed(reg) & mask; + return readl_relaxed(reg) & BIT(offset); } -static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned gpio, - unsigned offset) +static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned offset) { if (!LINE_USED(bank->mod_usage, offset)) { omap_enable_gpio_module(bank, offset); omap_set_gpio_direction(bank, offset, 1); } - bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio)); + bank->irq_usage |= BIT(offset); } static int omap_gpio_irq_type(struct irq_data *d, unsigned type) { struct gpio_bank *bank = omap_irq_data_get_bank(d); - unsigned gpio = 0; int retval; unsigned long flags; - unsigned offset; + unsigned offset = d->hwirq; if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); -#ifdef CONFIG_ARCH_OMAP1 - if (d->irq > IH_MPUIO_BASE) - gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE); -#endif - - if (!gpio) - gpio = omap_irq_to_gpio(bank, d->hwirq); - if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; @@ -516,10 +499,9 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) return -EINVAL; spin_lock_irqsave(&bank->lock, flags); - offset = GPIO_INDEX(bank, gpio); retval = omap_set_gpio_triggering(bank, offset, type); - omap_gpio_init_irq(bank, gpio, offset); - if (!omap_gpio_is_input(bank, BIT(offset))) { + omap_gpio_init_irq(bank, offset); + if (!omap_gpio_is_input(bank, offset)) { spin_unlock_irqrestore(&bank->lock, flags); return -EINVAL; } @@ -550,9 +532,10 @@ static void omap_clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) readl_relaxed(reg); } -static inline void omap_clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) +static inline void omap_clear_gpio_irqstatus(struct gpio_bank *bank, + unsigned offset) { - omap_clear_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + omap_clear_gpio_irqbank(bank, BIT(offset)); } static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank) @@ -613,13 +596,13 @@ static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) writel_relaxed(l, reg); } -static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, int gpio, - int enable) +static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, + unsigned offset, int enable) { if (enable) - omap_enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + omap_enable_gpio_irqbank(bank, BIT(offset)); else - omap_disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + omap_disable_gpio_irqbank(bank, BIT(offset)); } /* @@ -630,14 +613,16 @@ static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, int gpio, * enabled. When system is suspended, only selected GPIO interrupts need * to have wake-up enabled. */ -static int omap_set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) +static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset, + int enable) { - u32 gpio_bit = GPIO_BIT(bank, gpio); + u32 gpio_bit = BIT(offset); unsigned long flags; if (bank->non_wakeup_gpios & gpio_bit) { dev_err(bank->dev, - "Unable to modify wakeup on non-wakeup GPIO%d\n", gpio); + "Unable to modify wakeup on non-wakeup GPIO%d\n", + offset); return -EINVAL; } @@ -653,22 +638,22 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) return 0; } -static void omap_reset_gpio(struct gpio_bank *bank, int gpio) +static void omap_reset_gpio(struct gpio_bank *bank, unsigned offset) { - omap_set_gpio_direction(bank, GPIO_INDEX(bank, gpio), 1); - omap_set_gpio_irqenable(bank, gpio, 0); - omap_clear_gpio_irqstatus(bank, gpio); - omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE); - omap_clear_gpio_debounce(bank, gpio); + omap_set_gpio_direction(bank, offset, 1); + omap_set_gpio_irqenable(bank, offset, 0); + omap_clear_gpio_irqstatus(bank, offset); + omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); + omap_clear_gpio_debounce(bank, offset); } /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable) { struct gpio_bank *bank = omap_irq_data_get_bank(d); - unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); + unsigned offset = d->hwirq; - return omap_set_gpio_wakeup(bank, gpio, enable); + return omap_set_gpio_wakeup(bank, offset, enable); } static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -706,7 +691,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&bank->lock, flags); bank->mod_usage &= ~(BIT(offset)); omap_disable_gpio_module(bank, offset); - omap_reset_gpio(bank, bank->chip.base + offset); + omap_reset_gpio(bank, offset); spin_unlock_irqrestore(&bank->lock, flags); /* @@ -803,15 +788,14 @@ exit: static unsigned int omap_gpio_irq_startup(struct irq_data *d) { struct gpio_bank *bank = omap_irq_data_get_bank(d); - unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); unsigned long flags; - unsigned offset = GPIO_INDEX(bank, gpio); + unsigned offset = d->hwirq; if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); spin_lock_irqsave(&bank->lock, flags); - omap_gpio_init_irq(bank, gpio, offset); + omap_gpio_init_irq(bank, offset); spin_unlock_irqrestore(&bank->lock, flags); omap_gpio_unmask_irq(d); @@ -821,15 +805,13 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) static void omap_gpio_irq_shutdown(struct irq_data *d) { struct gpio_bank *bank = omap_irq_data_get_bank(d); - unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); unsigned long flags; - unsigned offset = GPIO_INDEX(bank, gpio); + unsigned offset = d->hwirq; spin_lock_irqsave(&bank->lock, flags); - gpiochip_unlock_as_irq(&bank->chip, offset); bank->irq_usage &= ~(BIT(offset)); omap_disable_gpio_module(bank, offset); - omap_reset_gpio(bank, gpio); + omap_reset_gpio(bank, offset); spin_unlock_irqrestore(&bank->lock, flags); /* @@ -843,43 +825,42 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) static void omap_gpio_ack_irq(struct irq_data *d) { struct gpio_bank *bank = omap_irq_data_get_bank(d); - unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); + unsigned offset = d->hwirq; - omap_clear_gpio_irqstatus(bank, gpio); + omap_clear_gpio_irqstatus(bank, offset); } static void omap_gpio_mask_irq(struct irq_data *d) { struct gpio_bank *bank = omap_irq_data_get_bank(d); - unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); + unsigned offset = d->hwirq; unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - omap_set_gpio_irqenable(bank, gpio, 0); - omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE); + omap_set_gpio_irqenable(bank, offset, 0); + omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); spin_unlock_irqrestore(&bank->lock, flags); } static void omap_gpio_unmask_irq(struct irq_data *d) { struct gpio_bank *bank = omap_irq_data_get_bank(d); - unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); - unsigned int irq_mask = GPIO_BIT(bank, gpio); + unsigned offset = d->hwirq; u32 trigger = irqd_get_trigger_type(d); unsigned long flags; spin_lock_irqsave(&bank->lock, flags); if (trigger) - omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), trigger); + omap_set_gpio_triggering(bank, offset, trigger); /* For level-triggered GPIOs, the clearing must be done after * the HW source is cleared, thus after the handler has run */ - if (bank->level_mask & irq_mask) { - omap_set_gpio_irqenable(bank, gpio, 0); - omap_clear_gpio_irqstatus(bank, gpio); + if (bank->level_mask & BIT(offset)) { + omap_set_gpio_irqenable(bank, offset, 0); + omap_clear_gpio_irqstatus(bank, offset); } - omap_set_gpio_irqenable(bank, gpio, 1); + omap_set_gpio_irqenable(bank, offset, 1); spin_unlock_irqrestore(&bank->lock, flags); } @@ -977,12 +958,10 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) static int omap_gpio_get(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank; - u32 mask; bank = container_of(chip, struct gpio_bank, chip); - mask = (BIT(offset)); - if (omap_gpio_is_input(bank, mask)) + if (omap_gpio_is_input(bank, offset)) return omap_get_gpio_datain(bank, offset); else return omap_get_gpio_dataout(bank, offset); diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 236708a..945f0cd 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -88,11 +88,9 @@ struct pcf857x { struct gpio_chip chip; struct i2c_client *client; struct mutex lock; /* protect 'out' */ - struct irq_domain *irq_domain; /* for irq demux */ spinlock_t slock; /* protect irq demux */ unsigned out; /* software latch */ unsigned status; /* current status */ - unsigned irq_mapped; /* mapped gpio irqs */ int (*write)(struct i2c_client *client, unsigned data); int (*read)(struct i2c_client *client); @@ -182,18 +180,6 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) /*-------------------------------------------------------------------------*/ -static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); - int ret; - - ret = irq_create_mapping(gpio->irq_domain, offset); - if (ret > 0) - gpio->irq_mapped |= (1 << offset); - - return ret; -} - static irqreturn_t pcf857x_irq(int irq, void *data) { struct pcf857x *gpio = data; @@ -208,9 +194,9 @@ static irqreturn_t pcf857x_irq(int irq, void *data) * interrupt source, just to avoid bad irqs */ - change = ((gpio->status ^ status) & gpio->irq_mapped); + change = (gpio->status ^ status); for_each_set_bit(i, &change, gpio->chip.ngpio) - generic_handle_irq(irq_find_mapping(gpio->irq_domain, i)); + handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i)); gpio->status = status; spin_unlock_irqrestore(&gpio->slock, flags); @@ -218,66 +204,36 @@ static irqreturn_t pcf857x_irq(int irq, void *data) return IRQ_HANDLED; } -static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int irq, - irq_hw_number_t hw) -{ - struct pcf857x *gpio = domain->host_data; - - irq_set_chip_and_handler(irq, - &dummy_irq_chip, - handle_level_irq); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - gpio->irq_mapped |= (1 << hw); - - return 0; -} - -static struct irq_domain_ops pcf857x_irq_domain_ops = { - .map = pcf857x_irq_domain_map, -}; +/* + * NOP functions + */ +static void noop(struct irq_data *data) { } -static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) +static unsigned int noop_ret(struct irq_data *data) { - if (gpio->irq_domain) - irq_domain_remove(gpio->irq_domain); - + return 0; } -static int pcf857x_irq_domain_init(struct pcf857x *gpio, - struct i2c_client *client) +static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on) { - int status; - - gpio->irq_domain = irq_domain_add_linear(client->dev.of_node, - gpio->chip.ngpio, - &pcf857x_irq_domain_ops, - gpio); - if (!gpio->irq_domain) - goto fail; - - /* enable real irq */ - status = devm_request_threaded_irq(&client->dev, client->irq, - NULL, pcf857x_irq, IRQF_ONESHOT | - IRQF_TRIGGER_FALLING | IRQF_SHARED, - dev_name(&client->dev), gpio); - - if (status) - goto fail; - - /* enable gpio_to_irq() */ - gpio->chip.to_irq = pcf857x_to_irq; + struct pcf857x *gpio = irq_data_get_irq_chip_data(data); + irq_set_irq_wake(gpio->client->irq, on); return 0; - -fail: - pcf857x_irq_domain_cleanup(gpio); - return -EINVAL; } +static struct irq_chip pcf857x_irq_chip = { + .name = "pcf857x", + .irq_startup = noop_ret, + .irq_shutdown = noop, + .irq_enable = noop, + .irq_disable = noop, + .irq_ack = noop, + .irq_mask = noop, + .irq_unmask = noop, + .irq_set_wake = pcf857x_irq_set_wake, +}; + /*-------------------------------------------------------------------------*/ static int pcf857x_probe(struct i2c_client *client, @@ -314,15 +270,6 @@ static int pcf857x_probe(struct i2c_client *client, gpio->chip.direction_output = pcf857x_output; gpio->chip.ngpio = id->driver_data; - /* enable gpio_to_irq() if platform has settings */ - if (client->irq) { - status = pcf857x_irq_domain_init(gpio, client); - if (status < 0) { - dev_err(&client->dev, "irq_domain init failed\n"); - goto fail_irq_domain; - } - } - /* NOTE: the OnSemi jlc1562b is also largely compatible with * these parts, notably for output. It has a low-resolution * DAC instead of pin change IRQs; and its inputs can be the @@ -398,6 +345,27 @@ static int pcf857x_probe(struct i2c_client *client, if (status < 0) goto fail; + /* Enable irqchip if we have an interrupt */ + if (client->irq) { + status = gpiochip_irqchip_add(&gpio->chip, &pcf857x_irq_chip, + 0, handle_level_irq, + IRQ_TYPE_NONE); + if (status) { + dev_err(&client->dev, "cannot add irqchip\n"); + goto fail_irq; + } + + status = devm_request_threaded_irq(&client->dev, client->irq, + NULL, pcf857x_irq, IRQF_ONESHOT | + IRQF_TRIGGER_FALLING | IRQF_SHARED, + dev_name(&client->dev), gpio); + if (status) + goto fail_irq; + + gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip, + client->irq, NULL); + } + /* Let platform code set up the GPIOs and their users. * Now is the first time anyone could use them. */ @@ -413,13 +381,12 @@ static int pcf857x_probe(struct i2c_client *client, return 0; -fail: - if (client->irq) - pcf857x_irq_domain_cleanup(gpio); +fail_irq: + gpiochip_remove(&gpio->chip); -fail_irq_domain: - dev_dbg(&client->dev, "probe error %d for '%s'\n", - status, client->name); +fail: + dev_dbg(&client->dev, "probe error %d for '%s'\n", status, + client->name); return status; } @@ -441,9 +408,6 @@ static int pcf857x_remove(struct i2c_client *client) } } - if (client->irq) - pcf857x_irq_domain_cleanup(gpio); - gpiochip_remove(&gpio->chip); return status; } diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 2fdb04b..cdbbcf0 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -59,8 +59,7 @@ #define GAFR_OFFSET 0x54 #define ED_MASK_OFFSET 0x9C /* GPIO edge detection for AP side */ -#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : ((n) > 5 ? 0x200 : 0x100) \ - + (((n) % 3) << 2)) +#define BANK_OFF(n) (((n) / 3) << 8) + (((n) % 3) << 2) int pxa_last_gpio; static int irq_base; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index c49522e..fd39774 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -14,6 +14,7 @@ * GNU General Public License for more details. */ +#include <linux/clk.h> #include <linux/err.h> #include <linux/gpio.h> #include <linux/init.h> @@ -37,20 +38,22 @@ struct gpio_rcar_priv { struct platform_device *pdev; struct gpio_chip gpio_chip; struct irq_chip irq_chip; + unsigned int irq_parent; + struct clk *clk; }; -#define IOINTSEL 0x00 -#define INOUTSEL 0x04 -#define OUTDT 0x08 -#define INDT 0x0c -#define INTDT 0x10 -#define INTCLR 0x14 -#define INTMSK 0x18 -#define MSKCLR 0x1c -#define POSNEG 0x20 -#define EDGLEVEL 0x24 -#define FILONOFF 0x28 -#define BOTHEDGE 0x4c +#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ +#define INOUTSEL 0x04 /* General Input/Output Switching Register */ +#define OUTDT 0x08 /* General Output Register */ +#define INDT 0x0c /* General Input Register */ +#define INTDT 0x10 /* Interrupt Display Register */ +#define INTCLR 0x14 /* Interrupt Clear Register */ +#define INTMSK 0x18 /* Interrupt Mask Register */ +#define MSKCLR 0x1c /* Interrupt Mask Clear Register */ +#define POSNEG 0x20 /* Positive/Negative Logic Select Register */ +#define EDGLEVEL 0x24 /* Edge/level Select Register */ +#define FILONOFF 0x28 /* Chattering Prevention On/Off Register */ +#define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */ #define RCAR_MAX_GPIO_PER_BANK 32 @@ -169,6 +172,25 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type) return 0; } +static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, + gpio_chip); + + irq_set_irq_wake(p->irq_parent, on); + + if (!p->clk) + return 0; + + if (on) + clk_enable(p->clk); + else + clk_disable(p->clk); + + return 0; +} + static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id) { struct gpio_rcar_priv *p = dev_id; @@ -367,6 +389,12 @@ static int gpio_rcar_probe(struct platform_device *pdev) platform_set_drvdata(pdev, p); + p->clk = devm_clk_get(dev, NULL); + if (IS_ERR(p->clk)) { + dev_warn(dev, "unable to get clock\n"); + p->clk = NULL; + } + pm_runtime_enable(dev); pm_runtime_get_sync(dev); @@ -404,8 +432,8 @@ static int gpio_rcar_probe(struct platform_device *pdev) irq_chip->irq_mask = gpio_rcar_irq_disable; irq_chip->irq_unmask = gpio_rcar_irq_enable; irq_chip->irq_set_type = gpio_rcar_irq_set_type; - irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED - | IRQCHIP_MASK_ON_SUSPEND; + irq_chip->irq_set_wake = gpio_rcar_irq_set_wake; + irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; ret = gpiochip_add(gpio_chip); if (ret) { @@ -413,13 +441,14 @@ static int gpio_rcar_probe(struct platform_device *pdev) goto err0; } - ret = gpiochip_irqchip_add(&p->gpio_chip, irq_chip, p->config.irq_base, + ret = gpiochip_irqchip_add(gpio_chip, irq_chip, p->config.irq_base, handle_level_irq, IRQ_TYPE_NONE); if (ret) { dev_err(dev, "cannot add irqchip\n"); goto err1; } + p->irq_parent = irq->start; if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, IRQF_SHARED, name, p)) { dev_err(dev, "failed to request IRQ\n"); @@ -431,7 +460,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) /* warn in case of mismatch if irq base is specified */ if (p->config.irq_base) { - ret = irq_find_mapping(p->gpio_chip.irqdomain, 0); + ret = irq_find_mapping(gpio_chip->irqdomain, 0); if (p->config.irq_base != ret) dev_warn(dev, "irq base mismatch (%u/%u)\n", p->config.irq_base, ret); @@ -447,7 +476,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) return 0; err1: - gpiochip_remove(&p->gpio_chip); + gpiochip_remove(gpio_chip); err0: pm_runtime_put(dev); pm_runtime_disable(dev); diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index 62ab9f4..46b8961 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -283,7 +283,7 @@ fail_ioremap: return ret; } -static int __exit tb10x_gpio_remove(struct platform_device *pdev) +static int tb10x_gpio_remove(struct platform_device *pdev) { struct tb10x_gpio *tb10x_gpio = platform_get_drvdata(pdev); diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 971c739..7bd9f20 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -244,16 +244,16 @@ static int vf610_gpio_probe(struct platform_device *pdev) gc = &port->gc; gc->of_node = np; gc->dev = dev; - gc->label = "vf610-gpio", - gc->ngpio = VF610_GPIO_PER_PORT, + gc->label = "vf610-gpio"; + gc->ngpio = VF610_GPIO_PER_PORT; gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT; - gc->request = vf610_gpio_request, - gc->free = vf610_gpio_free, - gc->direction_input = vf610_gpio_direction_input, - gc->get = vf610_gpio_get, - gc->direction_output = vf610_gpio_direction_output, - gc->set = vf610_gpio_set, + gc->request = vf610_gpio_request; + gc->free = vf610_gpio_free; + gc->direction_input = vf610_gpio_direction_input; + gc->get = vf610_gpio_get; + gc->direction_output = vf610_gpio_direction_output; + gc->set = vf610_gpio_set; ret = gpiochip_add(gc); if (ret < 0) diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index b6a15c3..fb9d29a 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -93,7 +93,7 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); - if (!regs) + if (IS_ERR(regs)) return PTR_ERR(regs); ret = bgpio_init(&priv->bgc, &pdev->dev, 4, diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index df990f2..d2303d5 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -304,7 +304,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) return; INIT_LIST_HEAD(&acpi_gpio->events); - acpi_walk_resources(ACPI_HANDLE(chip->dev), "_AEI", + acpi_walk_resources(handle, "_AEI", acpi_gpiochip_request_interrupt, acpi_gpio); } @@ -722,3 +722,87 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) acpi_detach_data(handle, acpi_gpio_chip_dh); kfree(acpi_gpio); } + +static unsigned int acpi_gpio_package_count(const union acpi_object *obj) +{ + const union acpi_object *element = obj->package.elements; + const union acpi_object *end = element + obj->package.count; + unsigned int count = 0; + + while (element < end) { + if (element->type == ACPI_TYPE_LOCAL_REFERENCE) + count++; + + element++; + } + return count; +} + +static int acpi_find_gpio_count(struct acpi_resource *ares, void *data) +{ + unsigned int *count = data; + + if (ares->type == ACPI_RESOURCE_TYPE_GPIO) + *count += ares->data.gpio.pin_table_length; + + return 1; +} + +/** + * acpi_gpio_count - return the number of GPIOs associated with a + * device / function or -ENOENT if no GPIO has been + * assigned to the requested function. + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + */ +int acpi_gpio_count(struct device *dev, const char *con_id) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + const union acpi_object *obj; + const struct acpi_gpio_mapping *gm; + int count = -ENOENT; + int ret; + char propname[32]; + unsigned int i; + + /* Try first from _DSD */ + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { + if (con_id && strcmp(con_id, "gpios")) + snprintf(propname, sizeof(propname), "%s-%s", + con_id, gpio_suffixes[i]); + else + snprintf(propname, sizeof(propname), "%s", + gpio_suffixes[i]); + + ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY, + &obj); + if (ret == 0) { + if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) + count = 1; + else if (obj->type == ACPI_TYPE_PACKAGE) + count = acpi_gpio_package_count(obj); + } else if (adev->driver_gpios) { + for (gm = adev->driver_gpios; gm->name; gm++) + if (strcmp(propname, gm->name) == 0) { + count = gm->size; + break; + } + } + if (count >= 0) + break; + } + + /* Then from plain _CRS GPIOs */ + if (count < 0) { + struct list_head resource_list; + unsigned int crs_count = 0; + + INIT_LIST_HEAD(&resource_list); + acpi_dev_get_resources(adev, &resource_list, + acpi_find_gpio_count, &crs_count); + acpi_dev_free_resource_list(&resource_list); + if (crs_count > 0) + count = crs_count; + } + return count; +} diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 4650bf8..a6c67c6 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -22,6 +22,7 @@ #include <linux/of_gpio.h> #include <linux/pinctrl/pinctrl.h> #include <linux/slab.h> +#include <linux/gpio/machine.h> #include "gpiolib.h" @@ -118,6 +119,114 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name, EXPORT_SYMBOL(of_get_named_gpio_flags); /** + * of_get_gpio_hog() - Get a GPIO hog descriptor, names and flags for GPIO API + * @np: device node to get GPIO from + * @name: GPIO line name + * @lflags: gpio_lookup_flags - returned from of_find_gpio() or + * of_get_gpio_hog() + * @dflags: gpiod_flags - optional GPIO initialization flags + * + * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno + * value on the error condition. + */ +static struct gpio_desc *of_get_gpio_hog(struct device_node *np, + const char **name, + enum gpio_lookup_flags *lflags, + enum gpiod_flags *dflags) +{ + struct device_node *chip_np; + enum of_gpio_flags xlate_flags; + struct gpio_desc *desc; + struct gg_data gg_data = { + .flags = &xlate_flags, + }; + u32 tmp; + int i, ret; + + chip_np = np->parent; + if (!chip_np) + return ERR_PTR(-EINVAL); + + xlate_flags = 0; + *lflags = 0; + *dflags = 0; + + ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp); + if (ret) + return ERR_PTR(ret); + + if (tmp > MAX_PHANDLE_ARGS) + return ERR_PTR(-EINVAL); + + gg_data.gpiospec.args_count = tmp; + gg_data.gpiospec.np = chip_np; + for (i = 0; i < tmp; i++) { + ret = of_property_read_u32_index(np, "gpios", i, + &gg_data.gpiospec.args[i]); + if (ret) + return ERR_PTR(ret); + } + + gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); + if (!gg_data.out_gpio) { + if (np->parent == np) + return ERR_PTR(-ENXIO); + else + return ERR_PTR(-EINVAL); + } + + if (xlate_flags & OF_GPIO_ACTIVE_LOW) + *lflags |= GPIO_ACTIVE_LOW; + + if (of_property_read_bool(np, "input")) + *dflags |= GPIOD_IN; + else if (of_property_read_bool(np, "output-low")) + *dflags |= GPIOD_OUT_LOW; + else if (of_property_read_bool(np, "output-high")) + *dflags |= GPIOD_OUT_HIGH; + else { + pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n", + desc_to_gpio(gg_data.out_gpio), np->name); + return ERR_PTR(-EINVAL); + } + + if (name && of_property_read_string(np, "line-name", name)) + *name = np->name; + + desc = gg_data.out_gpio; + + return desc; +} + +/** + * of_gpiochip_scan_hogs - Scan gpio-controller and apply GPIO hog as requested + * @chip: gpio chip to act on + * + * This is only used by of_gpiochip_add to request/set GPIO initial + * configuration. + */ +static void of_gpiochip_scan_hogs(struct gpio_chip *chip) +{ + struct gpio_desc *desc = NULL; + struct device_node *np; + const char *name; + enum gpio_lookup_flags lflags; + enum gpiod_flags dflags; + + for_each_child_of_node(chip->of_node, np) { + if (!of_property_read_bool(np, "gpio-hog")) + continue; + + desc = of_get_gpio_hog(np, &name, &lflags, &dflags); + if (IS_ERR(desc)) + continue; + + if (gpiod_hog(desc, name, lflags, dflags)) + continue; + } +} + +/** * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags * @gc: pointer to the gpio_chip structure * @np: device node of the GPIO chip @@ -326,6 +435,8 @@ void of_gpiochip_add(struct gpio_chip *chip) of_gpiochip_add_pin_range(chip); of_node_get(chip->of_node); + + of_gpiochip_scan_hogs(chip); } void of_gpiochip_remove(struct gpio_chip *chip) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1ca9295..59eaa23 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -315,6 +315,7 @@ EXPORT_SYMBOL_GPL(gpiochip_add); /* Forward-declaration */ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); +static void gpiochip_free_hogs(struct gpio_chip *chip); /** * gpiochip_remove() - unregister a gpio_chip @@ -333,6 +334,7 @@ void gpiochip_remove(struct gpio_chip *chip) acpi_gpiochip_remove(chip); gpiochip_remove_pin_ranges(chip); + gpiochip_free_hogs(chip); of_gpiochip_remove(chip); spin_lock_irqsave(&gpio_lock, flags); @@ -866,6 +868,7 @@ static bool __gpiod_free(struct gpio_desc *desc) clear_bit(FLAG_REQUESTED, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_SOURCE, &desc->flags); + clear_bit(FLAG_IS_HOGGED, &desc->flags); ret = true; } @@ -1659,19 +1662,18 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { - static const char * const suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ enum of_gpio_flags of_flags; struct gpio_desc *desc; unsigned int i; - for (i = 0; i < ARRAY_SIZE(suffixes); i++) { + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { if (con_id) snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id, - suffixes[i]); + gpio_suffixes[i]); else snprintf(prop_name, sizeof(prop_name), "%s", - suffixes[i]); + gpio_suffixes[i]); desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, &of_flags); @@ -1692,7 +1694,6 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { - static const char * const suffixes[] = { "gpios", "gpio" }; struct acpi_device *adev = ACPI_COMPANION(dev); struct acpi_gpio_info info; struct gpio_desc *desc; @@ -1700,13 +1701,13 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, int i; /* Try first from _DSD */ - for (i = 0; i < ARRAY_SIZE(suffixes); i++) { + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { if (con_id && strcmp(con_id, "gpios")) { snprintf(propname, sizeof(propname), "%s-%s", - con_id, suffixes[i]); + con_id, gpio_suffixes[i]); } else { snprintf(propname, sizeof(propname), "%s", - suffixes[i]); + gpio_suffixes[i]); } desc = acpi_get_gpiod_by_index(adev, propname, idx, &info); @@ -1805,6 +1806,70 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return desc; } +static int dt_gpio_count(struct device *dev, const char *con_id) +{ + int ret; + char propname[32]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { + if (con_id) + snprintf(propname, sizeof(propname), "%s-%s", + con_id, gpio_suffixes[i]); + else + snprintf(propname, sizeof(propname), "%s", + gpio_suffixes[i]); + + ret = of_gpio_named_count(dev->of_node, propname); + if (ret >= 0) + break; + } + return ret; +} + +static int platform_gpio_count(struct device *dev, const char *con_id) +{ + struct gpiod_lookup_table *table; + struct gpiod_lookup *p; + unsigned int count = 0; + + table = gpiod_find_lookup_table(dev); + if (!table) + return -ENOENT; + + for (p = &table->table[0]; p->chip_label; p++) { + if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) || + (!con_id && !p->con_id)) + count++; + } + if (!count) + return -ENOENT; + + return count; +} + +/** + * gpiod_count - return the number of GPIOs associated with a device / function + * or -ENOENT if no GPIO has been assigned to the requested function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + */ +int gpiod_count(struct device *dev, const char *con_id) +{ + int count = -ENOENT; + + if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) + count = dt_gpio_count(dev, con_id); + else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) + count = acpi_gpio_count(dev, con_id); + + if (count < 0) + count = platform_gpio_count(dev, con_id); + + return count; +} +EXPORT_SYMBOL_GPL(gpiod_count); + /** * gpiod_get - obtain a GPIO for a given GPIO function * @dev: GPIO consumer, can be NULL for system-global GPIOs @@ -1840,6 +1905,47 @@ struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev, } EXPORT_SYMBOL_GPL(__gpiod_get_optional); + +/** + * gpiod_configure_flags - helper function to configure a given GPIO + * @desc: gpio whose value will be assigned + * @con_id: function within the GPIO consumer + * @lflags: gpio_lookup_flags - returned from of_find_gpio() or + * of_get_gpio_hog() + * @dflags: gpiod_flags - optional GPIO initialization flags + * + * Return 0 on success, -ENOENT if no GPIO has been assigned to the + * requested function and/or index, or another IS_ERR() code if an error + * occurred while trying to acquire the GPIO. + */ +static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, + unsigned long lflags, enum gpiod_flags dflags) +{ + int status; + + if (lflags & GPIO_ACTIVE_LOW) + set_bit(FLAG_ACTIVE_LOW, &desc->flags); + if (lflags & GPIO_OPEN_DRAIN) + set_bit(FLAG_OPEN_DRAIN, &desc->flags); + if (lflags & GPIO_OPEN_SOURCE) + set_bit(FLAG_OPEN_SOURCE, &desc->flags); + + /* No particular flag request, return here... */ + if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { + pr_debug("no flags found for %s\n", con_id); + return 0; + } + + /* Process flags */ + if (dflags & GPIOD_FLAGS_BIT_DIR_OUT) + status = gpiod_direction_output(desc, + dflags & GPIOD_FLAGS_BIT_DIR_VAL); + else + status = gpiod_direction_input(desc); + + return status; +} + /** * gpiod_get_index - obtain a GPIO from a multi-index GPIO function * @dev: GPIO consumer, can be NULL for system-global GPIOs @@ -1865,13 +1971,15 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); - /* Using device tree? */ - if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) { - dev_dbg(dev, "using device tree for GPIO lookup\n"); - desc = of_find_gpio(dev, con_id, idx, &lookupflags); - } else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) { - dev_dbg(dev, "using ACPI for GPIO lookup\n"); - desc = acpi_find_gpio(dev, con_id, idx, &lookupflags); + if (dev) { + /* Using device tree? */ + if (IS_ENABLED(CONFIG_OF) && dev->of_node) { + dev_dbg(dev, "using device tree for GPIO lookup\n"); + desc = of_find_gpio(dev, con_id, idx, &lookupflags); + } else if (ACPI_COMPANION(dev)) { + dev_dbg(dev, "using ACPI for GPIO lookup\n"); + desc = acpi_find_gpio(dev, con_id, idx, &lookupflags); + } } /* @@ -1889,28 +1997,10 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, } status = gpiod_request(desc, con_id); - if (status < 0) return ERR_PTR(status); - if (lookupflags & GPIO_ACTIVE_LOW) - set_bit(FLAG_ACTIVE_LOW, &desc->flags); - if (lookupflags & GPIO_OPEN_DRAIN) - set_bit(FLAG_OPEN_DRAIN, &desc->flags); - if (lookupflags & GPIO_OPEN_SOURCE) - set_bit(FLAG_OPEN_SOURCE, &desc->flags); - - /* No particular flag request, return here... */ - if (!(flags & GPIOD_FLAGS_BIT_DIR_SET)) - return desc; - - /* Process flags */ - if (flags & GPIOD_FLAGS_BIT_DIR_OUT) - status = gpiod_direction_output(desc, - flags & GPIOD_FLAGS_BIT_DIR_VAL); - else - status = gpiod_direction_input(desc); - + status = gpiod_configure_flags(desc, con_id, lookupflags, flags); if (status < 0) { dev_dbg(dev, "setup of GPIO %s failed\n", con_id); gpiod_put(desc); @@ -2006,6 +2096,132 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, EXPORT_SYMBOL_GPL(__gpiod_get_index_optional); /** + * gpiod_hog - Hog the specified GPIO desc given the provided flags + * @desc: gpio whose value will be assigned + * @name: gpio line name + * @lflags: gpio_lookup_flags - returned from of_find_gpio() or + * of_get_gpio_hog() + * @dflags: gpiod_flags - optional GPIO initialization flags + */ +int gpiod_hog(struct gpio_desc *desc, const char *name, + unsigned long lflags, enum gpiod_flags dflags) +{ + struct gpio_chip *chip; + struct gpio_desc *local_desc; + int hwnum; + int status; + + chip = gpiod_to_chip(desc); + hwnum = gpio_chip_hwgpio(desc); + + local_desc = gpiochip_request_own_desc(chip, hwnum, name); + if (IS_ERR(local_desc)) { + pr_debug("requesting own GPIO %s failed\n", name); + return PTR_ERR(local_desc); + } + + status = gpiod_configure_flags(desc, name, lflags, dflags); + if (status < 0) { + pr_debug("setup of GPIO %s failed\n", name); + gpiochip_free_own_desc(desc); + return status; + } + + /* Mark GPIO as hogged so it can be identified and removed later */ + set_bit(FLAG_IS_HOGGED, &desc->flags); + + pr_info("GPIO line %d (%s) hogged as %s%s\n", + desc_to_gpio(desc), name, + (dflags&GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input", + (dflags&GPIOD_FLAGS_BIT_DIR_OUT) ? + (dflags&GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low":""); + + return 0; +} + +/** + * gpiochip_free_hogs - Scan gpio-controller chip and release GPIO hog + * @chip: gpio chip to act on + * + * This is only used by of_gpiochip_remove to free hogged gpios + */ +static void gpiochip_free_hogs(struct gpio_chip *chip) +{ + int id; + + for (id = 0; id < chip->ngpio; id++) { + if (test_bit(FLAG_IS_HOGGED, &chip->desc[id].flags)) + gpiochip_free_own_desc(&chip->desc[id]); + } +} + +/** + * gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * This function acquires all the GPIOs defined under a given function. + * + * Return a struct gpio_descs containing an array of descriptors, -ENOENT if + * no GPIO has been assigned to the requested function, or another IS_ERR() + * code if an error occurred while trying to acquire the GPIOs. + */ +struct gpio_descs *__must_check gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_desc *desc; + struct gpio_descs *descs; + int count; + + count = gpiod_count(dev, con_id); + if (count < 0) + return ERR_PTR(count); + + descs = kzalloc(sizeof(*descs) + sizeof(descs->desc[0]) * count, + GFP_KERNEL); + if (!descs) + return ERR_PTR(-ENOMEM); + + for (descs->ndescs = 0; descs->ndescs < count; ) { + desc = gpiod_get_index(dev, con_id, descs->ndescs, flags); + if (IS_ERR(desc)) { + gpiod_put_array(descs); + return ERR_CAST(desc); + } + descs->desc[descs->ndescs] = desc; + descs->ndescs++; + } + return descs; +} +EXPORT_SYMBOL_GPL(gpiod_get_array); + +/** + * gpiod_get_array_optional - obtain multiple GPIOs from a multi-index GPIO + * function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * This is equivalent to gpiod_get_array(), except that when no GPIO was + * assigned to the requested function it will return NULL. + */ +struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_descs *descs; + + descs = gpiod_get_array(dev, con_id, flags); + if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT)) + return NULL; + + return descs; +} +EXPORT_SYMBOL_GPL(gpiod_get_array_optional); + +/** * gpiod_put - dispose of a GPIO descriptor * @desc: GPIO descriptor to dispose of * @@ -2017,6 +2233,21 @@ void gpiod_put(struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_put); +/** + * gpiod_put_array - dispose of multiple GPIO descriptors + * @descs: struct gpio_descs containing an array of descriptors + */ +void gpiod_put_array(struct gpio_descs *descs) +{ + unsigned int i; + + for (i = 0; i < descs->ndescs; i++) + gpiod_put(descs->desc[i]); + + kfree(descs); +} +EXPORT_SYMBOL_GPL(gpiod_put_array); + #ifdef CONFIG_DEBUG_FS static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index ab892be..594b179 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -29,6 +29,9 @@ struct acpi_gpio_info { bool active_low; }; +/* gpio suffixes used for ACPI and device tree lookup */ +static const char * const gpio_suffixes[] = { "gpios", "gpio" }; + #ifdef CONFIG_ACPI void acpi_gpiochip_add(struct gpio_chip *chip); void acpi_gpiochip_remove(struct gpio_chip *chip); @@ -39,6 +42,8 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, int index, struct acpi_gpio_info *info); + +int acpi_gpio_count(struct device *dev, const char *con_id); #else static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } @@ -55,6 +60,11 @@ acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, { return ERR_PTR(-ENOSYS); } + +static inline int acpi_gpio_count(struct device *dev, const char *con_id) +{ + return -ENODEV; +} #endif struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, @@ -80,6 +90,7 @@ struct gpio_desc { #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */ +#define FLAG_IS_HOGGED 11 /* GPIO is hogged */ #define ID_SHIFT 16 /* add new flags before this one */ @@ -91,6 +102,8 @@ struct gpio_desc { int gpiod_request(struct gpio_desc *desc, const char *label); void gpiod_free(struct gpio_desc *desc); +int gpiod_hog(struct gpio_desc *desc, const char *name, + unsigned long lflags, enum gpiod_flags dflags); /* * Return the GPIO number of the passed descriptor relative to its chip |