common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-TZ1090's pin configuration nodes act as a container for an abitrary number of
+TZ1090's pin configuration nodes act as a container for an arbitrary number of
subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those pin(s)/group(s), and various pin configuration
They also all support the some form of muxing. Any pins which are contained
in one of the mux groups (see below) can be muxed only to the functions
supported by the mux group. All other pins can be muxed to the "perip"
- function which which enables them with their intended peripheral.
+ function which enables them with their intended peripheral.
Different pins in the same mux group cannot be muxed to different functions,
however it is possible to mux only a subset of the pins in a mux group to a
W: http://www.linux4sam.org
S: Supported
F: arch/arm/mach-at91/
+F: include/soc/at91/
F: arch/arm/boot/dts/at91*.dts
F: arch/arm/boot/dts/at91*.dtsi
F: arch/arm/boot/dts/sama*.dts
F: drivers/*/*/*rockchip*
F: sound/soc/rockchip/
-ARM/SAMSUNG ARM ARCHITECTURES
+ARM/SAMSUNG EXYNOS ARM ARCHITECTURES
-W: http://www.fluff.org/ben/linux/
S: Maintained
F: arch/arm/boot/dts/s3c*
F: arch/arm/boot/dts/exynos*
F: arch/arm/plat-samsung/
F: arch/arm/mach-s3c24*/
F: arch/arm/mach-s3c64xx/
+F: arch/arm/mach-s5p*/
+F: arch/arm/mach-exynos*/
F: drivers/*/*s3c2410*
F: drivers/*/*/*s3c2410*
F: drivers/spi/spi-s3c*
F: sound/soc/samsung/*
-
-ARM/S5P EXYNOS ARM ARCHITECTURES
-S: Maintained
-F: arch/arm/mach-s5p*/
-F: arch/arm/mach-exynos*/
N: exynos
ARM/SAMSUNG MOBILE MACHINE SUPPORT
F: arch/arm/configs/ape6evm_defconfig
F: arch/arm/configs/armadillo800eva_defconfig
F: arch/arm/configs/bockw_defconfig
-F: arch/arm/configs/koelsch_defconfig
F: arch/arm/configs/kzm9g_defconfig
F: arch/arm/configs/lager_defconfig
F: arch/arm/configs/mackerel_defconfig
F: arch/arm/configs/marzen_defconfig
F: arch/arm/configs/shmobile_defconfig
+F: arch/arm/include/debug/renesas-scif.S
F: arch/arm/mach-shmobile/
F: drivers/sh/
F: drivers/usb/dwc3/dwc3-st.c
F: drivers/usb/host/ehci-st.c
F: drivers/usb/host/ohci-st.c
+F: drivers/ata/ahci_st.c
ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
F: drivers/clk/ux500/
F: include/linux/platform_data/clk-ux500.h
+ARM/VERSATILE EXPRESS PLATFORM
+S: Maintained
+F: arch/arm/boot/dts/vexpress*
+F: arch/arm/mach-vexpress/
+F: */*/vexpress*
+F: */*/*/vexpress*
+F: drivers/clk/versatile/clk-vexpress-osc.c
+F: drivers/clocksource/versatile.c
+
ARM/VFP SUPPORT
ARM/ZYNQ ARCHITECTURE
W: http://wiki.xilinx.com
T: git git://git.xilinx.com/linux-xlnx.git
S: Supported
F: drivers/spi/spi-atmel.*
+ATMEL SSC DRIVER
+S: Supported
+F: drivers/misc/atmel-ssc.c
+F: include/linux/atmel-ssc.h
+
ATMEL Timer Counter (TC) AND CLOCKSOURCE DRIVERS
F: net/ax25/
AZ6007 DVB DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
BROADCOM BCM2835 ARM ARCHITECTURE
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-rpi.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/rpi/linux-rpi.git
S: Maintained
N: bcm2835
BROADCOM BCM7XXX ARM ARCHITECTURE
S: Maintained
F: arch/arm/mach-bcm/*brcmstb*
F: arch/arm/boot/dts/bcm7*.dts*
+F: drivers/bus/brcmstb_gisb.c
BROADCOM TG3 GIGABIT ETHERNET DRIVER
S: Supported
F: drivers/scsi/bnx2i/
+BROADCOM CYGNUS/IPROC ARM ARCHITECTURE
+T: git git://git.github.com/brcm/linux.git
+S: Maintained
+N: iproc
+N: cygnus
+N: bcm9113*
+N: bcm9583*
+N: bcm583*
+N: bcm113*
+
BROADCOM KONA GPIO DRIVER
F: fs/btrfs/
BTTV VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
W: http://linux-cifs.samba.org/
-Q: http://patchwork.ozlabs.org/project/linux-cifs-client/list/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
+T: git git://git.samba.org/sfrench/cifs-2.6.git
S: Supported
F: Documentation/filesystems/cifs/
F: fs/cifs/
S: Maintained
F: mm/memcontrol.c
-F: mm/page_cgroup.c
+F: mm/swap_cgroup.c
CORETEMP HARDWARE MONITORING DRIVER
S: Maintained
F: drivers/cpuidle/cpuidle-big_little.c
+CPUIDLE DRIVER - ARM EXYNOS
+S: Supported
+F: drivers/cpuidle/cpuidle-exynos.c
+F: arch/arm/mach-exynos/pm.c
+
CPUIDLE DRIVERS
CX18 VIDEO4LINUX DRIVER
T: git git://linuxtv.org/media_tree.git
W: http://linuxtv.org
F: include/media/cx2341x*
CX88 VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Supported
F: drivers/net/ethernet/chelsio/cxgb3/
+CXGB3 ISCSI DRIVER (CXGB3I)
+W: http://www.chelsio.com
+S: Supported
+F: drivers/scsi/cxgbi/cxgb3i
+
CXGB3 IWARP RNIC DRIVER (IW_CXGB3)
S: Supported
F: drivers/net/ethernet/chelsio/cxgb4/
+CXGB4 ISCSI DRIVER (CXGB4I)
+W: http://www.chelsio.com
+S: Supported
+F: drivers/scsi/cxgbi/cxgb4i
+
CXGB4 IWARP RNIC DRIVER (IW_CXGB4)
F: drivers/net/ethernet/dec/tulip/dmfe.c
DC390/AM53C974 SCSI driver
-W: http://www.garloff.de/kurt/linux/dc390/
S: Maintained
-F: drivers/scsi/tmscsim.*
+F: drivers/scsi/am53c974.c
DC395x SCSI driver
EDAC-CORE
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: bluesmoke.sourceforge.net
S: Supported
F: drivers/edac/e7xxx_edac.c
EDAC-GHES
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5000_edac.c
EDAC-I5400
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5400_edac.c
EDAC-I7300
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i7300_edac.c
EDAC-I7CORE
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/r82600_edac.c
EDAC-SBRIDGE
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/net/ethernet/ibm/ehea/
EM28XX VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/block/cpqarray.*
HEWLETT-PACKARD SMART ARRAY RAID DRIVER (hpsa)
+M: Don Brace <don.brace@pmcs.com>
S: Supported
F: Documentation/scsi/hpsa.txt
F: drivers/scsi/hpsa*.[ch]
F: include/uapi/linux/cciss*.h
HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
-M: Mike Miller <mike.miller@hp.com>
+M: Don Brace <don.brace@pmcs.com>
S: Supported
F: Documentation/blockdev/cciss.txt
F: drivers/block/cciss*
F: drivers/crypto/nx/
IBM Power 842 compression accelerator
+M: Dan Streetman <ddstreet@us.ibm.com>
S: Supported
F: drivers/crypto/nx/nx-842.c
F: include/linux/nx842.h
S: Maintained
F: drivers/iio/
F: drivers/staging/iio/
+F: include/linux/iio/
IKANOS/ADI EAGLE ADSL USB DRIVER
IVTV VIDEO4LINUX DRIVER
T: git git://linuxtv.org/media_tree.git
W: http://www.ivtvdriver.org
F: drivers/net/macvlan.c
F: include/linux/if_macvlan.h
+MAILBOX API
+S: Maintained
+F: drivers/mailbox/
+F: include/linux/mailbox_client.h
+F: include/linux/mailbox_controller.h
+
MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
W: http://www.kernel.org/doc/man-pages
F: drivers/media/radio/radio-maxiradio*
MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
P: LinuxTV.org Project
W: http://linuxtv.org
S: Odd Fixes
F: drivers/media/parport/pms*
-MEGARAID SCSI DRIVERS
+MEGARAID SCSI/SAS DRIVERS
-W: http://megaraid.lsilogic.com
+W: http://www.lsi.com
S: Maintained
F: Documentation/scsi/megaraid.txt
F: drivers/scsi/megaraid.*
F: drivers/scsi/g_NCR5380_mmio.c
F: drivers/scsi/mac_scsi.*
F: drivers/scsi/pas16.*
-F: drivers/scsi/sun3_NCR5380.c
F: drivers/scsi/sun3_scsi.*
F: drivers/scsi/sun3_scsi_vme.c
F: drivers/scsi/t128.*
F: Documentation/scsi/NinjaSCSI.txt
F: drivers/scsi/nsp32*
+NIOS2 ARCHITECTURE
+T: git git://git.rocketboards.org/linux-socfpga.git
+S: Maintained
+F: arch/nios2/
+
NTB DRIVER
S: Maintained
F: arch/arm/*omap*/
F: drivers/i2c/busses/i2c-omap.c
+F: drivers/irqchip/irq-omap-intc.c
+F: drivers/mfd/*omap*.c
+F: drivers/mfd/menelaus.c
+F: drivers/mfd/palmas.c
+F: drivers/mfd/tps65217.c
+F: drivers/mfd/tps65218.c
+F: drivers/mfd/tps65910.c
+F: drivers/mfd/twl-core.[ch]
+F: drivers/mfd/twl4030*.c
+F: drivers/mfd/twl6030*.c
+F: drivers/mfd/twl6040*.c
+F: drivers/regulator/palmas-regulator*.c
+F: drivers/regulator/pbias-regulator.c
+F: drivers/regulator/tps65217-regulator.c
+F: drivers/regulator/tps65218-regulator.c
+F: drivers/regulator/tps65910-regulator.c
+F: drivers/regulator/twl-regulator.c
F: include/linux/i2c-omap.h
OMAP DEVICE TREE SUPPORT
S: Maintained
F: arch/arm/boot/dts/*omap*
F: arch/arm/boot/dts/*am3*
+F: arch/arm/boot/dts/*am4*
+F: arch/arm/boot/dts/*am5*
+F: arch/arm/boot/dts/*dra7*
OMAP CLOCK FRAMEWORK SUPPORT
S: Maintained
F: sound/soc/omap/
+OMAP GENERAL PURPOSE MEMORY CONTROLLER SUPPORT
+S: Maintained
+F: drivers/memory/omap-gpmc.c
+F: arch/arm/mach-omap2/*gpmc*
+
OMAP FRAMEBUFFER SUPPORT
F: drivers/net/wireless/orinoco/
OSD LIBRARY and FILESYSTEM
-M: Boaz Harrosh <bharrosh@panasas.com>
+M: Boaz Harrosh <ooo@electrozaur.com>
W: http://open-osd.org
F: include/scsi/osd_*
F: fs/exofs/
+OVERLAY FILESYSTEM
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
+S: Supported
+F: fs/overlayfs/
+F: Documentation/filesystems/overlayfs.txt
+
P54 WIRELESS DRIVER
F: Documentation/devicetree/bindings/pci/xgene-pci.txt
F: drivers/pci/host/pci-xgene.c
+PCI DRIVER FOR FREESCALE LAYERSCAPE
+S: Maintained
+F: drivers/pci/host/*layerscape*
+
PCI DRIVER FOR IMX6
PIN CONTROL SUBSYSTEM
S: Maintained
F: drivers/pinctrl/
F: include/linux/pinctrl/
S: Maintained
- F: drivers/pinctrl/pinctrl-at91.c
+ F: drivers/pinctrl/pinctrl-at91.*
+
+ PIN CONTROLLER - INTEL
+ S: Maintained
+ F: drivers/pinctrl/intel/
PIN CONTROLLER - RENESAS
F: drivers/media/i2c/saa6588*
SAA7134 VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/media/radio/si4713/radio-usb-si4713.c
SIANO DVB DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
TI DAVINCI MACHINE SUPPORT
T: git git://gitorious.org/linux-davinci/linux-davinci.git
Q: http://patchwork.kernel.org/project/linux-davinci/list/
S: Supported
TI DAVINCI SERIES MEDIA DRIVER
W: http://linuxtv.org/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
F: drivers/leds/leds-net48xx.c
SOFTLOGIC 6x10 MPEG CODEC
S: Supported
F: drivers/media/pci/solo6x10/
F: drivers/media/i2c/tda9840*
TEA5761 TUNER DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/media/tuners/tea5761.*
TEA5767 TUNER DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: mm/shmem.c
TM6000 VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER
S: Supported
F: Documentation/scsi/ufs.txt
F: Documentation/hid/hiddev.txt
F: drivers/hid/usbhid/
-USB/IP DRIVERS
-S: Orphan
-F: drivers/staging/usbip/
-
USB ISP116X DRIVER
F: arch/x86/kernel/cpu/mcheck/*
XC2028/3028 TUNER DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
*/
/dts-v1/;
+#include <dt-bindings/interrupt-controller/irq.h>
#include "ste-nomadik-stn8815.dtsi"
/ {
bootargs = "root=/dev/ram0 console=ttyAMA1,115200n8 earlyprintk";
};
- /* This is where the interrupt is routed on the S8815 board */
- external-bus@34000000 {
- ethernet@300 {
- interrupt-parent = <&gpio3>;
- interrupts = <8 0x1>;
- };
- };
-
src@101e0000 {
/* These chrystal drivers are not used on this board */
disable-sxtalo;
cd_default_mode: cd_default {
cd_default_cfg1 {
/* CD input GPIO */
- ste,pins = "GPIO111_H21";
+ pins = "GPIO111_H21";
ste,input = <0>;
};
cd_default_cfg2 {
/* CD GPIO biasing */
- ste,pins = "GPIO112_J21";
+ pins = "GPIO112_J21";
ste,output = <0>;
};
};
};
- ste,pins = "GPIO73_C21", "GPIO74_C20";
+ gpioi2c {
+ gpioi2c_default_mode: gpioi2c_default {
+ gpioi2c_default_cfg {
++ pins = "GPIO73_C21", "GPIO74_C20";
+ ste,input = <0>;
+ };
+ };
+ };
user-led {
user_led_default_mode: user_led_default {
user_led_default_cfg {
- ste,pins = "GPIO2_C5";
+ pins = "GPIO2_C5";
ste,output = <1>;
};
};
user-button {
user_button_default_mode: user_button_default {
user_button_default_cfg {
- ste,pins = "GPIO3_A4";
+ pins = "GPIO3_A4";
ste,input = <0>;
};
};
};
};
+ /* Ethernet */
+ external-bus@34000000 {
+ compatible = "simple-bus";
+ reg = <0x34000000 0x1000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x34000000 0x1000000>;
+ ethernet@300 {
+ compatible = "smsc,lan91c111";
+ reg = <0x300 0x0fd00>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <8 IRQ_TYPE_EDGE_RISING>;
+ };
+ };
+
+ /* GPIO I2C connected to the USB portions of the STw4811 only */
+ gpio-i2c {
+ compatible = "i2c-gpio";
+ gpios = <&gpio2 10 0>, /* sda */
+ <&gpio2 9 0>; /* scl */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpioi2c_default_mode>;
+
+ stw4811@2d {
+ compatible = "st,stw4811-usb";
+ reg = <0x2d>;
+ };
+ };
+
+
+ /* Configure card detect for the uSD slot */
+ amba {
+ mmcsd: sdi@101f6000 {
+ cd-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>;
+ };
+ };
+
/* Custom board node with GPIO pins to active etc */
usb-s8815 {
/* This will bias the MMC/SD card detect line */
uart0 {
uart0_default_mux: uart0_mux {
u0_default_mux {
- ste,function = "u0";
- ste,pins = "u0_a_1";
+ function = "u0";
+ groups = "u0_a_1";
};
};
};
uart1 {
uart1_default_mux: uart1_mux {
u1_default_mux {
- ste,function = "u1";
- ste,pins = "u1_a_1";
+ function = "u1";
+ groups = "u1_a_1";
};
};
};
mmcsd {
mmcsd_default_mux: mmcsd_mux {
mmcsd_default_mux {
- ste,function = "mmcsd";
- ste,pins = "mmcsd_a_1", "mmcsd_b_1";
+ function = "mmcsd";
- groups = "mmcsd_a_1";
++ groups = "mmcsd_a_1", "mmcsd_b_1";
};
};
mmcsd_default_mode: mmcsd_default {
mmcsd_default_cfg1 {
/* MCCLK */
- ste,pins = "GPIO8_B10";
+ pins = "GPIO8_B10";
ste,output = <0>;
};
mmcsd_default_cfg2 {
- /* MCCMDDIR, MCDAT0DIR, MCDAT31DIR */
+ /* MCCMDDIR, MCDAT0DIR, MCDAT31DIR, MCDATDIR2 */
- ste,pins = "GPIO10_C11", "GPIO15_A12",
+ pins = "GPIO10_C11", "GPIO15_A12",
- "GPIO16_C13";
+ "GPIO16_C13", "GPIO23_D15";
ste,output = <1>;
};
mmcsd_default_cfg3 {
/* MCCMD, MCDAT3-0, MCMSFBCLK */
- ste,pins = "GPIO9_A10", "GPIO11_B11",
+ pins = "GPIO9_A10", "GPIO11_B11",
"GPIO12_A11", "GPIO13_C12",
"GPIO14_B12", "GPIO24_C15";
ste,input = <1>;
i2c0 {
i2c0_default_mux: i2c0_mux {
i2c0_default_mux {
- ste,function = "i2c0";
- ste,pins = "i2c0_a_1";
+ function = "i2c0";
+ groups = "i2c0_a_1";
};
};
i2c0_default_mode: i2c0_default {
i2c0_default_cfg {
- ste,pins = "GPIO62_D3", "GPIO63_D2";
+ pins = "GPIO62_D3", "GPIO63_D2";
ste,input = <0>;
};
};
i2c1 {
i2c1_default_mux: i2c1_mux {
i2c1_default_mux {
- ste,function = "i2c1";
- ste,pins = "i2c1_a_1";
+ function = "i2c1";
+ groups = "i2c1_a_1";
};
};
i2c1_default_mode: i2c1_default {
i2c1_default_cfg {
- ste,pins = "GPIO53_L4", "GPIO54_L3";
+ pins = "GPIO53_L4", "GPIO54_L3";
ste,input = <0>;
};
};
};
- i2c2 {
- i2c2_default_mode: i2c2_default {
- i2c2_default_cfg {
- pins = "GPIO73_C21", "GPIO74_C20";
- ste,input = <0>;
- };
- };
- };
};
src: src@101e0000 {
compatible = "stericsson,nomadik-src";
reg = <0x101e0000 0x1000>;
- disable-sxtalo;
- disable-mxtalo;
/*
* MXTAL "Main Chrystal" is a chrystal oscillator @19.2 MHz
};
};
- external-bus@34000000 {
- compatible = "simple-bus";
- reg = <0x34000000 0x1000000>;
- #address-cells = <1>;
- #size-cells = <1>;
- ranges = <0 0x34000000 0x1000000>;
- ethernet@300 {
- compatible = "smsc,lan91c111";
- reg = <0x300 0x0fd00>;
- };
- };
-
/* I2C0 connected to the STw4811 power management chip */
i2c0 {
compatible = "st,nomadik-i2c", "arm,primecell";
};
};
- /* I2C2 connected to the USB portions of the STw4811 only */
- i2c2 {
- compatible = "i2c-gpio";
- gpios = <&gpio2 10 0>, /* sda */
- <&gpio2 9 0>; /* scl */
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_default_mode>;
-
- stw4811@2d {
- compatible = "st,stw4811-usb";
- reg = <0x2d>;
- };
- };
-
amba {
compatible = "arm,amba-bus";
#address-cells = <1>;
bus-width = <4>;
cap-mmc-highspeed;
cap-sd-highspeed;
- cd-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&mmcsd_default_mux>, <&mmcsd_default_mode>;
vmmc-supply = <&vmmc_regulator>;
*/
#include <linux/errno.h>
+ #include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/export.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
+ #include <linux/pinctrl/pinctrl.h>
#include "gpiolib.h"
return ACPI_HANDLE(gc->dev) == data;
}
+ #ifdef CONFIG_PINCTRL
+ /**
+ * acpi_gpiochip_pin_to_gpio_offset() - translates ACPI GPIO to Linux GPIO
+ * @chip: GPIO chip
+ * @pin: ACPI GPIO pin number from GpioIo/GpioInt resource
+ *
+ * Function takes ACPI GpioIo/GpioInt pin number as a parameter and
+ * translates it to a corresponding offset suitable to be passed to a
+ * GPIO controller driver.
+ *
+ * Typically the returned offset is same as @pin, but if the GPIO
+ * controller uses pin controller and the mapping is not contigous the
+ * offset might be different.
+ */
+ static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin)
+ {
+ struct gpio_pin_range *pin_range;
+
+ /* If there are no ranges in this chip, use 1:1 mapping */
+ if (list_empty(&chip->pin_ranges))
+ return pin;
+
+ list_for_each_entry(pin_range, &chip->pin_ranges, node) {
+ const struct pinctrl_gpio_range *range = &pin_range->range;
+ int i;
+
+ if (range->pins) {
+ for (i = 0; i < range->npins; i++) {
+ if (range->pins[i] == pin)
+ return range->base + i - chip->base;
+ }
+ } else {
+ if (pin >= range->pin_base &&
+ pin < range->pin_base + range->npins) {
+ unsigned gpio_base;
+
+ gpio_base = range->base - chip->base;
+ return gpio_base + pin - range->pin_base;
+ }
+ }
+ }
+
+ return -EINVAL;
+ }
+ #else
+ static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip,
+ int pin)
+ {
+ return pin;
+ }
+ #endif
+
/**
* acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API
* @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
struct gpio_chip *chip;
acpi_handle handle;
acpi_status status;
+ int offset;
status = acpi_get_handle(NULL, path, &handle);
if (ACPI_FAILURE(status))
if (!chip)
return ERR_PTR(-ENODEV);
- if (pin < 0 || pin > chip->ngpio)
- return ERR_PTR(-EINVAL);
+ offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
+ if (offset < 0)
+ return ERR_PTR(offset);
- return gpiochip_get_desc(chip, pin);
+ return gpiochip_get_desc(chip, offset);
}
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
}
}
+int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+ const struct acpi_gpio_mapping *gpios)
+{
+ if (adev && gpios) {
+ adev->driver_gpios = gpios;
+ return 0;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
+
+static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
+ const char *name, int index,
+ struct acpi_reference_args *args)
+{
+ const struct acpi_gpio_mapping *gm;
+
+ if (!adev->driver_gpios)
+ return false;
+
+ for (gm = adev->driver_gpios; gm->name; gm++)
+ if (!strcmp(name, gm->name) && gm->data && index < gm->size) {
+ const struct acpi_gpio_params *par = gm->data + index;
+
+ args->adev = adev;
+ args->args[0] = par->crs_entry_index;
+ args->args[1] = par->line_index;
+ args->args[2] = par->active_low;
+ args->nargs = 3;
+ return true;
+ }
+
+ return false;
+}
+
struct acpi_gpio_lookup {
struct acpi_gpio_info info;
int index;
+ int pin_index;
struct gpio_desc *desc;
int n;
};
if (lookup->n++ == lookup->index && !lookup->desc) {
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
+ int pin_index = lookup->pin_index;
+
+ if (pin_index >= agpio->pin_table_length)
+ return 1;
lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
- agpio->pin_table[0]);
+ agpio->pin_table[pin_index]);
lookup->info.gpioint =
agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
- lookup->info.active_low =
- agpio->polarity == ACPI_ACTIVE_LOW;
+
+ /*
+ * ActiveLow is only specified for GpioInt resource. If
+ * GpioIo is used then the only way to set the flag is
+ * to use _DSD "gpios" property.
+ */
+ if (lookup->info.gpioint)
+ lookup->info.active_low =
+ agpio->polarity == ACPI_ACTIVE_LOW;
}
return 1;
/**
* acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
- * @dev: pointer to a device to get GPIO from
+ * @adev: pointer to a ACPI device to get GPIO from
+ * @propname: Property name of the GPIO (optional)
* @index: index of GpioIo/GpioInt resource (starting from %0)
* @info: info pointer to fill in (optional)
*
- * Function goes through ACPI resources for @dev and based on @index looks
+ * Function goes through ACPI resources for @adev and based on @index looks
* up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
* and returns it. @index matches GpioIo/GpioInt resources only so if there
* are total %3 GPIO resources, the index goes from %0 to %2.
*
+ * If @propname is specified the GPIO is looked using device property. In
+ * that case @index is used to select the GPIO entry in the property value
+ * (in case of multiple).
+ *
* If the GPIO cannot be translated or there is an error an ERR_PTR is
* returned.
*
* 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 device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
struct list_head resource_list;
- struct acpi_device *adev;
- acpi_handle handle;
+ bool active_low = false;
int ret;
- if (!dev)
- return ERR_PTR(-EINVAL);
-
- handle = ACPI_HANDLE(dev);
- if (!handle || acpi_bus_get_device(handle, &adev))
+ if (!adev)
return ERR_PTR(-ENODEV);
memset(&lookup, 0, sizeof(lookup));
lookup.index = index;
+ if (propname) {
+ struct acpi_reference_args args;
+
+ dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
+
+ memset(&args, 0, sizeof(args));
+ ret = acpi_dev_get_property_reference(adev, propname,
+ index, &args);
+ if (ret) {
+ bool found = acpi_get_driver_gpio_data(adev, propname,
+ index, &args);
+ if (!found)
+ return ERR_PTR(ret);
+ }
+
+ /*
+ * The property was found and resolved so need to
+ * lookup the GPIO based on returned args instead.
+ */
+ adev = args.adev;
+ if (args.nargs >= 2) {
+ lookup.index = args.args[0];
+ lookup.pin_index = args.args[1];
+ /*
+ * 3rd argument, if present is used to
+ * specify active_low.
+ */
+ if (args.nargs >= 3)
+ active_low = !!args.args[2];
+ }
+
+ dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n",
+ dev_name(&adev->dev), args.nargs,
+ args.args[0], args.args[1], args.args[2]);
+ } else {
+ dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);
+ }
+
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
&lookup);
acpi_dev_free_resource_list(&resource_list);
- if (lookup.desc && info)
+ if (lookup.desc && info) {
*info = lookup.info;
+ if (active_low)
+ info->active_low = active_low;
+ }
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
}
--- /dev/null
- value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
+ /*
+ * Pinctrl GPIO driver for Intel Baytrail
+ * Copyright (c) 2012-2013, Intel Corporation.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/types.h>
+ #include <linux/bitops.h>
+ #include <linux/interrupt.h>
+ #include <linux/gpio.h>
+ #include <linux/acpi.h>
+ #include <linux/platform_device.h>
+ #include <linux/seq_file.h>
+ #include <linux/io.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/pinctrl/pinctrl.h>
+
+ /* memory mapped register offsets */
+ #define BYT_CONF0_REG 0x000
+ #define BYT_CONF1_REG 0x004
+ #define BYT_VAL_REG 0x008
+ #define BYT_DFT_REG 0x00c
+ #define BYT_INT_STAT_REG 0x800
+
+ /* BYT_CONF0_REG register bits */
+ #define BYT_IODEN BIT(31)
+ #define BYT_DIRECT_IRQ_EN BIT(27)
+ #define BYT_TRIG_NEG BIT(26)
+ #define BYT_TRIG_POS BIT(25)
+ #define BYT_TRIG_LVL BIT(24)
+ #define BYT_PULL_STR_SHIFT 9
+ #define BYT_PULL_STR_MASK (3 << BYT_PULL_STR_SHIFT)
+ #define BYT_PULL_STR_2K (0 << BYT_PULL_STR_SHIFT)
+ #define BYT_PULL_STR_10K (1 << BYT_PULL_STR_SHIFT)
+ #define BYT_PULL_STR_20K (2 << BYT_PULL_STR_SHIFT)
+ #define BYT_PULL_STR_40K (3 << BYT_PULL_STR_SHIFT)
+ #define BYT_PULL_ASSIGN_SHIFT 7
+ #define BYT_PULL_ASSIGN_MASK (3 << BYT_PULL_ASSIGN_SHIFT)
+ #define BYT_PULL_ASSIGN_UP (1 << BYT_PULL_ASSIGN_SHIFT)
+ #define BYT_PULL_ASSIGN_DOWN (2 << BYT_PULL_ASSIGN_SHIFT)
+ #define BYT_PIN_MUX 0x07
+
+ /* BYT_VAL_REG register bits */
+ #define BYT_INPUT_EN BIT(2) /* 0: input enabled (active low)*/
+ #define BYT_OUTPUT_EN BIT(1) /* 0: output enabled (active low)*/
+ #define BYT_LEVEL BIT(0)
+
+ #define BYT_DIR_MASK (BIT(1) | BIT(2))
+ #define BYT_TRIG_MASK (BIT(26) | BIT(25) | BIT(24))
+
+ #define BYT_NGPIO_SCORE 102
+ #define BYT_NGPIO_NCORE 28
+ #define BYT_NGPIO_SUS 44
+
+ #define BYT_SCORE_ACPI_UID "1"
+ #define BYT_NCORE_ACPI_UID "2"
+ #define BYT_SUS_ACPI_UID "3"
+
+ /*
+ * Baytrail gpio controller consist of three separate sub-controllers called
+ * SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID.
+ *
+ * GPIO numbering is _not_ ordered meaning that gpio # 0 in ACPI namespace does
+ * _not_ correspond to the first gpio register at controller's gpio base.
+ * There is no logic or pattern in mapping gpio numbers to registers (pads) so
+ * each sub-controller needs to have its own mapping table
+ */
+
+ /* score_pins[gpio_nr] = pad_nr */
+
+ static unsigned const score_pins[BYT_NGPIO_SCORE] = {
+ 85, 89, 93, 96, 99, 102, 98, 101, 34, 37,
+ 36, 38, 39, 35, 40, 84, 62, 61, 64, 59,
+ 54, 56, 60, 55, 63, 57, 51, 50, 53, 47,
+ 52, 49, 48, 43, 46, 41, 45, 42, 58, 44,
+ 95, 105, 70, 68, 67, 66, 69, 71, 65, 72,
+ 86, 90, 88, 92, 103, 77, 79, 83, 78, 81,
+ 80, 82, 13, 12, 15, 14, 17, 18, 19, 16,
+ 2, 1, 0, 4, 6, 7, 9, 8, 33, 32,
+ 31, 30, 29, 27, 25, 28, 26, 23, 21, 20,
+ 24, 22, 5, 3, 10, 11, 106, 87, 91, 104,
+ 97, 100,
+ };
+
+ static unsigned const ncore_pins[BYT_NGPIO_NCORE] = {
+ 19, 18, 17, 20, 21, 22, 24, 25, 23, 16,
+ 14, 15, 12, 26, 27, 1, 4, 8, 11, 0,
+ 3, 6, 10, 13, 2, 5, 9, 7,
+ };
+
+ static unsigned const sus_pins[BYT_NGPIO_SUS] = {
+ 29, 33, 30, 31, 32, 34, 36, 35, 38, 37,
+ 18, 7, 11, 20, 17, 1, 8, 10, 19, 12,
+ 0, 2, 23, 39, 28, 27, 22, 21, 24, 25,
+ 26, 51, 56, 54, 49, 55, 48, 57, 50, 58,
+ 52, 53, 59, 40,
+ };
+
+ static struct pinctrl_gpio_range byt_ranges[] = {
+ {
+ .name = BYT_SCORE_ACPI_UID, /* match with acpi _UID in probe */
+ .npins = BYT_NGPIO_SCORE,
+ .pins = score_pins,
+ },
+ {
+ .name = BYT_NCORE_ACPI_UID,
+ .npins = BYT_NGPIO_NCORE,
+ .pins = ncore_pins,
+ },
+ {
+ .name = BYT_SUS_ACPI_UID,
+ .npins = BYT_NGPIO_SUS,
+ .pins = sus_pins,
+ },
+ {
+ },
+ };
+
+ struct byt_gpio {
+ struct gpio_chip chip;
+ struct platform_device *pdev;
+ spinlock_t lock;
+ void __iomem *reg_base;
+ struct pinctrl_gpio_range *range;
+ };
+
+ #define to_byt_gpio(c) container_of(c, struct byt_gpio, chip)
+
+ static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
+ int reg)
+ {
+ struct byt_gpio *vg = to_byt_gpio(chip);
+ u32 reg_offset;
+
+ if (reg == BYT_INT_STAT_REG)
+ reg_offset = (offset / 32) * 4;
+ else
+ reg_offset = vg->range->pins[offset] * 16;
+
+ return vg->reg_base + reg_offset + reg;
+ }
+
+ static bool is_special_pin(struct byt_gpio *vg, unsigned offset)
+ {
+ /* SCORE pin 92-93 */
+ if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) &&
+ offset >= 92 && offset <= 93)
+ return true;
+
+ /* SUS pin 11-21 */
+ if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) &&
+ offset >= 11 && offset <= 21)
+ return true;
+
+ return false;
+ }
+
+ static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
+ {
+ struct byt_gpio *vg = to_byt_gpio(chip);
+ void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
+ u32 value;
+ bool special;
+
+ /*
+ * In most cases, func pin mux 000 means GPIO function.
+ * But, some pins may have func pin mux 001 represents
+ * GPIO function. Only allow user to export pin with
+ * func pin mux preset as GPIO function by BIOS/FW.
+ */
+ value = readl(reg) & BYT_PIN_MUX;
+ special = is_special_pin(vg, offset);
+ if ((special && value != 1) || (!special && value)) {
+ dev_err(&vg->pdev->dev,
+ "pin %u cannot be used as GPIO.\n", offset);
+ return -EINVAL;
+ }
+
+ pm_runtime_get(&vg->pdev->dev);
+
+ return 0;
+ }
+
+ static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
+ {
+ struct byt_gpio *vg = to_byt_gpio(chip);
+ void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+ u32 value;
+
+ /* clear interrupt triggering */
+ value = readl(reg);
+ value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
+ writel(value, reg);
+
+ pm_runtime_put(&vg->pdev->dev);
+ }
+
+ static int byt_irq_type(struct irq_data *d, unsigned type)
+ {
+ struct byt_gpio *vg = to_byt_gpio(irq_data_get_irq_chip_data(d));
+ u32 offset = irqd_to_hwirq(d);
+ u32 value;
+ unsigned long flags;
+ void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+
+ if (offset >= vg->chip.ngpio)
+ return -EINVAL;
+
+ spin_lock_irqsave(&vg->lock, flags);
+ value = readl(reg);
+
++ WARN(value & BYT_DIRECT_IRQ_EN,
++ "Bad pad config for io mode, force direct_irq_en bit clearing");
++
+ /* For level trigges the BYT_TRIG_POS and BYT_TRIG_NEG bits
+ * are used to indicate high and low level triggering
+ */
- reg_val &= ~BYT_OUTPUT_EN;
++ value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG |
++ BYT_TRIG_LVL);
+
+ switch (type) {
+ case IRQ_TYPE_LEVEL_HIGH:
+ value |= BYT_TRIG_LVL;
+ case IRQ_TYPE_EDGE_RISING:
+ value |= BYT_TRIG_POS;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ value |= BYT_TRIG_LVL;
+ case IRQ_TYPE_EDGE_FALLING:
+ value |= BYT_TRIG_NEG;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
+ break;
+ }
+ writel(value, reg);
+
+ spin_unlock_irqrestore(&vg->lock, flags);
+
+ return 0;
+ }
+
+ static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
+ {
+ void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
+ return readl(reg) & BYT_LEVEL;
+ }
+
+ static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+ {
+ struct byt_gpio *vg = to_byt_gpio(chip);
+ void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
+ unsigned long flags;
+ u32 old_val;
+
+ spin_lock_irqsave(&vg->lock, flags);
+
+ old_val = readl(reg);
+
+ if (value)
+ writel(old_val | BYT_LEVEL, reg);
+ else
+ writel(old_val & ~BYT_LEVEL, reg);
+
+ spin_unlock_irqrestore(&vg->lock, flags);
+ }
+
+ static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+ {
+ struct byt_gpio *vg = to_byt_gpio(chip);
+ void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&vg->lock, flags);
+
+ value = readl(reg) | BYT_DIR_MASK;
+ value &= ~BYT_INPUT_EN; /* active low */
+ writel(value, reg);
+
+ spin_unlock_irqrestore(&vg->lock, flags);
+
+ return 0;
+ }
+
+ static int byt_gpio_direction_output(struct gpio_chip *chip,
+ unsigned gpio, int value)
+ {
+ struct byt_gpio *vg = to_byt_gpio(chip);
+ void __iomem *conf_reg = byt_gpio_reg(chip, gpio, BYT_CONF0_REG);
+ void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG);
+ unsigned long flags;
+ u32 reg_val;
+
+ spin_lock_irqsave(&vg->lock, flags);
+
+ /*
+ * Before making any direction modifications, do a check if gpio
+ * is set for direct IRQ. On baytrail, setting GPIO to output does
+ * not make sense, so let's at least warn the caller before they shoot
+ * themselves in the foot.
+ */
+ WARN(readl(conf_reg) & BYT_DIRECT_IRQ_EN,
+ "Potential Error: Setting GPIO with direct_irq_en to output");
+
+ reg_val = readl(reg) | BYT_DIR_MASK;
++ reg_val &= ~(BYT_OUTPUT_EN | BYT_INPUT_EN);
+
+ if (value)
+ writel(reg_val | BYT_LEVEL, reg);
+ else
+ writel(reg_val & ~BYT_LEVEL, reg);
+
+ spin_unlock_irqrestore(&vg->lock, flags);
+
+ return 0;
+ }
+
+ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+ {
+ struct byt_gpio *vg = to_byt_gpio(chip);
+ int i;
+ unsigned long flags;
+ u32 conf0, val, offs;
+
+ spin_lock_irqsave(&vg->lock, flags);
+
+ for (i = 0; i < vg->chip.ngpio; i++) {
+ const char *pull_str = NULL;
+ const char *pull = NULL;
+ const char *label;
+ offs = vg->range->pins[i] * 16;
+ conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG);
+ val = readl(vg->reg_base + offs + BYT_VAL_REG);
+
+ label = gpiochip_is_requested(chip, i);
+ if (!label)
+ label = "Unrequested";
+
+ switch (conf0 & BYT_PULL_ASSIGN_MASK) {
+ case BYT_PULL_ASSIGN_UP:
+ pull = "up";
+ break;
+ case BYT_PULL_ASSIGN_DOWN:
+ pull = "down";
+ break;
+ }
+
+ switch (conf0 & BYT_PULL_STR_MASK) {
+ case BYT_PULL_STR_2K:
+ pull_str = "2k";
+ break;
+ case BYT_PULL_STR_10K:
+ pull_str = "10k";
+ break;
+ case BYT_PULL_STR_20K:
+ pull_str = "20k";
+ break;
+ case BYT_PULL_STR_40K:
+ pull_str = "40k";
+ break;
+ }
+
+ seq_printf(s,
+ " gpio-%-3d (%-20.20s) %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s",
+ i,
+ label,
+ val & BYT_INPUT_EN ? " " : "in",
+ val & BYT_OUTPUT_EN ? " " : "out",
+ val & BYT_LEVEL ? "hi" : "lo",
+ vg->range->pins[i], offs,
+ conf0 & 0x7,
+ conf0 & BYT_TRIG_NEG ? " fall" : " ",
+ conf0 & BYT_TRIG_POS ? " rise" : " ",
+ conf0 & BYT_TRIG_LVL ? " level" : " ");
+
+ if (pull && pull_str)
+ seq_printf(s, " %-4s %-3s", pull, pull_str);
+ else
+ seq_puts(s, " ");
+
+ if (conf0 & BYT_IODEN)
+ seq_puts(s, " open-drain");
+
+ seq_puts(s, "\n");
+ }
+ spin_unlock_irqrestore(&vg->lock, flags);
+ }
+
+ static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+ {
+ struct irq_data *data = irq_desc_get_irq_data(desc);
+ struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc));
+ struct irq_chip *chip = irq_data_get_irq_chip(data);
+ u32 base, pin, mask;
+ void __iomem *reg;
+ u32 pending;
+ unsigned virq;
+ int looplimit = 0;
+
+ /* check from GPIO controller which pin triggered the interrupt */
+ for (base = 0; base < vg->chip.ngpio; base += 32) {
+
+ reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
+
+ while ((pending = readl(reg))) {
+ pin = __ffs(pending);
+ mask = BIT(pin);
+ /* Clear before handling so we can't lose an edge */
+ writel(mask, reg);
+
+ virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
+ generic_handle_irq(virq);
+
+ /* In case bios or user sets triggering incorretly a pin
+ * might remain in "interrupt triggered" state.
+ */
+ if (looplimit++ > 32) {
+ dev_err(&vg->pdev->dev,
+ "Gpio %d interrupt flood, disabling\n",
+ base + pin);
+
+ reg = byt_gpio_reg(&vg->chip, base + pin,
+ BYT_CONF0_REG);
+ mask = readl(reg);
+ mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS |
+ BYT_TRIG_LVL);
+ writel(mask, reg);
+ mask = readl(reg); /* flush */
+ break;
+ }
+ }
+ }
+ chip->irq_eoi(data);
+ }
+
+ static void byt_irq_unmask(struct irq_data *d)
+ {
+ }
+
+ static void byt_irq_mask(struct irq_data *d)
+ {
+ }
+
+ static struct irq_chip byt_irqchip = {
+ .name = "BYT-GPIO",
+ .irq_mask = byt_irq_mask,
+ .irq_unmask = byt_irq_unmask,
+ .irq_set_type = byt_irq_type,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+ };
+
+ static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
+ {
+ void __iomem *reg;
+ u32 base, value;
+
+ /* clear interrupt status trigger registers */
+ for (base = 0; base < vg->chip.ngpio; base += 32) {
+ reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
+ writel(0xffffffff, reg);
+ /* make sure trigger bits are cleared, if not then a pin
+ might be misconfigured in bios */
+ value = readl(reg);
+ if (value)
+ dev_err(&vg->pdev->dev,
+ "GPIO interrupt error, pins misconfigured\n");
+ }
+ }
+
+ static int byt_gpio_probe(struct platform_device *pdev)
+ {
+ struct byt_gpio *vg;
+ struct gpio_chip *gc;
+ struct resource *mem_rc, *irq_rc;
+ struct device *dev = &pdev->dev;
+ struct acpi_device *acpi_dev;
+ struct pinctrl_gpio_range *range;
+ acpi_handle handle = ACPI_HANDLE(dev);
+ int ret;
+
+ if (acpi_bus_get_device(handle, &acpi_dev))
+ return -ENODEV;
+
+ vg = devm_kzalloc(dev, sizeof(struct byt_gpio), GFP_KERNEL);
+ if (!vg) {
+ dev_err(&pdev->dev, "can't allocate byt_gpio chip data\n");
+ return -ENOMEM;
+ }
+
+ for (range = byt_ranges; range->name; range++) {
+ if (!strcmp(acpi_dev->pnp.unique_id, range->name)) {
+ vg->chip.ngpio = range->npins;
+ vg->range = range;
+ break;
+ }
+ }
+
+ if (!vg->chip.ngpio || !vg->range)
+ return -ENODEV;
+
+ vg->pdev = pdev;
+ platform_set_drvdata(pdev, vg);
+
+ mem_rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ vg->reg_base = devm_ioremap_resource(dev, mem_rc);
+ if (IS_ERR(vg->reg_base))
+ return PTR_ERR(vg->reg_base);
+
+ spin_lock_init(&vg->lock);
+
+ gc = &vg->chip;
+ gc->label = dev_name(&pdev->dev);
+ gc->owner = THIS_MODULE;
+ gc->request = byt_gpio_request;
+ gc->free = byt_gpio_free;
+ gc->direction_input = byt_gpio_direction_input;
+ gc->direction_output = byt_gpio_direction_output;
+ gc->get = byt_gpio_get;
+ gc->set = byt_gpio_set;
+ gc->dbg_show = byt_gpio_dbg_show;
+ gc->base = -1;
+ gc->can_sleep = false;
+ gc->dev = dev;
+
+ ret = gpiochip_add(gc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
+ return ret;
+ }
+
+ /* set up interrupts */
+ irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (irq_rc && irq_rc->start) {
+ byt_gpio_irq_init_hw(vg);
+ ret = gpiochip_irqchip_add(gc, &byt_irqchip, 0,
+ handle_simple_irq, IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(dev, "failed to add irqchip\n");
+ gpiochip_remove(gc);
+ return ret;
+ }
+
+ gpiochip_set_chained_irqchip(gc, &byt_irqchip,
+ (unsigned)irq_rc->start,
+ byt_gpio_irq_handler);
+ }
+
+ pm_runtime_enable(dev);
+
+ return 0;
+ }
+
+ static int byt_gpio_runtime_suspend(struct device *dev)
+ {
+ return 0;
+ }
+
+ static int byt_gpio_runtime_resume(struct device *dev)
+ {
+ return 0;
+ }
+
+ static const struct dev_pm_ops byt_gpio_pm_ops = {
+ .runtime_suspend = byt_gpio_runtime_suspend,
+ .runtime_resume = byt_gpio_runtime_resume,
+ };
+
+ static const struct acpi_device_id byt_gpio_acpi_match[] = {
+ { "INT33B2", 0 },
+ { "INT33FC", 0 },
+ { }
+ };
+ MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match);
+
+ static int byt_gpio_remove(struct platform_device *pdev)
+ {
+ struct byt_gpio *vg = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+ gpiochip_remove(&vg->chip);
+
+ return 0;
+ }
+
+ static struct platform_driver byt_gpio_driver = {
+ .probe = byt_gpio_probe,
+ .remove = byt_gpio_remove,
+ .driver = {
+ .name = "byt_gpio",
+ .owner = THIS_MODULE,
+ .pm = &byt_gpio_pm_ops,
+ .acpi_match_table = ACPI_PTR(byt_gpio_acpi_match),
+ },
+ };
+
+ static int __init byt_gpio_init(void)
+ {
+ return platform_driver_register(&byt_gpio_driver);
+ }
+ subsys_initcall(byt_gpio_init);
+
+ static void __exit byt_gpio_exit(void)
+ {
+ platform_driver_unregister(&byt_gpio_driver);
+ }
+ module_exit(byt_gpio_exit);