diff options
84 files changed, 3459 insertions, 688 deletions
diff --git a/Documentation/devicetree/bindings/gpio/brcm,bcm6345-gpio.txt b/Documentation/devicetree/bindings/gpio/brcm,bcm6345-gpio.txt new file mode 100644 index 000000000000..e7853143fa42 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/brcm,bcm6345-gpio.txt @@ -0,0 +1,46 @@ +Bindings for the Broadcom's brcm,bcm6345-gpio memory-mapped GPIO controllers. + +These bindings can be used on any BCM63xx SoC. However, BCM6338 and BCM6345 +are the only ones which don't need a pinctrl driver. +BCM6338 have 8-bit data and dirout registers, where GPIO state can be read +and/or written, and the direction changed from input to output. +BCM6345 have 16-bit data and dirout registers, where GPIO state can be read +and/or written, and the direction changed from input to output. + +Required properties: + - compatible: should be "brcm,bcm6345-gpio" + - reg-names: must contain + "dat" - data register + "dirout" - direction (output) register + - reg: address + size pairs describing the GPIO register sets; + order must correspond with the order of entries in reg-names + - #gpio-cells: must be set to 2. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low + - gpio-controller: Marks the device node as a gpio controller. + +Optional properties: + - native-endian: use native endian memory. + +Examples: + - BCM6338: + gpio: gpio-controller@fffe0407 { + compatible = "brcm,bcm6345-gpio"; + reg-names = "dirout", "dat"; + reg = <0xfffe0407 1>, <0xfffe040f 1>; + + #gpio-cells = <2>; + gpio-controller; + }; + + - BCM6345: + gpio: gpio-controller@fffe0406 { + compatible = "brcm,bcm6345-gpio"; + reg-names = "dirout", "dat"; + reg = <0xfffe0406 2>, <0xfffe040a 2>; + native-endian; + + #gpio-cells = <2>; + gpio-controller; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt b/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt new file mode 100644 index 000000000000..393bb2ed8a77 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt @@ -0,0 +1,36 @@ +Aspeed GPIO controller Device Tree Bindings +------------------------------------------- + +Required properties: +- compatible : Either "aspeed,ast2400-gpio" or "aspeed,ast2500-gpio" + +- #gpio-cells : Should be two + - First cell is the GPIO line number + - Second cell is used to specify optional + parameters (unused) + +- reg : Address and length of the register set for the device +- gpio-controller : Marks the device node as a GPIO controller. +- interrupts : Interrupt specifier (see interrupt bindings for + details) +- interrupt-controller : Mark the GPIO controller as an interrupt-controller + +Optional properties: + +- interrupt-parent : The parent interrupt controller, optional if inherited + +The gpio and interrupt properties are further described in their respective +bindings documentation: + +- Documentation/devicetree/bindings/gpio/gpio.txt +- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + + Example: + gpio@1e780000 { + #gpio-cells = <2>; + compatible = "aspeed,ast2400-gpio"; + gpio-controller; + interrupts = <20>; + reg = <0x1e780000 0x1000>; + interrupt-controller; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt new file mode 100644 index 000000000000..a6611304dd3c --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt @@ -0,0 +1,30 @@ +AXP209 GPIO controller + +This driver follows the usual GPIO bindings found in +Documentation/devicetree/bindings/gpio/gpio.txt + +Required properties: +- compatible: Should be "x-powers,axp209-gpio" +- #gpio-cells: Should be two. The first cell is the pin number and the + second is the GPIO flags. +- gpio-controller: Marks the device node as a GPIO controller. + +This node must be a subnode of the axp20x PMIC, documented in +Documentation/devicetree/bindings/mfd/axp20x.txt + +Example: + +axp209: pmic@34 { + compatible = "x-powers,axp209"; + reg = <0x34>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <1>; + + axp_gpio: gpio { + compatible = "x-powers,axp209-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; +}; diff --git a/Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt b/Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt new file mode 100644 index 000000000000..1afc2de7a537 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt @@ -0,0 +1,16 @@ +TPIC2810 GPIO controller bindings + +Required properties: + - compatible : Should be "ti,tpic2810". + - reg : The I2C address of the device + - gpio-controller : Marks the device node as a GPIO controller. + - #gpio-cells : Should be two. For consumer use see gpio.txt. + +Example: + + gpio@60 { + compatible = "ti,tpic2810"; + reg = <0x60>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt b/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt deleted file mode 100644 index ba051074bedc..000000000000 --- a/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt +++ /dev/null @@ -1,16 +0,0 @@ -* TPS65086 GPO Controller bindings - -Required properties: - - compatible : Should be "ti,tps65086-gpio". - - gpio-controller : Marks the device node as a GPIO Controller. - - #gpio-cells : Should be two. The first cell is the pin number - and the second cell is used to specify flags. - See ../gpio/gpio.txt for possible values. - -Example: - - gpio4: gpio { - compatible = "ti,tps65086-gpio"; - gpio-controller; - #gpio-cells = <2>; - }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-ts4900.txt b/Documentation/devicetree/bindings/gpio/gpio-ts4900.txt new file mode 100644 index 000000000000..3f8e71b1ab2a --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-ts4900.txt @@ -0,0 +1,30 @@ +* Technologic Systems I2C-FPGA's GPIO controller bindings + +This bindings describes the GPIO controller for Technologic's FPGA core. +TS-4900's FPGA encodes the GPIO state on 3 bits, whereas the TS-7970's FPGA +uses 2 bits: it doesn't use a dedicated input bit. + +Required properties: +- compatible: Should be one of the following + "technologic,ts4900-gpio" + "technologic,ts7970-gpio" +- reg: Physical base address of the controller and length + of memory mapped region. +- #gpio-cells: Should be two. The first cell is the pin number. +- gpio-controller: Marks the device node as a gpio controller. + +Optional property: +- ngpios: Number of GPIOs this controller is instantiated with, + the default is 32. See gpio.txt for more details. + +Example: + +&i2c2 { + gpio8: gpio@28 { + compatible = "technologic,ts4900-gpio"; + reg = <0x28>; + #gpio-cells = <2>; + gpio-controller; + ngpios = <32>; + }; +}; diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt index 98d198396956..c3d016532d8e 100644 --- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt @@ -44,26 +44,3 @@ Example for a PXA3xx platform: interrupt-controller; #interrupt-cells = <0x2>; }; - -* Marvell Orion GPIO Controller - -Required properties: -- compatible : Should be "marvell,orion-gpio" -- reg : Address and length of the register set for controller. -- gpio-controller : So we know this is a gpio controller. -- ngpio : How many gpios this controller has. -- interrupts : Up to 4 Interrupts for the controller. - -Optional properties: -- mask-offset : For SMP Orions, offset for Nth CPU - -Example: - - gpio0: gpio@10100 { - compatible = "marvell,orion-gpio"; - #gpio-cells = <2>; - gpio-controller; - reg = <0x10100 0x40>; - ngpio = <32>; - interrupts = <35>, <36>, <37>, <38>; - }; diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index 8da26b35b5c3..7c1ab3b3254f 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -11,6 +11,7 @@ Required Properties: - "renesas,gpio-r8a7793": for R8A7793 (R-Car M2-N) compatible GPIO controller. - "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller. - "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller. + - "renesas,gpio-r8a7796": for R8A7796 (R-Car M3-W) compatible GPIO controller. - "renesas,gpio-rcar": for generic R-Car GPIO controller. - reg: Base address and length of each memory resource used by the GPIO diff --git a/Documentation/devicetree/bindings/mfd/stmpe.txt b/Documentation/devicetree/bindings/mfd/stmpe.txt index 3fb68bfefc8b..f9065a5781a2 100644 --- a/Documentation/devicetree/bindings/mfd/stmpe.txt +++ b/Documentation/devicetree/bindings/mfd/stmpe.txt @@ -4,7 +4,7 @@ STMPE is an MFD device which may expose the following inbuilt devices: gpio, keypad, touchscreen, adc, pwm, rotator. Required properties: - - compatible : "st,stmpe[610|801|811|1601|2401|2403]" + - compatible : "st,stmpe[610|801|811|1600|1601|2401|2403]" - reg : I2C/SPI address of the device Optional properties: diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt index 86d3fa95fd12..40884c4fe40c 100644 --- a/Documentation/gpio/board.txt +++ b/Documentation/gpio/board.txt @@ -8,9 +8,9 @@ gpio-legacy.txt (actually, there is no real mapping possible with the old interface; you just fetch an integer from somewhere and request the corresponding GPIO. -Platforms that make use of GPIOs must select ARCH_REQUIRE_GPIOLIB (if GPIO usage -is mandatory) or ARCH_WANT_OPTIONAL_GPIOLIB (if GPIO support can be omitted) in -their Kconfig. Then, how GPIOs are mapped depends on what the platform uses to +All platforms can enable the GPIO library, but if the platform strictly +requires GPIO functionality to be present, it needs to select GPIOLIB from its +Kconfig. Then, how GPIOs are mapped depends on what the platform uses to describe its hardware layout. Currently, mappings can be defined through device tree, ACPI, and platform data. diff --git a/Documentation/gpio/gpio-legacy.txt b/Documentation/gpio/gpio-legacy.txt index 79ab5648d69b..b34fd94f7089 100644 --- a/Documentation/gpio/gpio-legacy.txt +++ b/Documentation/gpio/gpio-legacy.txt @@ -72,8 +72,8 @@ in this document, but drivers acting as clients to the GPIO interface must not care how it's implemented.) That said, if the convention is supported on their platform, drivers should -use it when possible. Platforms must select ARCH_REQUIRE_GPIOLIB or -ARCH_WANT_OPTIONAL_GPIOLIB in their Kconfig. Drivers that can't work without +use it when possible. Platforms must select GPIOLIB if GPIO functionality +is strictly required. Drivers that can't work without standard GPIO calls should have Kconfig entries which depend on GPIOLIB. The GPIO calls are available, either as "real code" or as optimized-away stubs, when drivers use the include file: @@ -553,22 +553,14 @@ either NULL or the label associated with that GPIO when it was requested. Platform Support ---------------- -To support this framework, a platform's Kconfig will "select" either -ARCH_REQUIRE_GPIOLIB or ARCH_WANT_OPTIONAL_GPIOLIB -and arrange that its <asm/gpio.h> includes <asm-generic/gpio.h> and defines -three functions: gpio_get_value(), gpio_set_value(), and gpio_cansleep(). +To force-enable this framework, a platform's Kconfig will "select" GPIOLIB, +else it is up to the user to configure support for GPIO. It may also provide a custom value for ARCH_NR_GPIOS, so that it better reflects the number of GPIOs in actual use on that platform, without wasting static table space. (It should count both built-in/SoC GPIOs and also ones on GPIO expanders. -ARCH_REQUIRE_GPIOLIB means that the gpiolib code will always get compiled -into the kernel on that architecture. - -ARCH_WANT_OPTIONAL_GPIOLIB means the gpiolib code defaults to off and the user -can enable it and build it into the kernel optionally. - If neither of these options are selected, the platform does not support GPIOs through GPIO-lib and the code cannot be enabled by the user. diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index fcf05a07b06a..6fa1d8ab973c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1374,6 +1374,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Format: <unsigned int> such that (rxsize & ~0x1fffc0) == 0. Default: 1024 + gpio-mockup.gpio_mockup_ranges + [HW] Sets the ranges of gpiochip of for this device. + Format: <start1>,<end1>,<start2>,<end2>... + hardlockup_all_cpu_backtrace= [KNL] Should the hard-lockup detector generate backtraces on all cpus. diff --git a/MAINTAINERS b/MAINTAINERS index f4b944c2683a..4f4d56123099 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3794,6 +3794,12 @@ F: include/linux/regulator/da9211.h F: include/sound/da[79]*.h F: sound/soc/codecs/da[79]*.[ch] +DIAMOND SYSTEMS GPIO-MM GPIO DRIVER +M: William Breathitt Gray <vilhelm.gray@gmail.com> +L: linux-gpio@vger.kernel.org +S: Maintained +F: drivers/gpio/gpio-gpio-mm.c + DIGI NEO AND CLASSIC PCI PRODUCTS M: Lidza Louina <lidza.louina@gmail.com> M: Mark Hounschell <markh@compro.net> @@ -5274,6 +5280,13 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/input/touchscreen/goodix.c +GPIO MOCKUP DRIVER +M: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org> +L: linux-gpio@vger.kernel.org +S: Maintained +F: drivers/gpio/gpio-mockup.c +F: tools/testing/selftests/gpio/ + GPIO SUBSYSTEM M: Linus Walleij <linus.walleij@linaro.org> M: Alexandre Courbot <gnurou@gmail.com> diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index a5ab712c1a59..6d3af43ae3e4 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -29,6 +29,7 @@ #include <linux/power/isp1704_charger.h> #include <linux/platform_data/spi-omap2-mcspi.h> #include <linux/platform_data/mtd-onenand-omap2.h> +#include <linux/module.h> #include <plat/dmtimer.h> diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index 4a2f9aba93ea..66184f5cbe40 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -24,10 +24,10 @@ #include <linux/input.h> #include <linux/input/navpoint.h> #include <linux/lcd.h> -#include <linux/mfd/htc-egpio.h> #include <linux/mfd/asic3.h> #include <linux/mtd/physmap.h> #include <linux/pda_power.h> +#include <linux/platform_data/gpio-htc-egpio.h> #include <linux/pwm.h> #include <linux/pwm_backlight.h> #include <linux/regulator/driver.h> diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index abc918169367..265f48be32c1 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -20,10 +20,10 @@ #include <linux/gpio.h> #include <linux/gpio_keys.h> #include <linux/input.h> -#include <linux/mfd/htc-egpio.h> #include <linux/mfd/htc-pasic3.h> #include <linux/mtd/physmap.h> #include <linux/pda_power.h> +#include <linux/platform_data/gpio-htc-egpio.h> #include <linux/pwm.h> #include <linux/pwm_backlight.h> #include <linux/regulator/driver.h> diff --git a/arch/arm/mach-sa1100/h3xxx.c b/arch/arm/mach-sa1100/h3xxx.c index b1d4faa12f9a..b69e76614d5b 100644 --- a/arch/arm/mach-sa1100/h3xxx.c +++ b/arch/arm/mach-sa1100/h3xxx.c @@ -14,9 +14,9 @@ #include <linux/gpio.h> #include <linux/gpio_keys.h> #include <linux/input.h> -#include <linux/mfd/htc-egpio.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/platform_data/gpio-htc-egpio.h> #include <linux/platform_data/sa11x0-serial.h> #include <linux/platform_device.h> #include <linux/serial_core.h> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 7d6bcf6339e1..01600401a53e 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -17,7 +17,6 @@ config ARM64 select ARCH_USE_CMPXCHG_LOCKREF select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_NUMA_BALANCING - select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_WANT_COMPAT_IPC_PARSE_VERSION select ARCH_WANT_FRAME_POINTERS select ARCH_HAS_UBSAN_SANITIZE_ALL diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 96ef543f6bd8..b6b36570b1c0 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -15,8 +15,8 @@ config ARCH_ALPINE config ARCH_BCM2835 bool "Broadcom BCM2835 family" - select ARCH_REQUIRE_GPIOLIB select CLKSRC_OF + select GPIOLIB select PINCTRL select PINCTRL_BCM2835 select ARM_AMBA @@ -29,15 +29,15 @@ config ARCH_BCM2835 config ARCH_BCM_IPROC bool "Broadcom iProc SoC Family" select COMMON_CLK_IPROC + select GPIOLIB select PINCTRL - select ARCH_REQUIRE_GPIOLIB help This enables support for Broadcom iProc based SoCs config ARCH_BERLIN bool "Marvell Berlin SoC Family" - select ARCH_REQUIRE_GPIOLIB select DW_APB_ICTL + select GPIOLIB select PINCTRL help This enables support for Marvell Berlin SoC Family @@ -110,7 +110,7 @@ config ARCH_QCOM config ARCH_ROCKCHIP bool "Rockchip Platforms" select ARCH_HAS_RESET_CONTROLLER - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select PINCTRL select PINCTRL_ROCKCHIP select ROCKCHIP_TIMER @@ -156,11 +156,11 @@ config ARCH_STRATIX10 config ARCH_TEGRA bool "NVIDIA Tegra SoC Family" select ARCH_HAS_RESET_CONTROLLER - select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP select CLKSRC_MMIO select CLKSRC_OF select GENERIC_CLOCKEVENTS + select GPIOLIB select PINCTRL select RESET_CONTROLLER help @@ -184,8 +184,8 @@ config ARCH_UNIPHIER config ARCH_VEXPRESS bool "ARMv8 software model (Versatile Express)" - select ARCH_REQUIRE_GPIOLIB select COMMON_CLK_VERSATILE + select GPIOLIB select PM select PM_GENERIC_DOMAINS select POWER_RESET_VEXPRESS diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 28c63fea786d..3c1bd640042a 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -26,7 +26,7 @@ config BLACKFIN select HAVE_OPROFILE select HAVE_PERF_EVENTS select ARCH_HAVE_CUSTOM_GPIO_H - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select HAVE_UID16 select HAVE_UNDERSCORE_SYMBOL_PREFIX select VIRT_TO_BUS diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 24caedb00a7a..26ee00f6bd58 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -10,27 +10,6 @@ config ARCH_HAVE_CUSTOM_GPIO_H overriding the default implementations. New uses of this are strongly discouraged. -config ARCH_WANT_OPTIONAL_GPIOLIB - bool - help - Select this config option from the architecture Kconfig, if - it is possible to use gpiolib on the architecture, but let the - user decide whether to actually build it or not. - Select this instead of ARCH_REQUIRE_GPIOLIB, if your architecture does - not depend on GPIOs being available, but rather let the user - decide whether he needs it or not. - -config ARCH_REQUIRE_GPIOLIB - bool - select GPIOLIB - help - Platforms select gpiolib if they use this infrastructure - for all their GPIOs, usually starting with ones integrated - into SOC processors. - Selecting this from the architecture code will cause the gpiolib - code to always get built in. - - menuconfig GPIOLIB bool "GPIO Support" select ANON_INODES @@ -87,6 +66,7 @@ config GPIO_SYSFS exported to userspace; this can be useful when debugging. config GPIO_GENERIC + depends on HAS_IOMEM # Only for IOMEM drivers tristate # put drivers in the right section, in alphabetical order @@ -96,6 +76,7 @@ config GPIO_MAX730X tristate menu "Memory mapped GPIO drivers" + depends on HAS_IOMEM config GPIO_74XX_MMIO tristate "GPIO driver for 74xx-ICs with MMIO access" @@ -128,6 +109,13 @@ config GPIO_AMDPT driver for GPIO functionality on Promontory IOHub Require ACPI ASL code to enumerate as a platform device. +config GPIO_ASPEED + tristate "Aspeed GPIO support" + depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO + select GPIOLIB_IRQCHIP + help + Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers. + config GPIO_ATH79 tristate "Atheros AR71XX/AR724X/AR913X GPIO support" default y if ATH79 @@ -138,6 +126,12 @@ config GPIO_ATH79 Select this option to enable GPIO driver for Atheros AR71XX/AR724X/AR913X SoC devices. +config GPIO_AXP209 + tristate "X-Powers AXP209 PMIC GPIO Support" + depends on MFD_AXP20X + help + Say yes to enable GPIO support for the AXP209 PMIC + config GPIO_BCM_KONA bool "Broadcom Kona GPIO" depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) @@ -237,7 +231,8 @@ config GPIO_ICH config GPIO_IOP tristate "Intel IOP GPIO" - depends on ARM && (ARCH_IOP32X || ARCH_IOP33X) + depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST + select GPIO_GENERIC help Say yes here to support the GPIO functionality of a number of Intel IOP32X or IOP33X. @@ -287,6 +282,18 @@ config GPIO_MM_LANTIQ (EBU) found on Lantiq SoCs. The gpios are output only as they are created by attaching a 16bit latch to the bus. +config GPIO_MOCKUP + tristate "GPIO Testing Driver" + depends on GPIOLIB + select GPIO_SYSFS + help + This enables GPIO Testing driver, which provides a way to test GPIO + subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS + must be selected for this test. + User could use it through the script in + tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in + it. + config GPIO_MOXART bool "MOXART GPIO support" depends on ARCH_MOXART || COMPILE_TEST @@ -574,6 +581,19 @@ config GPIO_F7188X To compile this driver as a module, choose M here: the module will be called f7188x-gpio. +config GPIO_GPIO_MM + tristate "Diamond Systems GPIO-MM GPIO support" + depends on ISA_BUS_API + help + Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12. + + The Diamond Systems GPIO-MM device features 48 lines of digital I/O + via the emulation of dual 82C55A PPI chips. This driver provides GPIO + support for these 48 channels of digital I/O. + + The base port addresses for the devices may be configured via the base + array module parameter. + config GPIO_IT87 tristate "IT87xx GPIO support" help @@ -780,6 +800,13 @@ config GPIO_TPIC2810 To compile this driver as a module, choose M here: the module will be called gpio-tpic2810. +config GPIO_TS4900 + tristate "Technologic Systems FPGA I2C GPIO" + select REGMAP_I2C + help + Say yes here to enabled the GPIO driver for Technologic's FPGA core. + Series supported include TS-4100, TS-4900, TS-7970 and TS-7990. + endmenu menu "MFD GPIO expanders" @@ -849,6 +876,14 @@ config GPIO_DLN2 This driver can also be built as a module. If so, the module will be called gpio-dln2. +config HTC_EGPIO + bool "HTC EGPIO support" + depends on GPIOLIB && ARM + help + This driver supports the CPLD egpio chip present on + several HTC phones. It provides basic support for input + pins, output pins, and irqs. + config GPIO_JANZ_TTL tristate "Janz VMOD-TTL Digital IO Module" depends on MFD_JANZ_CMODIO @@ -875,6 +910,16 @@ config GPIO_LP3943 LP3943 can be used as a GPIO expander which provides up to 16 GPIOs. Open drain outputs are required for this usage. +config GPIO_LP873X + tristate "TI LP873X GPO" + depends on MFD_TI_LP873X + help + This driver supports the GPO on TI Lp873x PMICs. 2 GPOs are present + on LP873X PMICs. + + This driver can also be built as a module. If so, the module will be + called gpio-lp873x. + config GPIO_MAX77620 tristate "GPIO support for PMIC MAX77620 and MAX20024" depends on MFD_MAX77620 @@ -985,6 +1030,19 @@ config GPIO_UCB1400 This enables support for the Philips UCB1400 GPIO pins. The UCB1400 is an AC97 audio codec. +config GPIO_WHISKEY_COVE + tristate "GPIO support for Whiskey Cove PMIC" + depends on INTEL_SOC_PMIC + select GPIOLIB_IRQCHIP + help + Support for GPIO pins on Whiskey Cove PMIC. + + Say Yes if you have a Intel SoC based tablet with Whiskey Cove PMIC + inside. + + This driver can also be built as a module. If so, the module will be + called gpio-wcove. + config GPIO_WM831X tristate "WM831x GPIOs" depends on MFD_WM831X diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 2a035ed8f168..ab28a2daeacc 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -28,6 +28,8 @@ obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o +obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o +obj-$(CONFIG_GPIO_AXP209) += gpio-axp209.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o @@ -44,7 +46,9 @@ obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o +obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o +obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o obj-$(CONFIG_GPIO_IOP) += gpio-iop.o obj-$(CONFIG_GPIO_IT87) += gpio-it87.o @@ -56,6 +60,7 @@ obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o +obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o @@ -70,6 +75,7 @@ obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o +obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o @@ -110,6 +116,7 @@ obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o +obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o @@ -120,6 +127,7 @@ obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o +obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 3f87a03abc22..5bddbd507ca9 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -17,6 +17,7 @@ */ #include <linux/io.h> +#include <linux/module.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 991370494922..482462889c8f 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -79,7 +79,7 @@ static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ARIZONA_GPN_LVL, value); } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "arizona", .owner = THIS_MODULE, .direction_input = arizona_gpio_direction_in, diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c new file mode 100644 index 000000000000..03a5925a423c --- /dev/null +++ b/drivers/gpio/gpio-aspeed.c @@ -0,0 +1,455 @@ +/* + * Copyright 2015 IBM Corp. + * + * Joel Stanley <joel@jms.id.au> + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/gpio/driver.h> +#include <linux/pinctrl/consumer.h> + +struct aspeed_gpio { + struct gpio_chip chip; + spinlock_t lock; + void __iomem *base; + int irq; +}; + +struct aspeed_gpio_bank { + uint16_t val_regs; + uint16_t irq_regs; + const char names[4]; +}; + +static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { + { + .val_regs = 0x0000, + .irq_regs = 0x0008, + .names = { 'A', 'B', 'C', 'D' }, + }, + { + .val_regs = 0x0020, + .irq_regs = 0x0028, + .names = { 'E', 'F', 'G', 'H' }, + }, + { + .val_regs = 0x0070, + .irq_regs = 0x0098, + .names = { 'I', 'J', 'K', 'L' }, + }, + { + .val_regs = 0x0078, + .irq_regs = 0x00e8, + .names = { 'M', 'N', 'O', 'P' }, + }, + { + .val_regs = 0x0080, + .irq_regs = 0x0118, + .names = { 'Q', 'R', 'S', 'T' }, + }, + { + .val_regs = 0x0088, + .irq_regs = 0x0148, + .names = { 'U', 'V', 'W', 'X' }, + }, + /* + * A bank exists for { 'Y', 'Z', "AA", "AB" }, but is not implemented. + * Only half of GPIOs Y support interrupt configuration, and none of Z, + * AA or AB do as they are output only. + */ +}; + +#define GPIO_BANK(x) ((x) >> 5) +#define GPIO_OFFSET(x) ((x) & 0x1f) +#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) + +#define GPIO_DATA 0x00 +#define GPIO_DIR 0x04 + +#define GPIO_IRQ_ENABLE 0x00 +#define GPIO_IRQ_TYPE0 0x04 +#define GPIO_IRQ_TYPE1 0x08 +#define GPIO_IRQ_TYPE2 0x0c +#define GPIO_IRQ_STATUS 0x10 + +static const struct aspeed_gpio_bank *to_bank(unsigned int offset) +{ + unsigned int bank = GPIO_BANK(offset); + + WARN_ON(bank > ARRAY_SIZE(aspeed_gpio_banks)); + return &aspeed_gpio_banks[bank]; +} + +static void __iomem *bank_val_reg(struct aspeed_gpio *gpio, + const struct aspeed_gpio_bank *bank, + unsigned int reg) +{ + return gpio->base + bank->val_regs + reg; +} + +static void __iomem *bank_irq_reg(struct aspeed_gpio *gpio, + const struct aspeed_gpio_bank *bank, + unsigned int reg) +{ + return gpio->base + bank->irq_regs + reg; +} + +static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(gc); + const struct aspeed_gpio_bank *bank = to_bank(offset); + + return !!(ioread32(bank_val_reg(gpio, bank, GPIO_DATA)) + & GPIO_BIT(offset)); +} + +static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, + int val) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(gc); + const struct aspeed_gpio_bank *bank = to_bank(offset); + void __iomem *addr; + u32 reg; + + addr = bank_val_reg(gpio, bank, GPIO_DATA); + reg = ioread32(addr); + + if (val) + reg |= GPIO_BIT(offset); + else + reg &= ~GPIO_BIT(offset); + + iowrite32(reg, addr); +} + +static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, + int val) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&gpio->lock, flags); + + __aspeed_gpio_set(gc, offset, val); + + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(gc); + const struct aspeed_gpio_bank *bank = to_bank(offset); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&gpio->lock, flags); + + reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)); + iowrite32(reg & ~GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR)); + + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int aspeed_gpio_dir_out(struct gpio_chip *gc, + unsigned int offset, int val) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(gc); + const struct aspeed_gpio_bank *bank = to_bank(offset); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&gpio->lock, flags); + + reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)); + iowrite32(reg | GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR)); + + __aspeed_gpio_set(gc, offset, val); + + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(gc); + const struct aspeed_gpio_bank *bank = to_bank(offset); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gpio->lock, flags); + + val = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)) & GPIO_BIT(offset); + + spin_unlock_irqrestore(&gpio->lock, flags); + + return !val; + +} + +static inline int irqd_to_aspeed_gpio_data(struct irq_data *d, + struct aspeed_gpio **gpio, + const struct aspeed_gpio_bank **bank, + u32 *bit) +{ + int offset; + + offset = irqd_to_hwirq(d); + + *gpio = irq_data_get_irq_chip_data(d); + *bank = to_bank(offset); + *bit = GPIO_BIT(offset); + + return 0; +} + +static void aspeed_gpio_irq_ack(struct irq_data *d) +{ + const struct aspeed_gpio_bank *bank; + struct aspeed_gpio *gpio; + unsigned long flags; + void __iomem *status_addr; + u32 bit; + int rc; + + rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit); + if (rc) + return; + + status_addr = bank_irq_reg(gpio, bank, GPIO_IRQ_STATUS); + + spin_lock_irqsave(&gpio->lock, flags); + iowrite32(bit, status_addr); + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) +{ + const struct aspeed_gpio_bank *bank; + struct aspeed_gpio *gpio; + unsigned long flags; + u32 reg, bit; + void __iomem *addr; + int rc; + + rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit); + if (rc) + return; + + addr = bank_irq_reg(gpio, bank, GPIO_IRQ_ENABLE); + + spin_lock_irqsave(&gpio->lock, flags); + + reg = ioread32(addr); + if (set) + reg |= bit; + else + reg &= bit; + iowrite32(reg, addr); + + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static void aspeed_gpio_irq_mask(struct irq_data *d) +{ + aspeed_gpio_irq_set_mask(d, false); +} + +static void aspeed_gpio_irq_unmask(struct irq_data *d) +{ + aspeed_gpio_irq_set_mask(d, true); +} + +static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) +{ + u32 type0 = 0; + u32 type1 = 0; + u32 type2 = 0; + u32 bit, reg; + const struct aspeed_gpio_bank *bank; + irq_flow_handler_t handler; + struct aspeed_gpio *gpio; + unsigned long flags; + void __iomem *addr; + int rc; + + rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit); + if (rc) + return -EINVAL; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_BOTH: + type2 |= bit; + case IRQ_TYPE_EDGE_RISING: + type0 |= bit; + case IRQ_TYPE_EDGE_FALLING: + handler = handle_edge_irq; + break; + case IRQ_TYPE_LEVEL_HIGH: + type0 |= bit; + case IRQ_TYPE_LEVEL_LOW: + type1 |= bit; + handler = handle_level_irq; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&gpio->lock, flags); + + addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE0); + reg = ioread32(addr); + reg = (reg & ~bit) | type0; + iowrite32(reg, addr); + + addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE1); + reg = ioread32(addr); + reg = (reg & ~bit) | type1; + iowrite32(reg, addr); + + addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE2); + reg = ioread32(addr); + reg = (reg & ~bit) | type2; + iowrite32(reg, addr); + + spin_unlock_irqrestore(&gpio->lock, flags); + + irq_set_handler_locked(d, handler); + + return 0; +} + +static void aspeed_gpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct irq_chip *ic = irq_desc_get_chip(desc); + struct aspeed_gpio *data = gpiochip_get_data(gc); + unsigned int i, p, girq; + unsigned long reg; + + chained_irq_enter(ic, desc); + + for (i = 0; i < ARRAY_SIZE(aspeed_gpio_banks); i++) { + const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; + + reg = ioread32(bank_irq_reg(data, bank, GPIO_IRQ_STATUS)); + + for_each_set_bit(p, ®, 32) { + girq = irq_find_mapping(gc->irqdomain, i * 32 + p); + generic_handle_irq(girq); + } + + } + + chained_irq_exit(ic, desc); +} + +static struct irq_chip aspeed_gpio_irqchip = { + .name = "aspeed-gpio", + .irq_ack = aspeed_gpio_irq_ack, + .irq_mask = aspeed_gpio_irq_mask, + .irq_unmask = aspeed_gpio_irq_unmask, + .irq_set_type = aspeed_gpio_set_type, +}; + +static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio, + struct platform_device *pdev) +{ + int rc; + + rc = platform_get_irq(pdev, 0); + if (rc < 0) + return rc; + + gpio->irq = rc; + + rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_gpio_irqchip, + 0, handle_bad_irq, IRQ_TYPE_NONE); + if (rc) { + dev_info(&pdev->dev, "Could not add irqchip\n"); + return rc; + } + + gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_gpio_irqchip, + gpio->irq, aspeed_gpio_irq_handler); + + return 0; +} + +static int aspeed_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void aspeed_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + pinctrl_free_gpio(chip->base + offset); +} + +static int __init aspeed_gpio_probe(struct platform_device *pdev) +{ + struct aspeed_gpio *gpio; + struct resource *res; + int rc; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gpio->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio->base)) + return PTR_ERR(gpio->base); + + spin_lock_init(&gpio->lock); + + gpio->chip.ngpio = ARRAY_SIZE(aspeed_gpio_banks) * 32; + + gpio->chip.parent = &pdev->dev; + gpio->chip.direction_input = aspeed_gpio_dir_in; + gpio->chip.direction_output = aspeed_gpio_dir_out; + gpio->chip.get_direction = aspeed_gpio_get_direction; + gpio->chip.request = aspeed_gpio_request; + gpio->chip.free = aspeed_gpio_free; + gpio->chip.get = aspeed_gpio_get; + gpio->chip.set = aspeed_gpio_set; + gpio->chip.label = dev_name(&pdev->dev); + gpio->chip.base = -1; + + rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); + if (rc < 0) + return rc; + + return aspeed_gpio_setup_irqs(gpio, pdev); +} + +static const struct of_device_id aspeed_gpio_of_table[] = { + { .compatible = "aspeed,ast2400-gpio" }, + { .compatible = "aspeed,ast2500-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table); + +static struct platform_driver aspeed_gpio_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = aspeed_gpio_of_table, + }, +}; + +module_platform_driver_probe(aspeed_gpio_driver, aspeed_gpio_probe); + +MODULE_DESCRIPTION("Aspeed GPIO Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index c4f4cddc7c1a..9457e2022bf6 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -15,6 +15,7 @@ #include <linux/platform_data/gpio-ath79.h> #include <linux/of_device.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/irq.h> #define AR71XX_GPIO_REG_OE 0x00 diff --git a/drivers/gpio/gpio-axp209.c b/drivers/gpio/gpio-axp209.c new file mode 100644 index 000000000000..d9c2a517c6df --- /dev/null +++ b/drivers/gpio/gpio-axp209.c @@ -0,0 +1,192 @@ +/* + * AXP20x GPIO driver + * + * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.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/bitops.h> +#include <linux/device.h> +#include <linux/gpio/driver.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/axp20x.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#define AXP20X_GPIO_FUNCTIONS 0x7 +#define AXP20X_GPIO_FUNCTION_OUT_LOW 0 +#define AXP20X_GPIO_FUNCTION_OUT_HIGH 1 +#define AXP20X_GPIO_FUNCTION_INPUT 2 + +struct axp20x_gpio { + struct gpio_chip chip; + struct regmap *regmap; +}; + +static int axp20x_gpio_get_reg(unsigned offset) +{ + switch (offset) { + case 0: + return AXP20X_GPIO0_CTRL; + case 1: + return AXP20X_GPIO1_CTRL; + case 2: + return AXP20X_GPIO2_CTRL; + } + + return -EINVAL; +} + +static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset) +{ + struct axp20x_gpio *gpio = gpiochip_get_data(chip); + int reg; + + reg = axp20x_gpio_get_reg(offset); + if (reg < 0) + return reg; + + return regmap_update_bits(gpio->regmap, reg, + AXP20X_GPIO_FUNCTIONS, + AXP20X_GPIO_FUNCTION_INPUT); +} + +static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct axp20x_gpio *gpio = gpiochip_get_data(chip); + unsigned int val; + int reg, ret; + + reg = axp20x_gpio_get_reg(offset); + if (reg < 0) + return reg; + + ret = regmap_read(gpio->regmap, reg, &val); + if (ret) + return ret; + + return !!(val & BIT(offset + 4)); +} + +static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct axp20x_gpio *gpio = gpiochip_get_data(chip); + unsigned int val; + int reg, ret; + + reg = axp20x_gpio_get_reg(offset); + if (reg < 0) + return reg; + + ret = regmap_read(gpio->regmap, reg, &val); + if (ret) + return ret; + + /* + * This shouldn't really happen if the pin is in use already, + * or if it's not in use yet, it doesn't matter since we're + * going to change the value soon anyway. Default to output. + */ + if ((val & AXP20X_GPIO_FUNCTIONS) > 2) + return 0; + + /* + * The GPIO directions are the three lowest values. + * 2 is input, 0 and 1 are output + */ + return val & 2; +} + +static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct axp20x_gpio *gpio = gpiochip_get_data(chip); + int reg; + + reg = axp20x_gpio_get_reg(offset); + if (reg < 0) + return reg; + + return regmap_update_bits(gpio->regmap, reg, + AXP20X_GPIO_FUNCTIONS, + value ? AXP20X_GPIO_FUNCTION_OUT_HIGH + : AXP20X_GPIO_FUNCTION_OUT_LOW); +} + +static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + axp20x_gpio_output(chip, offset, value); +} + +static int axp20x_gpio_probe(struct platform_device *pdev) +{ + struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); + struct axp20x_gpio *gpio; + int ret; + + if (!of_device_is_available(pdev->dev.of_node)) + return -ENODEV; + + if (!axp20x) { + dev_err(&pdev->dev, "Parent drvdata not set\n"); + return -EINVAL; + } + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + gpio->chip.base = -1; + gpio->chip.can_sleep = true; + gpio->chip.parent = &pdev->dev; + gpio->chip.label = dev_name(&pdev->dev); + gpio->chip.owner = THIS_MODULE; + gpio->chip.get = axp20x_gpio_get; + gpio->chip.get_direction = axp20x_gpio_get_direction; + gpio->chip.set = axp20x_gpio_set; + gpio->chip.direction_input = axp20x_gpio_input; + gpio->chip.direction_output = axp20x_gpio_output; + gpio->chip.ngpio = 3; + + gpio->regmap = axp20x->regmap; + + ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); + if (ret) { + dev_err(&pdev->dev, "Failed to register GPIO chip\n"); + return ret; + } + + dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n"); + + return 0; +} + +static const struct of_device_id axp20x_gpio_match[] = { + { .compatible = "x-powers,axp209-gpio" }, + { } +}; +MODULE_DEVICE_TABLE(of, axp20x_gpio_match); + +static struct platform_driver axp20x_gpio_driver = { + .probe = axp20x_gpio_probe, + .driver = { + .name = "axp20x-gpio", + .of_match_table = axp20x_gpio_match, + }, +}; + +module_platform_driver(axp20x_gpio_driver); + +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); +MODULE_DESCRIPTION("AXP20x PMIC GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 953e4b829e32..3d1cf018e8e7 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -308,7 +308,7 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, return 0; } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "bcm-kona-gpio", .owner = THIS_MODULE, .request = bcm_kona_gpio_request, diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index e29553b7ccdb..dd8977cf3e85 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -184,7 +184,7 @@ static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset) return irq; } -static struct gpio_chip reference_gp = { +static const struct gpio_chip reference_gp = { .label = "da9052-gpio", .owner = THIS_MODULE, .get = da9052_gpio_get, diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c index 2c2c18dc6c4f..82053b52cba0 100644 --- a/drivers/gpio/gpio-da9055.c +++ b/drivers/gpio/gpio-da9055.c @@ -121,7 +121,7 @@ static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset) DA9055_IRQ_GPI0 + offset); } -static struct gpio_chip reference_gp = { +static const struct gpio_chip reference_gp = { .label = "da9055-gpio", .owner = THIS_MODULE, .get = da9055_gpio_get, diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index 600be8418707..e8accde62aa7 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -214,8 +214,7 @@ static struct f7188x_gpio_bank f81866_gpio_bank[] = { static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { int err; - struct f7188x_gpio_bank *bank = - container_of(chip, struct f7188x_gpio_bank, chip); + struct f7188x_gpio_bank *bank = gpiochip_get_data(chip); struct f7188x_sio *sio = bank->data->sio; u8 dir; diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c new file mode 100644 index 000000000000..1e7def9449ce --- /dev/null +++ b/drivers/gpio/gpio-gpio-mm.c @@ -0,0 +1,267 @@ +/* + * GPIO driver for the Diamond Systems GPIO-MM + * Copyright (C) 2016 William Breathitt Gray + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * 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. + * + * This driver supports the following Diamond Systems devices: GPIO-MM and + * GPIO-MM-12. + */ +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/gpio/driver.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/isa.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/spinlock.h> + +#define GPIOMM_EXTENT 8 +#define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT) + +static unsigned int base[MAX_NUM_GPIOMM]; +static unsigned int num_gpiomm; +module_param_array(base, uint, &num_gpiomm, 0); +MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses"); + +/** + * struct gpiomm_gpio - GPIO device private data structure + * @chip: instance of the gpio_chip + * @io_state: bit I/O state (whether bit is set to input or output) + * @out_state: output bits state + * @control: Control registers state + * @lock: synchronization lock to prevent I/O race conditions + * @base: base port address of the GPIO device + */ +struct gpiomm_gpio { + struct gpio_chip chip; + unsigned char io_state[6]; + unsigned char out_state[6]; + unsigned char control[2]; + spinlock_t lock; + unsigned int base; +}; + +static int gpiomm_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); + const unsigned int port = offset / 8; + const unsigned int mask = BIT(offset % 8); + + return !!(gpiommgpio->io_state[port] & mask); +} + +static int gpiomm_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); + const unsigned int io_port = offset / 8; + const unsigned int control_port = io_port / 3; + const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4; + unsigned long flags; + unsigned int control; + + spin_lock_irqsave(&gpiommgpio->lock, flags); + + /* Check if configuring Port C */ + if (io_port == 2 || io_port == 5) { + /* Port C can be configured by nibble */ + if (offset % 8 > 3) { + gpiommgpio->io_state[io_port] |= 0xF0; + gpiommgpio->control[control_port] |= BIT(3); + } else { + gpiommgpio->io_state[io_port] |= 0x0F; + gpiommgpio->control[control_port] |= BIT(0); + } + } else { + gpiommgpio->io_state[io_port] |= 0xFF; + if (io_port == 0 || io_port == 3) + gpiommgpio->control[control_port] |= BIT(4); + else + gpiommgpio->control[control_port] |= BIT(1); + } + + control = BIT(7) | gpiommgpio->control[control_port]; + outb(control, control_addr); + + spin_unlock_irqrestore(&gpiommgpio->lock, flags); + + return 0; +} + +static int gpiomm_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); + const unsigned int io_port = offset / 8; + const unsigned int control_port = io_port / 3; + const unsigned int mask = BIT(offset % 8); + const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4; + const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port; + unsigned long flags; + unsigned int control; + + spin_lock_irqsave(&gpiommgpio->lock, flags); + + /* Check if configuring Port C */ + if (io_port == 2 || io_port == 5) { + /* Port C can be configured by nibble */ + if (offset % 8 > 3) { + gpiommgpio->io_state[io_port] &= 0x0F; + gpiommgpio->control[control_port] &= ~BIT(3); + } else { + gpiommgpio->io_state[io_port] &= 0xF0; + gpiommgpio->control[control_port] &= ~BIT(0); + } + } else { + gpiommgpio->io_state[io_port] &= 0x00; + if (io_port == 0 || io_port == 3) + gpiommgpio->control[control_port] &= ~BIT(4); + else + gpiommgpio->control[control_port] &= ~BIT(1); + } + + if (value) + gpiommgpio->out_state[io_port] |= mask; + else + gpiommgpio->out_state[io_port] &= ~mask; + + control = BIT(7) | gpiommgpio->control[control_port]; + outb(control, control_addr); + + outb(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port); + + spin_unlock_irqrestore(&gpiommgpio->lock, flags); + + return 0; +} + +static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); + const unsigned int port = offset / 8; + const unsigned int mask = BIT(offset % 8); + const unsigned int in_port = (port > 2) ? port + 1 : port; + unsigned long flags; + unsigned int port_state; + + spin_lock_irqsave(&gpiommgpio->lock, flags); + + /* ensure that GPIO is set for input */ + if (!(gpiommgpio->io_state[port] & mask)) { + spin_unlock_irqrestore(&gpiommgpio->lock, flags); + return -EINVAL; + } + + port_state = inb(gpiommgpio->base + in_port); + + spin_unlock_irqrestore(&gpiommgpio->lock, flags); + + return !!(port_state & mask); +} + +static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); + const unsigned int port = offset / 8; + const unsigned int mask = BIT(offset % 8); + const unsigned int out_port = (port > 2) ? port + 1 : port; + unsigned long flags; + + spin_lock_irqsave(&gpiommgpio->lock, flags); + + if (value) + gpiommgpio->out_state[port] |= mask; + else + gpiommgpio->out_state[port] &= ~mask; + + outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port); + + spin_unlock_irqrestore(&gpiommgpio->lock, flags); +} + +static int gpiomm_probe(struct device *dev, unsigned int id) +{ + struct gpiomm_gpio *gpiommgpio; + const char *const name = dev_name(dev); + int err; + + gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL); + if (!gpiommgpio) + return -ENOMEM; + + if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) { + dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", + base[id], base[id] + GPIOMM_EXTENT); + return -EBUSY; + } + + gpiommgpio->chip.label = name; + gpiommgpio->chip.parent = dev; + gpiommgpio->chip.owner = THIS_MODULE; + gpiommgpio->chip.base = -1; + gpiommgpio->chip.ngpio = 48; + gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction; + gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input; + gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; + gpiommgpio->chip.get = gpiomm_gpio_get; + gpiommgpio->chip.set = gpiomm_gpio_set; + gpiommgpio->base = base[id]; + + spin_lock_init(&gpiommgpio->lock); + + dev_set_drvdata(dev, gpiommgpio); + + err = gpiochip_add_data(&gpiommgpio->chip, gpiommgpio); + if (err) { + dev_err(dev, "GPIO registering failed (%d)\n", err); + return err; + } + + /* initialize all GPIO as output */ + outb(0x80, base[id] + 3); + outb(0x00, base[id]); + outb(0x00, base[id] + 1); + outb(0x00, base[id] + 2); + outb(0x80, base[id] + 7); + outb(0x00, base[id] + 4); + outb(0x00, base[id] + 5); + outb(0x00, base[id] + 6); + + return 0; +} + +static int gpiomm_remove(struct device *dev, unsigned int id) +{ + struct gpiomm_gpio *const gpiommgpio = dev_get_drvdata(dev); + + gpiochip_remove(&gpiommgpio->chip); + + return 0; +} + +static struct isa_driver gpiomm_driver = { + .probe = gpiomm_probe, + .driver = { + .name = "gpio-mm" + }, + .remove = gpiomm_remove +}; + +module_isa_driver(gpiomm_driver, num_gpiomm); + +MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); +MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index 513cfc5c8fb6..0b4df6051097 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -14,10 +14,10 @@ #include <linux/irq.h> #include <linux/io.h> #include <linux/spinlock.h> +#include <linux/platform_data/gpio-htc-egpio.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/mfd/htc-egpio.h> struct egpio_chip { int reg_start; diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c index 860c535922fd..98c7ff2a76e7 100644 --- a/drivers/gpio/gpio-iop.c +++ b/drivers/gpio/gpio-iop.c @@ -10,111 +10,40 @@ * your option) any later version. */ -#include <linux/device.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/gpio.h> -#include <linux/export.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/gpio/driver.h> #include <linux/platform_device.h> -#include <linux/bitops.h> -#include <linux/io.h> -#define IOP3XX_N_GPIOS 8 - -#define GPIO_IN 0 -#define GPIO_OUT 1 -#define GPIO_LOW 0 -#define GPIO_HIGH 1 - -/* Memory base offset */ -static void __iomem *base; - -#define IOP3XX_GPIO_REG(reg) (base + (reg)) -#define IOP3XX_GPOE IOP3XX_GPIO_REG(0x0000) -#define IOP3XX_GPID IOP3XX_GPIO_REG(0x0004) -#define IOP3XX_GPOD IOP3XX_GPIO_REG(0x0008) - -static void gpio_line_config(int line, int direction) -{ - unsigned long flags; - u32 val; - - local_irq_save(flags); - val = readl(IOP3XX_GPOE); - if (direction == GPIO_IN) { - val |= BIT(line); - } else if (direction == GPIO_OUT) { - val &= ~BIT(line); - } - writel(val, IOP3XX_GPOE); - local_irq_restore(flags); -} - -static int gpio_line_get(int line) -{ - return !!(readl(IOP3XX_GPID) & BIT(line)); -} - -static void gpio_line_set(int line, int value) -{ - unsigned long flags; - u32 val; - - local_irq_save(flags); - val = readl(IOP3XX_GPOD); - if (value == GPIO_LOW) { - val &= ~BIT(line); - } else if (value == GPIO_HIGH) { - val |= BIT(line); - } - writel(val, IOP3XX_GPOD); - local_irq_restore(flags); -} - -static int iop3xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) -{ - gpio_line_config(gpio, GPIO_IN); - return 0; -} - -static int iop3xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level) -{ - gpio_line_set(gpio, level); - gpio_line_config(gpio, GPIO_OUT); - return 0; -} - -static int iop3xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio) -{ - return gpio_line_get(gpio); -} - -static void iop3xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) -{ - gpio_line_set(gpio, value); -} - -static struct gpio_chip iop3xx_chip = { - .label = "iop3xx", - .direction_input = iop3xx_gpio_direction_input, - .get = iop3xx_gpio_get_value, - .direction_output = iop3xx_gpio_direction_output, - .set = iop3xx_gpio_set_value, - .base = 0, - .ngpio = IOP3XX_N_GPIOS, -}; +#define IOP3XX_GPOE 0x0000 +#define IOP3XX_GPID 0x0004 +#define IOP3XX_GPOD 0x0008 static int iop3xx_gpio_probe(struct platform_device *pdev) { struct resource *res; + struct gpio_chip *gc; + void __iomem *base; + int err; + + gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); + if (!gc) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) return PTR_ERR(base); - return devm_gpiochip_add_data(&pdev->dev, &iop3xx_chip, NULL); + err = bgpio_init(gc, &pdev->dev, 1, base + IOP3XX_GPID, + base + IOP3XX_GPOD, NULL, NULL, base + IOP3XX_GPOE, 0); + if (err) + return err; + + gc->base = 0; + gc->owner = THIS_MODULE; + + return devm_gpiochip_add_data(&pdev->dev, gc, NULL); } static struct platform_driver iop3xx_gpio_driver = { diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index 63a962d18cd6..45d29e488dbb 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -273,7 +273,7 @@ exit: return rc; } -static struct gpio_chip it87_template_chip = { +static const struct gpio_chip it87_template_chip = { .label = KBUILD_MODNAME, .owner = THIS_MODULE, .request = it87_gpio_request, diff --git a/drivers/gpio/gpio-loongson1.c b/drivers/gpio/gpio-loongson1.c index 10c09bdd8514..72b64039241a 100644 --- a/drivers/gpio/gpio-loongson1.c +++ b/drivers/gpio/gpio-loongson1.c @@ -8,6 +8,7 @@ * warranty of any kind, whether express or implied. */ +#include <linux/module.h> #include <linux/gpio/driver.h> #include <linux/platform_device.h> @@ -55,11 +56,6 @@ static int ls1x_gpio_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "failed to get I/O memory\n"); - return -EINVAL; - } - gpio_reg_base = devm_ioremap_resource(dev, res); if (IS_ERR(gpio_reg_base)) return PTR_ERR(gpio_reg_base); diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c new file mode 100644 index 000000000000..218c706359aa --- /dev/null +++ b/drivers/gpio/gpio-lp873x.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * Keerthy <j-keerthy@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether expressed or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + * + * Based on the TPS65218 driver + */ + +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <linux/mfd/lp873x.h> + +#define BITS_PER_GPO 0x4 +#define LP873X_GPO_CTRL_OD 0x2 + +struct lp873x_gpio { + struct gpio_chip chip; + struct lp873x *lp873; +}; + +static int lp873x_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + /* This device is output only */ + return 0; +} + +static int lp873x_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + /* This device is output only */ + return -EINVAL; +} + +static int lp873x_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct lp873x_gpio *gpio = gpiochip_get_data(chip); + + /* Set the initial value */ + return regmap_update_bits(gpio->lp873->regmap, LP873X_REG_GPO_CTRL, + BIT(offset * BITS_PER_GPO), + value ? BIT(offset * BITS_PER_GPO) : 0); +} + +static int lp873x_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct lp873x_gpio *gpio = gpiochip_get_data(chip); + int ret, val; + + ret = regmap_read(gpio->lp873->regmap, LP873X_REG_GPO_CTRL, &val); + if (ret < 0) + return ret; + + return val & BIT(offset * BITS_PER_GPO); +} + +static void lp873x_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct lp873x_gpio *gpio = gpiochip_get_data(chip); + + regmap_update_bits(gpio->lp873->regmap, LP873X_REG_GPO_CTRL, + BIT(offset * BITS_PER_GPO), + value ? BIT(offset * BITS_PER_GPO) : 0); +} + +static int lp873x_gpio_request(struct gpio_chip *gc, unsigned int offset) +{ + struct lp873x_gpio *gpio = gpiochip_get_data(gc); + int ret; + + switch (offset) { + case 0: + /* No MUX Set up Needed for GPO */ + break; + case 1: + /* Setup the CLKIN_PIN_SEL MUX to GPO2 */ + ret = regmap_update_bits(gpio->lp873->regmap, LP873X_REG_CONFIG, + LP873X_CONFIG_CLKIN_PIN_SEL, 0); + if (ret) + return ret; + + break; + default: + return -EINVAL; + } + + return 0; +} + +static int lp873x_gpio_set_single_ended(struct gpio_chip *gc, + unsigned int offset, + enum single_ended_mode mode) +{ + struct lp873x_gpio *gpio = gpiochip_get_data(gc); + + switch (mode) { + case LINE_MODE_OPEN_DRAIN: + return regmap_update_bits(gpio->lp873->regmap, + LP873X_REG_GPO_CTRL, + BIT(offset * BITS_PER_GPO + + LP873X_GPO_CTRL_OD), + BIT(offset * BITS_PER_GPO + + LP873X_GPO_CTRL_OD)); + case LINE_MODE_PUSH_PULL: + return regmap_update_bits(gpio->lp873->regmap, + LP873X_REG_GPO_CTRL, + BIT(offset * BITS_PER_GPO + + LP873X_GPO_CTRL_OD), 0); + default: + return -ENOTSUPP; + } +} + +static const struct gpio_chip template_chip = { + .label = "lp873x-gpio", + .owner = THIS_MODULE, + .request = lp873x_gpio_request, + .get_direction = lp873x_gpio_get_direction, + .direction_input = lp873x_gpio_direction_input, + .direction_output = lp873x_gpio_direction_output, + .get = lp873x_gpio_get, + .set = lp873x_gpio_set, + .set_single_ended = lp873x_gpio_set_single_ended, + .base = -1, + .ngpio = 2, + .can_sleep = true, +}; + +static int lp873x_gpio_probe(struct platform_device *pdev) +{ + struct lp873x_gpio *gpio; + int ret; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + platform_set_drvdata(pdev, gpio); + + gpio->lp873 = dev_get_drvdata(pdev->dev.parent); + gpio->chip = template_chip; + gpio->chip.parent = gpio->lp873->dev; + + ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + return ret; + } + + return 0; +} + +static const struct platform_device_id lp873x_gpio_id_table[] = { + { "lp873x-gpio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, lp873x_gpio_id_table); + +static struct platform_driver lp873x_gpio_driver = { + .driver = { + .name = "lp873x-gpio", + }, + .probe = lp873x_gpio_probe, + .id_table = lp873x_gpio_id_table, +}; +module_platform_driver(lp873x_gpio_driver); + +MODULE_AUTHOR("Keerthy <j-keerthy@ti.com>"); +MODULE_DESCRIPTION("LP873X GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-lpc18xx.c b/drivers/gpio/gpio-lpc18xx.c index 98832c9f614a..f12e02e1016d 100644 --- a/drivers/gpio/gpio-lpc18xx.c +++ b/drivers/gpio/gpio-lpc18xx.c @@ -78,7 +78,7 @@ static int lpc18xx_gpio_direction_output(struct gpio_chip *chip, return lpc18xx_gpio_direction(chip, offset, true); } -static struct gpio_chip lpc18xx_chip = { +static const struct gpio_chip lpc18xx_chip = { .label = "lpc18xx/43xx-gpio", .request = gpiochip_generic_request, .free = gpiochip_generic_free, diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index fc5f197906ac..92b3ae2a6735 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -25,7 +25,6 @@ #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/platform_data/gpio-lpc32xx.h> #include <mach/hardware.h> #include <mach/platform.h> @@ -68,6 +67,20 @@ #define GPI3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1) #define GPO3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1) +#define LPC32XX_GPIO_P0_MAX 8 +#define LPC32XX_GPIO_P1_MAX 24 +#define LPC32XX_GPIO_P2_MAX 13 +#define LPC32XX_GPIO_P3_MAX 6 +#define LPC32XX_GPI_P3_MAX 29 +#define LPC32XX_GPO_P3_MAX 24 + +#define LPC32XX_GPIO_P0_GRP 0 +#define LPC32XX_GPIO_P1_GRP (LPC32XX_GPIO_P0_GRP + LPC32XX_GPIO_P0_MAX) +#define LPC32XX_GPIO_P2_GRP (LPC32XX_GPIO_P1_GRP + LPC32XX_GPIO_P1_MAX) +#define LPC32XX_GPIO_P3_GRP (LPC32XX_GPIO_P2_GRP + LPC32XX_GPIO_P2_MAX) +#define LPC32XX_GPI_P3_GRP (LPC32XX_GPIO_P3_GRP + LPC32XX_GPIO_P3_MAX) +#define LPC32XX_GPO_P3_GRP (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX) + struct gpio_regs { void __iomem *inp_state; void __iomem *outp_state; diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index 6ec144baeb11..d7d03ad052d0 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -573,6 +573,7 @@ static void __iomem *bgpio_map(struct platform_device *pdev, #ifdef CONFIG_OF static const struct of_device_id bgpio_of_match[] = { + { .compatible = "brcm,bcm6345-gpio" }, { .compatible = "wd,mbl-gpio" }, { } }; @@ -593,6 +594,9 @@ static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev, pdata->base = -1; + if (of_device_is_big_endian(pdev->dev.of_node)) + *flags |= BGPIOF_BIG_ENDIAN_BYTE_ORDER; + if (of_property_read_bool(pdev->dev.of_node, "no-output")) *flags |= BGPIOF_NO_OUTPUT; diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c new file mode 100644 index 000000000000..1ef85b0c2b1f --- /dev/null +++ b/drivers/gpio/gpio-mockup.c @@ -0,0 +1,214 @@ +/* + * GPIO Testing Device Driver + * + * Copyright (C) 2014 Kamlakant Patel <kamlakant.patel@broadcom.com> + * Copyright (C) 2015-2016 Bamvor Jian Zhang <bamvor.zhangjian@linaro.org> + * + * 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/init.h> +#include <linux/module.h> +#include <linux/gpio/driver.h> +#include <linux/platform_device.h> + +#define GPIO_NAME "gpio-mockup" +#define MAX_GC 10 + +enum direction { + OUT, + IN +}; + +/* + * struct gpio_pin_status - structure describing a GPIO status + * @dir: Configures direction of gpio as "in" or "out", 0=in, 1=out + * @value: Configures status of the gpio as 0(low) or 1(high) + */ +struct gpio_pin_status { + enum direction dir; + bool value; +}; + +struct mockup_gpio_controller { + struct gpio_chip gc; + struct gpio_pin_status *stats; +}; + +static int gpio_mockup_ranges[MAX_GC << 1]; +static int gpio_mockup_params_nr; +module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400); + +const char pins_name_start = 'A'; + +static int mockup_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); + + return cntr->stats[offset].value; +} + +static void mockup_gpio_set(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); + + cntr->stats[offset].value = !!value; +} + +static int mockup_gpio_dirout(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); + + mockup_gpio_set(gc, offset, value); + cntr->stats[offset].dir = OUT; + return 0; +} + +static int mockup_gpio_dirin(struct gpio_chip *gc, unsigned int offset) +{ + struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); + + cntr->stats[offset].dir = IN; + return 0; +} + +static int mockup_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); + + return cntr->stats[offset].dir; +} + +static int mockup_gpio_add(struct device *dev, + struct mockup_gpio_controller *cntr, + const char *name, int base, int ngpio) +{ + int ret; + + cntr->gc.base = base; + cntr->gc.ngpio = ngpio; + cntr->gc.label = name; + cntr->gc.owner = THIS_MODULE; + cntr->gc.parent = dev; + cntr->gc.get = mockup_gpio_get; + cntr->gc.set = mockup_gpio_set; + cntr->gc.direction_output = mockup_gpio_dirout; + cntr->gc.direction_input = mockup_gpio_dirin; + cntr->gc.get_direction = mockup_gpio_get_direction; + cntr->stats = devm_kzalloc(dev, sizeof(*cntr->stats) * cntr->gc.ngpio, + GFP_KERNEL); + if (!cntr->stats) { + ret = -ENOMEM; + goto err; + } + ret = devm_gpiochip_add_data(dev, &cntr->gc, cntr); + if (ret) + goto err; + + dev_info(dev, "gpio<%d..%d> add successful!", base, base + ngpio); + return 0; +err: + dev_err(dev, "gpio<%d..%d> add failed!", base, base + ngpio); + return ret; +} + +static int mockup_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mockup_gpio_controller *cntr; + int ret; + int i; + int base; + int ngpio; + char chip_name[sizeof(GPIO_NAME) + 3]; + + if (gpio_mockup_params_nr < 2) + return -EINVAL; + + cntr = devm_kzalloc(dev, sizeof(*cntr) * (gpio_mockup_params_nr >> 1), + GFP_KERNEL); + if (!cntr) + return -ENOMEM; + + platform_set_drvdata(pdev, cntr); + + for (i = 0; i < gpio_mockup_params_nr >> 1; i++) { + base = gpio_mockup_ranges[i * 2]; + if (base == -1) + ngpio = gpio_mockup_ranges[i * 2 + 1]; + else + ngpio = gpio_mockup_ranges[i * 2 + 1] - base; + + if (ngpio >= 0) { + sprintf(chip_name, "%s-%c", GPIO_NAME, + pins_name_start + i); + ret = mockup_gpio_add(dev, &cntr[i], + chip_name, base, ngpio); + } else { + ret = -1; + } + if (ret) { + if (base < 0) + dev_err(dev, "gpio<%d..%d> add failed\n", + base, ngpio); + else + dev_err(dev, "gpio<%d..%d> add failed\n", + base, base + ngpio); + + return ret; + } + } + + return 0; +} + +static struct platform_driver mockup_gpio_driver = { + .driver = { + .name = GPIO_NAME, + }, + .probe = mockup_gpio_probe, +}; + +static struct platform_device *pdev; +static int __init mock_device_init(void) +{ + int err; + + pdev = platform_device_alloc(GPIO_NAME, -1); + if (!pdev) + return -ENOMEM; + + err = platform_device_add(pdev); + if (err) { + platform_device_put(pdev); + return err; + } + + err = platform_driver_register(&mockup_gpio_driver); + if (err) { + platform_device_unregister(pdev); + return err; + } + + return 0; +} + +static void __exit mock_device_exit(void) +{ + platform_driver_unregister(&mockup_gpio_driver); + platform_device_unregister(pdev); +} + +module_init(mock_device_init); +module_exit(mock_device_exit); + +MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>"); +MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>"); +MODULE_DESCRIPTION("GPIO Testing driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c index d75649787e6c..1b7ce7f85886 100644 --- a/drivers/gpio/gpio-msic.c +++ b/drivers/gpio/gpio-msic.c @@ -20,7 +20,6 @@ * */ -#include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/interrupt.h> @@ -328,9 +327,4 @@ static int __init platform_msic_gpio_init(void) { return platform_driver_register(&platform_msic_gpio_driver); } - subsys_initcall(platform_msic_gpio_init); - -MODULE_AUTHOR("Mathias Nyman <mathias.nyman@linux.intel.com>"); -MODULE_DESCRIPTION("Intel Medfield MSIC GPIO driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index e38989a4fa0c..c1a1e00b8cb0 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -2,7 +2,8 @@ * MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de> * Copyright 2008 Juergen Beisert, kernel@pengutronix.de * - * Based on code from Freescale, + * Based on code from Freescale Semiconductor, + * Authors: Daniel Mack, Juergen Beisert. * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -33,7 +34,6 @@ #include <linux/gpio.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/module.h> #include <linux/bug.h> enum mxc_gpio_hwtype { @@ -516,9 +516,3 @@ static int __init gpio_mxc_init(void) return platform_driver_register(&mxc_gpio_driver); } subsys_initcall(gpio_mxc_init); - -MODULE_AUTHOR("Freescale Semiconductor, " - "Daniel Mack <danielncaiaq.de>, " - "Juergen Beisert <kernel@pengutronix.de>"); -MODULE_DESCRIPTION("Freescale MXC GPIO"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 839474430229..3d818195e351 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -152,7 +152,6 @@ static const struct of_device_id of_palmas_gpio_match[] = { { .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,}, { }, }; -MODULE_DEVICE_TABLE(of, of_palmas_gpio_match); static int palmas_gpio_probe(struct platform_device *pdev) { diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 02f2a5621bb0..5d059866d17a 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -21,6 +21,7 @@ #include <asm/unaligned.h> #include <linux/of_platform.h> #include <linux/acpi.h> +#include <linux/regulator/consumer.h> #define PCA953X_INPUT 0 #define PCA953X_OUTPUT 1 @@ -94,6 +95,24 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids); #define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ) +struct pca953x_reg_config { + int direction; + int output; + int input; +}; + +static const struct pca953x_reg_config pca953x_regs = { + .direction = PCA953X_DIRECTION, + .output = PCA953X_OUTPUT, + .input = PCA953X_INPUT, +}; + +static const struct pca953x_reg_config pca957x_regs = { + .direction = PCA957X_CFG, + .output = PCA957X_OUT, + .input = PCA957X_IN, +}; + struct pca953x_chip { unsigned gpio_start; u8 reg_output[MAX_BANK]; @@ -111,8 +130,13 @@ struct pca953x_chip { struct i2c_client *client; struct gpio_chip gpio_chip; const char *const *names; - int chip_type; unsigned long driver_data; + struct regulator *regulator; + + const struct pca953x_reg_config *regs; + + int (*write_regs)(struct pca953x_chip *, int, u8 *); + int (*read_regs)(struct pca953x_chip *, int, u8 *); }; static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val, @@ -152,38 +176,44 @@ static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val, return 0; } -static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val) +static int pca953x_write_regs_8(struct pca953x_chip *chip, int reg, u8 *val) { - int ret = 0; + return i2c_smbus_write_byte_data(chip->client, reg, *val); +} - if (chip->gpio_chip.ngpio <= 8) - ret = i2c_smbus_write_byte_data(chip->client, reg, *val); - else if (chip->gpio_chip.ngpio >= 24) { - int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); - ret = i2c_smbus_write_i2c_block_data(chip->client, - (reg << bank_shift) | REG_ADDR_AI, - NBANK(chip), val); - } else { - switch (chip->chip_type) { - case PCA953X_TYPE: { - __le16 word = cpu_to_le16(get_unaligned((u16 *)val)); +static int pca953x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val) +{ + __le16 word = cpu_to_le16(get_unaligned((u16 *)val)); - ret = i2c_smbus_write_word_data(chip->client, reg << 1, - (__force u16)word); - break; - } - case PCA957X_TYPE: - ret = i2c_smbus_write_byte_data(chip->client, reg << 1, - val[0]); - if (ret < 0) - break; - ret = i2c_smbus_write_byte_data(chip->client, - (reg << 1) + 1, - val[1]); - break; - } - } + return i2c_smbus_write_word_data(chip->client, + reg << 1, (__force u16)word); +} + +static int pca957x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val) +{ + int ret; + + ret = i2c_smbus_write_byte_data(chip->client, reg << 1, val[0]); + if (ret < 0) + return ret; + + return i2c_smbus_write_byte_data(chip->client, (reg << 1) + 1, val[1]); +} + +static int pca953x_write_regs_24(struct pca953x_chip *chip, int reg, u8 *val) +{ + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); + + return i2c_smbus_write_i2c_block_data(chip->client, + (reg << bank_shift) | REG_ADDR_AI, + NBANK(chip), val); +} +static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val) +{ + int ret = 0; + + ret = chip->write_regs(chip, reg, val); if (ret < 0) { dev_err(&chip->client->dev, "failed writing register\n"); return ret; @@ -192,24 +222,41 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val) return 0; } -static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val) +static int pca953x_read_regs_8(struct pca953x_chip *chip, int reg, u8 *val) { int ret; - if (chip->gpio_chip.ngpio <= 8) { - ret = i2c_smbus_read_byte_data(chip->client, reg); - *val = ret; - } else if (chip->gpio_chip.ngpio >= 24) { - int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); + ret = i2c_smbus_read_byte_data(chip->client, reg); + *val = ret; - ret = i2c_smbus_read_i2c_block_data(chip->client, - (reg << bank_shift) | REG_ADDR_AI, - NBANK(chip), val); - } else { - ret = i2c_smbus_read_word_data(chip->client, reg << 1); - val[0] = (u16)ret & 0xFF; - val[1] = (u16)ret >> 8; - } + return ret; +} + +static int pca953x_read_regs_16(struct pca953x_chip *chip, int reg, u8 *val) +{ + int ret; + + ret = i2c_smbus_read_word_data(chip->client, reg << 1); + val[0] = (u16)ret & 0xFF; + val[1] = (u16)ret >> 8; + + return ret; +} + +static int pca953x_read_regs_24(struct pca953x_chip *chip, int reg, u8 *val) +{ + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); + + return i2c_smbus_read_i2c_block_data(chip->client, + (reg << bank_shift) | REG_ADDR_AI, + NBANK(chip), val); +} + +static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val) +{ + int ret; + + ret = chip->read_regs(chip, reg, val); if (ret < 0) { dev_err(&chip->client->dev, "failed reading register\n"); return ret; @@ -222,20 +269,12 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { struct pca953x_chip *chip = gpiochip_get_data(gc); u8 reg_val; - int ret, offset = 0; + int ret; mutex_lock(&chip->i2c_lock); reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ)); - switch (chip->chip_type) { - case PCA953X_TYPE: - offset = PCA953X_DIRECTION; - break; - case PCA957X_TYPE: - offset = PCA957X_CFG; - break; - } - ret = pca953x_write_single(chip, offset, reg_val, off); + ret = pca953x_write_single(chip, chip->regs->direction, reg_val, off); if (ret) goto exit; @@ -250,7 +289,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, { struct pca953x_chip *chip = gpiochip_get_data(gc); u8 reg_val; - int ret, offset = 0; + int ret; mutex_lock(&chip->i2c_lock); /* set output level */ @@ -261,15 +300,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, reg_val = chip->reg_output[off / BANK_SZ] & ~(1u << (off % BANK_SZ)); - switch (chip->chip_type) { - case PCA953X_TYPE: - offset = PCA953X_OUTPUT; - break; - case PCA957X_TYPE: - offset = PCA957X_OUT; - break; - } - ret = pca953x_write_single(chip, offset, reg_val, off); + ret = pca953x_write_single(chip, chip->regs->output, reg_val, off); if (ret) goto exit; @@ -277,15 +308,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, /* then direction */ reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ)); - switch (chip->chip_type) { - case PCA953X_TYPE: - offset = PCA953X_DIRECTION; - break; - case PCA957X_TYPE: - offset = PCA957X_CFG; - break; - } - ret = pca953x_write_single(chip, offset, reg_val, off); + ret = pca953x_write_single(chip, chip->regs->direction, reg_val, off); if (ret) goto exit; @@ -299,18 +322,10 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) { struct pca953x_chip *chip = gpiochip_get_data(gc); u32 reg_val; - int ret, offset = 0; + int ret; mutex_lock(&chip->i2c_lock); - switch (chip->chip_type) { - case PCA953X_TYPE: - offset = PCA953X_INPUT; - break; - case PCA957X_TYPE: - offset = PCA957X_IN; - break; - } - ret = pca953x_read_single(chip, offset, ®_val, off); + ret = pca953x_read_single(chip, chip->regs->input, ®_val, off); mutex_unlock(&chip->i2c_lock); if (ret < 0) { /* NOTE: diagnostic already emitted; that's all we should @@ -327,7 +342,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) { struct pca953x_chip *chip = gpiochip_get_data(gc); u8 reg_val; - int ret, offset = 0; + int ret; mutex_lock(&chip->i2c_lock); if (val) @@ -337,15 +352,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) reg_val = chip->reg_output[off / BANK_SZ] & ~(1u << (off % BANK_SZ)); - switch (chip->chip_type) { - case PCA953X_TYPE: - offset = PCA953X_OUTPUT; - break; - case PCA957X_TYPE: - offset = PCA957X_OUT; - break; - } - ret = pca953x_write_single(chip, offset, reg_val, off); + ret = pca953x_write_single(chip, chip->regs->output, reg_val, off); if (ret) goto exit; @@ -355,35 +362,31 @@ exit: } static void pca953x_gpio_set_multiple(struct gpio_chip *gc, - unsigned long *mask, unsigned long *bits) + unsigned long *mask, unsigned long *bits) { struct pca953x_chip *chip = gpiochip_get_data(gc); + unsigned int bank_mask, bank_val; + int bank_shift, bank; u8 reg_val[MAX_BANK]; - int ret, offset = 0; - int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); - int bank; - - switch (chip->chip_type) { - case PCA953X_TYPE: - offset = PCA953X_OUTPUT; - break; - case PCA957X_TYPE: - offset = PCA957X_OUT; - break; - } + int ret; + + bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); memcpy(reg_val, chip->reg_output, NBANK(chip)); mutex_lock(&chip->i2c_lock); - for(bank=0; bank<NBANK(chip); bank++) { - unsigned bankmask = mask[bank / sizeof(*mask)] >> - ((bank % sizeof(*mask)) * 8); - if(bankmask) { - unsigned bankval = bits[bank / sizeof(*bits)] >> - ((bank % sizeof(*bits)) * 8); - reg_val[bank] = (reg_val[bank] & ~bankmask) | bankval; + for (bank = 0; bank < NBANK(chip); bank++) { + bank_mask = mask[bank / sizeof(*mask)] >> + ((bank % sizeof(*mask)) * 8); + if (bank_mask) { + bank_val = bits[bank / sizeof(*bits)] >> + ((bank % sizeof(*bits)) * 8); + reg_val[bank] = (reg_val[bank] & ~bank_mask) | bank_val; } } - ret = i2c_smbus_write_i2c_block_data(chip->client, offset << bank_shift, NBANK(chip), reg_val); + + ret = i2c_smbus_write_i2c_block_data(chip->client, + chip->regs->output << bank_shift, + NBANK(chip), reg_val); if (ret) goto exit; @@ -515,7 +518,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) bool pending_seen = false; bool trigger_seen = false; u8 trigger[MAX_BANK]; - int ret, i, offset = 0; + int ret, i; if (chip->driver_data & PCA_PCAL) { /* Read the current interrupt status from the device */ @@ -540,15 +543,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) return pending_seen; } - switch (chip->chip_type) { - case PCA953X_TYPE: - offset = PCA953X_INPUT; - break; - case PCA957X_TYPE: - offset = PCA957X_IN; - break; - } - ret = pca953x_read_regs(chip, offset, cur_stat); + ret = pca953x_read_regs(chip, chip->regs->input, cur_stat); if (ret) return false; @@ -608,20 +603,13 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) { struct i2c_client *client = chip->client; - int ret, i, offset = 0; + int ret, i; if (client->irq && irq_base != -1 && (chip->driver_data & PCA_INT)) { - switch (chip->chip_type) { - case PCA953X_TYPE: - offset = PCA953X_INPUT; - break; - case PCA957X_TYPE: - offset = PCA957X_IN; - break; - } - ret = pca953x_read_regs(chip, offset, chip->irq_stat); + ret = pca953x_read_regs(chip, + chip->regs->input, chip->irq_stat); if (ret) return ret; @@ -684,12 +672,14 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) int ret; u8 val[MAX_BANK]; - ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output); + chip->regs = &pca953x_regs; + + ret = pca953x_read_regs(chip, chip->regs->output, chip->reg_output); if (ret) goto out; - ret = pca953x_read_regs(chip, PCA953X_DIRECTION, - chip->reg_direction); + ret = pca953x_read_regs(chip, chip->regs->direction, + chip->reg_direction); if (ret) goto out; @@ -709,10 +699,13 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) int ret; u8 val[MAX_BANK]; - ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output); + chip->regs = &pca957x_regs; + + ret = pca953x_read_regs(chip, chip->regs->output, chip->reg_output); if (ret) goto out; - ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction); + ret = pca953x_read_regs(chip, chip->regs->direction, + chip->reg_direction); if (ret) goto out; @@ -746,6 +739,7 @@ static int pca953x_probe(struct i2c_client *client, int irq_base = 0; int ret; u32 invert = 0; + struct regulator *reg; chip = devm_kzalloc(&client->dev, sizeof(struct pca953x_chip), GFP_KERNEL); @@ -765,6 +759,20 @@ static int pca953x_probe(struct i2c_client *client, chip->client = client; + reg = devm_regulator_get(&client->dev, "vcc"); + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + if (ret != -EPROBE_DEFER) + dev_err(&client->dev, "reg get err: %d\n", ret); + return ret; + } + ret = regulator_enable(reg); + if (ret) { + dev_err(&client->dev, "reg en err: %d\n", ret); + return ret; + } + chip->regulator = reg; + if (id) { chip->driver_data = id->driver_data; } else { @@ -776,15 +784,15 @@ static int pca953x_probe(struct i2c_client *client, chip->driver_data = (int)(uintptr_t)match->data; } else { id = acpi_match_device(pca953x_acpi_ids, &client->dev); - if (!id) - return -ENODEV; + if (!id) { + ret = -ENODEV; + goto err_exit; + } chip->driver_data = id->driver_data; } } - chip->chip_type = PCA_CHIP_TYPE(chip->driver_data); - mutex_init(&chip->i2c_lock); /* initialize cached registers from their original values. @@ -792,20 +800,34 @@ static int pca953x_probe(struct i2c_client *client, */ pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); - if (chip->chip_type == PCA953X_TYPE) + if (chip->gpio_chip.ngpio <= 8) { + chip->write_regs = pca953x_write_regs_8; + chip->read_regs = pca953x_read_regs_8; + } else if (chip->gpio_chip.ngpio >= 24) { + chip->write_regs = pca953x_write_regs_24; + chip->read_regs = pca953x_read_regs_24; + } else { + if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) + chip->write_regs = pca953x_write_regs_16; + else + chip->write_regs = pca957x_write_regs_16; + chip->read_regs = pca953x_read_regs_16; + } + + if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) ret = device_pca953x_init(chip, invert); else ret = device_pca957x_init(chip, invert); if (ret) - return ret; + goto err_exit; ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip); if (ret) - return ret; + goto err_exit; ret = pca953x_irq_setup(chip, irq_base); if (ret) - return ret; + goto err_exit; if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, @@ -816,6 +838,10 @@ static int pca953x_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); return 0; + +err_exit: + regulator_disable(chip->regulator); + return ret; } static int pca953x_remove(struct i2c_client *client) @@ -827,14 +853,16 @@ static int pca953x_remove(struct i2c_client *client) if (pdata && pdata->teardown) { ret = pdata->teardown(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); - if (ret < 0) { + if (ret < 0) dev_err(&client->dev, "%s failed, %d\n", "teardown", ret); - return ret; - } + } else { + ret = 0; } - return 0; + regulator_disable(chip->regulator); + + return ret; } /* convenience to stop overlong match-table lines */ diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c index cb14b8d1d512..f5545049c187 100644 --- a/drivers/gpio/gpio-pisosr.c +++ b/drivers/gpio/gpio-pisosr.c @@ -90,7 +90,7 @@ static int pisosr_gpio_get(struct gpio_chip *chip, unsigned offset) return (gpio->buffer[offset / 8] >> (offset % 8)) & 0x1; } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "pisosr-gpio", .owner = THIS_MODULE, .get_direction = pisosr_gpio_get_direction, diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index b96e0b466f74..2be48f5eba36 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -348,6 +348,10 @@ static const struct of_device_id gpio_rcar_of_table[] = { /* Gen3 GPIO is identical to Gen2. */ .data = &gpio_rcar_info_gen2, }, { + .compatible = "renesas,gpio-r8a7796", + /* Gen3 GPIO is identical to Gen2. */ + .data = &gpio_rcar_info_gen2, + }, { .compatible = "renesas,gpio-rcar", .data = &gpio_rcar_info_gen1, }, { diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index eb43ae4835c1..545004445846 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -138,7 +138,7 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num, return 0; } -static struct gpio_chip sch_gpio_chip = { +static const struct gpio_chip sch_gpio_chip = { .label = "sch_gpio", .owner = THIS_MODULE, .direction_input = sch_gpio_direction_in, diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c index 7ffd16495286..22267479ba68 100644 --- a/drivers/gpio/gpio-spear-spics.c +++ b/drivers/gpio/gpio-spear-spics.c @@ -12,7 +12,7 @@ #include <linux/err.h> #include <linux/gpio.h> #include <linux/io.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/types.h> @@ -183,7 +183,6 @@ static const struct of_device_id spics_gpio_of_match[] = { { .compatible = "st,spear-spics-gpio" }, {} }; -MODULE_DEVICE_TABLE(of, spics_gpio_of_match); static struct platform_driver spics_gpio_driver = { .probe = spics_gpio_probe, @@ -198,7 +197,3 @@ static int __init spics_gpio_init(void) return platform_driver_register(&spics_gpio_driver); } subsys_initcall(spics_gpio_init); - -MODULE_AUTHOR("Shiraz Hashim <shiraz.linux.kernel@gmail.com>"); -MODULE_DESCRIPTION("STMicroelectronics SPEAr SPI Chip Select Abstraction"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index f675132de10e..e7d422a6b90b 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -13,6 +13,7 @@ #include <linux/of.h> #include <linux/mfd/stmpe.h> #include <linux/seq_file.h> +#include <linux/bitops.h> /* * These registers are modified under the irq bus lock and cached to avoid @@ -20,6 +21,8 @@ */ enum { REG_RE, REG_FE, REG_IE }; +enum { LSB, CSB, MSB }; + #define CACHE_NR_REGS 3 /* No variant has more than 24 GPIOs */ #define CACHE_NR_BANKS (24 / 8) @@ -39,8 +42,8 @@ static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset) { struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); struct stmpe *stmpe = stmpe_gpio->stmpe; - u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB] - (offset / 8); - u8 mask = 1 << (offset % 8); + u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB + (offset / 8)]; + u8 mask = BIT(offset % 8); int ret; ret = stmpe_reg_read(stmpe, reg); @@ -55,8 +58,8 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val) struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); struct stmpe *stmpe = stmpe_gpio->stmpe; int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB; - u8 reg = stmpe->regs[which] - (offset / 8); - u8 mask = 1 << (offset % 8); + u8 reg = stmpe->regs[which + (offset / 8)]; + u8 mask = BIT(offset % 8); /* * Some variants have single register for gpio set/clear functionality. @@ -74,7 +77,7 @@ static int stmpe_gpio_get_direction(struct gpio_chip *chip, struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); struct stmpe *stmpe = stmpe_gpio->stmpe; u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8); - u8 mask = 1 << (offset % 8); + u8 mask = BIT(offset % 8); int ret; ret = stmpe_reg_read(stmpe, reg); @@ -89,8 +92,8 @@ static int stmpe_gpio_direction_output(struct gpio_chip *chip, { struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); struct stmpe *stmpe = stmpe_gpio->stmpe; - u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8); - u8 mask = 1 << (offset % 8); + u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB + (offset / 8)]; + u8 mask = BIT(offset % 8); stmpe_gpio_set(chip, offset, val); @@ -102,8 +105,8 @@ static int stmpe_gpio_direction_input(struct gpio_chip *chip, { struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); struct stmpe *stmpe = stmpe_gpio->stmpe; - u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8); - u8 mask = 1 << (offset % 8); + u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB + (offset / 8)]; + u8 mask = BIT(offset % 8); return stmpe_set_bits(stmpe, reg, mask, 0); } @@ -113,13 +116,13 @@ static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset) struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); struct stmpe *stmpe = stmpe_gpio->stmpe; - if (stmpe_gpio->norequest_mask & (1 << offset)) + if (stmpe_gpio->norequest_mask & BIT(offset)) return -EINVAL; - return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO); + return stmpe_set_altfunc(stmpe, BIT(offset), STMPE_BLOCK_GPIO); } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "stmpe", .owner = THIS_MODULE, .get_direction = stmpe_gpio_get_direction, @@ -137,13 +140,14 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); int offset = d->hwirq; int regoffset = offset / 8; - int mask = 1 << (offset % 8); + int mask = BIT(offset % 8); if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH) return -EINVAL; - /* STMPE801 doesn't have RE and FE registers */ - if (stmpe_gpio->stmpe->partnum == STMPE801) + /* STMPE801 and STMPE 1600 don't have RE and FE registers */ + if (stmpe_gpio->stmpe->partnum == STMPE801 || + stmpe_gpio->stmpe->partnum == STMPE1600) return 0; if (type & IRQ_TYPE_EDGE_RISING) @@ -173,17 +177,24 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); struct stmpe *stmpe = stmpe_gpio->stmpe; int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); - static const u8 regmap[] = { - [REG_RE] = STMPE_IDX_GPRER_LSB, - [REG_FE] = STMPE_IDX_GPFER_LSB, - [REG_IE] = STMPE_IDX_IEGPIOR_LSB, + static const u8 regmap[CACHE_NR_REGS][CACHE_NR_BANKS] = { + [REG_RE][LSB] = STMPE_IDX_GPRER_LSB, + [REG_RE][CSB] = STMPE_IDX_GPRER_CSB, + [REG_RE][MSB] = STMPE_IDX_GPRER_MSB, + [REG_FE][LSB] = STMPE_IDX_GPFER_LSB, + [REG_FE][CSB] = STMPE_IDX_GPFER_CSB, + [REG_FE][MSB] = STMPE_IDX_GPFER_MSB, + [REG_IE][LSB] = STMPE_IDX_IEGPIOR_LSB, + [REG_IE][CSB] = STMPE_IDX_IEGPIOR_CSB, + [REG_IE][MSB] = STMPE_IDX_IEGPIOR_MSB, }; int i, j; for (i = 0; i < CACHE_NR_REGS; i++) { - /* STMPE801 doesn't have RE and FE registers */ - if ((stmpe->partnum == STMPE801) && - (i != REG_IE)) + /* STMPE801 and STMPE1600 don't have RE and FE registers */ + if ((stmpe->partnum == STMPE801 || + stmpe->partnum == STMPE1600) && + (i != REG_IE)) continue; for (j = 0; j < num_banks; j++) { @@ -194,7 +205,7 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) continue; stmpe_gpio->oldregs[i][j] = new; - stmpe_reg_write(stmpe, stmpe->regs[regmap[i]] - j, new); + stmpe_reg_write(stmpe, stmpe->regs[regmap[i][j]], new); } } @@ -207,7 +218,7 @@ static void stmpe_gpio_irq_mask(struct irq_data *d) struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); int offset = d->hwirq; int regoffset = offset / 8; - int mask = 1 << (offset % 8); + int mask = BIT(offset % 8); stmpe_gpio->regs[REG_IE][regoffset] &= ~mask; } @@ -216,11 +227,21 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); + struct stmpe *stmpe = stmpe_gpio->stmpe; int offset = d->hwirq; int regoffset = offset / 8; - int mask = 1 << (offset % 8); + int mask = BIT(offset % 8); stmpe_gpio->regs[REG_IE][regoffset] |= mask; + + /* + * STMPE1600 workaround: to be able to get IRQ from pins, + * a read must be done on GPMR register, or a write in + * GPSR or GPCR registers + */ + if (stmpe->partnum == STMPE1600) + stmpe_reg_read(stmpe, + stmpe->regs[STMPE_IDX_GPMR_LSB + regoffset]); } static void stmpe_dbg_show_one(struct seq_file *s, @@ -230,10 +251,10 @@ static void stmpe_dbg_show_one(struct seq_file *s, struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); struct stmpe *stmpe = stmpe_gpio->stmpe; const char *label = gpiochip_is_requested(gc, offset); - int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); bool val = !!stmpe_gpio_get(gc, offset); - u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8); - u8 mask = 1 << (offset % 8); + u8 bank = offset / 8; + u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB + bank]; + u8 mask = BIT(offset % 8); int ret; u8 dir; @@ -247,39 +268,72 @@ static void stmpe_dbg_show_one(struct seq_file *s, gpio, label ?: "(none)", val ? "hi" : "lo"); } else { - u8 edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_MSB] + num_banks - 1 - (offset / 8); - u8 rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB] - (offset / 8); - u8 fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB] - (offset / 8); - u8 irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB] - (offset / 8); - bool edge_det; - bool rise; - bool fall; + u8 edge_det_reg; + u8 rise_reg; + u8 fall_reg; + u8 irqen_reg; + + char *edge_det_values[] = {"edge-inactive", + "edge-asserted", + "not-supported"}; + char *rise_values[] = {"no-rising-edge-detection", + "rising-edge-detection", + "not-supported"}; + char *fall_values[] = {"no-falling-edge-detection", + "falling-edge-detection", + "not-supported"}; + #define NOT_SUPPORTED_IDX 2 + u8 edge_det = NOT_SUPPORTED_IDX; + u8 rise = NOT_SUPPORTED_IDX; + u8 fall = NOT_SUPPORTED_IDX; bool irqen; - ret = stmpe_reg_read(stmpe, edge_det_reg); - if (ret < 0) + switch (stmpe->partnum) { + case STMPE610: + case STMPE811: + case STMPE1601: + case STMPE2401: + case STMPE2403: + edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_LSB + bank]; + ret = stmpe_reg_read(stmpe, edge_det_reg); + if (ret < 0) + return; + edge_det = !!(ret & mask); + + case STMPE1801: + rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB + bank]; + fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB + bank]; + + ret = stmpe_reg_read(stmpe, rise_reg); + if (ret < 0) + return; + rise = !!(ret & mask); + ret = stmpe_reg_read(stmpe, fall_reg); + if (ret < 0) + return; + fall = !!(ret & mask); + + case STMPE801: + case STMPE1600: + irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB + bank]; + break; + + default: return; - edge_det = !!(ret & mask); - ret = stmpe_reg_read(stmpe, rise_reg); - if (ret < 0) - return; - rise = !!(ret & mask); - ret = stmpe_reg_read(stmpe, fall_reg); - if (ret < 0) - return; - fall = !!(ret & mask); + } + ret = stmpe_reg_read(stmpe, irqen_reg); if (ret < 0) return; irqen = !!(ret & mask); - seq_printf(s, " gpio-%-3d (%-20.20s) in %s %s %s%s%s", + seq_printf(s, " gpio-%-3d (%-20.20s) in %s %13s %13s %25s %25s", gpio, label ?: "(none)", val ? "hi" : "lo", - edge_det ? "edge-asserted" : "edge-inactive", - irqen ? "IRQ-enabled" : "", - rise ? " rising-edge-detection" : "", - fall ? " falling-edge-detection" : ""); + edge_det_values[edge_det], + irqen ? "IRQ-enabled" : "IRQ-disabled", + rise_values[rise], + fall_values[fall]); } } @@ -307,18 +361,32 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) { struct stmpe_gpio *stmpe_gpio = dev; struct stmpe *stmpe = stmpe_gpio->stmpe; - u8 statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB]; + u8 statmsbreg; int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); u8 status[num_banks]; int ret; int i; + /* + * the stmpe_block_read() call below, imposes to set statmsbreg + * with the register located at the lowest address. As STMPE1600 + * variant is the only one which respect registers address's order + * (LSB regs located at lowest address than MSB ones) whereas all + * the others have a registers layout with MSB located before the + * LSB regs. + */ + if (stmpe->partnum == STMPE1600) + statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_LSB]; + else + statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB]; + ret = stmpe_block_read(stmpe, statmsbreg, num_banks, status); if (ret < 0) return IRQ_NONE; for (i = 0; i < num_banks; i++) { - int bank = num_banks - i - 1; + int bank = (stmpe_gpio->stmpe->partnum == STMPE1600) ? i : + num_banks - i - 1; unsigned int enabled = stmpe_gpio->regs[REG_IE][bank]; unsigned int stat = status[i]; @@ -333,15 +401,21 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) line); handle_nested_irq(child_irq); - stat &= ~(1 << bit); + stat &= ~BIT(bit); } - stmpe_reg_write(stmpe, statmsbreg + i, status[i]); - - /* Edge detect register is not present on 801 */ - if (stmpe->partnum != STMPE801) - stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] - + i, status[i]); + /* + * interrupt status register write has no effect on + * 801/1801/1600, bits are cleared when read. + * Edge detect register is not present on 801/1600/1801 + */ + if (stmpe->partnum != STMPE801 || stmpe->partnum != STMPE1600 || + stmpe->partnum != STMPE1801) { + stmpe_reg_write(stmpe, statmsbreg + i, status[i]); + stmpe_reg_write(stmpe, + stmpe->regs[STMPE_IDX_GPEDR_LSB + i], + status[i]); + } } return IRQ_HANDLED; @@ -376,6 +450,8 @@ static int stmpe_gpio_probe(struct platform_device *pdev) of_property_read_u32(np, "st,norequest-mask", &stmpe_gpio->norequest_mask); + if (stmpe_gpio->norequest_mask) + stmpe_gpio->chip.irq_need_valid_mask = true; if (irq < 0) dev_info(&pdev->dev, @@ -400,6 +476,14 @@ static int stmpe_gpio_probe(struct platform_device *pdev) dev_err(&pdev->dev, "unable to get irq: %d\n", ret); goto out_disable; } + if (stmpe_gpio->norequest_mask) { + int i; + + /* Forbid unused lines to be mapped as IRQs */ + for (i = 0; i < sizeof(u32); i++) + if (stmpe_gpio->norequest_mask & BIT(i)) + clear_bit(i, stmpe_gpio->chip.irq_valid_mask); + } ret = gpiochip_irqchip_add(&stmpe_gpio->chip, &stmpe_gpio_irq_chip, 0, diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index a177ebd921d5..af95de89db01 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -236,7 +236,6 @@ static const struct i2c_device_id sx150x_id[] = { {"sx1502q", 3}, {} }; -MODULE_DEVICE_TABLE(i2c, sx150x_id); static const struct of_device_id sx150x_of_match[] = { { .compatible = "semtech,sx1508q" }, @@ -245,7 +244,6 @@ static const struct of_device_id sx150x_of_match[] = { { .compatible = "semtech,sx1502q" }, {}, }; -MODULE_DEVICE_TABLE(of, sx150x_of_match); static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val) { diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 8b3659352e49..5a5a6cb00eea 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -34,7 +34,7 @@ struct tc3589x_gpio { u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; }; -static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset) +static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; @@ -49,24 +49,24 @@ static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(ret & mask); } -static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned int offset, int val) { struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2; - unsigned pos = offset % 8; + unsigned int pos = offset % 8; u8 data[] = {val ? BIT(pos) : 0, BIT(pos)}; tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data); } static int tc3589x_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int val) + unsigned int offset, int val) { struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; u8 reg = TC3589x_GPIODIR0 + offset / 8; - unsigned pos = offset % 8; + unsigned int pos = offset % 8; tc3589x_gpio_set(chip, offset, val); @@ -74,19 +74,35 @@ static int tc3589x_gpio_direction_output(struct gpio_chip *chip, } static int tc3589x_gpio_direction_input(struct gpio_chip *chip, - unsigned offset) + unsigned int offset) { struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; u8 reg = TC3589x_GPIODIR0 + offset / 8; - unsigned pos = offset % 8; + unsigned int pos = offset % 8; return tc3589x_set_bits(tc3589x, reg, BIT(pos), 0); } -static int tc3589x_gpio_single_ended(struct gpio_chip *chip, - unsigned offset, - enum single_ended_mode mode) +static int tc3589x_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip); + struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; + u8 reg = TC3589x_GPIODIR0 + offset / 8; + unsigned int pos = offset % 8; + int ret; + + ret = tc3589x_reg_read(tc3589x, reg); + if (ret < 0) + return ret; + + return !!(ret & BIT(pos)); +} + +static int tc3589x_gpio_set_single_ended(struct gpio_chip *chip, + unsigned int offset, + enum single_ended_mode mode) { struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; @@ -97,7 +113,7 @@ static int tc3589x_gpio_single_ended(struct gpio_chip *chip, */ u8 odmreg = TC3589x_GPIOODM0 + (offset / 8) * 2; u8 odereg = TC3589x_GPIOODE0 + (offset / 8) * 2; - unsigned pos = offset % 8; + unsigned int pos = offset % 8; int ret; switch(mode) { @@ -124,14 +140,15 @@ static int tc3589x_gpio_single_ended(struct gpio_chip *chip, return -ENOTSUPP; } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "tc3589x", .owner = THIS_MODULE, - .direction_input = tc3589x_gpio_direction_input, .get = tc3589x_gpio_get, - .direction_output = tc3589x_gpio_direction_output, .set = tc3589x_gpio_set, - .set_single_ended = tc3589x_gpio_single_ended, + .direction_output = tc3589x_gpio_direction_output, + .direction_input = tc3589x_gpio_direction_input, + .get_direction = tc3589x_gpio_get_direction, + .set_single_ended = tc3589x_gpio_set_single_ended, .can_sleep = true, }; diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c index cace79c1b70a..c8b34d787eed 100644 --- a/drivers/gpio/gpio-tpic2810.c +++ b/drivers/gpio/gpio-tpic2810.c @@ -87,7 +87,7 @@ static void tpic2810_set_multiple(struct gpio_chip *chip, unsigned long *mask, tpic2810_set_mask_bits(chip, *mask, *bits); } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "tpic2810", .owner = THIS_MODULE, .get_direction = tpic2810_get_direction, diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c index 8e25f01ac314..b23c4d2429be 100644 --- a/drivers/gpio/gpio-tps65086.c +++ b/drivers/gpio/gpio-tps65086.c @@ -72,7 +72,7 @@ static void tps65086_gpio_set(struct gpio_chip *chip, unsigned offset, BIT(4 + offset), value ? BIT(4 + offset) : 0); } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "tps65086-gpio", .owner = THIS_MODULE, .get_direction = tps65086_gpio_get_direction, diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c index 1c09a19ae10c..d779307a9685 100644 --- a/drivers/gpio/gpio-tps65218.c +++ b/drivers/gpio/gpio-tps65218.c @@ -172,7 +172,7 @@ static int tps65218_gpio_set_single_ended(struct gpio_chip *gc, return -ENOTSUPP; } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "gpio-tps65218", .owner = THIS_MODULE, .request = tps65218_gpio_request, @@ -204,7 +204,8 @@ static int tps65218_gpio_probe(struct platform_device *pdev) tps65218_gpio->gpio_chip.of_node = pdev->dev.of_node; #endif - ret = gpiochip_add_data(&tps65218_gpio->gpio_chip, tps65218_gpio); + ret = devm_gpiochip_add_data(&pdev->dev, &tps65218_gpio->gpio_chip, + tps65218_gpio); if (ret < 0) { dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret); return ret; @@ -215,15 +216,6 @@ static int tps65218_gpio_probe(struct platform_device *pdev) return ret; } -static int tps65218_gpio_remove(struct platform_device *pdev) -{ - struct tps65218_gpio *tps65218_gpio = platform_get_drvdata(pdev); - - gpiochip_remove(&tps65218_gpio->gpio_chip); - - return 0; -} - static const struct of_device_id tps65218_dt_match[] = { { .compatible = "ti,tps65218-gpio" }, { } @@ -242,7 +234,6 @@ static struct platform_driver tps65218_gpio_driver = { .of_match_table = of_match_ptr(tps65218_dt_match) }, .probe = tps65218_gpio_probe, - .remove = tps65218_gpio_remove, .id_table = tps65218_gpio_id_table, }; diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index acfd30a13a56..abc0798ef843 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -90,7 +90,7 @@ static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset, GPIO_SET_MASK, value ? GPIO_SET_MASK : 0); } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "tps65912-gpio", .owner = THIS_MODULE, .get_direction = tps65912_gpio_get_direction, diff --git a/drivers/gpio/gpio-ts4800.c b/drivers/gpio/gpio-ts4800.c index 0c144a72f9af..99256115bea5 100644 --- a/drivers/gpio/gpio-ts4800.c +++ b/drivers/gpio/gpio-ts4800.c @@ -9,6 +9,7 @@ */ #include <linux/gpio/driver.h> +#include <linux/module.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/platform_device.h> diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c new file mode 100644 index 000000000000..5bd21725e604 --- /dev/null +++ b/drivers/gpio/gpio-ts4900.c @@ -0,0 +1,190 @@ +/* + * Digital I/O driver for Technologic Systems I2C FPGA Core + * + * Copyright (C) 2015 Technologic Systems + * Copyright (C) 2016 Savoir-Faire Linux + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether expressed or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + */ + +#include <linux/gpio/driver.h> +#include <linux/i2c.h> +#include <linux/of_device.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#define DEFAULT_PIN_NUMBER 32 +/* + * Register bits used by the GPIO device + * Some boards, such as TS-7970 do not have a separate input bit + */ +#define TS4900_GPIO_OE 0x01 +#define TS4900_GPIO_OUT 0x02 +#define TS4900_GPIO_IN 0x04 +#define TS7970_GPIO_IN 0x02 + +struct ts4900_gpio_priv { + struct regmap *regmap; + struct gpio_chip gpio_chip; + unsigned int input_bit; +}; + +static int ts4900_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct ts4900_gpio_priv *priv = gpiochip_get_data(chip); + unsigned int reg; + + regmap_read(priv->regmap, offset, ®); + + return !(reg & TS4900_GPIO_OE); +} + +static int ts4900_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct ts4900_gpio_priv *priv = gpiochip_get_data(chip); + + /* + * This will clear the output enable bit, the other bits are + * dontcare when this is cleared + */ + return regmap_write(priv->regmap, offset, 0); +} + +static int ts4900_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct ts4900_gpio_priv *priv = gpiochip_get_data(chip); + int ret; + + if (value) + ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE | + TS4900_GPIO_OUT); + else + ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE); + + return ret; +} + +static int ts4900_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct ts4900_gpio_priv *priv = gpiochip_get_data(chip); + unsigned int reg; + + regmap_read(priv->regmap, offset, ®); + + return !!(reg & priv->input_bit); +} + +static void ts4900_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct ts4900_gpio_priv *priv = gpiochip_get_data(chip); + + if (value) + regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OUT, + TS4900_GPIO_OUT); + else + regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OUT, 0); +} + +static const struct regmap_config ts4900_regmap_config = { + .reg_bits = 16, + .val_bits = 8, +}; + +static const struct gpio_chip template_chip = { + .label = "ts4900-gpio", + .owner = THIS_MODULE, + .get_direction = ts4900_gpio_get_direction, + .direction_input = ts4900_gpio_direction_input, + .direction_output = ts4900_gpio_direction_output, + .get = ts4900_gpio_get, + .set = ts4900_gpio_set, + .base = -1, + .can_sleep = true, +}; + +static const struct of_device_id ts4900_gpio_of_match_table[] = { + { + .compatible = "technologic,ts4900-gpio", + .data = (void *)TS4900_GPIO_IN, + }, { + .compatible = "technologic,ts7970-gpio", + .data = (void *)TS7970_GPIO_IN, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ts4900_gpio_of_match_table); + +static int ts4900_gpio_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct of_device_id *match; + struct ts4900_gpio_priv *priv; + u32 ngpio; + int ret; + + match = of_match_device(ts4900_gpio_of_match_table, &client->dev); + if (!match) + return -EINVAL; + + if (of_property_read_u32(client->dev.of_node, "ngpios", &ngpio)) + ngpio = DEFAULT_PIN_NUMBER; + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->gpio_chip = template_chip; + priv->gpio_chip.label = "ts4900-gpio"; + priv->gpio_chip.ngpio = ngpio; + priv->gpio_chip.parent = &client->dev; + priv->input_bit = (uintptr_t)match->data; + + priv->regmap = devm_regmap_init_i2c(client, &ts4900_regmap_config); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = devm_gpiochip_add_data(&client->dev, &priv->gpio_chip, priv); + if (ret < 0) { + dev_err(&client->dev, "Unable to register gpiochip\n"); + return ret; + } + + i2c_set_clientdata(client, priv); + + return 0; +} + +static const struct i2c_device_id ts4900_gpio_id_table[] = { + { "ts4900-gpio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, ts4900_gpio_id_table); + +static struct i2c_driver ts4900_gpio_driver = { + .driver = { + .name = "ts4900-gpio", + .of_match_table = ts4900_gpio_of_match_table, + }, + .probe = ts4900_gpio_probe, + .id_table = ts4900_gpio_id_table, +}; +module_i2c_driver(ts4900_gpio_driver); + +MODULE_AUTHOR("Technologic Systems"); +MODULE_DESCRIPTION("GPIO interface for Technologic Systems I2C-FPGA core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 4b807b0e0c8e..dfcfbba74416 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -381,7 +381,7 @@ static int twl_to_irq(struct gpio_chip *chip, unsigned offset) : -EINVAL; } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "twl4030", .owner = THIS_MODULE, .request = twl_request, diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 6284bdbe1e0c..3edb09cb9ee0 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -1,5 +1,5 @@ /* - * vf610 GPIO support through PORT and GPIO module + * Freescale vf610 GPIO support through PORT and GPIO * * Copyright (c) 2014 Toradex AG. * @@ -23,7 +23,6 @@ #include <linux/io.h> #include <linux/ioport.h> #include <linux/irq.h> -#include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_device.h> @@ -289,7 +288,3 @@ static int __init gpio_vf610_init(void) return platform_driver_register(&vf610_gpio_driver); } device_initcall(gpio_vf610_init); - -MODULE_AUTHOR("Stefan Agner <stefan@agner.ch>"); -MODULE_DESCRIPTION("Freescale VF610 GPIO"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c new file mode 100644 index 000000000000..d0ddba7a9d08 --- /dev/null +++ b/drivers/gpio/gpio-wcove.c @@ -0,0 +1,470 @@ +/* + * Intel Whiskey Cove PMIC GPIO Driver + * + * This driver is written based on gpio-crystalcove.c + * + * Copyright (C) 2016 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include <linux/bitops.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/gpio/driver.h> +#include <linux/mfd/intel_soc_pmic.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/seq_file.h> + +/* + * Whiskey Cove PMIC has 13 physical GPIO pins divided into 3 banks: + * Bank 0: Pin 0 - 6 + * Bank 1: Pin 7 - 10 + * Bank 2: Pin 11 -12 + * Each pin has one output control register and one input control register. + */ +#define BANK0_NR_PINS 7 +#define BANK1_NR_PINS 4 +#define BANK2_NR_PINS 2 +#define WCOVE_GPIO_NUM (BANK0_NR_PINS + BANK1_NR_PINS + BANK2_NR_PINS) +#define WCOVE_VGPIO_NUM 94 +/* GPIO output control registers (one per pin): 0x4e44 - 0x4e50 */ +#define GPIO_OUT_CTRL_BASE 0x4e44 +/* GPIO input control registers (one per pin): 0x4e51 - 0x4e5d */ +#define GPIO_IN_CTRL_BASE 0x4e51 + +/* + * GPIO interrupts are organized in two groups: + * Group 0: Bank 0 pins (Pin 0 - 6) + * Group 1: Bank 1 and Bank 2 pins (Pin 7 - 12) + * Each group has two registers (one bit per pin): status and mask. + */ +#define GROUP0_NR_IRQS 7 +#define GROUP1_NR_IRQS 6 +#define IRQ_MASK_BASE 0x4e19 +#define IRQ_STATUS_BASE 0x4e0b +#define UPDATE_IRQ_TYPE BIT(0) +#define UPDATE_IRQ_MASK BIT(1) + +#define CTLI_INTCNT_DIS (0 << 1) +#define CTLI_INTCNT_NE (1 << 1) +#define CTLI_INTCNT_PE (2 << 1) +#define CTLI_INTCNT_BE (3 << 1) + +#define CTLO_DIR_IN (0 << 5) +#define CTLO_DIR_OUT (1 << 5) + +#define CTLO_DRV_MASK (1 << 4) +#define CTLO_DRV_OD (0 << 4) +#define CTLO_DRV_CMOS (1 << 4) + +#define CTLO_DRV_REN (1 << 3) + +#define CTLO_RVAL_2KDOWN (0 << 1) +#define CTLO_RVAL_2KUP (1 << 1) +#define CTLO_RVAL_50KDOWN (2 << 1) +#define CTLO_RVAL_50KUP (3 << 1) + +#define CTLO_INPUT_SET (CTLO_DRV_CMOS | CTLO_DRV_REN | CTLO_RVAL_2KUP) +#define CTLO_OUTPUT_SET (CTLO_DIR_OUT | CTLO_INPUT_SET) + +enum ctrl_register { + CTRL_IN, + CTRL_OUT, +}; + +/* + * struct wcove_gpio - Whiskey Cove GPIO controller + * @buslock: for bus lock/sync and unlock. + * @chip: the abstract gpio_chip structure. + * @dev: the gpio device + * @regmap: the regmap from the parent device. + * @regmap_irq_chip: the regmap of the gpio irq chip. + * @update: pending IRQ setting update, to be written to the chip upon unlock. + * @intcnt: the Interrupt Detect value to be written. + * @set_irq_mask: true if the IRQ mask needs to be set, false to clear. + */ +struct wcove_gpio { + struct mutex buslock; + struct gpio_chip chip; + struct device *dev; + struct regmap *regmap; + struct regmap_irq_chip_data *regmap_irq_chip; + int update; + int intcnt; + bool set_irq_mask; +}; + +static inline unsigned int to_reg(int gpio, enum ctrl_register reg_type) +{ + unsigned int reg; + int bank; + + if (gpio < BANK0_NR_PINS) + bank = 0; + else if (gpio < BANK0_NR_PINS + BANK1_NR_PINS) + bank = 1; + else + bank = 2; + + if (reg_type == CTRL_IN) + reg = GPIO_IN_CTRL_BASE + bank; + else + reg = GPIO_OUT_CTRL_BASE + bank; + + return reg; +} + +static void wcove_update_irq_mask(struct wcove_gpio *wg, int gpio) +{ + unsigned int reg, mask; + + if (gpio < GROUP0_NR_IRQS) { + reg = IRQ_MASK_BASE; + mask = BIT(gpio % GROUP0_NR_IRQS); + } else { + reg = IRQ_MASK_BASE + 1; + mask = BIT((gpio - GROUP0_NR_IRQS) % GROUP1_NR_IRQS); + } + + if (wg->set_irq_mask) + regmap_update_bits(wg->regmap, reg, mask, mask); + else + regmap_update_bits(wg->regmap, reg, mask, 0); +} + +static void wcove_update_irq_ctrl(struct wcove_gpio *wg, int gpio) +{ + unsigned int reg = to_reg(gpio, CTRL_IN); + + regmap_update_bits(wg->regmap, reg, CTLI_INTCNT_BE, wg->intcnt); +} + +static int wcove_gpio_dir_in(struct gpio_chip *chip, unsigned int gpio) +{ + struct wcove_gpio *wg = gpiochip_get_data(chip); + + return regmap_write(wg->regmap, to_reg(gpio, CTRL_OUT), + CTLO_INPUT_SET); +} + +static int wcove_gpio_dir_out(struct gpio_chip *chip, unsigned int gpio, + int value) +{ + struct wcove_gpio *wg = gpiochip_get_data(chip); + + return regmap_write(wg->regmap, to_reg(gpio, CTRL_OUT), + CTLO_OUTPUT_SET | value); +} + +static int wcove_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) +{ + struct wcove_gpio *wg = gpiochip_get_data(chip); + unsigned int val; + int ret; + + ret = regmap_read(wg->regmap, to_reg(gpio, CTRL_OUT), &val); + if (ret) + return ret; + + return !(val & CTLO_DIR_OUT); +} + +static int wcove_gpio_get(struct gpio_chip *chip, unsigned int gpio) +{ + struct wcove_gpio *wg = gpiochip_get_data(chip); + unsigned int val; + int ret; + + ret = regmap_read(wg->regmap, to_reg(gpio, CTRL_IN), &val); + if (ret) + return ret; + + return val & 0x1; +} + +static void wcove_gpio_set(struct gpio_chip *chip, + unsigned int gpio, int value) +{ + struct wcove_gpio *wg = gpiochip_get_data(chip); + + if (value) + regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT), 1, 1); + else + regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT), 1, 0); +} + +static int wcove_gpio_set_single_ended(struct gpio_chip *chip, + unsigned int gpio, + enum single_ended_mode mode) +{ + struct wcove_gpio *wg = gpiochip_get_data(chip); + + switch (mode) { + case LINE_MODE_OPEN_DRAIN: + return regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT), + CTLO_DRV_MASK, CTLO_DRV_OD); + case LINE_MODE_PUSH_PULL: + return regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT), + CTLO_DRV_MASK, CTLO_DRV_CMOS); + default: + break; + } + + return -ENOTSUPP; +} + +static int wcove_irq_type(struct irq_data *data, unsigned int type) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct wcove_gpio *wg = gpiochip_get_data(chip); + + switch (type) { + case IRQ_TYPE_NONE: + wg->intcnt = CTLI_INTCNT_DIS; + break; + case IRQ_TYPE_EDGE_BOTH: + wg->intcnt = CTLI_INTCNT_BE; + break; + case IRQ_TYPE_EDGE_RISING: + wg->intcnt = CTLI_INTCNT_PE; + break; + case IRQ_TYPE_EDGE_FALLING: + wg->intcnt = CTLI_INTCNT_NE; + break; + default: + return -EINVAL; + } + + wg->update |= UPDATE_IRQ_TYPE; + + return 0; +} + +static void wcove_bus_lock(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct wcove_gpio *wg = gpiochip_get_data(chip); + + mutex_lock(&wg->buslock); +} + +static void wcove_bus_sync_unlock(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct wcove_gpio *wg = gpiochip_get_data(chip); + int gpio = data->hwirq; + + if (wg->update & UPDATE_IRQ_TYPE) + wcove_update_irq_ctrl(wg, gpio); + if (wg->update & UPDATE_IRQ_MASK) + wcove_update_irq_mask(wg, gpio); + wg->update = 0; + + mutex_unlock(&wg->buslock); +} + +static void wcove_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct wcove_gpio *wg = gpiochip_get_data(chip); + + wg->set_irq_mask = false; + wg->update |= UPDATE_IRQ_MASK; +} + +static void wcove_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct wcove_gpio *wg = gpiochip_get_data(chip); + + wg->set_irq_mask = true; + wg->update |= UPDATE_IRQ_MASK; +} + +static struct irq_chip wcove_irqchip = { + .name = "Whiskey Cove", + .irq_mask = wcove_irq_mask, + .irq_unmask = wcove_irq_unmask, + .irq_set_type = wcove_irq_type, + .irq_bus_lock = wcove_bus_lock, + .irq_bus_sync_unlock = wcove_bus_sync_unlock, +}; + +static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) +{ + struct wcove_gpio *wg = (struct wcove_gpio *)data; + unsigned int pending, virq, gpio, mask, offset; + u8 p[2]; + + if (regmap_bulk_read(wg->regmap, IRQ_STATUS_BASE, p, 2)) { + dev_err(wg->dev, "Failed to read irq status register\n"); + return IRQ_NONE; + } + + pending = p[0] | (p[1] << 8); + if (!pending) + return IRQ_NONE; + + /* Iterate until no interrupt is pending */ + while (pending) { + /* One iteration is for all pending bits */ + for_each_set_bit(gpio, (const unsigned long *)&pending, + GROUP0_NR_IRQS) { + offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0; + mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) : + BIT(gpio); + virq = irq_find_mapping(wg->chip.irqdomain, gpio); + handle_nested_irq(virq); + regmap_update_bits(wg->regmap, IRQ_STATUS_BASE + offset, + mask, mask); + } + + /* Next iteration */ + if (regmap_bulk_read(wg->regmap, IRQ_STATUS_BASE, p, 2)) { + dev_err(wg->dev, "Failed to read irq status\n"); + break; + } + + pending = p[0] | (p[1] << 8); + } + + return IRQ_HANDLED; +} + +static void wcove_gpio_dbg_show(struct seq_file *s, + struct gpio_chip *chip) +{ + unsigned int ctlo, ctli, irq_mask, irq_status; + struct wcove_gpio *wg = gpiochip_get_data(chip); + int gpio, offset, group, ret = 0; + + for (gpio = 0; gpio < WCOVE_GPIO_NUM; gpio++) { + group = gpio < GROUP0_NR_IRQS ? 0 : 1; + ret += regmap_read(wg->regmap, to_reg(gpio, CTRL_OUT), &ctlo); + ret += regmap_read(wg->regmap, to_reg(gpio, CTRL_IN), &ctli); + ret += regmap_read(wg->regmap, IRQ_MASK_BASE + group, + &irq_mask); + ret += regmap_read(wg->regmap, IRQ_STATUS_BASE + group, + &irq_status); + if (ret) { + pr_err("Failed to read registers: ctrl out/in or irq status/mask\n"); + break; + } + + offset = gpio % 8; + seq_printf(s, " gpio-%-2d %s %s %s %s ctlo=%2x,%s %s\n", + gpio, ctlo & CTLO_DIR_OUT ? "out" : "in ", + ctli & 0x1 ? "hi" : "lo", + ctli & CTLI_INTCNT_NE ? "fall" : " ", + ctli & CTLI_INTCNT_PE ? "rise" : " ", + ctlo, + irq_mask & BIT(offset) ? "mask " : "unmask", + irq_status & BIT(offset) ? "pending" : " "); + } +} + +static int wcove_gpio_probe(struct platform_device *pdev) +{ + struct intel_soc_pmic *pmic; + struct wcove_gpio *wg; + int virq, ret, irq; + struct device *dev; + + /* + * This gpio platform device is created by a mfd device (see + * drivers/mfd/intel_soc_pmic_bxtwc.c for details). Information + * shared by all sub-devices created by the mfd device, the regmap + * pointer for instance, is stored as driver data of the mfd device + * driver. + */ + pmic = dev_get_drvdata(pdev->dev.parent); + if (!pmic) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + dev = &pdev->dev; + + wg = devm_kzalloc(dev, sizeof(*wg), GFP_KERNEL); + if (!wg) + return -ENOMEM; + + wg->regmap_irq_chip = pmic->irq_chip_data_level2; + + platform_set_drvdata(pdev, wg); + + mutex_init(&wg->buslock); + wg->chip.label = KBUILD_MODNAME; + wg->chip.direction_input = wcove_gpio_dir_in; + wg->chip.direction_output = wcove_gpio_dir_out; + wg->chip.get_direction = wcove_gpio_get_direction; + wg->chip.get = wcove_gpio_get; + wg->chip.set = wcove_gpio_set; + wg->chip.set_single_ended = wcove_gpio_set_single_ended, + wg->chip.base = -1; + wg->chip.ngpio = WCOVE_VGPIO_NUM; + wg->chip.can_sleep = true; + wg->chip.parent = pdev->dev.parent; + wg->chip.dbg_show = wcove_gpio_dbg_show; + wg->dev = dev; + wg->regmap = pmic->regmap; + + ret = devm_gpiochip_add_data(dev, &wg->chip, wg); + if (ret) { + dev_err(dev, "Failed to add gpiochip: %d\n", ret); + return ret; + } + + ret = gpiochip_irqchip_add(&wg->chip, &wcove_irqchip, 0, + handle_simple_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "Failed to add irqchip: %d\n", ret); + return ret; + } + + virq = regmap_irq_get_virq(wg->regmap_irq_chip, irq); + if (virq < 0) { + dev_err(dev, "Failed to get virq by irq %d\n", irq); + return virq; + } + + ret = devm_request_threaded_irq(dev, virq, NULL, + wcove_gpio_irq_handler, IRQF_ONESHOT, pdev->name, wg); + if (ret) { + dev_err(dev, "Failed to request irq %d\n", virq); + return ret; + } + + return 0; +} + +/* + * Whiskey Cove PMIC itself is a analog device(but with digital control + * interface) providing power management support for other devices in + * the accompanied SoC, so we have no .pm for Whiskey Cove GPIO driver. + */ +static struct platform_driver wcove_gpio_driver = { + .driver = { + .name = "bxt_wcove_gpio", + }, + .probe = wcove_gpio_probe, +}; + +module_platform_driver(wcove_gpio_driver); + +MODULE_AUTHOR("Ajay Thomas <ajay.thomas.david.rajamanickam@intel.com>"); +MODULE_AUTHOR("Bin Gao <bin.gao@intel.com>"); +MODULE_DESCRIPTION("Intel Whiskey Cove GPIO Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bxt_wcove_gpio"); diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 21f97bcd0062..533707f943f4 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -247,7 +247,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) #define wm831x_gpio_dbg_show NULL #endif -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "wm831x", .owner = THIS_MODULE, .direction_input = wm831x_gpio_direction_in, diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index e9765707d5c1..e46752e73dd9 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -93,7 +93,7 @@ static int wm8350_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return wm8350->irq_base + WM8350_IRQ_GPIO(offset); } -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "wm8350", .owner = THIS_MODULE, .direction_input = wm8350_gpio_direction_in, diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index 2457aac8592e..68410fda6138 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -249,7 +249,7 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) #define wm8994_gpio_dbg_show NULL #endif -static struct gpio_chip template_chip = { +static const struct gpio_chip template_chip = { .label = "wm8994", .owner = THIS_MODULE, .request = wm8994_gpio_request, diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index e72794e463aa..6b4d10d6e10f 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -96,6 +96,9 @@ /* GPIO upper 16 bit mask */ #define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000 +/* For GPIO quirks */ +#define ZYNQ_GPIO_QUIRK_FOO BIT(0) + /** * struct zynq_gpio - gpio device private data structure * @chip: instance of the gpio_chip @@ -122,6 +125,7 @@ struct zynq_gpio { */ struct zynq_platform_data { const char *label; + u32 quirks; u16 ngpio; int max_bank; int bank_min[ZYNQMP_GPIO_MAX_BANK]; @@ -238,13 +242,19 @@ static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin, static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin) { u32 reg; + bool is_zynq_gpio; unsigned int bank_num, bank_pin_num; struct zynq_gpio *gpio = gpiochip_get_data(chip); + is_zynq_gpio = gpio->p_data->quirks & ZYNQ_GPIO_QUIRK_FOO; zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); - /* bank 0 pins 7 and 8 are special and cannot be used as inputs */ - if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8)) + /* + * On zynq bank 0 pins 7 and 8 are special and cannot be used + * as inputs. + */ + if (is_zynq_gpio && bank_num == 0 && + (bank_pin_num == 7 || bank_pin_num == 8)) return -EINVAL; /* clear the bit in direction mode reg to set the pin as input */ @@ -627,6 +637,7 @@ static const struct zynq_platform_data zynqmp_gpio_def = { static const struct zynq_platform_data zynq_gpio_def = { .label = "zynq_gpio", + .quirks = ZYNQ_GPIO_QUIRK_FOO, .ngpio = ZYNQ_GPIO_NR_GPIOS, .max_bank = ZYNQ_GPIO_MAX_BANK, .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(), diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index af514618d7fb..58ece201b8e6 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -14,6 +14,7 @@ #include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> +#include <linux/gpio/machine.h> #include <linux/export.h> #include <linux/acpi.h> #include <linux/interrupt.h> @@ -395,7 +396,7 @@ struct acpi_gpio_lookup { int n; }; -static int acpi_find_gpio(struct acpi_resource *ares, void *data) +static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) { struct acpi_gpio_lookup *lookup = data; @@ -440,7 +441,8 @@ static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup, INIT_LIST_HEAD(&res_list); - ret = acpi_dev_get_resources(lookup->adev, &res_list, acpi_find_gpio, + ret = acpi_dev_get_resources(lookup->adev, &res_list, + acpi_populate_gpio_lookup, lookup); if (ret < 0) return ret; @@ -513,7 +515,7 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, * Note: if the GPIO resource has multiple entries in the pin list, this * function only returns the first. */ -struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, +static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, int index, struct acpi_gpio_info *info) { @@ -546,6 +548,55 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, return ret ? ERR_PTR(ret) : lookup.desc; } +struct gpio_desc *acpi_find_gpio(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags, + enum gpio_lookup_flags *lookupflags) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + struct acpi_gpio_info info; + struct gpio_desc *desc; + char propname[32]; + 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]); + } + + desc = acpi_get_gpiod_by_index(adev, propname, idx, &info); + if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER)) + break; + } + + /* Then from plain _CRS GPIOs */ + if (IS_ERR(desc)) { + if (!acpi_can_fallback_to_crs(adev, con_id)) + return ERR_PTR(-ENOENT); + + desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info); + if (IS_ERR(desc)) + return desc; + + if ((flags == GPIOD_OUT_LOW || flags == GPIOD_OUT_HIGH) && + info.gpioint) { + dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n"); + return ERR_PTR(-ENOENT); + } + } + + if (info.polarity == GPIO_ACTIVE_LOW) + *lookupflags |= GPIO_ACTIVE_LOW; + + return desc; +} + /** * acpi_node_get_gpiod() - get a GPIO descriptor from ACPI resources * @fwnode: pointer to an ACPI firmware node to get the GPIO information from diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index a28feb3edf33..ecad3f0e3b77 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -113,6 +113,45 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name, } EXPORT_SYMBOL(of_get_named_gpio_flags); +struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, + unsigned int idx, + enum gpio_lookup_flags *flags) +{ + 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(gpio_suffixes); i++) { + if (con_id) + snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id, + gpio_suffixes[i]); + else + snprintf(prop_name, sizeof(prop_name), "%s", + gpio_suffixes[i]); + + desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, + &of_flags); + if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) + break; + } + + if (IS_ERR(desc)) + return desc; + + if (of_flags & OF_GPIO_ACTIVE_LOW) + *flags |= GPIO_ACTIVE_LOW; + + if (of_flags & OF_GPIO_SINGLE_ENDED) { + if (of_flags & OF_GPIO_ACTIVE_LOW) + *flags |= GPIO_OPEN_DRAIN; + else + *flags |= GPIO_OPEN_SOURCE; + } + + return desc; +} + /** * of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API * @np: device node to get GPIO from diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 932e510aec50..4b44dd97c07f 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -670,10 +670,10 @@ int gpiod_export_link(struct device *dev, const char *name, EXPORT_SYMBOL_GPL(gpiod_export_link); /** - * gpiod_unexport - reverse effect of gpio_export() + * gpiod_unexport - reverse effect of gpiod_export() * @gpio: gpio to make unavailable * - * This is implicit on gpio_free(). + * This is implicit on gpiod_free(). */ void gpiod_unexport(struct gpio_desc *desc) { diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 23be4daefeed..f0fc3a0d37c8 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1370,19 +1370,15 @@ struct gpio_chip *gpiochip_find(void *data, void *data)) { struct gpio_device *gdev; - struct gpio_chip *chip; + struct gpio_chip *chip = NULL; unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); list_for_each_entry(gdev, &gpio_devices, list) - if (gdev->chip && match(gdev->chip, data)) + if (gdev->chip && match(gdev->chip, data)) { + chip = gdev->chip; break; - - /* No match? */ - if (&gdev->list == &gpio_devices) - chip = NULL; - else - chip = gdev->chip; + } spin_unlock_irqrestore(&gpio_lock, flags); @@ -1667,6 +1663,20 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, if (gpiochip->of_node) of_node = gpiochip->of_node; #endif + /* + * Specifying a default trigger is a terrible idea if DT or ACPI is + * used to configure the interrupts, as you may end-up with + * conflicting triggers. Tell the user, and reset to NONE. + */ + if (WARN(of_node && type != IRQ_TYPE_NONE, + "%s: Ignoring %d default trigger\n", of_node->full_name, type)) + type = IRQ_TYPE_NONE; + if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) { + acpi_handle_warn(ACPI_HANDLE(gpiochip->parent), + "Ignoring %d default trigger\n", type); + type = IRQ_TYPE_NONE; + } + gpiochip->irqchip = irqchip; gpiochip->irq_handler = handler; gpiochip->irq_default_type = type; @@ -2873,94 +2883,6 @@ void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) mutex_unlock(&gpio_lookup_lock); } -static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, - unsigned int idx, - enum gpio_lookup_flags *flags) -{ - 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(gpio_suffixes); i++) { - if (con_id) - snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id, - gpio_suffixes[i]); - else - snprintf(prop_name, sizeof(prop_name), "%s", - gpio_suffixes[i]); - - desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, - &of_flags); - if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) - break; - } - - if (IS_ERR(desc)) - return desc; - - if (of_flags & OF_GPIO_ACTIVE_LOW) - *flags |= GPIO_ACTIVE_LOW; - - if (of_flags & OF_GPIO_SINGLE_ENDED) { - if (of_flags & OF_GPIO_ACTIVE_LOW) - *flags |= GPIO_OPEN_DRAIN; - else - *flags |= GPIO_OPEN_SOURCE; - } - - return desc; -} - -static struct gpio_desc *acpi_find_gpio(struct device *dev, - const char *con_id, - unsigned int idx, - enum gpiod_flags flags, - enum gpio_lookup_flags *lookupflags) -{ - struct acpi_device *adev = ACPI_COMPANION(dev); - struct acpi_gpio_info info; - struct gpio_desc *desc; - char propname[32]; - 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]); - } - - desc = acpi_get_gpiod_by_index(adev, propname, idx, &info); - if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER)) - break; - } - - /* Then from plain _CRS GPIOs */ - if (IS_ERR(desc)) { - if (!acpi_can_fallback_to_crs(adev, con_id)) - return ERR_PTR(-ENOENT); - - desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info); - if (IS_ERR(desc)) - return desc; - - if ((flags == GPIOD_OUT_LOW || flags == GPIOD_OUT_HIGH) && - info.gpioint) { - dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n"); - return ERR_PTR(-ENOENT); - } - } - - if (info.polarity == GPIO_ACTIVE_LOW) - *lookupflags |= GPIO_ACTIVE_LOW; - - return desc; -} - static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) { const char *dev_id = dev ? dev_name(dev) : NULL; diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 2d9ea5e0cab3..346fbda39220 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -20,6 +20,7 @@ enum of_gpio_flags; enum gpiod_flags; +enum gpio_lookup_flags; struct acpi_device; /** @@ -86,6 +87,32 @@ struct acpi_gpio_info { /* gpio suffixes used for ACPI and device tree lookup */ static const char * const gpio_suffixes[] = { "gpios", "gpio" }; +#ifdef CONFIG_OF_GPIO +struct gpio_desc *of_find_gpio(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpio_lookup_flags *flags); +struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, + const char *list_name, int index, enum of_gpio_flags *flags); +int of_gpiochip_add(struct gpio_chip *gc); +void of_gpiochip_remove(struct gpio_chip *gc); +#else +static inline struct gpio_desc *of_find_gpio(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpio_lookup_flags *flags) +{ + return ERR_PTR(-ENOENT); +} +static inline struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, + const char *list_name, int index, enum of_gpio_flags *flags) +{ + return ERR_PTR(-ENOENT); +} +static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; } +static inline void of_gpiochip_remove(struct gpio_chip *gc) { } +#endif /* CONFIG_OF_GPIO */ + #ifdef CONFIG_ACPI void acpi_gpiochip_add(struct gpio_chip *chip); void acpi_gpiochip_remove(struct gpio_chip *chip); @@ -93,9 +120,11 @@ void acpi_gpiochip_remove(struct gpio_chip *chip); void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); 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); +struct gpio_desc *acpi_find_gpio(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags, + enum gpio_lookup_flags *lookupflags); struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname, int index, struct acpi_gpio_info *info); @@ -114,10 +143,11 @@ static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } static inline struct gpio_desc * -acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, - int index, struct acpi_gpio_info *info) +acpi_find_gpio(struct device *dev, const char *con_id, + unsigned int idx, enum gpiod_flags flags, + enum gpio_lookup_flags *lookupflags) { - return ERR_PTR(-ENOSYS); + return ERR_PTR(-ENOENT); } static inline struct gpio_desc * acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname, @@ -137,9 +167,6 @@ static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev, } #endif -struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, - const char *list_name, int index, enum of_gpio_flags *flags); - struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum); void gpiod_set_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 2d1fb6420592..2caf7e967390 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -340,14 +340,6 @@ config MFD_HI655X_PMIC help Select this option to enable Hisilicon hi655x series pmic driver. -config HTC_EGPIO - bool "HTC EGPIO support" - depends on GPIOLIB && ARM - help - This driver supports the CPLD egpio chip present on - several HTC phones. It provides basic support for input - pins, output pins, and irqs. - config HTC_PASIC3 tristate "HTC PASIC3 LED/DS1WM chip support" select MFD_CORE @@ -1224,6 +1216,20 @@ config MFD_TPS65217 This driver can also be built as a module. If so, the module will be called tps65217. +config MFD_TI_LP873X + tristate "TI LP873X Power Management IC" + depends on I2C + select MFD_CORE + select REGMAP_I2C + help + If you say yes here then you get support for the LP873X series of + Power Management Integrated Circuits (PMIC). + These include voltage regulators, thermal protection, configurable + General Purpose Outputs (GPO) that are used in portable devices. + + This driver can also be built as a module. If so, the module + will be called lp873x. + config MFD_TPS65218 tristate "TI TPS65218 Power Management chips" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2ba3ba35f745..2bf6a1ac7428 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -18,10 +18,11 @@ rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o obj-$(CONFIG_MFD_RTSX_USB) += rtsx_usb.o -obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o +obj-$(CONFIG_MFD_TI_LP873X) += lp873x.o + obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o diff --git a/drivers/mfd/lp873x.c b/drivers/mfd/lp873x.c new file mode 100644 index 000000000000..9af064c940ee --- /dev/null +++ b/drivers/mfd/lp873x.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * + * Author: Keerthy <j-keerthy@ti.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/interrupt.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regmap.h> + +#include <linux/mfd/lp873x.h> + +static const struct regmap_config lp873x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = LP873X_REG_MAX, +}; + +static const struct mfd_cell lp873x_cells[] = { + { .name = "lp873x-regulator", }, + { .name = "lp873x-gpio", }, +}; + +static int lp873x_probe(struct i2c_client *client, + const struct i2c_device_id *ids) +{ + struct lp873x *lp873; + int ret; + unsigned int otpid; + + lp873 = devm_kzalloc(&client->dev, sizeof(*lp873), GFP_KERNEL); + if (!lp873) + return -ENOMEM; + + lp873->dev = &client->dev; + + lp873->regmap = devm_regmap_init_i2c(client, &lp873x_regmap_config); + if (IS_ERR(lp873->regmap)) { + ret = PTR_ERR(lp873->regmap); + dev_err(lp873->dev, + "Failed to initialize register map: %d\n", ret); + return ret; + } + + mutex_init(&lp873->lock); + + ret = regmap_read(lp873->regmap, LP873X_REG_OTP_REV, &otpid); + if (ret) { + dev_err(lp873->dev, "Failed to read OTP ID\n"); + return ret; + } + + lp873->rev = otpid & LP873X_OTP_REV_OTP_ID; + + i2c_set_clientdata(client, lp873); + + ret = mfd_add_devices(lp873->dev, PLATFORM_DEVID_AUTO, lp873x_cells, + ARRAY_SIZE(lp873x_cells), NULL, 0, NULL); + + return ret; +} + +static const struct of_device_id of_lp873x_match_table[] = { + { .compatible = "ti,lp8733", }, + { .compatible = "ti,lp8732", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_lp873x_match_table); + +static const struct i2c_device_id lp873x_id_table[] = { + { "lp873x", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, lp873x_id_table); + +static struct i2c_driver lp873x_driver = { + .driver = { + .name = "lp873x", + .of_match_table = of_lp873x_match_table, + }, + .probe = lp873x_probe, + .id_table = lp873x_id_table, +}; +module_i2c_driver(lp873x_driver); + +MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>"); +MODULE_DESCRIPTION("LP873X chip family Multi-Function Device driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index c3f4aab53b07..863c39a3353c 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c @@ -57,6 +57,7 @@ static const struct of_device_id stmpe_of_match[] = { { .compatible = "st,stmpe610", .data = (void *)STMPE610, }, { .compatible = "st,stmpe801", .data = (void *)STMPE801, }, { .compatible = "st,stmpe811", .data = (void *)STMPE811, }, + { .compatible = "st,stmpe1600", .data = (void *)STMPE1600, }, { .compatible = "st,stmpe1601", .data = (void *)STMPE1601, }, { .compatible = "st,stmpe1801", .data = (void *)STMPE1801, }, { .compatible = "st,stmpe2401", .data = (void *)STMPE2401, }, @@ -101,6 +102,7 @@ static const struct i2c_device_id stmpe_i2c_id[] = { { "stmpe610", STMPE610 }, { "stmpe801", STMPE801 }, { "stmpe811", STMPE811 }, + { "stmpe1600", STMPE1600 }, { "stmpe1601", STMPE1601 }, { "stmpe1801", STMPE1801 }, { "stmpe2401", STMPE2401 }, diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 94c7cc02fdab..cfdae8a3d779 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -469,6 +469,8 @@ static const struct mfd_cell stmpe_ts_cell = { static const u8 stmpe811_regs[] = { [STMPE_IDX_CHIP_ID] = STMPE811_REG_CHIP_ID, + [STMPE_IDX_SYS_CTRL] = STMPE811_REG_SYS_CTRL, + [STMPE_IDX_SYS_CTRL2] = STMPE811_REG_SYS_CTRL2, [STMPE_IDX_ICR_LSB] = STMPE811_REG_INT_CTRL, [STMPE_IDX_IER_LSB] = STMPE811_REG_INT_EN, [STMPE_IDX_ISR_MSB] = STMPE811_REG_INT_STA, @@ -481,7 +483,7 @@ static const u8 stmpe811_regs[] = { [STMPE_IDX_GPAFR_U_MSB] = STMPE811_REG_GPIO_AF, [STMPE_IDX_IEGPIOR_LSB] = STMPE811_REG_GPIO_INT_EN, [STMPE_IDX_ISGPIOR_MSB] = STMPE811_REG_GPIO_INT_STA, - [STMPE_IDX_GPEDR_MSB] = STMPE811_REG_GPIO_ED, + [STMPE_IDX_GPEDR_LSB] = STMPE811_REG_GPIO_ED, }; static struct stmpe_variant_block stmpe811_blocks[] = { @@ -511,7 +513,7 @@ static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks, if (blocks & STMPE_BLOCK_TOUCHSCREEN) mask |= STMPE811_SYS_CTRL2_TSC_OFF; - return __stmpe_set_bits(stmpe, STMPE811_REG_SYS_CTRL2, mask, + return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL2], mask, enable ? 0 : mask); } @@ -551,25 +553,89 @@ static struct stmpe_variant_info stmpe610 = { }; /* + * STMPE1600 + * Compared to all others STMPE variant, LSB and MSB regs are located in this + * order : LSB addr + * MSB addr + 1 + * As there is only 2 * 8bits registers for GPMR/GPSR/IEGPIOPR, CSB index is MSB registers + */ + +static const u8 stmpe1600_regs[] = { + [STMPE_IDX_CHIP_ID] = STMPE1600_REG_CHIP_ID, + [STMPE_IDX_SYS_CTRL] = STMPE1600_REG_SYS_CTRL, + [STMPE_IDX_ICR_LSB] = STMPE1600_REG_SYS_CTRL, + [STMPE_IDX_GPMR_LSB] = STMPE1600_REG_GPMR_LSB, + [STMPE_IDX_GPMR_CSB] = STMPE1600_REG_GPMR_MSB, + [STMPE_IDX_GPSR_LSB] = STMPE1600_REG_GPSR_LSB, + [STMPE_IDX_GPSR_CSB] = STMPE1600_REG_GPSR_MSB, + [STMPE_IDX_GPDR_LSB] = STMPE1600_REG_GPDR_LSB, + [STMPE_IDX_GPDR_CSB] = STMPE1600_REG_GPDR_MSB, + [STMPE_IDX_IEGPIOR_LSB] = STMPE1600_REG_IEGPIOR_LSB, + [STMPE_IDX_IEGPIOR_CSB] = STMPE1600_REG_IEGPIOR_MSB, + [STMPE_IDX_ISGPIOR_LSB] = STMPE1600_REG_ISGPIOR_LSB, +}; + +static struct stmpe_variant_block stmpe1600_blocks[] = { + { + .cell = &stmpe_gpio_cell, + .irq = 0, + .block = STMPE_BLOCK_GPIO, + }, +}; + +static int stmpe1600_enable(struct stmpe *stmpe, unsigned int blocks, + bool enable) +{ + if (blocks & STMPE_BLOCK_GPIO) + return 0; + else + return -EINVAL; +} + +static struct stmpe_variant_info stmpe1600 = { + .name = "stmpe1600", + .id_val = STMPE1600_ID, + .id_mask = 0xffff, + .num_gpios = 16, + .af_bits = 0, + .regs = stmpe1600_regs, + .blocks = stmpe1600_blocks, + .num_blocks = ARRAY_SIZE(stmpe1600_blocks), + .num_irqs = STMPE1600_NR_INTERNAL_IRQS, + .enable = stmpe1600_enable, +}; + +/* * STMPE1601 */ static const u8 stmpe1601_regs[] = { [STMPE_IDX_CHIP_ID] = STMPE1601_REG_CHIP_ID, + [STMPE_IDX_SYS_CTRL] = STMPE1601_REG_SYS_CTRL, + [STMPE_IDX_SYS_CTRL2] = STMPE1601_REG_SYS_CTRL2, [STMPE_IDX_ICR_LSB] = STMPE1601_REG_ICR_LSB, + [STMPE_IDX_IER_MSB] = STMPE1601_REG_IER_MSB, [STMPE_IDX_IER_LSB] = STMPE1601_REG_IER_LSB, [STMPE_IDX_ISR_MSB] = STMPE1601_REG_ISR_MSB, [STMPE_IDX_GPMR_LSB] = STMPE1601_REG_GPIO_MP_LSB, + [STMPE_IDX_GPMR_CSB] = STMPE1601_REG_GPIO_MP_MSB, [STMPE_IDX_GPSR_LSB] = STMPE1601_REG_GPIO_SET_LSB, + [STMPE_IDX_GPSR_CSB] = STMPE1601_REG_GPIO_SET_MSB, [STMPE_IDX_GPCR_LSB] = STMPE1601_REG_GPIO_CLR_LSB, + [STMPE_IDX_GPCR_CSB] = STMPE1601_REG_GPIO_CLR_MSB, [STMPE_IDX_GPDR_LSB] = STMPE1601_REG_GPIO_SET_DIR_LSB, + [STMPE_IDX_GPDR_CSB] = STMPE1601_REG_GPIO_SET_DIR_MSB, + [STMPE_IDX_GPEDR_LSB] = STMPE1601_REG_GPIO_ED_LSB, + [STMPE_IDX_GPEDR_CSB] = STMPE1601_REG_GPIO_ED_MSB, [STMPE_IDX_GPRER_LSB] = STMPE1601_REG_GPIO_RE_LSB, + [STMPE_IDX_GPRER_CSB] = STMPE1601_REG_GPIO_RE_MSB, [STMPE_IDX_GPFER_LSB] = STMPE1601_REG_GPIO_FE_LSB, + [STMPE_IDX_GPFER_CSB] = STMPE1601_REG_GPIO_FE_MSB, [STMPE_IDX_GPPUR_LSB] = STMPE1601_REG_GPIO_PU_LSB, [STMPE_IDX_GPAFR_U_MSB] = STMPE1601_REG_GPIO_AF_U_MSB, [STMPE_IDX_IEGPIOR_LSB] = STMPE1601_REG_INT_EN_GPIO_MASK_LSB, + [STMPE_IDX_IEGPIOR_CSB] = STMPE1601_REG_INT_EN_GPIO_MASK_MSB, [STMPE_IDX_ISGPIOR_MSB] = STMPE1601_REG_INT_STA_GPIO_MSB, - [STMPE_IDX_GPEDR_MSB] = STMPE1601_REG_GPIO_ED_MSB, }; static struct stmpe_variant_block stmpe1601_blocks[] = { @@ -640,13 +706,13 @@ static int stmpe1601_autosleep(struct stmpe *stmpe, return timeout; } - ret = __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2, + ret = __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL2], STMPE1601_AUTOSLEEP_TIMEOUT_MASK, timeout); if (ret < 0) return ret; - return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2, + return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL2], STPME1601_AUTOSLEEP_ENABLE, STPME1601_AUTOSLEEP_ENABLE); } @@ -671,7 +737,7 @@ static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks, else mask &= ~STMPE1601_SYS_CTRL_ENABLE_SPWM; - return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask, + return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL], mask, enable ? mask : 0); } @@ -710,18 +776,33 @@ static struct stmpe_variant_info stmpe1601 = { */ static const u8 stmpe1801_regs[] = { [STMPE_IDX_CHIP_ID] = STMPE1801_REG_CHIP_ID, + [STMPE_IDX_SYS_CTRL] = STMPE1801_REG_SYS_CTRL, [STMPE_IDX_ICR_LSB] = STMPE1801_REG_INT_CTRL_LOW, [STMPE_IDX_IER_LSB] = STMPE1801_REG_INT_EN_MASK_LOW, [STMPE_IDX_ISR_LSB] = STMPE1801_REG_INT_STA_LOW, [STMPE_IDX_GPMR_LSB] = STMPE1801_REG_GPIO_MP_LOW, + [STMPE_IDX_GPMR_CSB] = STMPE1801_REG_GPIO_MP_MID, + [STMPE_IDX_GPMR_MSB] = STMPE1801_REG_GPIO_MP_HIGH, [STMPE_IDX_GPSR_LSB] = STMPE1801_REG_GPIO_SET_LOW, + [STMPE_IDX_GPSR_CSB] = STMPE1801_REG_GPIO_SET_MID, + [STMPE_IDX_GPSR_MSB] = STMPE1801_REG_GPIO_SET_HIGH, [STMPE_IDX_GPCR_LSB] = STMPE1801_REG_GPIO_CLR_LOW, + [STMPE_IDX_GPCR_CSB] = STMPE1801_REG_GPIO_CLR_MID, + [STMPE_IDX_GPCR_MSB] = STMPE1801_REG_GPIO_CLR_HIGH, [STMPE_IDX_GPDR_LSB] = STMPE1801_REG_GPIO_SET_DIR_LOW, + [STMPE_IDX_GPDR_CSB] = STMPE1801_REG_GPIO_SET_DIR_MID, + [STMPE_IDX_GPDR_MSB] = STMPE1801_REG_GPIO_SET_DIR_HIGH, [STMPE_IDX_GPRER_LSB] = STMPE1801_REG_GPIO_RE_LOW, + [STMPE_IDX_GPRER_CSB] = STMPE1801_REG_GPIO_RE_MID, + [STMPE_IDX_GPRER_MSB] = STMPE1801_REG_GPIO_RE_HIGH, [STMPE_IDX_GPFER_LSB] = STMPE1801_REG_GPIO_FE_LOW, + [STMPE_IDX_GPFER_CSB] = STMPE1801_REG_GPIO_FE_MID, + [STMPE_IDX_GPFER_MSB] = STMPE1801_REG_GPIO_FE_HIGH, [STMPE_IDX_GPPUR_LSB] = STMPE1801_REG_GPIO_PULL_UP_LOW, [STMPE_IDX_IEGPIOR_LSB] = STMPE1801_REG_INT_EN_GPIO_MASK_LOW, - [STMPE_IDX_ISGPIOR_LSB] = STMPE1801_REG_INT_STA_GPIO_LOW, + [STMPE_IDX_IEGPIOR_CSB] = STMPE1801_REG_INT_EN_GPIO_MASK_MID, + [STMPE_IDX_IEGPIOR_MSB] = STMPE1801_REG_INT_EN_GPIO_MASK_HIGH, + [STMPE_IDX_ISGPIOR_MSB] = STMPE1801_REG_INT_STA_GPIO_HIGH, }; static struct stmpe_variant_block stmpe1801_blocks[] = { @@ -751,22 +832,31 @@ static int stmpe1801_enable(struct stmpe *stmpe, unsigned int blocks, enable ? mask : 0); } -static int stmpe1801_reset(struct stmpe *stmpe) +static int stmpe_reset(struct stmpe *stmpe) { + u16 id_val = stmpe->variant->id_val; unsigned long timeout; int ret = 0; + u8 reset_bit; + + if (id_val == STMPE811_ID) + /* STMPE801 and STMPE610 use bit 1 of SYS_CTRL register */ + reset_bit = STMPE811_SYS_CTRL_RESET; + else + /* all other STMPE variant use bit 7 of SYS_CTRL register */ + reset_bit = STMPE_SYS_CTRL_RESET; - ret = __stmpe_set_bits(stmpe, STMPE1801_REG_SYS_CTRL, - STMPE1801_MSK_SYS_CTRL_RESET, STMPE1801_MSK_SYS_CTRL_RESET); + ret = __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL], + reset_bit, reset_bit); if (ret < 0) return ret; timeout = jiffies + msecs_to_jiffies(100); while (time_before(jiffies, timeout)) { - ret = __stmpe_reg_read(stmpe, STMPE1801_REG_SYS_CTRL); + ret = __stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL]); if (ret < 0) return ret; - if (!(ret & STMPE1801_MSK_SYS_CTRL_RESET)) + if (!(ret & reset_bit)) return 0; usleep_range(100, 200); } @@ -794,20 +884,39 @@ static struct stmpe_variant_info stmpe1801 = { static const u8 stmpe24xx_regs[] = { [STMPE_IDX_CHIP_ID] = STMPE24XX_REG_CHIP_ID, + [STMPE_IDX_SYS_CTRL] = STMPE24XX_REG_SYS_CTRL, + [STMPE_IDX_SYS_CTRL2] = STMPE24XX_REG_SYS_CTRL2, [STMPE_IDX_ICR_LSB] = STMPE24XX_REG_ICR_LSB, + [STMPE_IDX_IER_MSB] = STMPE24XX_REG_IER_MSB, [STMPE_IDX_IER_LSB] = STMPE24XX_REG_IER_LSB, [STMPE_IDX_ISR_MSB] = STMPE24XX_REG_ISR_MSB, [STMPE_IDX_GPMR_LSB] = STMPE24XX_REG_GPMR_LSB, + [STMPE_IDX_GPMR_CSB] = STMPE24XX_REG_GPMR_CSB, + [STMPE_IDX_GPMR_MSB] = STMPE24XX_REG_GPMR_MSB, [STMPE_IDX_GPSR_LSB] = STMPE24XX_REG_GPSR_LSB, + [STMPE_IDX_GPSR_CSB] = STMPE24XX_REG_GPSR_CSB, + [STMPE_IDX_GPSR_MSB] = STMPE24XX_REG_GPSR_MSB, [STMPE_IDX_GPCR_LSB] = STMPE24XX_REG_GPCR_LSB, + [STMPE_IDX_GPCR_CSB] = STMPE24XX_REG_GPCR_CSB, + [STMPE_IDX_GPCR_MSB] = STMPE24XX_REG_GPCR_MSB, [STMPE_IDX_GPDR_LSB] = STMPE24XX_REG_GPDR_LSB, + [STMPE_IDX_GPDR_CSB] = STMPE24XX_REG_GPDR_CSB, + [STMPE_IDX_GPDR_MSB] = STMPE24XX_REG_GPDR_MSB, [STMPE_IDX_GPRER_LSB] = STMPE24XX_REG_GPRER_LSB, + [STMPE_IDX_GPRER_CSB] = STMPE24XX_REG_GPRER_CSB, + [STMPE_IDX_GPRER_MSB] = STMPE24XX_REG_GPRER_MSB, [STMPE_IDX_GPFER_LSB] = STMPE24XX_REG_GPFER_LSB, + [STMPE_IDX_GPFER_CSB] = STMPE24XX_REG_GPFER_CSB, + [STMPE_IDX_GPFER_MSB] = STMPE24XX_REG_GPFER_MSB, [STMPE_IDX_GPPUR_LSB] = STMPE24XX_REG_GPPUR_LSB, [STMPE_IDX_GPPDR_LSB] = STMPE24XX_REG_GPPDR_LSB, [STMPE_IDX_GPAFR_U_MSB] = STMPE24XX_REG_GPAFR_U_MSB, [STMPE_IDX_IEGPIOR_LSB] = STMPE24XX_REG_IEGPIOR_LSB, + [STMPE_IDX_IEGPIOR_CSB] = STMPE24XX_REG_IEGPIOR_CSB, + [STMPE_IDX_IEGPIOR_MSB] = STMPE24XX_REG_IEGPIOR_MSB, [STMPE_IDX_ISGPIOR_MSB] = STMPE24XX_REG_ISGPIOR_MSB, + [STMPE_IDX_GPEDR_LSB] = STMPE24XX_REG_GPEDR_LSB, + [STMPE_IDX_GPEDR_CSB] = STMPE24XX_REG_GPEDR_CSB, [STMPE_IDX_GPEDR_MSB] = STMPE24XX_REG_GPEDR_MSB, }; @@ -840,7 +949,7 @@ static int stmpe24xx_enable(struct stmpe *stmpe, unsigned int blocks, if (blocks & STMPE_BLOCK_KEYPAD) mask |= STMPE24XX_SYS_CTRL_ENABLE_KPC; - return __stmpe_set_bits(stmpe, STMPE24XX_REG_SYS_CTRL, mask, + return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL], mask, enable ? mask : 0); } @@ -893,6 +1002,7 @@ static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = { [STMPE610] = &stmpe610, [STMPE801] = &stmpe801, [STMPE811] = &stmpe811, + [STMPE1600] = &stmpe1600, [STMPE1601] = &stmpe1601, [STMPE1801] = &stmpe1801, [STMPE2401] = &stmpe2401, @@ -919,7 +1029,8 @@ static irqreturn_t stmpe_irq(int irq, void *data) int ret; int i; - if (variant->id_val == STMPE801_ID) { + if (variant->id_val == STMPE801_ID || + variant->id_val == STMPE1600_ID) { int base = irq_create_mapping(stmpe->domain, 0); handle_nested_irq(base); @@ -982,7 +1093,7 @@ static void stmpe_irq_sync_unlock(struct irq_data *data) continue; stmpe->oldier[i] = new; - stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_IER_LSB] - i, new); + stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_IER_LSB + i], new); } mutex_unlock(&stmpe->irq_lock); @@ -1088,20 +1199,18 @@ static int stmpe_chip_init(struct stmpe *stmpe) if (ret) return ret; - if (id == STMPE1801_ID) { - ret = stmpe1801_reset(stmpe); - if (ret < 0) - return ret; - } + ret = stmpe_reset(stmpe); + if (ret < 0) + return ret; if (stmpe->irq >= 0) { - if (id == STMPE801_ID) - icr = STMPE801_REG_SYS_CTRL_INT_EN; + if (id == STMPE801_ID || id == STMPE1600_ID) + icr = STMPE_SYS_CTRL_INT_EN; else icr = STMPE_ICR_LSB_GIM; - /* STMPE801 doesn't support Edge interrupts */ - if (id != STMPE801_ID) { + /* STMPE801 and STMPE1600 don't support Edge interrupts */ + if (id != STMPE801_ID && id != STMPE1600_ID) { if (irq_trigger == IRQF_TRIGGER_FALLING || irq_trigger == IRQF_TRIGGER_RISING) icr |= STMPE_ICR_LSB_EDGE; @@ -1109,8 +1218,8 @@ static int stmpe_chip_init(struct stmpe *stmpe) if (irq_trigger == IRQF_TRIGGER_RISING || irq_trigger == IRQF_TRIGGER_HIGH) { - if (id == STMPE801_ID) - icr |= STMPE801_REG_SYS_CTRL_INT_HI; + if (id == STMPE801_ID || id == STMPE1600_ID) + icr |= STMPE_SYS_CTRL_INT_HI; else icr |= STMPE_ICR_LSB_HIGH; } diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index 84adb46b3e2f..f7efdd8a5fc6 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h @@ -104,6 +104,10 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE_ICR_LSB_EDGE (1 << 1) #define STMPE_ICR_LSB_GIM (1 << 0) +#define STMPE_SYS_CTRL_RESET (1 << 7) +#define STMPE_SYS_CTRL_INT_EN (1 << 2) +#define STMPE_SYS_CTRL_INT_HI (1 << 0) + /* * STMPE801 */ @@ -119,13 +123,10 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE801_REG_GPIO_SET_PIN 0x11 #define STMPE801_REG_GPIO_DIR 0x12 -#define STMPE801_REG_SYS_CTRL_RESET (1 << 7) -#define STMPE801_REG_SYS_CTRL_INT_EN (1 << 2) -#define STMPE801_REG_SYS_CTRL_INT_HI (1 << 0) - /* * STMPE811 */ +#define STMPE811_ID 0x0811 #define STMPE811_IRQ_TOUCH_DET 0 #define STMPE811_IRQ_FIFO_TH 1 @@ -138,6 +139,7 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE811_NR_INTERNAL_IRQS 8 #define STMPE811_REG_CHIP_ID 0x00 +#define STMPE811_REG_SYS_CTRL 0x03 #define STMPE811_REG_SYS_CTRL2 0x04 #define STMPE811_REG_SPI_CFG 0x08 #define STMPE811_REG_INT_CTRL 0x09 @@ -154,12 +156,35 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE811_REG_GPIO_FE 0x16 #define STMPE811_REG_GPIO_AF 0x17 +#define STMPE811_SYS_CTRL_RESET (1 << 1) + #define STMPE811_SYS_CTRL2_ADC_OFF (1 << 0) #define STMPE811_SYS_CTRL2_TSC_OFF (1 << 1) #define STMPE811_SYS_CTRL2_GPIO_OFF (1 << 2) #define STMPE811_SYS_CTRL2_TS_OFF (1 << 3) /* + * STMPE1600 + */ +#define STMPE1600_ID 0x0016 +#define STMPE1600_NR_INTERNAL_IRQS 16 + +#define STMPE1600_REG_CHIP_ID 0x00 +#define STMPE1600_REG_SYS_CTRL 0x03 +#define STMPE1600_REG_IEGPIOR_LSB 0x08 +#define STMPE1600_REG_IEGPIOR_MSB 0x09 +#define STMPE1600_REG_ISGPIOR_LSB 0x0A +#define STMPE1600_REG_ISGPIOR_MSB 0x0B +#define STMPE1600_REG_GPMR_LSB 0x10 +#define STMPE1600_REG_GPMR_MSB 0x11 +#define STMPE1600_REG_GPSR_LSB 0x12 +#define STMPE1600_REG_GPSR_MSB 0x13 +#define STMPE1600_REG_GPDR_LSB 0x14 +#define STMPE1600_REG_GPDR_MSB 0x15 +#define STMPE1600_REG_GPPIR_LSB 0x16 +#define STMPE1600_REG_GPPIR_MSB 0x17 + +/* * STMPE1601 */ @@ -175,19 +200,32 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE1601_REG_SYS_CTRL 0x02 #define STMPE1601_REG_SYS_CTRL2 0x03 +#define STMPE1601_REG_ICR_MSB 0x10 #define STMPE1601_REG_ICR_LSB 0x11 +#define STMPE1601_REG_IER_MSB 0x12 #define STMPE1601_REG_IER_LSB 0x13 #define STMPE1601_REG_ISR_MSB 0x14 -#define STMPE1601_REG_CHIP_ID 0x80 +#define STMPE1601_REG_ISR_LSB 0x15 +#define STMPE1601_REG_INT_EN_GPIO_MASK_MSB 0x16 #define STMPE1601_REG_INT_EN_GPIO_MASK_LSB 0x17 #define STMPE1601_REG_INT_STA_GPIO_MSB 0x18 -#define STMPE1601_REG_GPIO_MP_LSB 0x87 +#define STMPE1601_REG_INT_STA_GPIO_LSB 0x19 +#define STMPE1601_REG_CHIP_ID 0x80 +#define STMPE1601_REG_GPIO_SET_MSB 0x82 #define STMPE1601_REG_GPIO_SET_LSB 0x83 +#define STMPE1601_REG_GPIO_CLR_MSB 0x84 #define STMPE1601_REG_GPIO_CLR_LSB 0x85 +#define STMPE1601_REG_GPIO_MP_MSB 0x86 +#define STMPE1601_REG_GPIO_MP_LSB 0x87 +#define STMPE1601_REG_GPIO_SET_DIR_MSB 0x88 #define STMPE1601_REG_GPIO_SET_DIR_LSB 0x89 #define STMPE1601_REG_GPIO_ED_MSB 0x8A +#define STMPE1601_REG_GPIO_ED_LSB 0x8B +#define STMPE1601_REG_GPIO_RE_MSB 0x8C #define STMPE1601_REG_GPIO_RE_LSB 0x8D +#define STMPE1601_REG_GPIO_FE_MSB 0x8E #define STMPE1601_REG_GPIO_FE_LSB 0x8F +#define STMPE1601_REG_GPIO_PU_MSB 0x90 #define STMPE1601_REG_GPIO_PU_LSB 0x91 #define STMPE1601_REG_GPIO_AF_U_MSB 0x92 @@ -243,8 +281,6 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE1801_REG_GPIO_PULL_UP_MID 0x23 #define STMPE1801_REG_GPIO_PULL_UP_HIGH 0x24 -#define STMPE1801_MSK_SYS_CTRL_RESET (1 << 7) - #define STMPE1801_MSK_INT_EN_KPC (1 << 1) #define STMPE1801_MSK_INT_EN_GPIO (1 << 3) @@ -264,23 +300,48 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE24XX_NR_INTERNAL_IRQS 9 #define STMPE24XX_REG_SYS_CTRL 0x02 +#define STMPE24XX_REG_SYS_CTRL2 0x03 +#define STMPE24XX_REG_ICR_MSB 0x10 #define STMPE24XX_REG_ICR_LSB 0x11 +#define STMPE24XX_REG_IER_MSB 0x12 #define STMPE24XX_REG_IER_LSB 0x13 #define STMPE24XX_REG_ISR_MSB 0x14 -#define STMPE24XX_REG_CHIP_ID 0x80 +#define STMPE24XX_REG_ISR_LSB 0x15 +#define STMPE24XX_REG_IEGPIOR_MSB 0x16 +#define STMPE24XX_REG_IEGPIOR_CSB 0x17 #define STMPE24XX_REG_IEGPIOR_LSB 0x18 #define STMPE24XX_REG_ISGPIOR_MSB 0x19 -#define STMPE24XX_REG_GPMR_LSB 0xA4 +#define STMPE24XX_REG_ISGPIOR_CSB 0x1A +#define STMPE24XX_REG_ISGPIOR_LSB 0x1B +#define STMPE24XX_REG_CHIP_ID 0x80 +#define STMPE24XX_REG_GPSR_MSB 0x83 +#define STMPE24XX_REG_GPSR_CSB 0x84 #define STMPE24XX_REG_GPSR_LSB 0x85 +#define STMPE24XX_REG_GPCR_MSB 0x86 +#define STMPE24XX_REG_GPCR_CSB 0x87 #define STMPE24XX_REG_GPCR_LSB 0x88 +#define STMPE24XX_REG_GPDR_MSB 0x89 +#define STMPE24XX_REG_GPDR_CSB 0x8A #define STMPE24XX_REG_GPDR_LSB 0x8B #define STMPE24XX_REG_GPEDR_MSB 0x8C +#define STMPE24XX_REG_GPEDR_CSB 0x8D +#define STMPE24XX_REG_GPEDR_LSB 0x8E +#define STMPE24XX_REG_GPRER_MSB 0x8F +#define STMPE24XX_REG_GPRER_CSB 0x90 #define STMPE24XX_REG_GPRER_LSB 0x91 +#define STMPE24XX_REG_GPFER_MSB 0x92 +#define STMPE24XX_REG_GPFER_CSB 0x93 #define STMPE24XX_REG_GPFER_LSB 0x94 +#define STMPE24XX_REG_GPPUR_MSB 0x95 +#define STMPE24XX_REG_GPPUR_CSB 0x96 #define STMPE24XX_REG_GPPUR_LSB 0x97 -#define STMPE24XX_REG_GPPDR_LSB 0x9a +#define STMPE24XX_REG_GPPDR_MSB 0x98 +#define STMPE24XX_REG_GPPDR_CSB 0x99 +#define STMPE24XX_REG_GPPDR_LSB 0x9A #define STMPE24XX_REG_GPAFR_U_MSB 0x9B - +#define STMPE24XX_REG_GPMR_MSB 0xA2 +#define STMPE24XX_REG_GPMR_CSB 0xA3 +#define STMPE24XX_REG_GPMR_LSB 0xA4 #define STMPE24XX_SYS_CTRL_ENABLE_GPIO (1 << 3) #define STMPE24XX_SYSCON_ENABLE_PWM (1 << 2) #define STMPE24XX_SYS_CTRL_ENABLE_KPC (1 << 1) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 54455af566ec..0facbea5f465 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -29,7 +29,6 @@ #include <linux/slab.h> #include "../core.h" -#include "../../gpio/gpiolib.h" #include "pinctrl-sunxi.h" static struct irq_chip sunxi_pinctrl_edge_irq_chip; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 4c2631a2bb3c..06c75186af80 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -323,7 +323,7 @@ config REGULATOR_LP872X config REGULATOR_LP873X tristate "TI LP873X Power regulators" - depends on MFD_LP873X && OF + depends on MFD_TI_LP873X && OF help This driver supports LP873X voltage regulator chips. LP873X provides two step-down converters and two general-purpose LDO diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 420b837f2aa7..1f0be7213e6d 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -3,7 +3,6 @@ #include <linux/device.h> #include <linux/types.h> -#include <linux/module.h> #include <linux/irq.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> @@ -16,6 +15,7 @@ struct of_phandle_args; struct device_node; struct seq_file; struct gpio_device; +struct module; #ifdef CONFIG_GPIOLIB diff --git a/include/linux/mfd/lp873x.h b/include/linux/mfd/lp873x.h new file mode 100644 index 000000000000..83b1bd7588be --- /dev/null +++ b/include/linux/mfd/lp873x.h @@ -0,0 +1,269 @@ +/* + * Functions to access LP873X power management chip. + * + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LINUX_MFD_LP873X_H +#define __LINUX_MFD_LP873X_H + +#include <linux/i2c.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +/* LP873x chip id list */ +#define LP873X 0x00 + +/* All register addresses */ +#define LP873X_REG_DEV_REV 0X00 +#define LP873X_REG_OTP_REV 0X01 +#define LP873X_REG_BUCK0_CTRL_1 0X02 +#define LP873X_REG_BUCK0_CTRL_2 0X03 +#define LP873X_REG_BUCK1_CTRL_1 0X04 +#define LP873X_REG_BUCK1_CTRL_2 0X05 +#define LP873X_REG_BUCK0_VOUT 0X06 +#define LP873X_REG_BUCK1_VOUT 0X07 +#define LP873X_REG_LDO0_CTRL 0X08 +#define LP873X_REG_LDO1_CTRL 0X09 +#define LP873X_REG_LDO0_VOUT 0X0A +#define LP873X_REG_LDO1_VOUT 0X0B +#define LP873X_REG_BUCK0_DELAY 0X0C +#define LP873X_REG_BUCK1_DELAY 0X0D +#define LP873X_REG_LDO0_DELAY 0X0E +#define LP873X_REG_LDO1_DELAY 0X0F +#define LP873X_REG_GPO_DELAY 0X10 +#define LP873X_REG_GPO2_DELAY 0X11 +#define LP873X_REG_GPO_CTRL 0X12 +#define LP873X_REG_CONFIG 0X13 +#define LP873X_REG_PLL_CTRL 0X14 +#define LP873X_REG_PGOOD_CTRL1 0X15 +#define LP873X_REG_PGOOD_CTRL2 0X16 +#define LP873X_REG_PG_FAULT 0X17 +#define LP873X_REG_RESET 0X18 +#define LP873X_REG_INT_TOP_1 0X19 +#define LP873X_REG_INT_TOP_2 0X1A +#define LP873X_REG_INT_BUCK 0X1B +#define LP873X_REG_INT_LDO 0X1C +#define LP873X_REG_TOP_STAT 0X1D +#define LP873X_REG_BUCK_STAT 0X1E +#define LP873X_REG_LDO_STAT 0x1F +#define LP873X_REG_TOP_MASK_1 0x20 +#define LP873X_REG_TOP_MASK_2 0x21 +#define LP873X_REG_BUCK_MASK 0x22 +#define LP873X_REG_LDO_MASK 0x23 +#define LP873X_REG_SEL_I_LOAD 0x24 +#define LP873X_REG_I_LOAD_2 0x25 +#define LP873X_REG_I_LOAD_1 0x26 + +#define LP873X_REG_MAX LP873X_REG_I_LOAD_1 + +/* Register field definitions */ +#define LP873X_DEV_REV_DEV_ID 0xC0 +#define LP873X_DEV_REV_ALL_LAYER 0x30 +#define LP873X_DEV_REV_METAL_LAYER 0x0F + +#define LP873X_OTP_REV_OTP_ID 0xFF + +#define LP873X_BUCK0_CTRL_1_BUCK0_FPWM BIT(3) +#define LP873X_BUCK0_CTRL_1_BUCK0_RDIS_EN BIT(2) +#define LP873X_BUCK0_CTRL_1_BUCK0_EN_PIN_CTRL BIT(1) +#define LP873X_BUCK0_CTRL_1_BUCK0_EN BIT(0) + +#define LP873X_BUCK0_CTRL_2_BUCK0_ILIM 0x38 +#define LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE 0x07 + +#define LP873X_BUCK1_CTRL_1_BUCK1_FPWM BIT(3) +#define LP873X_BUCK1_CTRL_1_BUCK1_RDIS_EN BIT(2) +#define LP873X_BUCK1_CTRL_1_BUCK1_EN_PIN_CTRL BIT(1) +#define LP873X_BUCK1_CTRL_1_BUCK1_EN BIT(0) + +#define LP873X_BUCK1_CTRL_2_BUCK1_ILIM 0x38 +#define LP873X_BUCK1_CTRL_2_BUCK1_SLEW_RATE 0x07 + +#define LP873X_BUCK0_VOUT_BUCK0_VSET 0xFF + +#define LP873X_BUCK1_VOUT_BUCK1_VSET 0xFF + +#define LP873X_LDO0_CTRL_LDO0_RDIS_EN BIT(2) +#define LP873X_LDO0_CTRL_LDO0_EN_PIN_CTRL BIT(1) +#define LP873X_LDO0_CTRL_LDO0_EN BIT(0) + +#define LP873X_LDO1_CTRL_LDO1_RDIS_EN BIT(2) +#define LP873X_LDO1_CTRL_LDO1_EN_PIN_CTRL BIT(1) +#define LP873X_LDO1_CTRL_LDO1_EN BIT(0) + +#define LP873X_LDO0_VOUT_LDO0_VSET 0x1F + +#define LP873X_LDO1_VOUT_LDO1_VSET 0x1F + +#define LP873X_BUCK0_DELAY_BUCK0_SD_DELAY 0xF0 +#define LP873X_BUCK0_DELAY_BUCK0_SU_DELAY 0x0F + +#define LP873X_BUCK1_DELAY_BUCK1_SD_DELAY 0xF0 +#define LP873X_BUCK1_DELAY_BUCK1_SU_DELAY 0x0F + +#define LP873X_LDO0_DELAY_LDO0_SD_DELAY 0xF0 +#define LP873X_LDO0_DELAY_LDO0_SU_DELAY 0x0F + +#define LP873X_LDO1_DELAY_LDO1_SD_DELAY 0xF0 +#define LP873X_LDO1_DELAY_LDO1_SU_DELAY 0x0F + +#define LP873X_GPO_DELAY_GPO_SD_DELAY 0xF0 +#define LP873X_GPO_DELAY_GPO_SU_DELAY 0x0F + +#define LP873X_GPO2_DELAY_GPO2_SD_DELAY 0xF0 +#define LP873X_GPO2_DELAY_GPO2_SU_DELAY 0x0F + +#define LP873X_GPO_CTRL_GPO2_OD BIT(6) +#define LP873X_GPO_CTRL_GPO2_EN_PIN_CTRL BIT(5) +#define LP873X_GPO_CTRL_GPO2_EN BIT(4) +#define LP873X_GPO_CTRL_GPO_OD BIT(2) +#define LP873X_GPO_CTRL_GPO_EN_PIN_CTRL BIT(1) +#define LP873X_GPO_CTRL_GPO_EN BIT(0) + +#define LP873X_CONFIG_SU_DELAY_SEL BIT(6) +#define LP873X_CONFIG_SD_DELAY_SEL BIT(5) +#define LP873X_CONFIG_CLKIN_PIN_SEL BIT(4) +#define LP873X_CONFIG_CLKIN_PD BIT(3) +#define LP873X_CONFIG_EN_PD BIT(2) +#define LP873X_CONFIG_TDIE_WARN_LEVEL BIT(1) +#define LP873X_EN_SPREAD_SPEC BIT(0) + +#define LP873X_PLL_CTRL_EN_PLL BIT(6) +#define LP873X_EXT_CLK_FREQ 0x1F + +#define LP873X_PGOOD_CTRL1_PGOOD_POL BIT(7) +#define LP873X_PGOOD_CTRL1_PGOOD_OD BIT(6) +#define LP873X_PGOOD_CTRL1_PGOOD_WINDOW_LDO BIT(5) +#define LP873X_PGOOD_CTRL1_PGOOD_WINDOWN_BUCK BIT(4) +#define LP873X_PGOOD_CTRL1_PGOOD_EN_PGOOD_LDO1 BIT(3) +#define LP873X_PGOOD_CTRL1_PGOOD_EN_PGOOD_LDO0 BIT(2) +#define LP873X_PGOOD_CTRL1_PGOOD_EN_PGOOD_BUCK1 BIT(1) +#define LP873X_PGOOD_CTRL1_PGOOD_EN_PGOOD_BUCK0 BIT(0) + +#define LP873X_PGOOD_CTRL2_EN_PGOOD_TWARN BIT(2) +#define LP873X_PGOOD_CTRL2_EN_PG_FAULT_GATE BIT(1) +#define LP873X_PGOOD_CTRL2_PGOOD_MODE BIT(0) + +#define LP873X_PG_FAULT_PG_FAULT_LDO1 BIT(3) +#define LP873X_PG_FAULT_PG_FAULT_LDO0 BIT(2) +#define LP873X_PG_FAULT_PG_FAULT_BUCK1 BIT(1) +#define LP873X_PG_FAULT_PG_FAULT_BUCK0 BIT(0) + +#define LP873X_RESET_SW_RESET BIT(0) + +#define LP873X_INT_TOP_1_PGOOD_INT BIT(7) +#define LP873X_INT_TOP_1_LDO_INT BIT(6) +#define LP873X_INT_TOP_1_BUCK_INT BIT(5) +#define LP873X_INT_TOP_1_SYNC_CLK_INT BIT(4) +#define LP873X_INT_TOP_1_TDIE_SD_INT BIT(3) +#define LP873X_INT_TOP_1_TDIE_WARN_INT BIT(2) +#define LP873X_INT_TOP_1_OVP_INT BIT(1) +#define LP873X_INT_TOP_1_I_MEAS_INT BIT(0) + +#define LP873X_INT_TOP_2_RESET_REG_INT BIT(0) + +#define LP873X_INT_BUCK_BUCK1_PG_INT BIT(6) +#define LP873X_INT_BUCK_BUCK1_SC_INT BIT(5) +#define LP873X_INT_BUCK_BUCK1_ILIM_INT BIT(4) +#define LP873X_INT_BUCK_BUCK0_PG_INT BIT(2) +#define LP873X_INT_BUCK_BUCK0_SC_INT BIT(1) +#define LP873X_INT_BUCK_BUCK0_ILIM_INT BIT(0) + +#define LP873X_INT_LDO_LDO1_PG_INT BIT(6) +#define LP873X_INT_LDO_LDO1_SC_INT BIT(5) +#define LP873X_INT_LDO_LDO1_ILIM_INT BIT(4) +#define LP873X_INT_LDO_LDO0_PG_INT BIT(2) +#define LP873X_INT_LDO_LDO0_SC_INT BIT(1) +#define LP873X_INT_LDO_LDO0_ILIM_INT BIT(0) + +#define LP873X_TOP_STAT_PGOOD_STAT BIT(7) +#define LP873X_TOP_STAT_SYNC_CLK_STAT BIT(4) +#define LP873X_TOP_STAT_TDIE_SD_STAT BIT(3) +#define LP873X_TOP_STAT_TDIE_WARN_STAT BIT(2) +#define LP873X_TOP_STAT_OVP_STAT BIT(1) + +#define LP873X_BUCK_STAT_BUCK1_STAT BIT(7) +#define LP873X_BUCK_STAT_BUCK1_PG_STAT BIT(6) +#define LP873X_BUCK_STAT_BUCK1_ILIM_STAT BIT(4) +#define LP873X_BUCK_STAT_BUCK0_STAT BIT(3) +#define LP873X_BUCK_STAT_BUCK0_PG_STAT BIT(2) +#define LP873X_BUCK_STAT_BUCK0_ILIM_STAT BIT(0) + +#define LP873X_LDO_STAT_LDO1_STAT BIT(7) +#define LP873X_LDO_STAT_LDO1_PG_STAT BIT(6) +#define LP873X_LDO_STAT_LDO1_ILIM_STAT BIT(4) +#define LP873X_LDO_STAT_LDO0_STAT BIT(3) +#define LP873X_LDO_STAT_LDO0_PG_STAT BIT(2) +#define LP873X_LDO_STAT_LDO0_ILIM_STAT BIT(0) + +#define LP873X_TOP_MASK_1_PGOOD_INT_MASK BIT(7) +#define LP873X_TOP_MASK_1_SYNC_CLK_MASK BIT(4) +#define LP873X_TOP_MASK_1_TDIE_WARN_MASK BIT(2) +#define LP873X_TOP_MASK_1_I_MEAS_MASK BIT(0) + +#define LP873X_TOP_MASK_2_RESET_REG_MASK BIT(0) + +#define LP873X_BUCK_MASK_BUCK1_PGF_MASK BIT(7) +#define LP873X_BUCK_MASK_BUCK1_PGR_MASK BIT(6) +#define LP873X_BUCK_MASK_BUCK1_ILIM_MASK BIT(4) +#define LP873X_BUCK_MASK_BUCK0_PGF_MASK BIT(3) +#define LP873X_BUCK_MASK_BUCK0_PGR_MASK BIT(2) +#define LP873X_BUCK_MASK_BUCK0_ILIM_MASK BIT(0) + +#define LP873X_LDO_MASK_LDO1_PGF_MASK BIT(7) +#define LP873X_LDO_MASK_LDO1_PGR_MASK BIT(6) +#define LP873X_LDO_MASK_LDO1_ILIM_MASK BIT(4) +#define LP873X_LDO_MASK_LDO0_PGF_MASK BIT(3) +#define LP873X_LDO_MASK_LDO0_PGR_MASK BIT(2) +#define LP873X_LDO_MASK_LDO0_ILIM_MASK BIT(0) + +#define LP873X_SEL_I_LOAD_CURRENT_BUCK_SELECT BIT(0) + +#define LP873X_I_LOAD_2_BUCK_LOAD_CURRENT BIT(0) + +#define LP873X_I_LOAD_1_BUCK_LOAD_CURRENT 0xFF + +#define LP873X_MAX_REG_ID LP873X_LDO_1 + +/* Number of step-down converters available */ +#define LP873X_NUM_BUCK 2 +/* Number of LDO voltage regulators available */ +#define LP873X_NUM_LDO 2 +/* Number of total regulators available */ +#define LP873X_NUM_REGULATOR (LP873X_NUM_BUCK + LP873X_NUM_LDO) + +enum lp873x_regulator_id { + /* BUCK's */ + LP873X_BUCK_0, + LP873X_BUCK_1, + /* LDOs */ + LP873X_LDO_0, + LP873X_LDO_1, +}; + +/** + * struct lp873x - state holder for the lp873x driver + * @dev: struct device pointer for MFD device + * @rev: revision of the lp873x + * @lock: lock guarding the data structure + * @regmap: register map of the lp873x PMIC + * + * Device data may be used to access the LP873X chip + */ +struct lp873x { + struct device *dev; + u8 rev; + struct mutex lock; /* lock guarding the data structure */ + struct regmap *regmap; +}; +#endif /* __LINUX_MFD_LP873X_H */ diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h index de748bc7525e..4a827af17e59 100644 --- a/include/linux/mfd/stmpe.h +++ b/include/linux/mfd/stmpe.h @@ -26,6 +26,7 @@ enum stmpe_partnum { STMPE610, STMPE801, STMPE811, + STMPE1600, STMPE1601, STMPE1801, STMPE2401, @@ -39,22 +40,42 @@ enum stmpe_partnum { */ enum { STMPE_IDX_CHIP_ID, + STMPE_IDX_SYS_CTRL, + STMPE_IDX_SYS_CTRL2, STMPE_IDX_ICR_LSB, STMPE_IDX_IER_LSB, + STMPE_IDX_IER_MSB, STMPE_IDX_ISR_LSB, STMPE_IDX_ISR_MSB, STMPE_IDX_GPMR_LSB, + STMPE_IDX_GPMR_CSB, + STMPE_IDX_GPMR_MSB, STMPE_IDX_GPSR_LSB, + STMPE_IDX_GPSR_CSB, + STMPE_IDX_GPSR_MSB, STMPE_IDX_GPCR_LSB, + STMPE_IDX_GPCR_CSB, + STMPE_IDX_GPCR_MSB, STMPE_IDX_GPDR_LSB, + STMPE_IDX_GPDR_CSB, + STMPE_IDX_GPDR_MSB, + STMPE_IDX_GPEDR_LSB, + STMPE_IDX_GPEDR_CSB, STMPE_IDX_GPEDR_MSB, STMPE_IDX_GPRER_LSB, + STMPE_IDX_GPRER_CSB, + STMPE_IDX_GPRER_MSB, STMPE_IDX_GPFER_LSB, + STMPE_IDX_GPFER_CSB, + STMPE_IDX_GPFER_MSB, STMPE_IDX_GPPUR_LSB, STMPE_IDX_GPPDR_LSB, STMPE_IDX_GPAFR_U_MSB, STMPE_IDX_IEGPIOR_LSB, + STMPE_IDX_IEGPIOR_CSB, + STMPE_IDX_IEGPIOR_MSB, STMPE_IDX_ISGPIOR_LSB, + STMPE_IDX_ISGPIOR_CSB, STMPE_IDX_ISGPIOR_MSB, STMPE_IDX_MAX, }; diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 092186c62ff4..3f87ea5b8bee 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -61,8 +61,6 @@ static inline int of_mm_gpiochip_add(struct device_node *np, } extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc); -extern int of_gpiochip_add(struct gpio_chip *gc); -extern void of_gpiochip_remove(struct gpio_chip *gc); extern int of_gpio_simple_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags); @@ -86,9 +84,6 @@ static inline int of_gpio_simple_xlate(struct gpio_chip *gc, return -ENOSYS; } -static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; } -static inline void of_gpiochip_remove(struct gpio_chip *gc) { } - #endif /* CONFIG_OF_GPIO */ /** diff --git a/include/linux/mfd/htc-egpio.h b/include/linux/platform_data/gpio-htc-egpio.h index b4201c971367..b4201c971367 100644 --- a/include/linux/mfd/htc-egpio.h +++ b/include/linux/platform_data/gpio-htc-egpio.h diff --git a/include/linux/platform_data/gpio-lpc32xx.h b/include/linux/platform_data/gpio-lpc32xx.h deleted file mode 100644 index a544e962a818..000000000000 --- a/include/linux/platform_data/gpio-lpc32xx.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Author: Kevin Wells <kevin.wells@nxp.com> - * - * Copyright (C) 2010 NXP Semiconductors - * - * 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. - */ - -#ifndef __MACH_GPIO_LPC32XX_H -#define __MACH_GPIO_LPC32XX_H - -/* - * Note! - * Muxed GP pins need to be setup to the GP state in the board level - * code prior to using this driver. - * GPI pins : 28xP3 group - * GPO pins : 24xP3 group - * GPIO pins: 8xP0 group, 24xP1 group, 13xP2 group, 6xP3 group - */ - -#define LPC32XX_GPIO_P0_MAX 8 -#define LPC32XX_GPIO_P1_MAX 24 -#define LPC32XX_GPIO_P2_MAX 13 -#define LPC32XX_GPIO_P3_MAX 6 -#define LPC32XX_GPI_P3_MAX 29 -#define LPC32XX_GPO_P3_MAX 24 - -#define LPC32XX_GPIO_P0_GRP 0 -#define LPC32XX_GPIO_P1_GRP (LPC32XX_GPIO_P0_GRP + LPC32XX_GPIO_P0_MAX) -#define LPC32XX_GPIO_P2_GRP (LPC32XX_GPIO_P1_GRP + LPC32XX_GPIO_P1_MAX) -#define LPC32XX_GPIO_P3_GRP (LPC32XX_GPIO_P2_GRP + LPC32XX_GPIO_P2_MAX) -#define LPC32XX_GPI_P3_GRP (LPC32XX_GPIO_P3_GRP + LPC32XX_GPIO_P3_MAX) -#define LPC32XX_GPO_P3_GRP (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX) - -/* - * A specific GPIO can be selected with this macro - * ie, GPIO_05 can be selected with LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5) - * See the LPC32x0 User's guide for GPIO group numbers - */ -#define LPC32XX_GPIO(x, y) ((x) + (y)) - -#endif /* __MACH_GPIO_LPC32XX_H */ |